Updated on 2026-08-14
This commit is contained in:
parent
ac6f73170e
commit
bdcd8f2ce8
25 changed files with 224 additions and 30 deletions
|
|
@ -18,8 +18,10 @@ import com.tangem.data.walletconnect.sessions.DefaultWcSessionsManager
|
|||
import com.tangem.data.walletconnect.utils.WcNamespaceConverter
|
||||
import com.tangem.datasource.di.SdkMoshi
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletconnect.model.WcMethod
|
||||
import com.tangem.domain.walletconnect.model.legacy.WalletConnectSessionsRepository
|
||||
import com.tangem.domain.walletconnect.repository.WalletConnectRepository
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
import com.tangem.domain.walletconnect.request.WcRequestService
|
||||
|
|
@ -82,7 +84,21 @@ internal object WalletConnectDataModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun defaultWcSessionsManager(): DefaultWcSessionsManager = DefaultWcSessionsManager()
|
||||
fun defaultWcSessionsManager(
|
||||
store: WalletConnectStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
legacyStore: WalletConnectSessionsRepository,
|
||||
getWallets: GetWalletsUseCase,
|
||||
): DefaultWcSessionsManager {
|
||||
val scope = CoroutineScope(SupervisorJob() + dispatchers.io)
|
||||
return DefaultWcSessionsManager(
|
||||
store = store,
|
||||
dispatchers = dispatchers,
|
||||
legacyStore = legacyStore,
|
||||
getWallets = getWallets,
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ internal class DefaultWcPairUseCase(
|
|||
|
||||
is Wallet.Model.SettledSessionResponse.Result -> {
|
||||
val newSession = settledSession.session.toDomain(sessionForApprove.walletId)
|
||||
sessionsManager.saveSessions(sessionForApprove.walletId, newSession)
|
||||
sessionsManager.saveSession(sessionForApprove.walletId, newSession)
|
||||
newSession.right()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,92 @@
|
|||
package com.tangem.data.walletconnect.sessions
|
||||
|
||||
import com.reown.walletkit.client.Wallet
|
||||
import com.reown.walletkit.client.WalletKit
|
||||
import com.tangem.data.walletconnect.utils.WcSdkObserver
|
||||
import com.tangem.data.walletconnect.utils.toOurModel
|
||||
import com.tangem.datasource.local.walletconnect.WalletConnectStore
|
||||
import com.tangem.domain.walletconnect.model.WcSession
|
||||
import com.tangem.domain.walletconnect.model.WcSessionDTO
|
||||
import com.tangem.domain.walletconnect.model.legacy.WalletConnectSessionsRepository
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultWcSessionsManager : WcSessionsManager, WcSdkObserver {
|
||||
internal class DefaultWcSessionsManager constructor(
|
||||
private val store: WalletConnectStore,
|
||||
private val legacyStore: WalletConnectSessionsRepository,
|
||||
private val getWallets: GetWalletsUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val scope: CoroutineScope,
|
||||
) : WcSessionsManager, WcSdkObserver {
|
||||
|
||||
private val _sessions = MutableSharedFlow<Map<UserWalletId, List<WcSession>>>(
|
||||
replay = 1,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
override val sessions get() = _sessions.distinctUntilChanged()
|
||||
override val sessions: Flow<Map<UserWalletId, List<WcSession>>>
|
||||
get() = store.sessions
|
||||
.onEach(::migrateLegacyStore)
|
||||
.map(::associateWithSdk)
|
||||
.distinctUntilChanged()
|
||||
.flowOn(dispatchers.io)
|
||||
|
||||
override suspend fun saveSessions(userWalletId: UserWalletId, session: WcSession) {
|
||||
TODO("Not yet implemented")
|
||||
override suspend fun saveSession(userWalletId: UserWalletId, session: WcSession) {
|
||||
store.saveSession(WcSessionDTO(session.sdkModel.topic, session.userWalletId))
|
||||
}
|
||||
|
||||
override suspend fun removeSessions(userWalletId: UserWalletId, session: WcSession) {
|
||||
TODO("Not yet implemented")
|
||||
override suspend fun removeSession(userWalletId: UserWalletId, session: WcSession) {
|
||||
store.removeSession(WcSessionDTO(session.sdkModel.topic, session.userWalletId))
|
||||
}
|
||||
|
||||
override suspend fun findSessionByTopic(topic: String): WcSession? {
|
||||
TODO("Not yet implemented")
|
||||
override suspend fun findSessionByTopic(topic: String): WcSession? = withContext(dispatchers.io) {
|
||||
val storedSessions = store.findSessionByTopic(topic) ?: return@withContext null
|
||||
val sdkSession = WalletKit.getActiveSessionByTopic(topic) ?: return@withContext null
|
||||
WcSession(userWalletId = storedSessions.walletId, sdkModel = sdkSession.toOurModel())
|
||||
}
|
||||
|
||||
override fun onSessionDelete(sessionDelete: Wallet.Model.SessionDelete) {
|
||||
// Triggered when the session is deleted by the peer
|
||||
if (sessionDelete !is Wallet.Model.SessionDelete.Success) return
|
||||
Timber.i("onSessionDelete: $sessionDelete")
|
||||
// todo (wc) find session, delete and update sessions Flow
|
||||
scope.launch {
|
||||
val storedSessions = store.findSessionByTopic(sessionDelete.topic) ?: return@launch
|
||||
store.removeSession(storedSessions)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun migrateLegacyStore(inNewStoreSessions: Set<WcSessionDTO>) {
|
||||
val walletIds = getWallets.invokeSync().mapTo(mutableSetOf()) { it.walletId }
|
||||
val inLegacyStoreSessions = walletIds
|
||||
.map { walletId ->
|
||||
flow { emit(legacyStore.loadSessions(walletId.stringValue).map { WcSessionDTO(it.topic, walletId) }) }
|
||||
}
|
||||
.merge()
|
||||
.first()
|
||||
|
||||
val mustSaveInNewStore = inLegacyStoreSessions.subtract(inNewStoreSessions)
|
||||
if (mustSaveInNewStore.isNotEmpty()) store.saveSessions(mustSaveInNewStore)
|
||||
}
|
||||
|
||||
private suspend fun associateWithSdk(storeSessions: Set<WcSessionDTO>): Map<UserWalletId, List<WcSession>> {
|
||||
val sdkSessions = WalletKit.getListOfActiveSessions()
|
||||
val wcSessions = sdkSessions.mapNotNull { sdkSession ->
|
||||
val storedSessions = storeSessions.find { it.topic == sdkSession.topic }
|
||||
?: return@mapNotNull null
|
||||
WcSession(userWalletId = storedSessions.walletId, sdkModel = sdkSession.toOurModel())
|
||||
}
|
||||
|
||||
val unknownStoredSessions = storeSessions
|
||||
.filterNot { dto -> wcSessions.any { it.sdkModel.topic == dto.topic } }
|
||||
|
||||
if (unknownStoredSessions.isNotEmpty()) {
|
||||
unknownStoredSessions.forEach { unknown ->
|
||||
legacyStore.removeSession(unknown.walletId.stringValue, unknown.topic)
|
||||
}
|
||||
store.removeSessions(unknownStoredSessions.toSet())
|
||||
}
|
||||
|
||||
return wcSessions.groupBy { it.userWalletId }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
package com.tangem.data.walletconnect.utils
|
||||
|
||||
import com.reown.android.Core
|
||||
import com.reown.walletkit.client.Wallet
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcAppMetaData
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSession
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
|
||||
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest.JSONRPCRequest
|
||||
|
||||
internal fun Wallet.Model.Session.toOurModel(): WcSdkSession = WcSdkSession(
|
||||
topic = topic,
|
||||
appMetaData = metaData.toOurModel(),
|
||||
)
|
||||
|
||||
internal fun Wallet.Model.SessionRequest.toOurModel(): WcSdkSessionRequest = WcSdkSessionRequest(
|
||||
|
|
@ -19,4 +22,15 @@ internal fun Wallet.Model.SessionRequest.JSONRPCRequest.toOurModel(): JSONRPCReq
|
|||
id = this.id,
|
||||
method = this.method,
|
||||
params = this.params,
|
||||
)
|
||||
|
||||
internal fun Core.Model.AppMetaData?.toOurModel(): WcAppMetaData = WcAppMetaData(
|
||||
name = this?.name.orEmpty(),
|
||||
description = this?.description.orEmpty(),
|
||||
url = this?.url.orEmpty(),
|
||||
icons = this?.icons.orEmpty(),
|
||||
redirect = this?.redirect,
|
||||
appLink = this?.appLink,
|
||||
linkMode = this?.linkMode ?: false,
|
||||
verifyUrl = this?.verifyUrl,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue