mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
WIP: make attachment work
This commit is contained in:
parent
4a9ac91e5f
commit
0ea1ed15e7
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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? {
|
||||
|
@ -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>
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user