diff --git a/app/src/main/java/tech/relaycorp/letro/di/AwalaModule.kt b/app/src/main/java/tech/relaycorp/letro/di/AwalaModule.kt index 1cd4339c..5ce34155 100644 --- a/app/src/main/java/tech/relaycorp/letro/di/AwalaModule.kt +++ b/app/src/main/java/tech/relaycorp/letro/di/AwalaModule.kt @@ -13,6 +13,8 @@ import tech.relaycorp.letro.awala.message.MessageType import tech.relaycorp.letro.awala.processor.AwalaMessageProcessor import tech.relaycorp.letro.awala.processor.AwalaMessageProcessorImpl import tech.relaycorp.letro.awala.processor.UnknownMessageProcessor +import tech.relaycorp.letro.messages.processor.NewConversationProcessor +import tech.relaycorp.letro.messages.processor.NewMessageProcessor import tech.relaycorp.letro.onboarding.registration.processor.RegistrationMessageProcessor import tech.relaycorp.letro.pairing.processor.ContactPairingAuthorizationProcessor import tech.relaycorp.letro.pairing.processor.ContactPairingMatchProcessor @@ -27,12 +29,16 @@ object AwalaModule { registrationMessageProcessor: RegistrationMessageProcessor, contactPairingMatchProcessor: ContactPairingMatchProcessor, contactPairingAuthorizationProcessor: ContactPairingAuthorizationProcessor, + newConversationProcessor: NewConversationProcessor, + newMessageProcessor: NewMessageProcessor, unknownMessageProcessor: UnknownMessageProcessor, ): AwalaMessageProcessor { val processors = mapOf( MessageType.AccountCreationCompleted to registrationMessageProcessor, MessageType.ContactPairingMatch to contactPairingMatchProcessor, MessageType.ContactPairingAuthorization to contactPairingAuthorizationProcessor, + MessageType.NewConversation to newConversationProcessor, + MessageType.NewMessage to newMessageProcessor, MessageType.Unknown to unknownMessageProcessor, ) return AwalaMessageProcessorImpl(processors) diff --git a/app/src/main/java/tech/relaycorp/letro/di/ConversationsModule.kt b/app/src/main/java/tech/relaycorp/letro/di/ConversationsModule.kt index 9d31a87c..e86e5d80 100644 --- a/app/src/main/java/tech/relaycorp/letro/di/ConversationsModule.kt +++ b/app/src/main/java/tech/relaycorp/letro/di/ConversationsModule.kt @@ -9,8 +9,16 @@ import tech.relaycorp.letro.messages.converter.ExtendedConversationConverter import tech.relaycorp.letro.messages.converter.ExtendedConversationConverterImpl import tech.relaycorp.letro.messages.converter.MessageTimestampConverter import tech.relaycorp.letro.messages.converter.MessageTimestampConverterImpl +import tech.relaycorp.letro.messages.parser.NewConversationMessageParser +import tech.relaycorp.letro.messages.parser.NewConversationMessageParserImpl +import tech.relaycorp.letro.messages.parser.NewMessageMessageParser +import tech.relaycorp.letro.messages.parser.NewMessageMessageParserImpl import tech.relaycorp.letro.messages.parser.OutgoingConversationMessageEncoder import tech.relaycorp.letro.messages.parser.OutgoingConversationMessageEncoderImpl +import tech.relaycorp.letro.messages.processor.NewConversationProcessor +import tech.relaycorp.letro.messages.processor.NewConversationProcessorImpl +import tech.relaycorp.letro.messages.processor.NewMessageProcessor +import tech.relaycorp.letro.messages.processor.NewMessageProcessorImpl import tech.relaycorp.letro.messages.repository.ConversationsRepository import tech.relaycorp.letro.messages.repository.ConversationsRepositoryImpl import tech.relaycorp.letro.messages.storage.ConversationsDao @@ -56,5 +64,25 @@ object ConversationsModule { fun bindOutgoingConversationMessageEncoder( impl: OutgoingConversationMessageEncoderImpl, ): OutgoingConversationMessageEncoder + + @Binds + fun bindNewConversationProcessor( + impl: NewConversationProcessorImpl, + ): NewConversationProcessor + + @Binds + fun bindNewConversationParser( + imp: NewConversationMessageParserImpl, + ): NewConversationMessageParser + + @Binds + fun bindNewMessageProcessor( + impl: NewMessageProcessorImpl, + ): NewMessageProcessor + + @Binds + fun bindNewMessageParser( + impl: NewMessageMessageParserImpl, + ): NewMessageMessageParser } } diff --git a/app/src/main/java/tech/relaycorp/letro/messages/dto/NewConversationIncomingMessage.kt b/app/src/main/java/tech/relaycorp/letro/messages/dto/NewConversationIncomingMessage.kt new file mode 100644 index 00000000..ca42f0c3 --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/dto/NewConversationIncomingMessage.kt @@ -0,0 +1,18 @@ +package tech.relaycorp.letro.messages.dto + +import tech.relaycorp.letro.awala.message.AwalaIncomingMessage +import tech.relaycorp.letro.awala.message.MessageType +import tech.relaycorp.letro.messages.storage.entity.Conversation +import tech.relaycorp.letro.messages.storage.entity.Message + +data class NewConversationIncomingMessageContent( + val conversation: Conversation, + val message: Message, +) + +data class NewConversationIncomingMessage( + override val content: NewConversationIncomingMessageContent, +) : AwalaIncomingMessage { + override val type: MessageType + get() = MessageType.NewConversation +} diff --git a/app/src/main/java/tech/relaycorp/letro/messages/dto/NewMessageIncomingMessage.kt b/app/src/main/java/tech/relaycorp/letro/messages/dto/NewMessageIncomingMessage.kt new file mode 100644 index 00000000..095b835b --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/dto/NewMessageIncomingMessage.kt @@ -0,0 +1,12 @@ +package tech.relaycorp.letro.messages.dto + +import tech.relaycorp.letro.awala.message.AwalaIncomingMessage +import tech.relaycorp.letro.awala.message.MessageType +import tech.relaycorp.letro.messages.storage.entity.Message + +data class NewMessageIncomingMessage( + override val content: Message, +) : AwalaIncomingMessage { + override val type: MessageType + get() = MessageType.NewMessage +} diff --git a/app/src/main/java/tech/relaycorp/letro/messages/parser/NewConversationMessageParser.kt b/app/src/main/java/tech/relaycorp/letro/messages/parser/NewConversationMessageParser.kt new file mode 100644 index 00000000..bd5247bc --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/parser/NewConversationMessageParser.kt @@ -0,0 +1,33 @@ +package tech.relaycorp.letro.messages.parser + +import tech.relaycorp.letro.awala.parser.AwalaMessageParser +import tech.relaycorp.letro.messages.dto.NewConversationIncomingMessage +import tech.relaycorp.letro.messages.dto.NewConversationIncomingMessageContent +import tech.relaycorp.letro.messages.storage.entity.Conversation +import java.util.UUID +import javax.inject.Inject + +interface NewConversationMessageParser : AwalaMessageParser + +class NewConversationMessageParserImpl @Inject constructor() : NewConversationMessageParser { + + override fun parse(content: ByteArray): NewConversationIncomingMessage { + val conversation = mockConversation() // TODO: parse conversation + val message = mockMessage(conversation.conversationId) + return NewConversationIncomingMessage( + content = NewConversationIncomingMessageContent( + conversation = conversation, + message = message, + ), + ) + } + + private fun mockConversation() = Conversation( + ownerVeraId = "ff@cuppa.fans", + contactVeraId = "ff@applepie.rocks", + subject = "Test subject", + conversationId = MOCK_CONVERSATION_ID, + ) +} + +private val MOCK_CONVERSATION_ID = UUID.randomUUID() diff --git a/app/src/main/java/tech/relaycorp/letro/messages/parser/NewMessageMessageParser.kt b/app/src/main/java/tech/relaycorp/letro/messages/parser/NewMessageMessageParser.kt new file mode 100644 index 00000000..315aeb03 --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/parser/NewMessageMessageParser.kt @@ -0,0 +1,29 @@ +package tech.relaycorp.letro.messages.parser + +import tech.relaycorp.letro.awala.parser.AwalaMessageParser +import tech.relaycorp.letro.messages.dto.NewMessageIncomingMessage +import tech.relaycorp.letro.messages.storage.entity.Message +import java.time.LocalDateTime +import java.util.UUID +import javax.inject.Inject + +interface NewMessageMessageParser : AwalaMessageParser + +class NewMessageMessageParserImpl @Inject constructor() : NewMessageMessageParser { + + override fun parse(content: ByteArray): NewMessageIncomingMessage { + val message = mockMessage(UUID.randomUUID()) // TODO: parse message here + return NewMessageIncomingMessage( + content = message, + ) + } +} + +internal fun mockMessage(conversationId: UUID) = Message( + conversationId = conversationId, + text = "Hello, how are you?", + ownerVeraId = "ff@cuppa.fans", + recipientVeraId = "ff@cuppa.fans", + senderVeraId = "ff@applepie.rocks", + sentAt = LocalDateTime.now(), +) diff --git a/app/src/main/java/tech/relaycorp/letro/messages/processor/NewConversationProcessor.kt b/app/src/main/java/tech/relaycorp/letro/messages/processor/NewConversationProcessor.kt new file mode 100644 index 00000000..04d58fe1 --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/processor/NewConversationProcessor.kt @@ -0,0 +1,25 @@ +package tech.relaycorp.letro.messages.processor + +import tech.relaycorp.awaladroid.messaging.IncomingMessage +import tech.relaycorp.letro.awala.AwalaManager +import tech.relaycorp.letro.awala.processor.AwalaMessageProcessor +import tech.relaycorp.letro.messages.dto.NewConversationIncomingMessage +import tech.relaycorp.letro.messages.parser.NewConversationMessageParser +import tech.relaycorp.letro.messages.storage.ConversationsDao +import tech.relaycorp.letro.messages.storage.MessagesDao +import javax.inject.Inject + +interface NewConversationProcessor : AwalaMessageProcessor + +class NewConversationProcessorImpl @Inject constructor( + private val newConversationMessageParser: NewConversationMessageParser, + private val conversationsDao: ConversationsDao, + private val messagesDao: MessagesDao, +) : NewConversationProcessor { + + override suspend fun process(message: IncomingMessage, awalaManager: AwalaManager) { + val content = (newConversationMessageParser.parse(message.content) as NewConversationIncomingMessage).content + conversationsDao.createNewConversation(content.conversation) + messagesDao.insert(content.message) + } +} diff --git a/app/src/main/java/tech/relaycorp/letro/messages/processor/NewMessageProcessor.kt b/app/src/main/java/tech/relaycorp/letro/messages/processor/NewMessageProcessor.kt new file mode 100644 index 00000000..222263fd --- /dev/null +++ b/app/src/main/java/tech/relaycorp/letro/messages/processor/NewMessageProcessor.kt @@ -0,0 +1,21 @@ +package tech.relaycorp.letro.messages.processor + +import tech.relaycorp.awaladroid.messaging.IncomingMessage +import tech.relaycorp.letro.awala.AwalaManager +import tech.relaycorp.letro.awala.processor.AwalaMessageProcessor +import tech.relaycorp.letro.messages.dto.NewMessageIncomingMessage +import tech.relaycorp.letro.messages.parser.NewMessageMessageParser +import tech.relaycorp.letro.messages.storage.MessagesDao +import javax.inject.Inject + +interface NewMessageProcessor : AwalaMessageProcessor + +class NewMessageProcessorImpl @Inject constructor( + private val parser: NewMessageMessageParser, + private val messagesDao: MessagesDao, +) : NewMessageProcessor { + override suspend fun process(message: IncomingMessage, awalaManager: AwalaManager) { + val parsedMessage = (parser.parse(message.content) as NewMessageIncomingMessage).content + messagesDao.insert(parsedMessage) + } +} diff --git a/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Conversation.kt b/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Conversation.kt index da3013e3..bda2033f 100644 --- a/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Conversation.kt +++ b/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Conversation.kt @@ -9,6 +9,13 @@ const val TABLE_NAME_CONVERSATIONS = "conversations" @Entity( tableName = TABLE_NAME_CONVERSATIONS, ) +/** + * @param keyId - primary key for the conversations table. Autogenerated. + * @param conversationId - Unique ID of a conversation + * @param ownerVeraId - ID of the account, which this conversation belongs (for display this conversation only for a particular account) + * @param contactVeraId - ID of the contact + * @param subject - the subject of the conversation + */ data class Conversation( @PrimaryKey(autoGenerate = true) val keyId: Long = 0L, diff --git a/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Message.kt b/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Message.kt index 20863fa6..5f09ea37 100644 --- a/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Message.kt +++ b/app/src/main/java/tech/relaycorp/letro/messages/storage/entity/Message.kt @@ -10,6 +10,15 @@ const val TABLE_NAME_MESSAGES = "messages" @Entity( tableName = TABLE_NAME_MESSAGES, ) +/** + * @param id - primary key for the messages table. Autogenerated. + * @param conversationId - Unique ID of a conversation, which the message belongs to + * @param text - text of the message + * @param ownerVeraId - ID of the account, which this conversation belongs to (for display this message only for a particular account) + * @param recipientVeraId - the ID of the recipient of the message + * @param senderVeraId - the ID of the sender of the message + * @param sentAt - timestamp where this message was sent (or received) + */ data class Message( @PrimaryKey(autoGenerate = true) val id: Long = 0L,