full reborn

This commit is contained in:
2021-11-24 13:52:27 +06:00
parent 0ac6b0a4df
commit 6a6a197041
246 changed files with 4327 additions and 6952 deletions
.github/workflows
LICENSEREADME.mdbuild.gradle
business_cases/post_creating
client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
business_cases
post_creating
main
common
src
commonMain
kotlin
dev
inmo
postssystem
main
server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
business_cases
post_creating
client
core
defaultAndroidSettingsdefaultAndroidSettings.gradleextensions.gradle
features
auth
common
client
build.gradle
src
commonMain
kotlin
dev
inmo
main
common
build.gradle
src
commonMain
kotlin
dev
inmo
jvmMain
kotlin
dev
inmo
postssystem
features
main
server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
features
files
client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
main
common
server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
features
roles
status
client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
main
common
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
status
main
server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
features
template
users
client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
main
common
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
jvmMain
kotlin
dev
inmo
postssystem
features
main
server
build.gradle
src
jvmMain
kotlin
dev
inmo
postssystem
gradle.properties
gradle/wrapper
gradlewgradlew.bat
mimes_generator
mppAndroidProject.gradlemppJavaProject.gradlemppJsProject.gradlemppProjectWithSerialization.gradlepubconf.kpsbpublish.gradlepublish.kpsb
publishing
server
settings.gradle

@@ -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)
}
}

@@ -0,0 +1 @@
<manifest package="dev.inmo.postssystem.features.files.common"/>