This commit is contained in:
Ryan ZHAO 2020-12-07 15:26:52 +11:00
commit e2e78ce5fb
13 changed files with 200 additions and 15 deletions

View file

@ -12,6 +12,7 @@ public class DatabaseAttachment extends Attachment {
private final long mmsId;
private final boolean hasData;
private final boolean hasThumbnail;
private boolean isUploaded = false;
public DatabaseAttachment(AttachmentId attachmentId, long mmsId,
boolean hasData, boolean hasThumbnail,
@ -75,4 +76,12 @@ public class DatabaseAttachment extends Attachment {
public boolean hasThumbnail() {
return hasThumbnail;
}
public boolean isUploaded() {
return isUploaded;
}
public void setUploaded(boolean uploaded) {
isUploaded = uploaded;
}
}

View file

@ -0,0 +1,52 @@
package org.thoughtcrime.securesms.attachments
import android.content.Context
import com.google.protobuf.ByteString
import org.session.libsession.database.dto.DatabaseAttachmentDTO
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.util.MediaUtil
class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), MessageDataProvider {
override fun getAttachment(uniqueID: String): DatabaseAttachmentDTO? {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
val uniqueID = uniqueID.toLongOrNull() ?: return null
val attachmentID = AttachmentId(0, uniqueID)
val databaseAttachment = attachmentDatabase.getAttachment(attachmentID) ?: return null
return databaseAttachment.toDTO()
}
}
// Extension to DatabaseAttachment class
fun DatabaseAttachment.toDTO(): DatabaseAttachmentDTO {
var databaseAttachmentDTO = DatabaseAttachmentDTO()
databaseAttachmentDTO.contentType = this.contentType
databaseAttachmentDTO.fileName = this.fileName
databaseAttachmentDTO.caption = this.caption
databaseAttachmentDTO.size = this.size.toInt()
databaseAttachmentDTO.key = ByteString.copyFrom(this.key?.toByteArray())
databaseAttachmentDTO.digest = ByteString.copyFrom(this.digest)
databaseAttachmentDTO.flags = if (this.isVoiceNote) SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE.number else 0
databaseAttachmentDTO.url = this.url
if (this.shouldHaveImageSize()) {
databaseAttachmentDTO.shouldHaveImageSize = true
databaseAttachmentDTO.width = this.width
databaseAttachmentDTO.height = this.height
}
return databaseAttachmentDTO
}
fun DatabaseAttachment.shouldHaveImageSize(): Boolean {
return (MediaUtil.isVideo(this) || MediaUtil.isImage(this) || MediaUtil.isGif(this));
}

View file

@ -497,6 +497,7 @@ public class AttachmentDatabase extends Database {
database.update(TABLE_NAME, values, PART_ID_WHERE, ((DatabaseAttachment)attachment).getAttachmentId().toStrings());
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId));
((DatabaseAttachment) attachment).setUploaded(true);
}
public void setTransferState(long messageId, @NonNull Attachment attachment, int transferState) {

View file

@ -0,0 +1,9 @@
package org.session.libsession.database
import org.session.libsession.database.dto.DatabaseAttachmentDTO
interface MessageDataProvider {
fun getAttachment(uniqueID: String): DatabaseAttachmentDTO?
}

View file

@ -0,0 +1,73 @@
package org.session.libsession.database.dto
import android.util.Size
import com.google.protobuf.ByteString
import org.session.libsignal.service.internal.push.SignalServiceProtos
import kotlin.math.round
class DatabaseAttachmentDTO {
var contentType: String? = null
var fileName: String? = null
var url: String? = null
var caption: String? = null
var size: Int = 0
var key: ByteString? = null
var digest: ByteString? = null
var flags: Int = 0
var width: Int = 0
var height: Int = 0
val isVoiceNote: Boolean = false
var shouldHaveImageSize: Boolean = false
val isUploaded: Boolean = false
fun toProto(): SignalServiceProtos.AttachmentPointer? {
val builder = org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer.newBuilder()
builder.contentType = this.contentType
if (!this.fileName.isNullOrEmpty()) {
builder.fileName = this.fileName
}
if (!this.caption.isNullOrEmpty()) {
builder.caption = this.caption
}
builder.size = this.size
builder.key = this.key
builder.digest = this.digest
builder.flags = if (this.isVoiceNote) org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE.number else 0
//TODO I did copy the behavior of iOS below, not sure if that's relevant here...
if (this.shouldHaveImageSize) {
if (this.width < kotlin.Int.MAX_VALUE && this.height < kotlin.Int.MAX_VALUE) {
val imageSize: Size = Size(this.width, this.height)
val imageWidth = round(imageSize.width.toDouble())
val imageHeight = round(imageSize.height.toDouble())
if (imageWidth > 0 && imageHeight > 0) {
builder.width = imageWidth.toInt()
builder.height = imageHeight.toInt()
}
}
}
builder.url = this.url
try {
return builder.build()
} catch (e: Exception) {
return null
}
}
}

View file

@ -12,7 +12,7 @@ abstract class Message {
var sender: String? = null
var groupPublicKey: String? = null
var openGroupServerMessageID: Long? = null
val ttl: Long = 2 * 24 * 60 * 60 * 1000
open val ttl: Long = 2 * 24 * 60 * 60 * 1000
// validation
open fun isValid(): Boolean {

View file

@ -5,11 +5,11 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
class TypingIndicator() : ControlMessage() {
override val ttl: Long = 30 * 1000
companion object {
const val TAG = "TypingIndicator"
//val ttl: 30 * 1000 //TODO
fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator? {
val typingIndicatorProto = proto.typingMessage ?: return null
val kind = Kind.fromProto(typingIndicatorProto.action)

View file

@ -2,6 +2,7 @@ package org.session.libsession.messaging.messages.visible
import android.util.Size
import android.webkit.MimeTypeMap
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.internal.push.SignalServiceProtos
import java.io.File
@ -65,4 +66,8 @@ class Attachment {
fun toProto(): SignalServiceProtos.AttachmentPointer? {
TODO("Not implemented")
}
override fun toProto(messageDataProvider: MessageDataProvider): SignalServiceProtos.AttachmentPointer? {
TODO("Not implemented")
}
}

View file

@ -1,5 +1,6 @@
package org.session.libsession.messaging.messages.visible
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.internal.push.SignalServiceProtos
class Contact() {
@ -13,4 +14,8 @@ class Contact() {
fun toProto(): SignalServiceProtos.DataMessage.Contact? {
TODO("Not yet implemented")
}
override fun toProto(messageDataProvider: MessageDataProvider): SignalServiceProtos.DataMessage.Contact? {
TODO("Not yet implemented")
}
}

View file

@ -1,5 +1,7 @@
package org.session.libsession.messaging.messages.visible
import android.content.Context
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.libsignal.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
@ -43,7 +45,8 @@ class LinkPreview() {
title?.let { linkPreviewProto.title = title }
val attachmentID = attachmentID
attachmentID?.let {
//TODO database stuff
val attachmentProto = messageDataProvider.getAttachment(attachmentID)
attachmentProto?.let { linkPreviewProto.image = attachmentProto.toProto() }
}
// Build
try {

View file

@ -1,6 +1,7 @@
package org.session.libsession.messaging.messages.visible
import com.google.protobuf.ByteString
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.libsignal.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
@ -56,4 +57,8 @@ class Profile() {
return null
}
}
override fun toProto(messageDataProvider: MessageDataProvider): SignalServiceProtos.DataMessage? {
return toProto()
}
}

View file

@ -1,5 +1,7 @@
package org.session.libsession.messaging.messages.visible
import com.goterl.lazycode.lazysodium.BuildConfig
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.libsignal.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
@ -29,7 +31,6 @@ class Quote() {
this.attachmentID = attachmentID
}
// validation
fun isValid(): Boolean {
return (timestamp != null && publicKey != null)
@ -46,7 +47,7 @@ class Quote() {
quoteProto.id = timestamp
quoteProto.author = publicKey
text?.let { quoteProto.text = text }
addAttachmentsIfNeeded(quoteProto)
addAttachmentsIfNeeded(quoteProto, messageDataProvider)
// Build
try {
return quoteProto.build()
@ -56,12 +57,25 @@ class Quote() {
}
}
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder) {
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder, messageDataProvider: MessageDataProvider) {
val attachmentID = attachmentID ?: return
//TODO databas stuff
val attachmentProto = messageDataProvider.getAttachment(attachmentID)
if (attachmentProto == null) {
Log.w(TAG, "Ignoring invalid attachment for quoted message.")
return
}
if (!attachmentProto.isUploaded) {
if (BuildConfig.DEBUG) {
//TODO equivalent to iOS's preconditionFailure
Log.d(TAG,"Sending a message before all associated attachments have been uploaded.")
return
}
}
val quotedAttachmentProto = SignalServiceProtos.DataMessage.Quote.QuotedAttachment.newBuilder()
//TODO more database related stuff
//quotedAttachmentProto.contentType =
quotedAttachmentProto.contentType = attachmentProto.contentType
val fileName = attachmentProto.fileName
fileName?.let { quotedAttachmentProto.fileName = fileName }
quotedAttachmentProto.thumbnail = attachmentProto.toProto()
try {
quoteProto.addAttachments(quotedAttachmentProto.build())
} catch (e: Exception) {

View file

@ -1,6 +1,10 @@
package org.session.libsession.messaging.messages.visible
import com.goterl.lazycode.lazysodium.BuildConfig
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.messages.Message
import org.session.libsignal.libsignal.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
@ -47,7 +51,7 @@ class VisibleMessage : Message() {
return false
}
override fun toProto(): SignalServiceProtos.Content? {
fun toProto(): SignalServiceProtos.Content? {
val proto = SignalServiceProtos.Content.newBuilder()
var attachmentIDs = this.attachmentIDs
val dataMessage: SignalServiceProtos.DataMessage.Builder
@ -86,9 +90,15 @@ class VisibleMessage : Message() {
}
}
//Attachments
// TODO I'm blocking on that one...
//swift: let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) }
val attachments = attachmentIDs.mapNotNull { messageDataProvider.getAttachment(it) }
if (!attachments.all { it.isUploaded }) {
if (BuildConfig.DEBUG) {
//TODO equivalent to iOS's preconditionFailure
Log.d(TAG,"Sending a message before all associated attachments have been uploaded.")
}
}
val attachmentProtos = attachments.mapNotNull { it.toProto() }
dataMessage.addAllAttachments(attachmentProtos)
// TODO Contact
// Build
try {
@ -99,5 +109,4 @@ class VisibleMessage : Message() {
return null
}
}
}