diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index bfb226d002..489daf56df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -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 { + 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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index c0527b4dc2..c89314b46e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -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); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 4954d7c4e9..dd39bb9315 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -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 list = getAttachment(cursor); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 91cec2c2fd..38c7b473b4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -89,7 +89,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, override fun persistAttachments(messageId: Long, attachments: List): List { val database = DatabaseFactory.getAttachmentDatabase(context) - val databaseAttachments = attachments.map { it.toDatabaseAttachment() } + val databaseAttachments = attachments.mapNotNull { it.toSignalAttachment() } return database.insertAttachments(messageId, databaseAttachments) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionJobDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionJobDatabase.kt index 38975e2ffd..d2fb898796 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionJobDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionJobDatabase.kt @@ -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? { diff --git a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt index 758710840b..61013de273 100644 --- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt +++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt @@ -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 fun getMessageBodyFor(messageID: Long): String + fun getAttachmentIDsFor(messageID: Long): List + } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt index e507be5d65..d0426f7170 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt @@ -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) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt index 4ce92c1153..33701d6b50 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/MessageSendJob.kt @@ -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) } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt index 3e21e8303c..d2afce1564 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Attachment.kt @@ -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) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index 55bbd6afa9..0a663e595c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -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