diff --git a/app/build.gradle b/app/build.gradle index a52087c..0b091ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -106,6 +106,9 @@ dependencies { implementation project(":core") + implementation project(":chat-engine") + implementation project(":matrix-chat-engine") + implementation Dependencies.google.androidxComposeUi implementation Dependencies.mavenCentral.ktorAndroid implementation Dependencies.mavenCentral.sqldelightAndroid diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index 29abfe9..1bc4ddd 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -17,6 +17,7 @@ import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.directory.DirectoryModule import app.dapk.st.domain.StoreModule +import app.dapk.st.engine.MatrixEngine import app.dapk.st.firebase.messaging.MessagingModule import app.dapk.st.home.HomeModule import app.dapk.st.home.MainActivity @@ -164,12 +165,8 @@ internal class FeatureModules internal constructor( val directoryModule by unsafeLazy { DirectoryModule( - syncService = matrixModules.sync, - messageService = matrixModules.message, context = context, - credentialsStore = storeModule.value.credentialsStore(), - roomStore = storeModule.value.roomStore(), - roomService = matrixModules.room, + chatEngine = matrixModules.engine, ) } val loginModule by unsafeLazy { @@ -252,6 +249,30 @@ internal class MatrixModules( private val buildMeta: BuildMeta, ) { + val engine by unsafeLazy { + val store = storeModule.value + MatrixEngine.Factory().create( + base64, + buildMeta, + logger, + SmallTalkDeviceNameGenerator(), + coroutineDispatchers, + trackingModule.errorTracker, + imageContentReader, + BackgroundWorkAdapter(workModule.workScheduler()), + store.memberStore(), + store.roomStore(), + store.profileStore(), + store.syncStore(), + store.overviewStore(), + store.filterStore(), + store.localEchoStore, + store.credentialsStore(), + store.knownDevicesStore(), + OlmPersistenceWrapper(store.olmStore(), base64), + ) + } + val matrix by unsafeLazy { val store = storeModule.value val credentialsStore = store.credentialsStore() diff --git a/chat-engine/build.gradle b/chat-engine/build.gradle new file mode 100644 index 0000000..ee08897 --- /dev/null +++ b/chat-engine/build.gradle @@ -0,0 +1,12 @@ +plugins { + id 'kotlin' +} + +dependencies { + api Dependencies.mavenCentral.kotlinCoroutinesCore + api project(":matrix:common") + + implementation project(":matrix:services:sync") + implementation project(":matrix:services:message") + implementation project(":matrix:services:room") +} \ No newline at end of file diff --git a/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt b/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt new file mode 100644 index 0000000..556b478 --- /dev/null +++ b/chat-engine/src/main/kotlin/app/dapk/st/engine/ChatEngine.kt @@ -0,0 +1,46 @@ +package app.dapk.st.engine + +import app.dapk.st.matrix.common.AvatarUrl +import app.dapk.st.matrix.common.EventId +import app.dapk.st.matrix.common.RoomId +import app.dapk.st.matrix.common.RoomMember +import kotlinx.coroutines.flow.Flow + +interface ChatEngine { + + fun directory(): Flow + +} + +typealias DirectoryState = List +typealias OverviewState = List + +data class DirectoryItem( + val overview: RoomOverview, + val unreadCount: UnreadCount, + val typing: Typing? +) + +data class RoomOverview( + val roomId: RoomId, + val roomCreationUtc: Long, + val roomName: String?, + val roomAvatarUrl: AvatarUrl?, + val lastMessage: LastMessage?, + val isGroup: Boolean, + val readMarker: EventId?, + val isEncrypted: Boolean, +) { + + data class LastMessage( + val content: String, + val utcTimestamp: Long, + val author: RoomMember, + ) + +} + +@JvmInline +value class UnreadCount(val value: Int) + +data class Typing(val roomId: RoomId, val members: List) diff --git a/features/directory/build.gradle b/features/directory/build.gradle index b005881..44351f5 100644 --- a/features/directory/build.gradle +++ b/features/directory/build.gradle @@ -1,9 +1,7 @@ applyAndroidComposeLibraryModule(project) dependencies { - implementation project(":matrix:services:sync") - implementation project(":matrix:services:message") - implementation project(":matrix:services:room") + implementation project(":chat-engine") implementation project(":domains:android:compose-core") implementation project(":domains:android:viewmodel") implementation project(":features:messenger") diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryListingScreen.kt b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryListingScreen.kt index 284f728..1c14523 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryListingScreen.kt +++ b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryListingScreen.kt @@ -38,9 +38,10 @@ import app.dapk.st.design.components.Toolbar import app.dapk.st.directory.DirectoryEvent.OpenDownloadUrl import app.dapk.st.directory.DirectoryScreenState.Content import app.dapk.st.directory.DirectoryScreenState.EmptyLoading +import app.dapk.st.engine.DirectoryItem +import app.dapk.st.engine.RoomOverview +import app.dapk.st.engine.Typing import app.dapk.st.matrix.common.RoomId -import app.dapk.st.matrix.sync.RoomOverview -import app.dapk.st.matrix.sync.SyncService import app.dapk.st.messenger.MessengerActivity import kotlinx.coroutines.launch import java.time.Clock @@ -147,7 +148,7 @@ private fun Content(listState: LazyListState, state: Content) { } @Composable -private fun DirectoryItem(room: RoomFoo, onClick: (RoomId) -> Unit, clock: Clock) { +private fun DirectoryItem(room: DirectoryItem, onClick: (RoomId) -> Unit, clock: Clock) { val overview = room.overview val roomName = overview.roomName ?: "Empty room" val hasUnread = room.unreadCount.value > 0 @@ -233,7 +234,7 @@ private fun DirectoryItem(room: RoomFoo, onClick: (RoomId) -> Unit, clock: Clock } @Composable -private fun body(overview: RoomOverview, secondaryText: Color, typing: SyncService.SyncEvent.Typing?) { +private fun body(overview: RoomOverview, secondaryText: Color, typing: Typing?) { val bodySize = 14.sp when { diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryModule.kt b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryModule.kt index 5ef40d9..a21ede3 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryModule.kt +++ b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryModule.kt @@ -2,31 +2,17 @@ package app.dapk.st.directory import android.content.Context import app.dapk.st.core.ProvidableModule -import app.dapk.st.matrix.common.CredentialsStore -import app.dapk.st.matrix.message.MessageService -import app.dapk.st.matrix.room.RoomService -import app.dapk.st.matrix.sync.RoomStore -import app.dapk.st.matrix.sync.SyncService +import app.dapk.st.engine.ChatEngine class DirectoryModule( - private val syncService: SyncService, - private val messageService: MessageService, - private val roomService: RoomService, private val context: Context, - private val credentialsStore: CredentialsStore, - private val roomStore: RoomStore, + private val chatEngine: ChatEngine, ) : ProvidableModule { fun directoryViewModel(): DirectoryViewModel { return DirectoryViewModel( ShortcutHandler(context), - DirectoryUseCase( - syncService, - messageService, - roomService, - credentialsStore, - roomStore, - ) + chatEngine, ) } } \ No newline at end of file diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryState.kt b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryState.kt index 2cf51fa..0dd1a41 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryState.kt +++ b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryState.kt @@ -1,5 +1,7 @@ package app.dapk.st.directory +import app.dapk.st.engine.DirectoryState + sealed interface DirectoryScreenState { object EmptyLoading : DirectoryScreenState diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryViewModel.kt b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryViewModel.kt index d8c4fdc..92757f9 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryViewModel.kt +++ b/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryViewModel.kt @@ -2,6 +2,7 @@ package app.dapk.st.directory import androidx.lifecycle.viewModelScope import app.dapk.st.directory.DirectoryScreenState.* +import app.dapk.st.engine.ChatEngine import app.dapk.st.viewmodel.DapkViewModel import app.dapk.st.viewmodel.MutableStateFactory import app.dapk.st.viewmodel.defaultStateFactory @@ -12,7 +13,7 @@ import kotlinx.coroutines.launch class DirectoryViewModel( private val shortcutHandler: ShortcutHandler, - private val directoryUseCase: DirectoryUseCase, + private val chatEngine: ChatEngine, factory: MutableStateFactory = defaultStateFactory(), ) : DapkViewModel( initialState = EmptyLoading, @@ -23,7 +24,7 @@ class DirectoryViewModel( fun start() { syncJob = viewModelScope.launch { - directoryUseCase.state().onEach { + chatEngine.directory().onEach { shortcutHandler.onDirectoryUpdate(it.map { it.overview }) state = when (it.isEmpty()) { true -> Empty diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/ShortcutHandler.kt b/features/directory/src/main/kotlin/app/dapk/st/directory/ShortcutHandler.kt index 87b4980..276a8d3 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/ShortcutHandler.kt +++ b/features/directory/src/main/kotlin/app/dapk/st/directory/ShortcutHandler.kt @@ -5,8 +5,8 @@ import android.content.pm.ShortcutInfo import androidx.core.app.Person import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat +import app.dapk.st.engine.RoomOverview import app.dapk.st.matrix.common.RoomId -import app.dapk.st.matrix.sync.RoomOverview import app.dapk.st.messenger.MessengerActivity class ShortcutHandler(private val context: Context) { diff --git a/matrix-chat-engine/build.gradle b/matrix-chat-engine/build.gradle new file mode 100644 index 0000000..140832c --- /dev/null +++ b/matrix-chat-engine/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'kotlin' +} + +dependencies { + api Dependencies.mavenCentral.kotlinCoroutinesCore + + implementation project(":core") + implementation project(":chat-engine") + + implementation project(":domains:olm") + + implementation project(":matrix:matrix") + implementation project(":matrix:matrix-http-ktor") + implementation project(":matrix:services:auth") + implementation project(":matrix:services:sync") + implementation project(":matrix:services:room") + implementation project(":matrix:services:push") + implementation project(":matrix:services:message") + implementation project(":matrix:services:device") + implementation project(":matrix:services:crypto") + implementation project(":matrix:services:profile") +} \ No newline at end of file diff --git a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryUseCase.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/DirectoryUseCase.kt similarity index 87% rename from features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryUseCase.kt rename to matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/DirectoryUseCase.kt index b6a7bf6..b2bec77 100644 --- a/features/directory/src/main/kotlin/app/dapk/st/directory/DirectoryUseCase.kt +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/DirectoryUseCase.kt @@ -1,4 +1,4 @@ -package app.dapk.st.directory +package app.dapk.st.engine import app.dapk.st.matrix.common.CredentialsStore import app.dapk.st.matrix.common.RoomId @@ -6,22 +6,12 @@ import app.dapk.st.matrix.common.RoomMember import app.dapk.st.matrix.common.UserId import app.dapk.st.matrix.message.MessageService import app.dapk.st.matrix.room.RoomService -import app.dapk.st.matrix.sync.* +import app.dapk.st.matrix.sync.RoomStore +import app.dapk.st.matrix.sync.SyncService import app.dapk.st.matrix.sync.SyncService.SyncEvent.Typing import kotlinx.coroutines.flow.* -@JvmInline -value class UnreadCount(val value: Int) - -typealias DirectoryState = List - -data class RoomFoo( - val overview: RoomOverview, - val unreadCount: UnreadCount, - val typing: Typing? -) - -class DirectoryUseCase( +internal class DirectoryUseCase( private val syncService: SyncService, private val messageService: MessageService, private val roomService: RoomService, @@ -38,10 +28,10 @@ class DirectoryUseCase( syncService.events() ) { overviewState, localEchos, unread, events -> overviewState.mergeWithLocalEchos(localEchos, userId).map { roomOverview -> - RoomFoo( + DirectoryItem( overview = roomOverview, unreadCount = UnreadCount(unread[roomOverview.roomId] ?: 0), - typing = events.filterIsInstance().firstOrNull { it.roomId == roomOverview.roomId } + typing = events.filterIsInstance().firstOrNull { it.roomId == roomOverview.roomId }?.engine() ) } } @@ -50,7 +40,7 @@ class DirectoryUseCase( private fun overviewDatasource() = combine( syncService.startSyncing().map { false }.onStart { emit(true) }, - syncService.overview() + syncService.overview().map { it.map { it.engine() } } ) { isFirstLoad, overview -> when { isFirstLoad && overview.isEmpty() -> null @@ -81,7 +71,7 @@ class DirectoryUseCase( val latestEcho = echos.maxByOrNull { it.timestampUtc } return if (latestEcho != null && latestEcho.timestampUtc > (this.lastMessage?.utcTimestamp ?: 0)) { this.copy( - lastMessage = LastMessage( + lastMessage = RoomOverview.LastMessage( content = when (val message = latestEcho.message) { is MessageService.Message.TextMessage -> message.content.body is MessageService.Message.ImageMessage -> "\uD83D\uDCF7" @@ -96,3 +86,6 @@ class DirectoryUseCase( } } + + + diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt new file mode 100644 index 0000000..0486699 --- /dev/null +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt @@ -0,0 +1,27 @@ +package app.dapk.st.engine + +import app.dapk.st.matrix.sync.LastMessage as MatrixLastMessage +import app.dapk.st.matrix.sync.RoomOverview as MatrixRoomOverview +import app.dapk.st.matrix.sync.SyncService.SyncEvent.Typing as MatrixTyping + +fun MatrixRoomOverview.engine() = RoomOverview( + this.roomId, + this.roomCreationUtc, + this.roomName, + this.roomAvatarUrl, + this.lastMessage?.engine(), + this.isGroup, + this.readMarker, + this.isEncrypted +) + +fun MatrixLastMessage.engine() = RoomOverview.LastMessage( + this.content, + this.utcTimestamp, + this.author, +) + +fun MatrixTyping.engine() = Typing( + this.roomId, + this.members, +) \ No newline at end of file diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt new file mode 100644 index 0000000..e58235d --- /dev/null +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MatrixEngine.kt @@ -0,0 +1,317 @@ +package app.dapk.st.engine + +import app.dapk.st.core.Base64 +import app.dapk.st.core.BuildMeta +import app.dapk.st.core.CoroutineDispatchers +import app.dapk.st.core.SingletonFlows +import app.dapk.st.core.extensions.ErrorTracker +import app.dapk.st.matrix.MatrixClient +import app.dapk.st.matrix.auth.DeviceDisplayNameGenerator +import app.dapk.st.matrix.auth.installAuthService +import app.dapk.st.matrix.common.* +import app.dapk.st.matrix.crypto.RoomMembersProvider +import app.dapk.st.matrix.crypto.Verification +import app.dapk.st.matrix.crypto.cryptoService +import app.dapk.st.matrix.crypto.installCryptoService +import app.dapk.st.matrix.device.KnownDeviceStore +import app.dapk.st.matrix.device.deviceService +import app.dapk.st.matrix.device.installEncryptionService +import app.dapk.st.matrix.http.ktor.KtorMatrixHttpClientFactory +import app.dapk.st.matrix.message.* +import app.dapk.st.matrix.message.internal.ImageContentReader +import app.dapk.st.matrix.push.installPushService +import app.dapk.st.matrix.room.* +import app.dapk.st.matrix.sync.* +import app.dapk.st.matrix.sync.internal.request.ApiToDeviceEvent +import app.dapk.st.matrix.sync.internal.room.MessageDecrypter +import app.dapk.st.olm.DeviceKeyFactory +import app.dapk.st.olm.OlmStore +import app.dapk.st.olm.OlmWrapper +import java.time.Clock + +class MatrixEngine internal constructor( + private val directoryUseCase: Lazy, +) : ChatEngine { + + override fun directory() = directoryUseCase.value.state() + + class Factory { + + fun create( + base64: Base64, + buildMeta: BuildMeta, + logger: MatrixLogger, + nameGenerator: DeviceDisplayNameGenerator, + coroutineDispatchers: CoroutineDispatchers, + errorTracker: ErrorTracker, + imageContentReader: ImageContentReader, + backgroundScheduler: BackgroundScheduler, + memberStore: MemberStore, + roomStore: RoomStore, + profileStore: ProfileStore, + syncStore: SyncStore, + overviewStore: OverviewStore, + filterStore: FilterStore, + localEchoStore: LocalEchoStore, + credentialsStore: CredentialsStore, + knownDeviceStore: KnownDeviceStore, + olmStore: OlmStore, + ): ChatEngine { + val matrix = MatrixFactory.createMatrix( + base64, + buildMeta, + logger, + nameGenerator, + coroutineDispatchers, + errorTracker, + imageContentReader, + backgroundScheduler, + memberStore, + roomStore, + profileStore, + syncStore, + overviewStore, + filterStore, + localEchoStore, + credentialsStore, + knownDeviceStore, + olmStore + ) + + val directoryUseCase = unsafeLazy { + DirectoryUseCase( + matrix.syncService(), + matrix.messageService(), + matrix.roomService(), + credentialsStore, + roomStore + ) + } + + return MatrixEngine(directoryUseCase) + + } + + } + +} + + +object MatrixFactory { + + fun createMatrix( + base64: Base64, + buildMeta: BuildMeta, + logger: MatrixLogger, + nameGenerator: DeviceDisplayNameGenerator, + coroutineDispatchers: CoroutineDispatchers, + errorTracker: ErrorTracker, + imageContentReader: ImageContentReader, + backgroundScheduler: BackgroundScheduler, + memberStore: MemberStore, + roomStore: RoomStore, + profileStore: ProfileStore, + syncStore: SyncStore, + overviewStore: OverviewStore, + filterStore: FilterStore, + localEchoStore: LocalEchoStore, + credentialsStore: CredentialsStore, + knownDeviceStore: KnownDeviceStore, + olmStore: OlmStore, + ) = MatrixClient( + KtorMatrixHttpClientFactory( + credentialsStore, + includeLogging = buildMeta.isDebug, + ), + logger + ).also { + it.install { + installAuthService(credentialsStore, nameGenerator) + installEncryptionService(knownDeviceStore) + + val singletonFlows = SingletonFlows(coroutineDispatchers) + val olm = OlmWrapper( + olmStore = olmStore, + singletonFlows = singletonFlows, + jsonCanonicalizer = JsonCanonicalizer(), + deviceKeyFactory = DeviceKeyFactory(JsonCanonicalizer()), + errorTracker = errorTracker, + logger = logger, + clock = Clock.systemUTC(), + coroutineDispatchers = coroutineDispatchers, + ) + installCryptoService( + credentialsStore, + olm, + roomMembersProvider = { services -> + RoomMembersProvider { + services.roomService().joinedMembers(it).map { it.userId } + } + }, + base64 = base64, + coroutineDispatchers = coroutineDispatchers, + ) + installMessageService( + localEchoStore, + backgroundScheduler, + imageContentReader, + messageEncrypter = { + val cryptoService = it.cryptoService() + MessageEncrypter { message -> + val result = cryptoService.encrypt( + roomId = message.roomId, + credentials = credentialsStore.credentials()!!, + messageJson = message.contents, + ) + + MessageEncrypter.EncryptedMessagePayload( + result.algorithmName, + result.senderKey, + result.cipherText, + result.sessionId, + result.deviceId, + ) + } + }, + mediaEncrypter = { + val cryptoService = it.cryptoService() + MediaEncrypter { input -> + val result = cryptoService.encrypt(input) + MediaEncrypter.Result( + uri = result.uri, + contentLength = result.contentLength, + algorithm = result.algorithm, + ext = result.ext, + keyOperations = result.keyOperations, + kty = result.kty, + k = result.k, + iv = result.iv, + hashes = result.hashes, + v = result.v, + ) + } + }, + ) + + installRoomService( + memberStore, + roomMessenger = { + val messageService = it.messageService() + object : RoomMessenger { + override suspend fun enableEncryption(roomId: RoomId) { + messageService.sendEventMessage( + roomId, MessageService.EventMessage.Encryption( + algorithm = AlgorithmName("m.megolm.v1.aes-sha2") + ) + ) + } + } + }, + roomInviteRemover = { + overviewStore.removeInvites(listOf(it)) + } + ) + + installProfileService(profileStore, singletonFlows, credentialsStore) + + installSyncService( + credentialsStore, + overviewStore, + roomStore, + syncStore, + filterStore, + deviceNotifier = { services -> + val encryption = services.deviceService() + val crypto = services.cryptoService() + DeviceNotifier { userIds, syncToken -> + encryption.updateStaleDevices(userIds) + crypto.updateOlmSession(userIds, syncToken) + } + }, + messageDecrypter = { serviceProvider -> + val cryptoService = serviceProvider.cryptoService() + MessageDecrypter { + cryptoService.decrypt(it) + } + }, + keySharer = { serviceProvider -> + val cryptoService = serviceProvider.cryptoService() + KeySharer { sharedRoomKeys -> + cryptoService.importRoomKeys(sharedRoomKeys) + } + }, + verificationHandler = { services -> + val cryptoService = services.cryptoService() + VerificationHandler { apiEvent -> + logger.matrixLog(MatrixLogTag.VERIFICATION, "got a verification request $it") + cryptoService.onVerificationEvent( + when (apiEvent) { + is ApiToDeviceEvent.VerificationRequest -> Verification.Event.Requested( + apiEvent.sender, + apiEvent.content.fromDevice, + apiEvent.content.transactionId, + apiEvent.content.methods, + apiEvent.content.timestampPosix, + ) + + is ApiToDeviceEvent.VerificationReady -> Verification.Event.Ready( + apiEvent.sender, + apiEvent.content.fromDevice, + apiEvent.content.transactionId, + apiEvent.content.methods, + ) + + is ApiToDeviceEvent.VerificationStart -> Verification.Event.Started( + apiEvent.sender, + apiEvent.content.fromDevice, + apiEvent.content.method, + apiEvent.content.protocols, + apiEvent.content.hashes, + apiEvent.content.codes, + apiEvent.content.short, + apiEvent.content.transactionId, + ) + + is ApiToDeviceEvent.VerificationCancel -> TODO() + is ApiToDeviceEvent.VerificationAccept -> TODO() + is ApiToDeviceEvent.VerificationKey -> Verification.Event.Key( + apiEvent.sender, + apiEvent.content.transactionId, + apiEvent.content.key + ) + + is ApiToDeviceEvent.VerificationMac -> Verification.Event.Mac( + apiEvent.sender, + apiEvent.content.transactionId, + apiEvent.content.keys, + apiEvent.content.mac, + ) + } + ) + } + }, + oneTimeKeyProducer = { services -> + val cryptoService = services.cryptoService() + MaybeCreateMoreKeys { + cryptoService.maybeCreateMoreKeys(it) + } + }, + roomMembersService = { services -> + val roomService = services.roomService() + object : RoomMembersService { + override suspend fun find(roomId: RoomId, userIds: List) = roomService.findMembers(roomId, userIds) + override suspend fun findSummary(roomId: RoomId) = roomService.findMembersSummary(roomId) + override suspend fun insert(roomId: RoomId, members: List) = roomService.insertMembers(roomId, members) + } + }, + errorTracker = errorTracker, + coroutineDispatchers = coroutineDispatchers, + ) + + installPushService(credentialsStore) + } + } + +} + +fun unsafeLazy(initializer: () -> T): Lazy = lazy(mode = LazyThreadSafetyMode.NONE, initializer = initializer) diff --git a/settings.gradle b/settings.gradle index 4b8bbf4..bb28dab 100644 --- a/settings.gradle +++ b/settings.gradle @@ -55,3 +55,6 @@ include ':matrix:services:profile' include ':core' include ':test-harness' + +include ':chat-engine' +include ':matrix-chat-engine' \ No newline at end of file