OpenedStorages больше не nullable

This commit is contained in:
2026-04-17 22:16:28 +03:00
parent d965dd8609
commit 51436401da
4 changed files with 72 additions and 67 deletions

View File

@@ -13,9 +13,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.UUID import java.util.UUID
@@ -24,43 +24,41 @@ class UnlockManager(
private val ioDispatcher: CoroutineDispatcher, private val ioDispatcher: CoroutineDispatcher,
vaultsManager: IVaultsManager vaultsManager: IVaultsManager
) : IUnlockManager { ) : IUnlockManager {
private val _openedStorages = MutableStateFlow<Map<UUID, EncryptedStorage>?>(null) private val _openedStorages = MutableStateFlow<Map<UUID, EncryptedStorage>>(emptyMap())
override val openedStorages: StateFlow<Map<UUID, IStorage>?> override val openedStorages: StateFlow<Map<UUID, IStorage>>
get() = _openedStorages get() = _openedStorages
private val mutex = Mutex() private val mutex = Mutex()
init { init {
CoroutineScope(ioDispatcher).launch { CoroutineScope(ioDispatcher).launch {
vaultsManager.allStorages.collectLatest { vaultsManager.allStorages.collectLatest {
mutex.lock() mutex.withLock {
val allKeys = keymapRepository.getAll() val allKeys = keymapRepository.getAll()
val usedKeys = mutableListOf<StorageKeyMap>() val keysToRemove = mutableListOf<StorageKeyMap>()
val keysToRemove = mutableListOf<StorageKeyMap>() val allStorages = it.toMutableList()
val allStorages = it.toMutableList() val map = _openedStorages.value.toMutableMap()
val map = _openedStorages.value?.toMutableMap() ?: mutableMapOf() while(allStorages.isNotEmpty()) {
while(allStorages.size > 0) { val storage = allStorages[allStorages.size-1]
val storage = allStorages[allStorages.size-1] val key = allKeys.find { key -> key.sourceUuid == storage.uuid }
val key = allKeys.find { key -> key.sourceUuid == storage.uuid } if(key == null) {
if(key == null) { allStorages.removeAt(allStorages.size - 1)
allStorages.removeAt(allStorages.size - 1) continue
continue }
} try {
try { val encStorage = createEncryptedStorage(storage, key.key, key.destUuid)
val encStorage = createEncryptedStorage(storage, key.key, key.destUuid) map[storage.uuid] = encStorage
map[storage.uuid] = encStorage allStorages.removeAt(allStorages.size - 1)
usedKeys.add(key) allStorages.add(encStorage)
allStorages.removeAt(allStorages.size - 1) }
allStorages.add(encStorage) catch (_: Exception) {
} // ключ не подошёл
catch (_: Exception) { keysToRemove.add(key)
// ключ не подошёл allStorages.removeAt(allStorages.size - 1)
keysToRemove.add(key) }
allStorages.removeAt(allStorages.size - 1)
} }
keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи
_openedStorages.value = map.toMap()
} }
keymapRepository.delete(*keysToRemove.toTypedArray()) // удалить мёртвые ключи
_openedStorages.value = map.toMap()
mutex.unlock()
} }
} }
} }
@@ -78,27 +76,27 @@ class UnlockManager(
storage: IStorage, storage: IStorage,
key: EncryptKey key: EncryptKey
): EncryptedStorage = withContext(ioDispatcher) { ): EncryptedStorage = withContext(ioDispatcher) {
mutex.lock() return@withContext mutex.withLock {
val encInfo = storage.metaInfo.value.encInfo ?: throw Exception("EncInfo is null") // TODO val encInfo = storage.metaInfo.value.encInfo ?: throw Exception("EncInfo is null") // TODO
if (!Encryptor.checkKey(key, encInfo)) if (!Encryptor.checkKey(key, encInfo))
throw Exception("Incorrect Key") throw Exception("Incorrect Key")
val opened = _openedStorages.first { it != null }!!.toMutableMap() val opened = _openedStorages.value.toMutableMap()
val cur = opened[storage.uuid] val cur = opened[storage.uuid]
if (cur != null) if (cur != null)
throw Exception("Storage is already open") throw Exception("Storage is already open")
val keymap = StorageKeyMap( val keymap = StorageKeyMap(
sourceUuid = storage.uuid, sourceUuid = storage.uuid,
destUuid = UUID.randomUUID(), destUuid = UUID.randomUUID(),
key = key key = key
) )
val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid) val encStorage = createEncryptedStorage(storage, keymap.key, keymap.destUuid)
opened[storage.uuid] = encStorage opened[storage.uuid] = encStorage
_openedStorages.value = opened _openedStorages.value = opened
keymapRepository.add(keymap) keymapRepository.add(keymap)
mutex.unlock() encStorage
return@withContext encStorage }
} }
/** /**
@@ -106,30 +104,37 @@ class UnlockManager(
* @param uuid uuid исходного хранилища * @param uuid uuid исходного хранилища
*/ */
override suspend fun close(uuid: UUID): Unit = withContext(ioDispatcher) { override suspend fun close(uuid: UUID): Unit = withContext(ioDispatcher) {
mutex.lock() mutex.withLock {
val opened = _openedStorages.first { it != null }!! val opened = _openedStorages.value.toMutableMap()
val enc = opened[uuid] ?: return@withContext closeBySourceUuid(opened, uuid)
close(enc) _openedStorages.value = opened
val model = StorageKeyMap(
sourceUuid = uuid,
destUuid = enc.uuid,
key = EncryptKey("")
)
_openedStorages.value = opened.toMutableMap().apply {
remove(uuid)
} }
enc.dispose()
keymapRepository.delete(model)
mutex.unlock()
} }
// Закрытие отображения по экземпляру (source или decrypted). // Закрытие отображения по экземпляру (source или decrypted).
override suspend fun close(storage: IStorage) { override suspend fun close(storage: IStorage) {
val opened = _openedStorages.first { it != null }!! val opened = _openedStorages.value
val source = opened.entries.firstOrNull { val source = opened.entries.firstOrNull {
it.key == storage.uuid || it.value.uuid == storage.uuid it.key == storage.uuid || it.value.uuid == storage.uuid
} }
if (source != null) if (source != null)
close(source.key) close(source.key)
} }
private suspend fun closeBySourceUuid(opened: MutableMap<UUID, EncryptedStorage>, sourceUuid: UUID) {
val enc = opened[sourceUuid] ?: return
val childSourceUuid = opened.entries.firstOrNull { it.value.uuid == enc.uuid }?.key
if (childSourceUuid != null) {
closeBySourceUuid(opened, childSourceUuid)
}
opened.remove(sourceUuid)
enc.dispose()
keymapRepository.delete(
StorageKeyMap(
sourceUuid = sourceUuid,
destUuid = enc.uuid,
key = EncryptKey("")
)
)
}
} }

View File

@@ -12,7 +12,7 @@ interface IUnlockManager {
/** /**
* Хранилища, для которых есть ключ шифрования * Хранилища, для которых есть ключ шифрования
*/ */
val openedStorages: StateFlow<Map<UUID, IStorage>?> val openedStorages: StateFlow<Map<UUID, IStorage>>
suspend fun open(storage: IStorage, key: EncryptKey): IStorage suspend fun open(storage: IStorage, key: EncryptKey): IStorage
suspend fun close(storage: IStorage) suspend fun close(storage: IStorage)

View File

@@ -7,6 +7,6 @@ import kotlinx.coroutines.flow.map
import java.util.UUID import java.util.UUID
class GetOpenedStoragesUseCase(private val unlockManager: IUnlockManager) { class GetOpenedStoragesUseCase(private val unlockManager: IUnlockManager) {
val openedStorages: StateFlow<Map<UUID, IStorageInfo>?> val openedStorages: StateFlow<Map<UUID, IStorageInfo>>
get() = unlockManager.openedStorages get() = unlockManager.openedStorages
} }

View File

@@ -59,7 +59,7 @@ class LocalVaultViewModel @Inject constructor(
private fun collectFlows() { private fun collectFlows() {
viewModelScope.launch { viewModelScope.launch {
manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened -> manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened ->
if(local == null || opened == null) if(local == null)
return@combine null return@combine null
val list = mutableListOf<Tree<IStorageInfo>>() val list = mutableListOf<Tree<IStorageInfo>>()
for (storage in local) { for (storage in local) {