start migration onto ktor-based serialization of data
This commit is contained in:
features
auth
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
auth
content
common
src
commonMain
kotlin
dev
inmo
postssystem
features
content
common
files
client
src
commonMain
kotlin
dev
inmo
postssystem
features
files
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
files
roles
client
src
commonMain
kotlin
dev
inmo
postssystem
common
src
commonMain
kotlin
dev
inmo
postssystem
features
roles
common
manager
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
roles
server
src
jvmMain
kotlin
dev
inmo
postssystem
users
client
src
commonMain
kotlin
dev
inmo
postssystem
features
users
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
users
publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client
server/src/main/java/dev/inmo/postssystem/server
services/posts
client
src
commonMain
kotlin
dev
inmo
postssystem
services
server
src
jvmMain
kotlin
dev
inmo
postssystem
services
posts
@ -5,7 +5,7 @@ import dev.inmo.postssystem.services.posts.common.*
|
||||
|
||||
class ClientPostsService(
|
||||
baseUrl: String,
|
||||
unifiedRequester: UnifiedRequester
|
||||
client: HttpClient
|
||||
) : PostsService,
|
||||
ReadPostsService by ClientReadPostsService(baseUrl, unifiedRequester),
|
||||
WritePostsService by ClientWritePostsService(baseUrl, unifiedRequester)
|
||||
ReadPostsService by ClientReadPostsService(baseUrl, client),
|
||||
WritePostsService by ClientWritePostsService(baseUrl, client)
|
||||
|
@ -12,10 +12,10 @@ import kotlinx.serialization.builtins.nullable
|
||||
|
||||
class ClientReadPostsService(
|
||||
private val baseUrl: String,
|
||||
private val unifiedRequester: UnifiedRequester
|
||||
private val client: HttpClient
|
||||
) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo(
|
||||
buildStandardUrl(baseUrl, postsRootPath),
|
||||
unifiedRequester,
|
||||
client,
|
||||
RegisteredPost.serializer(),
|
||||
RegisteredPost.serializer().nullable,
|
||||
PostId.serializer()
|
||||
|
@ -25,17 +25,17 @@ import kotlinx.serialization.modules.polymorphic
|
||||
|
||||
class ClientWritePostsService(
|
||||
private val baseUrl: String,
|
||||
unifiedRequester: UnifiedRequester
|
||||
client: HttpClient
|
||||
) : WritePostsService {
|
||||
private val root = buildStandardUrl(baseUrl, postsRootPath)
|
||||
private val unifiedRequester = UnifiedRequester(
|
||||
unifiedRequester.client,
|
||||
unifiedRequester.serialFormat.createWithSerializerModuleExtension {
|
||||
polymorphic(Content::class) {
|
||||
subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
||||
}
|
||||
}
|
||||
)
|
||||
// private val unifiedRequester = UnifiedRequester(
|
||||
// unifiedRequester.client,
|
||||
// unifiedRequester.serialFormat.createWithSerializerModuleExtension {
|
||||
// polymorphic(Content::class) {
|
||||
// subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||
@ -58,7 +58,7 @@ class ClientWritePostsService(
|
||||
return (content as? BinaryContent) ?.let {
|
||||
when (val provider = it.inputProvider) {
|
||||
is FileBasedInputProvider -> {
|
||||
val fileId = unifiedRequester.tempUpload(
|
||||
val fileId = client.tempUpload(
|
||||
tempUploadFullPath,
|
||||
provider.file
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ import dev.inmo.micro_utils.mime_types.findBuiltinMimeType
|
||||
import dev.inmo.micro_utils.repos.ktor.common.crud.createRouting
|
||||
import dev.inmo.micro_utils.repos.ktor.common.crud.updateRouting
|
||||
import dev.inmo.micro_utils.repos.ktor.common.one_to_many.removeRoute
|
||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes
|
||||
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadCRUDRepoRoutes
|
||||
import dev.inmo.postssystem.features.common.common.FileBasedInputProvider
|
||||
import dev.inmo.postssystem.features.content.common.*
|
||||
import dev.inmo.postssystem.features.files.common.FileId
|
||||
@ -22,6 +22,7 @@ import io.ktor.http.content.streamProvider
|
||||
import io.ktor.server.application.ApplicationCall
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.auth.authenticate
|
||||
import io.ktor.server.request.receive
|
||||
import io.ktor.server.request.receiveMultipart
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.*
|
||||
@ -32,8 +33,6 @@ import io.ktor.utils.io.streams.asInput
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.serialization.builtins.*
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.attribute.FileTime
|
||||
@ -42,19 +41,8 @@ import java.util.concurrent.TimeUnit
|
||||
class ServerPostsServiceRoutingConfigurator(
|
||||
private val readPostsService: ReadPostsService,
|
||||
private val writePostsService: WritePostsService? = readPostsService as? WritePostsService,
|
||||
private val scope: CoroutineScope,
|
||||
unifiedRouter: UnifiedRouter
|
||||
private val scope: CoroutineScope
|
||||
) : ApplicationRoutingConfigurator.Element {
|
||||
private val unifiedRouter = UnifiedRouter(
|
||||
serialFormat = unifiedRouter.serialFormat.createWithSerializerModuleExtension {
|
||||
polymorphic(Content::class) {
|
||||
subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
|
||||
}
|
||||
}
|
||||
)
|
||||
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
|
||||
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
|
||||
private val contentsSerializer = ListSerializer(ContentSerializer)
|
||||
|
||||
private val temporalFilesMap = mutableMapOf<FileId, MPPFile>()
|
||||
private val temporalFilesMutex = Mutex()
|
||||
@ -97,20 +85,16 @@ class ServerPostsServiceRoutingConfigurator(
|
||||
}
|
||||
|
||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
|
||||
return unifiedRouter.run {
|
||||
uniload(contentsSerializer).mapNotNull {
|
||||
mapBinary(it as? BinaryContent ?: return@mapNotNull it)
|
||||
}
|
||||
return call.receive<ContentsWrapper>().content.mapNotNull {
|
||||
mapBinary(it as? BinaryContent ?: return@mapNotNull it)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> {
|
||||
return unifiedRouter.run {
|
||||
uniload(contentsEitherSerializer).mapNotNull {
|
||||
it.mapOnSecond {
|
||||
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
|
||||
} ?: it
|
||||
}
|
||||
return call.receive<ContentsEithersWrapper>().content.mapNotNull {
|
||||
it.mapOnSecond {
|
||||
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
|
||||
} ?: it
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,84 +103,70 @@ class ServerPostsServiceRoutingConfigurator(
|
||||
override fun Route.invoke() {
|
||||
authenticate {
|
||||
route(postsRootPath) {
|
||||
configureReadStandardCrudRepoRoutes(
|
||||
readPostsService,
|
||||
RegisteredPost.serializer(),
|
||||
RegisteredPost.serializer().nullable,
|
||||
PostId.serializer(),
|
||||
unifiedRouter
|
||||
)
|
||||
configureReadCRUDRepoRoutes(
|
||||
readPostsService
|
||||
) { PostId(it.toLong()) }
|
||||
|
||||
writePostsService ?.let {
|
||||
|
||||
unifiedRouter.apply {
|
||||
post(createRouting) {
|
||||
val data = receiveContents()
|
||||
|
||||
post(createRouting) {
|
||||
val data = receiveContents()
|
||||
call.respond(
|
||||
writePostsService.create(FullNewPost(data)) ?: HttpStatusCode.NoContent
|
||||
)
|
||||
}
|
||||
|
||||
unianswer(
|
||||
RegisteredPost.serializer().nullable,
|
||||
writePostsService.create(FullNewPost(data))
|
||||
post(updateRouting) {
|
||||
call.respond(
|
||||
writePostsService.update(
|
||||
call.getQueryParameterOrSendError(postsPostIdParameter)?.toLong()?.let(::PostId) ?: return@post,
|
||||
receiveContentsEithers()
|
||||
) ?: HttpStatusCode.NoContent
|
||||
)
|
||||
}
|
||||
|
||||
post(removeRoute) {
|
||||
call.respond(
|
||||
writePostsService.remove(
|
||||
call.receive()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
post(updateRouting) {
|
||||
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post
|
||||
val data = receiveContentsEithers()
|
||||
post(postsCreateTempPathPart) {
|
||||
val multipart = call.receiveMultipart()
|
||||
|
||||
unianswer(
|
||||
RegisteredPost.serializer().nullable,
|
||||
writePostsService.update(
|
||||
postId,
|
||||
data
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
post(removeRoute) {
|
||||
val postId = uniload(PostId.serializer())
|
||||
|
||||
unianswer(
|
||||
Unit.serializer(),
|
||||
writePostsService.remove(postId)
|
||||
)
|
||||
}
|
||||
|
||||
post(postsCreateTempPathPart) {
|
||||
val multipart = call.receiveMultipart()
|
||||
|
||||
var fileInfo: Pair<FileId, MPPFile>? = null
|
||||
var part = multipart.readPart()
|
||||
while (part != null) {
|
||||
if (part is PartData.FileItem) {
|
||||
break
|
||||
}
|
||||
part = multipart.readPart()
|
||||
var fileInfo: Pair<FileId, MPPFile>? = null
|
||||
var part = multipart.readPart()
|
||||
while (part != null) {
|
||||
if (part is PartData.FileItem) {
|
||||
break
|
||||
}
|
||||
part ?.let {
|
||||
if (it is PartData.FileItem) {
|
||||
val fileId = FileId(uuid4().toString())
|
||||
val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let
|
||||
fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply {
|
||||
outputStream().use { outputStream ->
|
||||
it.streamProvider().use {
|
||||
it.copyTo(outputStream)
|
||||
}
|
||||
part = multipart.readPart()
|
||||
}
|
||||
part ?.let {
|
||||
if (it is PartData.FileItem) {
|
||||
val fileId = FileId(uuid4().toString())
|
||||
val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let
|
||||
fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply {
|
||||
outputStream().use { outputStream ->
|
||||
it.streamProvider().use {
|
||||
it.copyTo(outputStream)
|
||||
}
|
||||
deleteOnExit()
|
||||
}
|
||||
deleteOnExit()
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo ?.also { (fileId, file) ->
|
||||
temporalFilesMutex.withLock {
|
||||
temporalFilesMap[fileId] = file
|
||||
}
|
||||
call.respond(fileId.string)
|
||||
} ?: call.respond(HttpStatusCode.BadRequest)
|
||||
|
||||
}
|
||||
|
||||
fileInfo ?.also { (fileId, file) ->
|
||||
temporalFilesMutex.withLock {
|
||||
temporalFilesMap[fileId] = file
|
||||
}
|
||||
call.respond(fileId.string)
|
||||
} ?: call.respond(HttpStatusCode.BadRequest)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user