WIP: make attachment work

This commit is contained in:
Ryan ZHAO 2021-03-02 17:22:56 +11:00
parent 4a9ac91e5f
commit 0ea1ed15e7
10 changed files with 52 additions and 38 deletions

View File

@ -6,6 +6,7 @@ import org.greenrobot.eventbus.EventBus
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.messages.SignalServiceAttachment
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
@ -51,12 +52,6 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
attachmentDatabase.setTransferState(messageID, AttachmentId(attachmentId, 0), attachmentState.value)
}
@Throws(Exception::class)
override fun uploadAttachment(attachmentId: Long) {
val attachmentUploadJob = AttachmentUploadJob(AttachmentId(attachmentId, 0), null)
attachmentUploadJob.onRun()
}
override fun getMessageForQuote(timestamp: Long, author: Address): Long? {
val messagingDatabase = DatabaseFactory.getMmsSmsDatabase(context)
return messagingDatabase.getMessageFor(timestamp, author)?.id
@ -72,6 +67,12 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return messagingDatabase.getMessage(messageID).body
}
override fun getAttachmentIDsFor(messageID: Long): List<Long> {
return DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(messageID).map {
it.attachmentId.rowId
}
}
override fun insertAttachment(messageId: Long, attachmentId: Long, stream: InputStream) {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
attachmentDatabase.insertAttachmentsForPlaceholder(messageId, AttachmentId(attachmentId, 0), stream)
@ -83,6 +84,14 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return smsDatabase.isOutgoingMessage(timestamp) || mmsDatabase.isOutgoingMessage(timestamp)
}
override fun updateAttachmentAfterUploadSucceeded(attachmentId: Long, uploadResult: DotNetAPI.UploadResult) {
TODO("Not yet implemented")
}
override fun updateAttachmentAfterUploadFailed(attachmentId: Long) {
TODO("Not yet implemented")
}
override fun getMessageID(serverID: Long): Long? {
val openGroupMessagingDatabase = DatabaseFactory.getLokiMessageDatabase(context)
return openGroupMessagingDatabase.getMessageID(serverID)
@ -93,6 +102,11 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
messagingDatabase.deleteMessage(messageID)
}
override fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment? {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
return attachmentDatabase.getAttachment(AttachmentId(attachmentId, 0))
}
}
fun DatabaseAttachment.toAttachmentPointer(): SessionServiceAttachmentPointer {

View File

@ -1806,7 +1806,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else {
allocatedThreadId = threadId;
}
DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMessage, allocatedThreadId, false, ()->fragment.releaseOutgoingMessage(id));
message.setId(DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMessage, allocatedThreadId, false, ()->fragment.releaseOutgoingMessage(id)));
MessageSender.send(message, recipient.getAddress(), attachments, quote, linkPreview.orNull());
sendComplete(allocatedThreadId);
} catch (MmsException e) {
@ -1843,7 +1843,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else {
allocatedThreadId = threadId;
}
DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(allocatedThreadId, outgoingTextMessage, false, message.getSentTimestamp(), ()->fragment.releaseOutgoingMessage(id));
message.setId(DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(allocatedThreadId, outgoingTextMessage, false, message.getSentTimestamp(), ()->fragment.releaseOutgoingMessage(id)));
MessageSender.send(message, recipient.getAddress());
sendComplete(allocatedThreadId);

View File

@ -121,6 +121,7 @@ public class AttachmentDatabase extends Database {
static final String AUDIO_DURATION = "audio_duration"; // Duration of the audio track in milliseconds.
private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?";
private static final String ROW_ID_WHERE = ROW_ID + " = ?";
private static final String PART_AUDIO_ONLY_WHERE = CONTENT_TYPE + " LIKE \"audio/%\"";
private static final String[] PROJECTION = new String[] {ROW_ID,
@ -221,7 +222,7 @@ public class AttachmentDatabase extends Database {
Cursor cursor = null;
try {
cursor = database.query(TABLE_NAME, PROJECTION, PART_ID_WHERE, attachmentId.toStrings(), null, null, null);
cursor = database.query(TABLE_NAME, PROJECTION, ROW_ID_WHERE, new String[]{String.valueOf(attachmentId.getRowId())}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
List<DatabaseAttachment> list = getAttachment(cursor);

View File

@ -89,7 +89,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun persistAttachments(messageId: Long, attachments: List<Attachment>): List<Long> {
val database = DatabaseFactory.getAttachmentDatabase(context)
val databaseAttachments = attachments.map { it.toDatabaseAttachment() }
val databaseAttachments = attachments.mapNotNull { it.toSignalAttachment() }
return database.insertAttachments(messageId, databaseAttachments)
}

View File

@ -22,12 +22,12 @@ class SessionJobDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
fun persistJob(job: Job) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(2)
val contentValues = ContentValues()
contentValues.put(jobID, job.id)
contentValues.put(jobType, job.getFactoryKey())
contentValues.put(failureCount, job.failureCount)
contentValues.put(serializedData, SessionJobHelper.dataSerializer.serialize(job.serialize()))
database.insertOrUpdate(sessionJobTable, contentValues, "$jobID = ?", arrayOf(jobID.toString()))
database.insertOrUpdate(sessionJobTable, contentValues, "$jobID = ?", arrayOf(jobID))
}
fun markJobAsSucceeded(job: Job) {
@ -51,7 +51,7 @@ class SessionJobDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
database.getAll(sessionJobTable, "$jobType = ?", arrayOf(AttachmentUploadJob.KEY)) { cursor ->
result.add(jobFromCursor(cursor) as AttachmentUploadJob)
}
return result.first { job -> job.attachmentID == attachmentID }
return result.firstOrNull { job -> job.attachmentID == attachmentID }
}
fun getMessageSendJob(messageSendJobID: String): MessageSendJob? {

View File

@ -1,10 +1,8 @@
package org.session.libsession.database
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachmentPointer
import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachmentStream
import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.messages.SignalServiceAttachmentStream
import java.io.InputStream
@ -14,6 +12,8 @@ interface MessageDataProvider {
fun getMessageID(serverID: Long): Long?
fun deleteMessage(messageID: Long)
fun getDatabaseAttachment(attachmentId: Long): DatabaseAttachment?
fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream?
fun getAttachmentPointer(attachmentId: Long): SessionServiceAttachmentPointer?
@ -26,12 +26,14 @@ interface MessageDataProvider {
fun isOutgoingMessage(timestamp: Long): Boolean
@Throws(Exception::class)
fun uploadAttachment(attachmentId: Long)
fun updateAttachmentAfterUploadSucceeded(attachmentId: Long, uploadResult: DotNetAPI.UploadResult)
fun updateAttachmentAfterUploadFailed(attachmentId: Long)
// Quotes
fun getMessageForQuote(timestamp: Long, author: Address): Long?
fun getAttachmentsAndLinkPreviewFor(messageID: Long): List<Attachment>
fun getMessageBodyFor(messageID: Long): String
fun getAttachmentIDsFor(messageID: Long): List<Long>
}

View File

@ -58,7 +58,8 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
val attachmentData = PushAttachmentData(attachmentStream.contentType, attachmentStream.inputStream, ciphertextLength, outputStreamFactory, attachmentStream.listener)
FileServerAPI.shared.uploadAttachment(server, attachmentData)
val uploadResult = FileServerAPI.shared.uploadAttachment(server, attachmentData)
handleSuccess(uploadResult)
} catch (e: java.lang.Exception) {
if (e is Error && e == Error.NoAttachment) {
@ -71,11 +72,11 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
}
}
private fun handleSuccess() {
private fun handleSuccess(uploadResult: DotNetAPI.UploadResult) {
Log.w(TAG, "Attachment uploaded successfully.")
delegate?.handleJobSucceeded(this)
//TODO: handle success in database
MessagingConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID)
//TODO interaction stuff, not sure how to deal with that
}
private fun handlePermanentFailure(e: Exception) {

View File

@ -32,13 +32,13 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
val message = message as? VisibleMessage
message?.let {
if(!messageDataProvider.isOutgoingMessage(message.sentTimestamp!!)) return // The message has been deleted
val attachments = message.attachmentIDs.map { messageDataProvider.getAttachmentStream(it) }.filterNotNull()
val attachmentsToUpload = attachments.filter { !it.isUploaded }
val attachments = message.attachmentIDs.map { messageDataProvider.getDatabaseAttachment(it) }.filterNotNull()
val attachmentsToUpload = attachments.filter { it.url.isNullOrEmpty() }
attachmentsToUpload.forEach {
if(MessagingConfiguration.shared.storage.getAttachmentUploadJob(it.attachmentId) != null) {
if (MessagingConfiguration.shared.storage.getAttachmentUploadJob(it.attachmentId.rowId) != null) {
// Wait for it to finish
} else {
val job = AttachmentUploadJob(it.attachmentId, message.threadID!!.toString(), message, id!!)
val job = AttachmentUploadJob(it.attachmentId.rowId, message.threadID!!.toString(), message, id!!)
JobQueue.shared.add(job)
}
}

View File

@ -2,8 +2,9 @@ package org.session.libsession.messaging.messages.visible
import android.util.Size
import android.webkit.MimeTypeMap
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
import org.session.libsignal.service.internal.push.SignalServiceProtos
import java.io.File
@ -66,8 +67,9 @@ class Attachment {
TODO("Not implemented")
}
fun toDatabaseAttachment(): org.session.libsession.messaging.sending_receiving.attachments.Attachment {
return DatabaseAttachment(null, 0, true, true, contentType, 0,
fun toSignalAttachment(): SignalAttachment? {
if (!isValid()) return null
return DatabaseAttachment(null, 0, false, false, contentType, 0,
sizeInBytes?.toLong() ?: 0, fileName, null, key.toString(), null, digest, null, kind == Kind.VOICE_MESSAGE,
size?.width ?: 0, size?.height ?: 0, false, caption, url)
}

View File

@ -74,8 +74,7 @@ object MessageSender {
attachment.size = Size(signalAttachment.width, signalAttachment.height)
attachments.add(attachment)
}
val attachmentIDs = MessagingConfiguration.shared.storage.persistAttachments(message.id
?: 0, attachments)
val attachmentIDs = MessagingConfiguration.shared.messageDataProvider.getAttachmentIDsFor(message.id!!)
message.attachmentIDs.addAll(attachmentIDs)
}
@ -94,7 +93,6 @@ object MessageSender {
val storage = MessagingConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()
val preconditionFailure = Exception("Destination should not be open groups!")
var snodeMessage: SnodeMessage? = null
// Set the timestamp, sender and recipient
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
message.sender = userPublicKey
@ -109,7 +107,7 @@ object MessageSender {
fun handleFailure(error: Exception) {
handleFailedMessageSend(message, error)
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
//TODO Notify user for send failure
SnodeConfiguration.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!)
}
deferred.reject(error)
}
@ -142,9 +140,6 @@ object MessageSender {
// Serialize the protobuf
val plaintext = proto.toByteArray()
// Encrypt the serialized protobuf
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
//TODO Notify user for encrypting message
}
val ciphertext: ByteArray
when (destination) {
is Destination.Contact -> ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, destination.publicKey)
@ -178,7 +173,7 @@ object MessageSender {
val timestamp = System.currentTimeMillis()
val nonce = ProofOfWork.calculate(base64EncodedData, recipient, timestamp, message.ttl.toInt()) ?: throw Error.ProofOfWorkCalculationFailed
// Send the result
snodeMessage = SnodeMessage(recipient, base64EncodedData, message.ttl, timestamp, nonce)
val snodeMessage = SnodeMessage(recipient, base64EncodedData, message.ttl, timestamp, nonce)
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
SnodeConfiguration.shared.broadcaster.broadcast("sendingMessage", message.sentTimestamp!!)
}
@ -299,7 +294,6 @@ object MessageSender {
fun handleFailedMessageSend(message: Message, error: Exception) {
val storage = MessagingConfiguration.shared.storage
storage.setErrorMessage(message.sentTimestamp!!, message.sender!!, error)
SnodeConfiguration.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!)
}
// Convenience