Большая реструктуризация проекта
This commit is contained in:
47
infrastructure-android/build.gradle.kts
Normal file
47
infrastructure-android/build.gradle.kts
Normal file
@@ -0,0 +1,47 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.ksp)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.github.nullptroma.wallenc.infrastructure.android"
|
||||
compileSdk = 37
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":domain"))
|
||||
implementation(project(":domain-storage"))
|
||||
implementation(project(":vault-contracts"))
|
||||
|
||||
implementation(libs.jackson.module.kotlin)
|
||||
implementation(libs.jackson.datatype.jsr310)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
||||
implementation(libs.room.ktx)
|
||||
implementation(libs.room.runtime)
|
||||
ksp(libs.room.compiler)
|
||||
|
||||
implementation(libs.androidx.core.ktx)
|
||||
testImplementation(libs.junit)
|
||||
}
|
||||
2
infrastructure-android/src/main/AndroidManifest.xml
Normal file
2
infrastructure-android/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.AppDb
|
||||
|
||||
class RoomFactory(private val context: Context) {
|
||||
fun buildAppDb(): AppDb {
|
||||
val room = Room.databaseBuilder(
|
||||
context, AppDb::class.java, "app-db"
|
||||
).fallbackToDestructiveMigration().build()
|
||||
return room
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.YandexAccountDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageMetaInfo
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbYandexAccount
|
||||
|
||||
interface IAppDb {
|
||||
val storageKeyMapDao: StorageKeyMapDao
|
||||
val storageMetaInfoDao: StorageMetaInfoDao
|
||||
val yandexAccountDao: YandexAccountDao
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [DbStorageKeyMap::class, DbStorageMetaInfo::class, DbYandexAccount::class],
|
||||
version = 4,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class AppDb : IAppDb, RoomDatabase() {
|
||||
abstract override val storageKeyMapDao: StorageKeyMapDao
|
||||
abstract override val storageMetaInfoDao: StorageMetaInfoDao
|
||||
abstract override val yandexAccountDao: YandexAccountDao
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageKeyMap
|
||||
|
||||
@Dao
|
||||
interface StorageKeyMapDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun add(vararg keymaps: DbStorageKeyMap)
|
||||
|
||||
@Query("SELECT * FROM storage_key_maps")
|
||||
suspend fun getAll(): List<DbStorageKeyMap>
|
||||
|
||||
@Delete
|
||||
suspend fun delete(vararg keymaps: DbStorageKeyMap)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageMetaInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.util.UUID
|
||||
|
||||
@Dao
|
||||
interface StorageMetaInfoDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun add(metaInfo: DbStorageMetaInfo)
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos")
|
||||
suspend fun getAll(): List<DbStorageMetaInfo>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos")
|
||||
fun getAllFlow(): Flow<List<DbStorageMetaInfo>>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid")
|
||||
fun getMetaInfoFlow(uuid: UUID): Flow<DbStorageMetaInfo>
|
||||
|
||||
@Query("SELECT * FROM storage_meta_infos WHERE uuid == :uuid")
|
||||
suspend fun getMetaInfo(uuid: UUID): DbStorageMetaInfo?
|
||||
|
||||
@Delete
|
||||
suspend fun delete(metaInfo: DbStorageMetaInfo)
|
||||
|
||||
@Query("DELETE FROM storage_meta_infos WHERE uuid == :uuid")
|
||||
suspend fun delete(uuid: UUID)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbYandexAccount
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface YandexAccountDao {
|
||||
@Query("SELECT * FROM yandex_accounts WHERE yandexUserId = :id LIMIT 1")
|
||||
suspend fun getByYandexUserId(id: String): DbYandexAccount?
|
||||
|
||||
@Query("SELECT * FROM yandex_accounts WHERE vaultUuid = :vaultUuid LIMIT 1")
|
||||
suspend fun getByVaultUuid(vaultUuid: String): DbYandexAccount?
|
||||
|
||||
@Insert
|
||||
suspend fun insert(account: DbYandexAccount)
|
||||
|
||||
@Query(
|
||||
"UPDATE yandex_accounts SET oauthToken = :token, email = :email WHERE vaultUuid = :vaultUuid",
|
||||
)
|
||||
suspend fun updateCredentials(vaultUuid: String, email: String, token: String)
|
||||
|
||||
@Query("SELECT * FROM yandex_accounts ORDER BY email COLLATE NOCASE ASC")
|
||||
fun observeAll(): Flow<List<DbYandexAccount>>
|
||||
|
||||
@Query("DELETE FROM yandex_accounts WHERE vaultUuid = :vaultUuid")
|
||||
suspend fun deleteByVaultUuid(vaultUuid: String)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import com.github.nullptroma.wallenc.infrastructure.model.StorageKeyMap
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import java.util.UUID
|
||||
|
||||
@Entity(tableName = "storage_key_maps")
|
||||
data class DbStorageKeyMap(
|
||||
@androidx.room.PrimaryKey
|
||||
@ColumnInfo(name = "source_uuid") val sourceUuid: UUID,
|
||||
@ColumnInfo(name = "key") val key: ByteArray
|
||||
) {
|
||||
fun toModel(): StorageKeyMap {
|
||||
return StorageKeyMap(
|
||||
sourceUuid = sourceUuid,
|
||||
key = EncryptKey(key)
|
||||
)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as DbStorageKeyMap
|
||||
|
||||
if (sourceUuid != other.sourceUuid) return false
|
||||
if (!key.contentEquals(other.key)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = sourceUuid.hashCode()
|
||||
result = 31 * result + key.contentHashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromModel(keymap: StorageKeyMap): DbStorageKeyMap {
|
||||
return DbStorageKeyMap(
|
||||
sourceUuid = keymap.sourceUuid,
|
||||
key = keymap.key.bytes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.util.UUID
|
||||
|
||||
@Entity(tableName = "storage_meta_infos")
|
||||
data class DbStorageMetaInfo(
|
||||
@PrimaryKey @ColumnInfo(name = "uuid") val uuid: UUID,
|
||||
@ColumnInfo(name = "meta_info") val metaInfoJson: String
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.model
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
tableName = "yandex_accounts",
|
||||
indices = [Index(value = ["yandexUserId"], unique = true)],
|
||||
)
|
||||
data class DbYandexAccount(
|
||||
@PrimaryKey val vaultUuid: String,
|
||||
val yandexUserId: String,
|
||||
val email: String,
|
||||
val oauthToken: String,
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.repository
|
||||
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageKeyMapDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageKeyMap
|
||||
import com.github.nullptroma.wallenc.infrastructure.model.StorageKeyMap
|
||||
import com.github.nullptroma.wallenc.infrastructure.ports.StorageKeyMapStore
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class StorageKeyMapRepository(
|
||||
private val dao: StorageKeyMapDao,
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) : StorageKeyMapStore {
|
||||
override suspend fun getAll() = withContext(ioDispatcher) { dao.getAll().map { it.toModel() } }
|
||||
override suspend fun add(value: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModel = DbStorageKeyMap.fromModel(value)
|
||||
dao.add(dbModel)
|
||||
}
|
||||
|
||||
suspend fun add(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) }
|
||||
dao.add(*dbModels.toTypedArray())
|
||||
}
|
||||
|
||||
override suspend fun delete(vararg keymaps: StorageKeyMap) = withContext(ioDispatcher) {
|
||||
val dbModels = keymaps.map { DbStorageKeyMap.fromModel(it) }
|
||||
dao.delete(*dbModels.toTypedArray())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.repository
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.StorageMetaInfoDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbStorageMetaInfo
|
||||
import com.github.nullptroma.wallenc.infrastructure.utils.IProvider
|
||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
|
||||
class StorageMetaInfoRepository(
|
||||
private val dao: StorageMetaInfoDao,
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) {
|
||||
fun getAllFlow() = dao.getAllFlow()
|
||||
suspend fun getAll() = withContext(ioDispatcher) { dao.getAll() }
|
||||
suspend fun getMeta(uuid: UUID): CommonStorageMetaInfo? = withContext(ioDispatcher) {
|
||||
val json = dao.getMetaInfo(uuid)?.metaInfoJson ?: return@withContext null
|
||||
return@withContext jackson.readValue(
|
||||
json,
|
||||
CommonStorageMetaInfo::class.java
|
||||
)
|
||||
}
|
||||
|
||||
fun observeMeta(uuid: UUID): Flow<CommonStorageMetaInfo> {
|
||||
return dao.getMetaInfoFlow(uuid)
|
||||
.map { jackson.readValue(it.metaInfoJson, CommonStorageMetaInfo::class.java) }
|
||||
}
|
||||
|
||||
suspend fun setMeta(uuid: UUID, metaInfo: CommonStorageMetaInfo) = withContext(ioDispatcher) {
|
||||
val json = jackson.writeValueAsString(metaInfo)
|
||||
dao.add(DbStorageMetaInfo(uuid, json))
|
||||
}
|
||||
|
||||
suspend fun delete(uuid: UUID) = withContext(ioDispatcher) {
|
||||
dao.delete(uuid)
|
||||
}
|
||||
|
||||
|
||||
fun createSingleStorageProvider(uuid: UUID): SingleStorageMetaInfoProvider {
|
||||
return SingleStorageMetaInfoProvider(this, uuid)
|
||||
}
|
||||
|
||||
class SingleStorageMetaInfoProvider (
|
||||
private val repo: StorageMetaInfoRepository,
|
||||
val uuid: UUID
|
||||
) : IProvider<CommonStorageMetaInfo> {
|
||||
override suspend fun get(): CommonStorageMetaInfo? = repo.getMeta(uuid)
|
||||
override suspend fun clear() = repo.delete(uuid)
|
||||
override suspend fun set(value: CommonStorageMetaInfo) = repo.setMeta(uuid, value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.db.app.repository
|
||||
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.dao.YandexAccountDao
|
||||
import com.github.nullptroma.wallenc.infrastructure.db.app.model.DbYandexAccount
|
||||
import com.github.nullptroma.wallenc.infrastructure.model.YandexAccount
|
||||
import com.github.nullptroma.wallenc.infrastructure.ports.YandexAccountStore
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class YandexAccountRepository(
|
||||
private val dao: YandexAccountDao,
|
||||
private val ioDispatcher: CoroutineDispatcher
|
||||
) : YandexAccountStore {
|
||||
override fun observeAll(): Flow<List<YandexAccount>> = dao.observeAll().map { rows ->
|
||||
rows.map { it.toModel() }
|
||||
}
|
||||
|
||||
override suspend fun getByYandexUserId(id: String): YandexAccount? = withContext(ioDispatcher) {
|
||||
dao.getByYandexUserId(id)?.toModel()
|
||||
}
|
||||
|
||||
override suspend fun getByVaultUuid(vaultUuid: String): YandexAccount? = withContext(ioDispatcher) {
|
||||
dao.getByVaultUuid(vaultUuid)?.toModel()
|
||||
}
|
||||
|
||||
override suspend fun insert(account: YandexAccount) = withContext(ioDispatcher) {
|
||||
dao.insert(fromModel(account))
|
||||
}
|
||||
|
||||
override suspend fun updateCredentials(vaultUuid: String, email: String, token: String) =
|
||||
withContext(ioDispatcher) {
|
||||
dao.updateCredentials(vaultUuid, email, token)
|
||||
}
|
||||
|
||||
override suspend fun deleteByVaultUuid(vaultUuid: String) = withContext(ioDispatcher) {
|
||||
dao.deleteByVaultUuid(vaultUuid)
|
||||
}
|
||||
|
||||
private fun DbYandexAccount.toModel(): YandexAccount =
|
||||
YandexAccount(
|
||||
vaultUuid = vaultUuid,
|
||||
yandexUserId = yandexUserId,
|
||||
email = email,
|
||||
oauthToken = oauthToken,
|
||||
)
|
||||
|
||||
private fun fromModel(model: YandexAccount): DbYandexAccount =
|
||||
DbYandexAccount(
|
||||
vaultUuid = model.vaultUuid,
|
||||
yandexUserId = model.yandexUserId,
|
||||
email = model.email,
|
||||
oauthToken = model.oauthToken,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.vaults.local
|
||||
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.infrastructure.storages.local.LocalStorage
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.vault.contract.DescribedVault
|
||||
import com.github.nullptroma.wallenc.vault.contract.VaultDescriptor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.createDirectory
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class LocalVault(
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
context: Context,
|
||||
idStore: LocalVaultIdStore,
|
||||
) : DescribedVault {
|
||||
|
||||
override val uuid: UUID = idStore.getOrCreate()
|
||||
|
||||
override val descriptor: VaultDescriptor = VaultDescriptor.LocalDevice(uuid)
|
||||
|
||||
private val _storages = MutableStateFlow<List<IStorage>>(emptyList())
|
||||
override val storages: StateFlow<List<IStorage>> = _storages
|
||||
|
||||
private val _isAvailable = MutableStateFlow(false)
|
||||
override val isAvailable: StateFlow<Boolean> = _isAvailable
|
||||
|
||||
private val _totalSpace = MutableStateFlow<Long?>(null)
|
||||
override val totalSpace: StateFlow<Long?> = _totalSpace
|
||||
|
||||
private val _availableSpace = MutableStateFlow<Long?>(null)
|
||||
override val availableSpace: StateFlow<Long?> = _availableSpace
|
||||
|
||||
private val path = MutableStateFlow<File?>(null)
|
||||
|
||||
init {
|
||||
CoroutineScope(ioDispatcher).launch {
|
||||
path.value = context.getExternalFilesDir("LocalVault")
|
||||
_isAvailable.value = path.value != null
|
||||
readStorages()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun readStorages() {
|
||||
val path = path.value
|
||||
if (path == null || !_isAvailable.value)
|
||||
throw Exception("Not available")
|
||||
|
||||
val dirs = path.listFiles()?.filter { it.isDirectory }
|
||||
if (dirs != null) {
|
||||
_storages.value = dirs.map {
|
||||
val uuid = UUID.fromString(it.name)
|
||||
LocalStorage(uuid, it.path, ioDispatcher).apply { init() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createStorage(): LocalStorage = withContext(ioDispatcher) {
|
||||
val path = path.value
|
||||
if (path == null || !_isAvailable.value)
|
||||
throw Exception("Not available")
|
||||
|
||||
val uuid = UUID.randomUUID()
|
||||
val next = Path(path.path, uuid.toString())
|
||||
next.createDirectory()
|
||||
val newStorage = LocalStorage(uuid, next.pathString, ioDispatcher)
|
||||
newStorage.init()
|
||||
_storages.value = _storages.value.toMutableList().apply {
|
||||
add(newStorage)
|
||||
}
|
||||
return@withContext newStorage
|
||||
}
|
||||
|
||||
override suspend fun createStorage(
|
||||
enc: StorageEncryptionInfo,
|
||||
): LocalStorage = withContext(ioDispatcher) {
|
||||
val storage = createStorage()
|
||||
storage.setEncInfo(enc)
|
||||
return@withContext storage
|
||||
}
|
||||
|
||||
override suspend fun remove(storage: IStorage) = withContext(ioDispatcher) {
|
||||
val path = path.value
|
||||
if (path == null || !_isAvailable.value)
|
||||
throw Exception("Not available")
|
||||
|
||||
val curStorages = _storages.value.toMutableList()
|
||||
val index = curStorages.indexOfFirst { it.uuid == storage.uuid }
|
||||
if (index != -1) {
|
||||
val localStorage = curStorages[index] as LocalStorage
|
||||
curStorages.removeAt(index)
|
||||
_storages.value = curStorages
|
||||
File(localStorage.absolutePath).deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.github.nullptroma.wallenc.infrastructure.vaults.local
|
||||
|
||||
import android.content.Context
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Хранит/восстанавливает идентификатор единственного локального vault'а
|
||||
* в [android.content.SharedPreferences]. При первом обращении генерирует новый UUID
|
||||
* и записывает его синхронно (`commit`), чтобы к моменту, когда другие подсистемы
|
||||
* (DB, шифр-ключи) начнут связывать с ним записи, значение уже было персистентно.
|
||||
*/
|
||||
class LocalVaultIdStore(context: Context) {
|
||||
|
||||
private val prefs = context.applicationContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
/** Возвращает существующий идентификатор или, если его нет, генерирует и сохраняет новый. */
|
||||
fun getOrCreate(): UUID {
|
||||
prefs.getString(KEY_LOCAL_VAULT_UUID, null)?.let { stored ->
|
||||
runCatching { UUID.fromString(stored) }.getOrNull()?.let { return it }
|
||||
}
|
||||
val generated = UUID.randomUUID()
|
||||
prefs.edit().putString(KEY_LOCAL_VAULT_UUID, generated.toString()).commit()
|
||||
return generated
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PREFS_NAME = "wallenc.vaults"
|
||||
const val KEY_LOCAL_VAULT_UUID = "local_vault_uuid"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user