diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/utils/CloseHandledStream.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/utils/CloseHandledStream.kt new file mode 100644 index 0000000..606ade1 --- /dev/null +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/utils/CloseHandledStream.kt @@ -0,0 +1,92 @@ +package com.github.nullptroma.wallenc.data.utils + +import java.io.InputStream +import java.io.OutputStream + +private class CloseHandledOutputStream( + private val stream: OutputStream, + private val onClose: () -> Unit +) : OutputStream() { + + override fun write(b: Int) { + stream.write(b) + } + + override fun write(b: ByteArray) { + stream.write(b) + } + + override fun write(b: ByteArray, off: Int, len: Int) { + stream.write(b, off, len) + } + + override fun flush() { + stream.flush() + } + + override fun close() { + try { + stream.close() + } finally { + onClose() + } + } +} + +private class CloseHandledInputStream( + private val stream: InputStream, + private val onClose: () -> Unit +) : InputStream() { + + override fun read(): Int { + return stream.read() + } + + override fun read(b: ByteArray): Int { + return stream.read(b) + } + + override fun read(b: ByteArray, off: Int, len: Int): Int { + return stream.read(b, off, len) + } + + override fun skip(n: Long): Long { + return stream.skip(n) + } + + override fun available(): Int { + return stream.available() + } + + override fun close() { + try { + stream.close() + } finally { + onClose() + } + } + + override fun mark(readlimit: Int) { + stream.mark(readlimit) + } + + override fun reset() { + stream.reset() + } + + override fun markSupported(): Boolean { + return stream.markSupported() + } +} + +class CloseHandledStreamExtension { + companion object { + fun OutputStream.onClose(callback: ()->Unit): OutputStream { + return CloseHandledOutputStream(this, callback) + } + + fun InputStream.onClose(callback: ()->Unit): InputStream { + return CloseHandledInputStream(this, callback) + } + } +} \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt index 6f8e85f..7c1fa92 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/UnlockManager.kt @@ -27,7 +27,7 @@ class UnlockManager( private val _openedStorages = MutableStateFlow?>(null) override val openedStorages: StateFlow?> get() = _openedStorages - val mutex = Mutex() + private val mutex = Mutex() init { CoroutineScope(ioDispatcher).launch { @@ -51,7 +51,7 @@ class UnlockManager( private fun createEncryptedStorage(storage: IStorage, key: EncryptKey, uuid: UUID): EncryptedStorage { return EncryptedStorage( - source = storage, + _source = storage, key = key, ioDispatcher = ioDispatcher, uuid = uuid @@ -63,13 +63,10 @@ class UnlockManager( key: EncryptKey ) = withContext(ioDispatcher) { mutex.lock() - val encInfo = storage.encInfo.value ?: throw Exception("EncInfo is null") // TODO + val encInfo = storage.metaInfo.value.encInfo ?: throw Exception("EncInfo is null") // TODO if (!Encryptor.checkKey(key, encInfo)) throw Exception("Incorrect Key") - if (_openedStorages.value == null) { - val childScope = CoroutineScope(ioDispatcher) - } val opened = _openedStorages.first { it != null }!!.toMutableMap() val cur = opened[storage.uuid] if (cur != null) diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt index e970822..c0312fe 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorage.kt @@ -1,35 +1,46 @@ package com.github.nullptroma.wallenc.data.vaults.local import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo import com.github.nullptroma.wallenc.domain.interfaces.IStorage import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor +import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.withContext +import java.io.InputStream import java.util.UUID class LocalStorage( override val uuid: UUID, absolutePath: String, - ioDispatcher: CoroutineDispatcher, + private val ioDispatcher: CoroutineDispatcher, ) : IStorage { override val size: StateFlow get() = accessor.size override val numberOfFiles: StateFlow get() = accessor.numberOfFiles + + private val _metaInfo = MutableStateFlow( + CommonStorageMetaInfo( + encInfo = StorageEncryptionInfo( + isEncrypted = false, + encryptedTestData = null + ), + name = null + ) + ) + override val metaInfo: StateFlow + get() = _metaInfo + override val isAvailable: StateFlow get() = accessor.isAvailable private val _accessor = LocalStorageAccessor(absolutePath, ioDispatcher) override val accessor: IStorageAccessor = _accessor - private val _encInfo = MutableStateFlow(null) - override val encInfo: StateFlow - get() = _encInfo - override val name: StateFlow - get() = TODO("Добавить класс в Domain, который с помощью accessor будет читать и сохранять имя в скрытую папку") - private val encInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX" suspend fun init() { @@ -37,15 +48,14 @@ class LocalStorage( readEncInfo() } - private suspend fun readEncInfo() { - val reader = _accessor.openReadSystemFile(encInfoFileName) + private suspend fun readEncInfo() = withContext(ioDispatcher) { var enc: StorageEncryptionInfo? = null + var reader: InputStream? = null try { - enc = _jackson.readValue(reader, StorageEncryptionInfo::class.java) - reader.close() + reader = _accessor.openReadSystemFile(encInfoFileName) + enc = jackson.readValue(reader, StorageEncryptionInfo::class.java) } catch(e: Exception) { - reader.close() // чтение не удалось, значит нужно записать файл enc = StorageEncryptionInfo( isEncrypted = false, @@ -53,19 +63,22 @@ class LocalStorage( ) setEncInfo(enc) } - _encInfo.value = enc + finally { + reader?.close() + } + _metaInfo.value = _metaInfo.value.copy(encInfo = enc) } - suspend fun setEncInfo(enc: StorageEncryptionInfo) { + suspend fun setEncInfo(enc: StorageEncryptionInfo) = withContext(ioDispatcher) { val writer = _accessor.openWriteSystemFile(encInfoFileName) try { - _jackson.writeValue(writer, enc) + jackson.writeValue(writer, enc) } catch (e: Exception) { TODO("Это никогда не должно произойти") } writer.close() - _encInfo.value = enc + _metaInfo.value = _metaInfo.value.copy(encInfo = enc) } override suspend fun rename(newName: String) { @@ -74,6 +87,6 @@ class LocalStorage( companion object { const val ENC_INFO_FILE_POSTFIX = ".enc-info" - private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() } + private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() } } } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt index faa12d4..ef2a5d6 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalStorageAccessor.kt @@ -3,6 +3,7 @@ package com.github.nullptroma.wallenc.data.vaults.local import com.fasterxml.jackson.core.JacksonException import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import com.github.nullptroma.wallenc.data.utils.CloseHandledStreamExtension.Companion.onClose import com.github.nullptroma.wallenc.domain.common.impl.CommonDirectory import com.github.nullptroma.wallenc.domain.common.impl.CommonFile import com.github.nullptroma.wallenc.domain.common.impl.CommonMetaInfo @@ -13,6 +14,7 @@ import com.github.nullptroma.wallenc.domain.interfaces.IFile import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -20,6 +22,7 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File import java.io.InputStream @@ -115,7 +118,7 @@ class LocalStorageAccessor( ) { companion object { - private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() } + private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() } fun fromFile(filesystemBasePath: Path, file: File): LocalStorageFilePair? { if (!file.exists()) @@ -140,19 +143,19 @@ class LocalStorageAccessor( size = filePath.fileSize(), path = storageFilePath ) - _jackson.writeValue(metaFile, metaInfo) + jackson.writeValue(metaFile, metaInfo) } else { var readMeta: CommonMetaInfo try { val reader = metaFile.bufferedReader() - readMeta = _jackson.readValue(reader) + readMeta = jackson.readValue(reader) } catch (e: JacksonException) { // если файл повреждён - пересоздать readMeta = CommonMetaInfo( size = filePath.fileSize(), path = storageFilePath ) - _jackson.writeValue(metaFile, readMeta) + jackson.writeValue(metaFile, readMeta) } metaInfo = readMeta } @@ -171,7 +174,7 @@ class LocalStorageAccessor( var pair: LocalStorageFilePair? = null try { val reader = metaFile.bufferedReader() - val metaInfo: CommonMetaInfo = _jackson.readValue(reader) + val metaInfo: CommonMetaInfo = jackson.readValue(reader) val pathString = Path(filesystemBasePath.pathString, metaInfo.path).pathString val file = File(pathString) if (!file.exists()) { @@ -258,8 +261,8 @@ class LocalStorageAccessor( var size = 0L var numOfFiles = 0 - scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, CommonFile -> - size += CommonFile.metaInfo.size + scanStorage(baseStoragePath = "/", maxDepth = -1, fileCallback = { _, commonFile -> + size += commonFile.metaInfo.size numOfFiles++ if (numOfFiles % DATA_PAGE_LENGTH == 0) { @@ -402,15 +405,17 @@ class LocalStorageAccessor( override suspend fun setHidden(path: String, hidden: Boolean) { val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Что то пошло не так") // TODO - if(pair.meta.isHidden == hidden) + if (pair.meta.isHidden == hidden) return val newMeta = pair.meta.copy(isHidden = hidden) writeMeta(pair.metaFile, newMeta) _filesUpdates.emit( DataPage( - list = listOf(CommonFile( - metaInfo = newMeta - )), + list = listOf( + CommonFile( + metaInfo = newMeta + ) + ), pageLength = 1, pageIndex = 0 ) @@ -419,31 +424,41 @@ class LocalStorageAccessor( private fun writeMeta(metaFile: File, meta: IMetaInfo) { - _jackson.writeValue(metaFile, meta) + jackson.writeValue(metaFile, meta) } - private fun createFile(storagePath: String): CommonFile { + private suspend fun createFile(storagePath: String): CommonFile = withContext(ioDispatcher) { val path = Path(_filesystemBasePath.pathString, storagePath) val file = path.toFile() - if (file.exists() && file.isDirectory) { + if (file.exists() && file.isDirectory) { throw Exception("Что то пошло не так") // TODO - } else { + } else if(!file.exists()) { file.createNewFile() + + val cur = _numberOfFiles.value + _numberOfFiles.value = if (cur == null) null else cur + 1 } val pair = LocalStorageFilePair.from(_filesystemBasePath, file) ?: throw Exception("Что то пошло не так") // TODO val newMeta = pair.meta.copy(lastModified = Clock.systemUTC().instant()) writeMeta(pair.metaFile, newMeta) - return CommonFile(newMeta) + _filesUpdates.emit( + DataPage( + list = listOf(CommonFile(pair.meta)), + pageLength = 1, + pageIndex = 0 + ) + ) + return@withContext CommonFile(newMeta) } - private fun createDir(storagePath: String): CommonDirectory { + private suspend fun createDir(storagePath: String): CommonDirectory = withContext(ioDispatcher) { val path = Path(_filesystemBasePath.pathString, storagePath) val file = path.toFile() if (file.exists() && !file.isDirectory) { throw Exception("Что то пошло не так") // TODO - } else { + } else if(!file.exists()) { Files.createDirectories(path) } @@ -451,11 +466,25 @@ class LocalStorageAccessor( ?: throw Exception("Что то пошло не так") // TODO val newMeta = pair.meta.copy(lastModified = Clock.systemUTC().instant()) writeMeta(pair.metaFile, newMeta) - return CommonDirectory(newMeta, 0) + _dirsUpdates.emit( + DataPage( + list = listOf(CommonDirectory(pair.meta, null)), + pageLength = 1, + pageIndex = 0 + ) + ) + return@withContext CommonDirectory(newMeta, 0) } override suspend fun touchFile(path: String): Unit = withContext(ioDispatcher) { createFile(path) + + // перебор все каталогов и обновление их времени модификации + var parent = Path(path).parent + while(parent != null) { + touchDir(parent.pathString) + parent = parent.parent + } } override suspend fun touchDir(path: String): Unit = withContext(ioDispatcher) { @@ -474,7 +503,11 @@ class LocalStorageAccessor( touchFile(path) val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO - return@withContext pair.file.outputStream() + return@withContext pair.file.outputStream().onClose { + CoroutineScope(ioDispatcher).launch { + touchFile(path) + } + } } override suspend fun openRead(path: String): InputStream = withContext(ioDispatcher) { @@ -519,6 +552,6 @@ class LocalStorageAccessor( private const val SYSTEM_HIDDEN_DIRNAME = "wallenc-local-storage-meta-dir" private const val META_INFO_POSTFIX = ".wallenc-meta" private const val DATA_PAGE_LENGTH = 10 - private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() } + private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() } } } \ No newline at end of file diff --git a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt index b391010..d9a1f31 100644 --- a/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt +++ b/data/src/main/java/com/github/nullptroma/wallenc/data/vaults/local/LocalVault.kt @@ -34,18 +34,18 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context private val _availableSpace = MutableStateFlow(null) override val availableSpace: StateFlow = _availableSpace - private val _path = MutableStateFlow(null) + private val path = MutableStateFlow(null) init { CoroutineScope(ioDispatcher).launch { - _path.value = context.getExternalFilesDir("LocalVault") - _isAvailable.value = _path.value != null + path.value = context.getExternalFilesDir("LocalVault") + _isAvailable.value = path.value != null readStorages() } } private suspend fun readStorages() { - val path = _path.value + val path = path.value if (path == null || !_isAvailable.value) return @@ -59,7 +59,7 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context } override suspend fun createStorage(): LocalStorage = withContext(ioDispatcher) { - val path = _path.value + val path = path.value if (path == null || !_isAvailable.value) throw Exception("Not available") diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt new file mode 100644 index 0000000..9fc2f77 --- /dev/null +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/common/impl/CommonStorageMetaInfo.kt @@ -0,0 +1,15 @@ +package com.github.nullptroma.wallenc.domain.common.impl + +import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo +import com.github.nullptroma.wallenc.domain.interfaces.IStorage +import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo +import java.time.Clock +import java.time.Instant + + +data class CommonStorageMetaInfo( + override val encInfo: StorageEncryptionInfo?, + override val name: String?, + override val lastModified: Instant = Clock.systemUTC().instant() +) : IStorageMetaInfo \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/DataPage.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/DataPage.kt index 35ae052..e76c493 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/DataPage.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/DataPage.kt @@ -2,9 +2,9 @@ package com.github.nullptroma.wallenc.domain.datatypes class DataPage( list: List, - isLoading: Boolean? = false, - isError: Boolean? = false, - val hasNext: Boolean? = false, + isLoading: Boolean? = null, + isError: Boolean? = null, + val hasNext: Boolean? = null, val pageLength: Int, val pageIndex: Int ) : DataPackage>(data = list, isLoading = isLoading, isError = isError) \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt index d03f5b5..bb81434 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorage.kt @@ -1,38 +1,46 @@ package com.github.nullptroma.wallenc.domain.encrypt +import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo -import com.github.nullptroma.wallenc.domain.interfaces.ILogger import com.github.nullptroma.wallenc.domain.interfaces.IStorage +import com.github.nullptroma.wallenc.domain.interfaces.IStorageMetaInfo import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import java.util.UUID class EncryptedStorage( - private val source: IStorage, + private val _source: IStorage, key: EncryptKey, - ioDispatcher: CoroutineDispatcher, + private val ioDispatcher: CoroutineDispatcher, override val uuid: UUID = UUID.randomUUID() ) : IStorage, DisposableHandle { override val size: StateFlow - get() = source.size + get() = _source.size override val numberOfFiles: StateFlow - get() = source.numberOfFiles - override val name: StateFlow - get() = TODO("Not yet implemented") - override val isAvailable: StateFlow - get() = source.isAvailable - override val encInfo: StateFlow - get() = MutableStateFlow( - StorageEncryptionInfo( + get() = _source.numberOfFiles + + private val _metaInfo = MutableStateFlow( + CommonStorageMetaInfo( + encInfo = StorageEncryptionInfo( isEncrypted = false, encryptedTestData = null - ) + ), + name = null ) + ) + override val metaInfo: StateFlow + get() = _metaInfo + + override val isAvailable: StateFlow + get() = _source.isAvailable override val accessor: EncryptedStorageAccessor = - EncryptedStorageAccessor(source.accessor, key, ioDispatcher) + EncryptedStorageAccessor(_source.accessor, key, ioDispatcher) override suspend fun rename(newName: String) { TODO("Not yet implemented") diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt index 0ffc50e..e082258 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/encrypt/EncryptedStorageAccessor.kt @@ -7,7 +7,6 @@ import com.github.nullptroma.wallenc.domain.datatypes.DataPackage import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey import com.github.nullptroma.wallenc.domain.interfaces.IDirectory import com.github.nullptroma.wallenc.domain.interfaces.IFile -import com.github.nullptroma.wallenc.domain.interfaces.ILogger import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor import kotlinx.coroutines.CoroutineDispatcher @@ -30,8 +29,8 @@ class EncryptedStorageAccessor( key: EncryptKey, ioDispatcher: CoroutineDispatcher ) : IStorageAccessor, DisposableHandle { - private val _job = Job() - private val _scope = CoroutineScope(ioDispatcher + _job) + private val job = Job() + private val scope = CoroutineScope(ioDispatcher + job) override val size: StateFlow = source.size override val numberOfFiles: StateFlow = source.numberOfFiles @@ -43,14 +42,14 @@ class EncryptedStorageAccessor( private val _dirsUpdates = MutableSharedFlow>>() override val dirsUpdates: SharedFlow>> = _dirsUpdates - private val _encryptor = Encryptor(key.toAesKey()) + private val encryptor = Encryptor(key.toAesKey()) init { collectSourceState() } private fun collectSourceState() { - _scope.launch { + scope.launch { launch { source.filesUpdates.collect { val files = it.data.map(::decryptEntity) @@ -116,7 +115,7 @@ class EncryptedStorageAccessor( val path = Path(pathStr) val segments = mutableListOf() for (segment in path) - segments.add(_encryptor.encryptString(segment.pathString)) + segments.add(encryptor.encryptString(segment.pathString)) val res = Path("/",*(segments.toTypedArray())) return res.pathString } @@ -125,7 +124,7 @@ class EncryptedStorageAccessor( val path = Path(pathStr) val segments = mutableListOf() for (segment in path) - segments.add(_encryptor.decryptString(segment.pathString)) + segments.add(encryptor.decryptString(segment.pathString)) val res = Path("/",*(segments.toTypedArray())) return res.pathString } @@ -198,12 +197,12 @@ class EncryptedStorageAccessor( override suspend fun openWrite(path: String): OutputStream { val stream = source.openWrite(encryptPath(path)) - return _encryptor.encryptStream(stream) + return encryptor.encryptStream(stream) } override suspend fun openRead(path: String): InputStream { val stream = source.openRead(encryptPath(path)) - return _encryptor.decryptStream(stream) + return encryptor.decryptStream(stream) } override suspend fun moveToTrash(path: String) { @@ -211,7 +210,8 @@ class EncryptedStorageAccessor( } override fun dispose() { - _job.cancel() - _encryptor.dispose() + job.cancel() + encryptor.dispose() } + } \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt index 3774745..cca8176 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageInfo.kt @@ -1,6 +1,5 @@ package com.github.nullptroma.wallenc.domain.interfaces -import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo import kotlinx.coroutines.flow.StateFlow import java.util.UUID @@ -9,6 +8,5 @@ sealed interface IStorageInfo { val isAvailable: StateFlow val size: StateFlow val numberOfFiles: StateFlow - val encInfo: StateFlow - val name: StateFlow + val metaInfo: StateFlow } \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt new file mode 100644 index 0000000..c17f25d --- /dev/null +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/interfaces/IStorageMetaInfo.kt @@ -0,0 +1,13 @@ +package com.github.nullptroma.wallenc.domain.interfaces + +import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo +import kotlinx.coroutines.flow.StateFlow +import java.time.Clock +import java.time.Instant + +interface IStorageMetaInfo { + val encInfo: StorageEncryptionInfo? + val name: String? + val lastModified: Instant + +} \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/extensions/StorageInfo.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/extensions/StorageInfo.kt index 3bdc329..9027b00 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/extensions/StorageInfo.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/extensions/StorageInfo.kt @@ -3,5 +3,5 @@ package com.github.nullptroma.wallenc.presentation.extensions import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo fun IStorageInfo.toPrintable(): String { - return "{ uuid: $uuid, enc: ${encInfo.value} }" + return "{ uuid: $uuid, enc: ${metaInfo.value.encInfo} }" } \ No newline at end of file diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt index 74b02da..6c4a8c6 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultScreen.kt @@ -48,7 +48,9 @@ fun LocalVaultScreen(modifier: Modifier = Modifier, val available by it.isAvailable.collectAsStateWithLifecycle() val numOfFiles by it.numberOfFiles.collectAsStateWithLifecycle() val size by it.size.collectAsStateWithLifecycle() - val enc by it.encInfo.collectAsStateWithLifecycle() + val metaInfo by it.metaInfo.collectAsStateWithLifecycle() + + val enc = metaInfo.encInfo Column { Text(it.uuid.toString()) Text("IsAvailable: $available") diff --git a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt index b9b911e..62b206b 100644 --- a/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt +++ b/presentation/src/main/java/com/github/nullptroma/wallenc/presentation/screens/main/screens/local/vault/LocalVaultViewModel.kt @@ -12,7 +12,6 @@ import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCas import com.github.nullptroma.wallenc.presentation.extensions.toPrintable import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -21,15 +20,15 @@ import kotlin.system.measureTimeMillis @HiltViewModel class LocalVaultViewModel @Inject constructor( - private val _manageLocalVaultUseCase: ManageLocalVaultUseCase, - private val _getOpenedStoragesUseCase: GetOpenedStoragesUseCase, - private val _storageFileManagementUseCase: StorageFileManagementUseCase, + private val manageLocalVaultUseCase: ManageLocalVaultUseCase, + private val getOpenedStoragesUseCase: GetOpenedStoragesUseCase, + private val storageFileManagementUseCase: StorageFileManagementUseCase, private val logger: ILogger ) : ViewModelBase(LocalVaultScreenState(listOf())) { init { viewModelScope.launch { - _manageLocalVaultUseCase.localStorages.combine(_getOpenedStoragesUseCase.openedStorages) { local, opened -> + manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened -> local + (opened?.map { it.value } ?: listOf()) }.collectLatest { val newState = state.value.copy( @@ -41,13 +40,13 @@ class LocalVaultViewModel @Inject constructor( } fun printStorageInfoToLog(storage: IStorageInfo) { - _storageFileManagementUseCase.setStorage(storage) + storageFileManagementUseCase.setStorage(storage) viewModelScope.launch { val files: List val dirs: List val time = measureTimeMillis { - files = _storageFileManagementUseCase.getAllFiles() - dirs = _storageFileManagementUseCase.getAllDirs() + files = storageFileManagementUseCase.getAllFiles() + dirs = storageFileManagementUseCase.getAllDirs() } for (file in files) { logger.debug("Files", file.metaInfo.toString()) @@ -62,7 +61,7 @@ class LocalVaultViewModel @Inject constructor( fun createStorage() { viewModelScope.launch { - _manageLocalVaultUseCase.createStorage(EncryptKey("hello")) + manageLocalVaultUseCase.createStorage(EncryptKey("hello")) } } } \ No newline at end of file