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 95c3a14..32cf6b4 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 @@ -26,6 +26,7 @@ import timber.log.Timber import java.io.File import java.io.InputStream import java.io.OutputStream +import java.nio.file.Files import java.nio.file.Path import kotlin.io.path.Path import kotlin.io.path.absolute @@ -34,10 +35,11 @@ import kotlin.io.path.pathString import kotlin.io.path.relativeTo class LocalStorageAccessor( - absolutePath: String, + filesystemBasePath: String, private val ioDispatcher: CoroutineDispatcher ) : IStorageAccessor { - private val _absolutePath: Path = Path(absolutePath).normalize().absolute() + private val _filesystemBasePath: Path = Path(filesystemBasePath).normalize().absolute() + private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() } private val _size = MutableStateFlow(null) override val size: StateFlow = _size @@ -57,7 +59,7 @@ class LocalStorageAccessor( init { // запускам сканирование хранилища CoroutineScope(ioDispatcher).launch { - Timber.d("Local storage path: $_absolutePath") + Timber.d("Local storage path: $_filesystemBasePath") scanSizeAndNumOfFiles() } } @@ -66,7 +68,7 @@ class LocalStorageAccessor( * Проверяет существование корневого пути Storage в файловой системе, изменяет _isAvailable */ private fun checkAvailable(): Boolean { - _isAvailable.value = _absolutePath.toFile().exists() + _isAvailable.value = _filesystemBasePath.toFile().exists() return _isAvailable.value } @@ -118,11 +120,11 @@ class LocalStorageAccessor( companion object { private val _jackson = jacksonObjectMapper().apply { findAndRegisterModules() } - fun fromFile(basePath: Path, file: File): LocalStorageFilePair? { + fun fromFile(filesystemBasePath: Path, file: File): LocalStorageFilePair? { if (!file.exists()) return null if (file.name.endsWith(META_INFO_POSTFIX)) - return fromMetaFile(basePath, file) + return fromMetaFile(filesystemBasePath, file) val filePath = file.toPath() val metaFilePath = Path( @@ -134,7 +136,7 @@ class LocalStorageAccessor( ) val metaFile = metaFilePath.toFile() val metaInfo: LocalMetaInfo - val storageFilePath = "/" + filePath.relativeTo(basePath) + val storageFilePath = "/" + filePath.relativeTo(filesystemBasePath) if (!metaFile.exists()) { metaInfo = LocalMetaInfo( @@ -164,16 +166,16 @@ class LocalStorageAccessor( ) } - fun fromMetaFile(basePath: Path, metaFile: File): LocalStorageFilePair? { + fun fromMetaFile(filesystemBasePath: Path, metaFile: File): LocalStorageFilePair? { if (!metaFile.exists()) return null if (!metaFile.name.endsWith(META_INFO_POSTFIX)) - return fromFile(basePath, metaFile) + return fromFile(filesystemBasePath, metaFile) var pair: LocalStorageFilePair? = null try { val reader = metaFile.bufferedReader() val metaInfo: LocalMetaInfo = _jackson.readValue(reader) - val pathString = Path(basePath.pathString, metaInfo.path).pathString + val pathString = Path(filesystemBasePath.pathString, metaInfo.path).pathString val file = File(pathString) if (!file.exists()) { metaFile.delete() @@ -190,16 +192,16 @@ class LocalStorageAccessor( return pair } - fun from(basePath: Path, anyFile: File): LocalStorageFilePair? { + fun from(filesystemBasePath: Path, anyFile: File): LocalStorageFilePair? { return if (anyFile.name.endsWith(META_INFO_POSTFIX)) - fromMetaFile(basePath, anyFile) + fromMetaFile(filesystemBasePath, anyFile) else - fromFile(basePath, anyFile) + fromFile(filesystemBasePath, anyFile) } - fun from(basePath: Path, storagePath: String): LocalStorageFilePair? { - val filePath = Path(basePath.pathString, storagePath) - return from(basePath, filePath.toFile()) + fun from(filesystemBasePath: Path, storagePath: String): LocalStorageFilePair? { + val filePath = Path(filesystemBasePath.pathString, storagePath) + return from(filesystemBasePath, filePath.toFile()) } } } @@ -216,7 +218,7 @@ class LocalStorageAccessor( ) { if (!checkAvailable()) throw Exception("Not available") - val basePath = Path(_absolutePath.pathString, baseStoragePath) + val basePath = Path(_filesystemBasePath.pathString, baseStoragePath) val workedFiles = mutableSetOf() val workedMetaFiles = mutableSetOf() @@ -226,7 +228,7 @@ class LocalStorageAccessor( return@scanFileSystem } - val pair = LocalStorageFilePair.from(_absolutePath, file) + val pair = LocalStorageFilePair.from(_filesystemBasePath, file) if(pair != null) { workedFiles.add(pair.file.absolutePath) workedMetaFiles.add(pair.metaFile.absolutePath) @@ -336,43 +338,116 @@ class LocalStorageAccessor( } override suspend fun getDirs(path: String): List = withContext(ioDispatcher) { - TODO("Not yet implemented") + if (!checkAvailable()) + return@withContext listOf() + + val list = mutableListOf() + scanStorage(baseStoragePath = path, maxDepth = 0, dirCallback = { _, localDir -> + list.add(localDir) + }) + return@withContext list } - override fun getDirsFlow(path: String): Flow>> { - TODO("Not yet implemented") + override fun getDirsFlow(path: String): Flow>> = flow { + if (!checkAvailable()) + return@flow + + val buf = mutableListOf() + var pageNumber = 0 + scanStorage(baseStoragePath = path, maxDepth = 0, dirCallback = { _, localDir -> + if (buf.size == DATA_PAGE_LENGTH) { + val page = DataPage( + list = buf.toList(), + isLoading = false, + isError = false, + hasNext = true, + pageLength = DATA_PAGE_LENGTH, + pageIndex = pageNumber++ + ) + emit(page) + buf.clear() + } + buf.add(localDir) + }) + // отправка последней страницы + val page = DataPage( + list = buf.toList(), + isLoading = false, + isError = false, + hasNext = false, + pageLength = DATA_PAGE_LENGTH, + pageIndex = pageNumber++ + ) + emit(page) + }.flowOn(ioDispatcher) + + private fun writeMeta(metaFile: File, meta: LocalMetaInfo) { + _jackson.writeValue(metaFile, meta) } - override suspend fun touchFile(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") + private fun createFile(storagePath: String): LocalFile { + val path = Path(_filesystemBasePath.pathString, storagePath) + val file = path.toFile() + if(file.exists() && file.isDirectory) { + throw Exception("Что то пошло не так") // TODO + } + else { + file.createNewFile() + } + + val pair = LocalStorageFilePair.from(_filesystemBasePath, file) ?: throw Exception("Что то пошло не так") // TODO + val newMeta = pair.meta.copy(lastModified = java.time.Clock.systemUTC().instant()) + writeMeta(pair.metaFile, newMeta) + return LocalFile(newMeta) } - override suspend fun touchDir(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") + private fun createDir(storagePath: String): LocalDirectory { + val path = Path(_filesystemBasePath.pathString, storagePath) + val file = path.toFile() + if(file.exists() && !file.isDirectory) { + throw Exception("Что то пошло не так") // TODO + } + else { + Files.createDirectories(path) + } + + val pair = LocalStorageFilePair.from(_filesystemBasePath, file) ?: throw Exception("Что то пошло не так") // TODO + val newMeta = pair.meta.copy(lastModified = java.time.Clock.systemUTC().instant()) + writeMeta(pair.metaFile, newMeta) + return LocalDirectory(newMeta, 0) + } + + override suspend fun touchFile(path: String): Unit = withContext(ioDispatcher) { + createFile(path) + } + + override suspend fun touchDir(path: String): Unit = withContext(ioDispatcher) { + createDir(path) } override suspend fun delete(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") + val pair = LocalStorageFilePair.from(_filesystemBasePath, path) + if(pair != null) { + pair.file.delete() + pair.metaFile.delete() + } } - override suspend fun getFileInfo(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") + override suspend fun openWrite(path: String): OutputStream = withContext(ioDispatcher) { + touchFile(path) + val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO + return@withContext pair.file.outputStream() } - override suspend fun getDirInfo(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") - } - - override suspend fun openWrite(path: String): InputStream = withContext(ioDispatcher) { - TODO("Not yet implemented") - } - - override suspend fun openRead(path: String): OutputStream = withContext(ioDispatcher) { - TODO("Not yet implemented") + override suspend fun openRead(path: String): InputStream = withContext(ioDispatcher) { + val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO + return@withContext pair.file.inputStream() } override suspend fun moveToTrash(path: String) = withContext(ioDispatcher) { - TODO("Not yet implemented") + val pair = LocalStorageFilePair.from(_filesystemBasePath, path) ?: throw Exception("Файла нет") // TODO + val newMeta = pair.meta.copy(isDeleted = true) + writeMeta(pair.metaFile, newMeta) } companion object { diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/EncryptKey.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/EncryptKey.kt index 679acaf..ccc94e6 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/EncryptKey.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/datatypes/EncryptKey.kt @@ -1,9 +1,5 @@ package com.github.nullptroma.wallenc.domain.datatypes -class EncryptKey { - val key: String +class EncryptKey(val key: String) { - constructor(key: String) { - this@EncryptKey.key = key - } } \ No newline at end of file diff --git a/domain/src/main/java/com/github/nullptroma/wallenc/domain/models/IStorageAccessor.kt b/domain/src/main/java/com/github/nullptroma/wallenc/domain/models/IStorageAccessor.kt index e845b95..310fab5 100644 --- a/domain/src/main/java/com/github/nullptroma/wallenc/domain/models/IStorageAccessor.kt +++ b/domain/src/main/java/com/github/nullptroma/wallenc/domain/models/IStorageAccessor.kt @@ -35,9 +35,7 @@ interface IStorageAccessor { suspend fun touchFile(path: String) suspend fun touchDir(path: String) suspend fun delete(path: String) - suspend fun getFileInfo(path: String) - suspend fun getDirInfo(path: String) - suspend fun openWrite(path: String): InputStream - suspend fun openRead(path: String): OutputStream + suspend fun openWrite(path: String): OutputStream + suspend fun openRead(path: String): InputStream suspend fun moveToTrash(path: String) } \ No newline at end of file diff --git a/wallenc-uml.gaphor b/wallenc-uml.gaphor index 11302ec..df0091d 100644 --- a/wallenc-uml.gaphor +++ b/wallenc-uml.gaphor @@ -1209,8 +1209,6 @@ existing classes or even new classes with specific responsibilities. - - @@ -1409,60 +1407,6 @@ existing classes or even new classes with specific responsibilities. Uri - - - - - -getFileInfo - - - - - - - - - -in - - -path - - - - - -Uri - - - - - - - -getDirInfo - - - - - - - - - -in - - -path - - - - - -Uri - -