full reborn
This commit is contained in:
19
features/files/common/build.gradle
Normal file
19
features/files/common/build.gradle
Normal file
@@ -0,0 +1,19 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppProjectWithSerializationPresetPath"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api project(":postssystem.features.common.common")
|
||||
api "dev.inmo:micro_utils.mime_types:$microutils_version"
|
||||
api "dev.inmo:micro_utils.repos.common:$microutils_version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
const val filesRootPathPart = "files"
|
||||
const val filesGetFilesPathPart = "getFiles"
|
||||
const val filesGetFullFileInfoPathPart = "getFullFileInfo"
|
||||
const val filesFileIdParameter = "fileId"
|
@@ -0,0 +1,35 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import dev.inmo.micro_utils.mime_types.MimeType
|
||||
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable(FileInfoSerializer::class)
|
||||
sealed interface FileInfo {
|
||||
val name: FileName
|
||||
val mimeType: MimeType
|
||||
|
||||
companion object {
|
||||
fun serializer(): KSerializer<FileInfo> = FileInfoSerializer
|
||||
}
|
||||
}
|
||||
|
||||
object FileInfoSerializer : KSerializer<FileInfo> by TypedSerializer(
|
||||
"meta" to MetaFileInfo.serializer(),
|
||||
"full" to FullFileInfo.serializer(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MetaFileInfo(override val name: FileName, override val mimeType: MimeType) : FileInfo
|
||||
|
||||
@Serializable
|
||||
data class FullFileInfo(
|
||||
override val name: FileName,
|
||||
override val mimeType: MimeType,
|
||||
@Serializable(ByteArrayAllocatorSerializer::class)
|
||||
val byteArrayAllocator: ByteArrayAllocator
|
||||
) : FileInfo
|
||||
|
||||
fun FullFileInfo.toMetaFileInfo() = MetaFileInfo(name, mimeType)
|
@@ -0,0 +1,21 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.jvm.JvmInline
|
||||
|
||||
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class FileId(val string: String) {
|
||||
override fun toString(): String = string.toString()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class FileInfoStorageWrapper {
|
||||
abstract val id: FileId
|
||||
abstract val fileInfo: FileInfo
|
||||
}
|
||||
@Serializable
|
||||
data class MetaFileInfoStorageWrapper(override val id: FileId, override val fileInfo: MetaFileInfo) : FileInfoStorageWrapper()
|
||||
@Serializable
|
||||
data class FullFileInfoStorageWrapper(override val id: FileId, override val fileInfo: FullFileInfo) : FileInfoStorageWrapper()
|
@@ -0,0 +1,9 @@
|
||||
package dev.inmo.postssystem.features.files.common.storage
|
||||
|
||||
import dev.inmo.postssystem.features.files.common.*
|
||||
import dev.inmo.micro_utils.repos.ReadCRUDRepo
|
||||
|
||||
interface FilesStorage : ReadCRUDRepo<MetaFileInfoStorageWrapper, FileId> {
|
||||
suspend fun getBytes(id: FileId): ByteArray
|
||||
suspend fun getFullFileInfo(id: FileId): FullFileInfoStorageWrapper?
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
package dev.inmo.postssystem.features.files.common.storage
|
||||
|
||||
interface FullFilesStorage : FilesStorage, WriteFilesStorage
|
||||
|
||||
class DefaultFullFilesStorage(
|
||||
filesStorage: FilesStorage,
|
||||
writeFilesStorage: WriteFilesStorage
|
||||
) : FullFilesStorage, FilesStorage by filesStorage, WriteFilesStorage by writeFilesStorage
|
@@ -0,0 +1,6 @@
|
||||
package dev.inmo.postssystem.features.files.common.storage
|
||||
|
||||
import dev.inmo.postssystem.features.files.common.*
|
||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
|
||||
|
||||
interface WriteFilesStorage : WriteCRUDRepo<FullFileInfoStorageWrapper, FileId, FullFileInfo>
|
@@ -0,0 +1,63 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
import dev.inmo.postssystem.features.files.common.storage.FilesStorage
|
||||
import dev.inmo.micro_utils.pagination.*
|
||||
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
|
||||
import java.io.File
|
||||
|
||||
class DiskFilesStorage(
|
||||
private val filesFolder: File,
|
||||
private val metasKeyValueRepo: ReadKeyValueRepo<FileId, MetaFileInfo>
|
||||
) : FilesStorage {
|
||||
private val FileId.file
|
||||
get() = File(filesFolder, string)
|
||||
|
||||
init {
|
||||
if (!filesFolder.exists()) {
|
||||
filesFolder.mkdirs()
|
||||
} else {
|
||||
require(filesFolder.isDirectory) { "$filesFolder must be a directory" }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun FileId.meta(): MetaFileInfoStorageWrapper? {
|
||||
return MetaFileInfoStorageWrapper(
|
||||
this,
|
||||
metasKeyValueRepo.get(this) ?: return null
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getBytes(id: FileId): ByteArray = id.file.readBytes()
|
||||
|
||||
override suspend fun getFullFileInfo(id: FileId): FullFileInfoStorageWrapper? = getById(
|
||||
id
|
||||
) ?.let {
|
||||
FullFileInfoStorageWrapper(
|
||||
id,
|
||||
FullFileInfo(
|
||||
it.fileInfo.name,
|
||||
it.fileInfo.mimeType
|
||||
) {
|
||||
id.file.readBytes()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun contains(id: FileId): Boolean = metasKeyValueRepo.contains(id)
|
||||
|
||||
override suspend fun count(): Long = metasKeyValueRepo.count()
|
||||
|
||||
override suspend fun getById(id: FileId): MetaFileInfoStorageWrapper? = id.meta()
|
||||
|
||||
override suspend fun getByPagination(pagination: Pagination): PaginationResult<MetaFileInfoStorageWrapper> {
|
||||
val keys = metasKeyValueRepo.keys(pagination)
|
||||
return keys.changeResults(
|
||||
keys.results.mapNotNull {
|
||||
MetaFileInfoStorageWrapper(
|
||||
it,
|
||||
metasKeyValueRepo.get(it) ?: return@mapNotNull null
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
||||
import dev.inmo.micro_utils.repos.mappers.withMapper
|
||||
import kotlinx.serialization.StringFormat
|
||||
|
||||
fun MetasKeyValueRepo(
|
||||
serialFormat: StringFormat,
|
||||
originalRepo: KeyValueRepo<String, String>
|
||||
) = originalRepo.withMapper<FileId, MetaFileInfo, String, String>(
|
||||
{ string },
|
||||
{ serialFormat.encodeToString(MetaFileInfo.serializer(), this) },
|
||||
{ FileId(this) },
|
||||
{ serialFormat.decodeFromString(MetaFileInfo.serializer(), this) }
|
||||
)
|
@@ -0,0 +1,69 @@
|
||||
package dev.inmo.postssystem.features.files.common
|
||||
|
||||
import com.benasher44.uuid.uuid4
|
||||
import dev.inmo.postssystem.features.files.common.storage.WriteFilesStorage
|
||||
import dev.inmo.micro_utils.repos.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.io.File
|
||||
|
||||
class WriteDistFilesStorage(
|
||||
private val filesFolder: File,
|
||||
private val metasKeyValueRepo: WriteKeyValueRepo<FileId, MetaFileInfo>
|
||||
) : WriteFilesStorage {
|
||||
private val FileId.file
|
||||
get() = File(filesFolder, string)
|
||||
|
||||
private val _deletedObjectsIdsFlow = MutableSharedFlow<FileId>()
|
||||
private val _newObjectsFlow = MutableSharedFlow<FullFileInfoStorageWrapper>()
|
||||
private val _updatedObjectsFlow = MutableSharedFlow<FullFileInfoStorageWrapper>()
|
||||
override val deletedObjectsIdsFlow: Flow<FileId> = _deletedObjectsIdsFlow.asSharedFlow()
|
||||
override val newObjectsFlow: Flow<FullFileInfoStorageWrapper> = _newObjectsFlow.asSharedFlow()
|
||||
override val updatedObjectsFlow: Flow<FullFileInfoStorageWrapper> = _updatedObjectsFlow.asSharedFlow()
|
||||
|
||||
init {
|
||||
if (!filesFolder.exists()) {
|
||||
filesFolder.mkdirs()
|
||||
} else {
|
||||
require(filesFolder.isDirectory) { "$filesFolder must be a directory" }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun create(values: List<FullFileInfo>): List<FullFileInfoStorageWrapper> = values.map {
|
||||
var newId: FileId
|
||||
var file: File
|
||||
do {
|
||||
newId = FileId(uuid4().toString())
|
||||
file = newId.file
|
||||
} while (file.exists())
|
||||
metasKeyValueRepo.set(newId, it.toMetaFileInfo())
|
||||
file.writeBytes(it.byteArrayAllocator())
|
||||
FullFileInfoStorageWrapper(newId, it)
|
||||
}
|
||||
|
||||
override suspend fun deleteById(ids: List<FileId>) {
|
||||
ids.forEach {
|
||||
if (it.file.delete()) {
|
||||
metasKeyValueRepo.unset(it)
|
||||
_deletedObjectsIdsFlow.emit(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun update(
|
||||
id: FileId,
|
||||
value: FullFileInfo
|
||||
): FullFileInfoStorageWrapper? = id.file.takeIf { it.exists() } ?.writeBytes(value.byteArrayAllocator()) ?.let {
|
||||
val result = FullFileInfoStorageWrapper(id, value.copy())
|
||||
|
||||
metasKeyValueRepo.set(id, value.toMetaFileInfo())
|
||||
_updatedObjectsFlow.emit(result)
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
override suspend fun update(
|
||||
values: List<UpdatedValuePair<FileId, FullFileInfo>>
|
||||
): List<FullFileInfoStorageWrapper> = values.mapNotNull { (id, file) ->
|
||||
update(id, file)
|
||||
}
|
||||
}
|
1
features/files/common/src/main/AndroidManifest.xml
Normal file
1
features/files/common/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest package="dev.inmo.postssystem.features.files.common"/>
|
Reference in New Issue
Block a user