start migration onto ktor-based serialization of data

This commit is contained in:
2022-06-12 18:54:28 +06:00
parent 399405a4fb
commit ff973e63fc
19 changed files with 201 additions and 257 deletions
features
auth
server
src
jvmMain
kotlin
dev
inmo
postssystem
content
common
src
commonMain
kotlin
dev
inmo
postssystem
features
content
files
client
src
commonMain
kotlin
dev
inmo
postssystem
features
server
src
jvmMain
kotlin
dev
inmo
postssystem
features
roles
client
common
src
commonMain
kotlin
dev
inmo
postssystem
features
roles
common
manager
server
src
jvmMain
kotlin
dev
inmo
server
users
client
src
commonMain
kotlin
dev
inmo
postssystem
features
server
src
jvmMain
kotlin
dev
inmo
postssystem
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
server
src
jvmMain
kotlin
dev
inmo
postssystem

@ -10,6 +10,7 @@ import dev.inmo.micro_utils.ktor.server.configurators.*
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.auth.* import io.ktor.server.auth.*
import io.ktor.server.request.receive
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.* import io.ktor.server.routing.*
import io.ktor.server.sessions.sessions import io.ktor.server.sessions.sessions
@ -24,11 +25,9 @@ fun User.principal() = AuthUserPrincipal(this)
class AuthenticationRoutingConfigurator( class AuthenticationRoutingConfigurator(
private val authFeature: AuthFeature, private val authFeature: AuthFeature,
private val authTokensService: AuthTokensService, private val authTokensService: AuthTokensService
private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element, ApplicationAuthenticationConfigurator.Element { ) : ApplicationRoutingConfigurator.Element, ApplicationAuthenticationConfigurator.Element {
override fun Route.invoke() { override fun Route.invoke() {
unifiedRouter.apply {
route(authRootPathPart) { route(authRootPathPart) {
post(authAuthPathPart) { post(authAuthPathPart) {
safely( safely(
@ -41,7 +40,7 @@ class AuthenticationRoutingConfigurator(
) )
} }
) { ) {
val creds = uniload(AuthCreds.serializer()) val creds = call.receive<AuthCreds>()
val tokenInfo = authFeature.auth(creds) val tokenInfo = authFeature.auth(creds)
@ -51,10 +50,7 @@ class AuthenticationRoutingConfigurator(
} }
} else { } else {
call.sessions.set(tokenSessionKey, tokenInfo.token) call.sessions.set(tokenSessionKey, tokenInfo.token)
unianswer( call.respond(tokenInfo)
AuthTokenInfo.serializer().nullable,
tokenInfo
)
} }
} }
} }
@ -68,7 +64,7 @@ class AuthenticationRoutingConfigurator(
) )
} }
) { ) {
val refreshToken = uniload(RefreshToken.serializer()) val refreshToken = call.receive<RefreshToken>()
val tokenInfo = authFeature.refresh(refreshToken) val tokenInfo = authFeature.refresh(refreshToken)
@ -78,10 +74,7 @@ class AuthenticationRoutingConfigurator(
} }
} else { } else {
call.sessions.set(tokenSessionKey, tokenInfo.token) call.sessions.set(tokenSessionKey, tokenInfo.token)
unianswer( call.respond(tokenInfo)
AuthTokenInfo.serializer().nullable,
tokenInfo
)
} }
} }
} }
@ -95,13 +88,9 @@ class AuthenticationRoutingConfigurator(
) )
} }
) { ) {
unianswer( call.respond(
User.serializer().nullable, authFeature.getMe(call.receive()) ?: HttpStatusCode.NoContent
authFeature.getMe(
uniload(AuthToken.serializer())
) )
)
}
} }
} }
} }

@ -1,7 +1,6 @@
package dev.inmo.postssystem.features.content.common package dev.inmo.postssystem.features.content.common
import dev.inmo.micro_utils.common.FileName import dev.inmo.micro_utils.common.*
import dev.inmo.micro_utils.common.MPPFile
import dev.inmo.micro_utils.mime_types.MimeType import dev.inmo.micro_utils.mime_types.MimeType
import dev.inmo.postssystem.features.common.common.SimpleInputProvider import dev.inmo.postssystem.features.common.common.SimpleInputProvider
import kotlinx.serialization.PolymorphicSerializer import kotlinx.serialization.PolymorphicSerializer
@ -30,6 +29,18 @@ data class BinaryContent(
) : Content ) : Content
val ContentSerializer = PolymorphicSerializer(Content::class) val ContentSerializer = PolymorphicSerializer(Content::class)
@Serializable
data class ContentWrapper(
val content: Content
)
@Serializable
data class ContentsWrapper(
val content: List<Content>
)
@Serializable
data class ContentsEithersWrapper(
val content: List<Either<ContentId, Content>>
)
/** /**
* Content which is already registered in database. Using its [id] you can retrieve all known * Content which is already registered in database. Using its [id] you can retrieve all known

@ -25,7 +25,6 @@ class ClientReadFilesStorage(
MetaFileInfoStorageWrapper.serializer().nullable, MetaFileInfoStorageWrapper.serializer().nullable,
FileId.serializer() FileId.serializer()
) { ) {
private val unifiedRequester = UnifiedRequester(client, serialFormat)
private val fullFilesPath = buildStandardUrl(baseUrl, filesRootPathPart) private val fullFilesPath = buildStandardUrl(baseUrl, filesRootPathPart)
private val fullFilesGetBytesPath = buildStandardUrl( private val fullFilesGetBytesPath = buildStandardUrl(
fullFilesPath, fullFilesPath,

@ -4,10 +4,13 @@ import dev.inmo.postssystem.features.files.common.*
import dev.inmo.postssystem.features.files.common.storage.* import dev.inmo.postssystem.features.files.common.storage.*
import dev.inmo.micro_utils.ktor.server.* import dev.inmo.micro_utils.ktor.server.*
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes import dev.inmo.micro_utils.repos.ktor.server.crud.*
import dev.inmo.micro_utils.repos.ktor.server.crud.configureWriteStandardCrudRepoRoutes import io.ktor.http.HttpStatusCode
import io.ktor.http.decodeURLQueryComponent
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.response.respondBytes import io.ktor.server.response.respondBytes
import io.ktor.server.routing.* import io.ktor.server.routing.*
import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.nullable
@ -15,47 +18,33 @@ import kotlinx.serialization.builtins.nullable
class FilesRoutingConfigurator( class FilesRoutingConfigurator(
private val filesStorage: ReadFilesStorage, private val filesStorage: ReadFilesStorage,
private val writeFilesStorage: WriteFilesStorage?, private val writeFilesStorage: WriteFilesStorage?,
private val unifierRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
constructor(filesStorage: FilesStorage, unifierRouter: UnifiedRouter) : this(filesStorage, filesStorage, unifierRouter) constructor(filesStorage: FilesStorage) : this(filesStorage, filesStorage)
override fun Route.invoke() { override fun Route.invoke() {
authenticate { authenticate {
route(filesRootPathPart) { route(filesRootPathPart) {
configureReadStandardCrudRepoRoutes( configureReadCRUDRepoRoutes(
filesStorage, filesStorage,
MetaFileInfoStorageWrapper.serializer(), ::FileId
MetaFileInfoStorageWrapper.serializer().nullable,
FileId.serializer(),
unifierRouter
) )
writeFilesStorage ?.let { writeFilesStorage ?.let {
configureWriteStandardCrudRepoRoutes( configureWriteCRUDRepoRoutes(writeFilesStorage)
writeFilesStorage,
FullFileInfoStorageWrapper.serializer(),
FullFileInfoStorageWrapper.serializer().nullable,
FullFileInfo.serializer(),
FileId.serializer(),
unifierRouter
)
} }
unifierRouter.apply {
post(filesGetFilesPathPart) { post(filesGetFilesPathPart) {
call.respondBytes( call.respondBytes(
filesStorage.getBytes( filesStorage.getBytes(
uniload(FileId.serializer()) call.receive()
) )
) )
} }
get(filesGetFullFileInfoPathPart) { get(filesGetFullFileInfoPathPart) {
unianswer( call.respond(
FullFileInfoStorageWrapper.serializer().nullable,
filesStorage.getFullFileInfo( filesStorage.getFullFileInfo(
decodeUrlQueryValueOrSendError(filesFileIdParameter, FileId.serializer()) ?: return@get FileId(call.getParameterOrSendError(filesFileIdParameter) ?.decodeURLQueryComponent() ?: return@get)
) ?: HttpStatusCode.NoContent
) )
)
}
} }
} }
} }

@ -6,12 +6,12 @@ import kotlinx.serialization.KSerializer
class ClientRolesStorage<T : Role>( class ClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val client: HttpClient,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : RolesStorage<T>, ) : RolesStorage<T>,
ReadRolesStorage<T> by ReadClientRolesStorage( ReadRolesStorage<T> by ReadClientRolesStorage(
baseUrl, unifiedRequester, serializer baseUrl, client, serializer
), ),
WriteRolesStorage<T> by WriteClientRolesStorage( WriteRolesStorage<T> by WriteClientRolesStorage(
baseUrl, unifiedRequester, serializer baseUrl, client, serializer
) )

@ -3,13 +3,15 @@ package dev.inmo.postssystem.features.roles.client
import dev.inmo.postssystem.features.roles.common.* import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.micro_utils.ktor.client.UnifiedRequester import dev.inmo.micro_utils.ktor.client.UnifiedRequester
import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.ktor.common.buildStandardUrl
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
class ReadClientRolesStorage<T : Role>( class ReadClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val client: HttpClient,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : ReadRolesStorage<T> { ) : ReadRolesStorage<T> {
private val userRolesSerializer = ListSerializer(serializer) private val userRolesSerializer = ListSerializer(serializer)
@ -21,14 +23,13 @@ class ReadClientRolesStorage<T : Role>(
override suspend fun getSubjects( override suspend fun getSubjects(
role: T role: T
): List<RoleSubject> = unifiedRequester.uniget( ): List<RoleSubject> = client.get(
buildStandardUrl( buildStandardUrl(
userRolesFullUrl, userRolesFullUrl,
usersRolesGetSubjectsPathPart, usersRolesGetSubjectsPathPart,
usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role) usersRolesRoleQueryParameterName to unifiedRequester.encodeUrlQueryValue(serializer, role)
),
RoleSubjectsSerializer
) )
).body()
override suspend fun getRoles( override suspend fun getRoles(
subject: RoleSubject subject: RoleSubject

@ -8,7 +8,7 @@ import kotlinx.serialization.builtins.serializer
class WriteClientRolesStorage<T : Role>( class WriteClientRolesStorage<T : Role>(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester, private val client: HttpClient,
private val serializer: KSerializer<T> private val serializer: KSerializer<T>
) : WriteRolesStorage<T> { ) : WriteRolesStorage<T> {
private val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer( private val wrapperSerializer = RolesStorageIncludeExcludeWrapper.serializer(

@ -6,7 +6,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.* import kotlinx.serialization.encoding.*
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
@Serializable(RoleSerializer::class) @Polymorphic
interface Role { interface Role {
companion object { companion object {
fun serializer(): KSerializer<Role> = RoleSerializer fun serializer(): KSerializer<Role> = RoleSerializer

@ -1,17 +1,14 @@
package dev.inmo.postssystem.features.roles.manager.server package dev.inmo.postssystem.features.roles.manager.server
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.postssystem.features.roles.common.RolesStorage import dev.inmo.postssystem.features.roles.common.RolesStorage
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole
import dev.inmo.postssystem.features.roles.server.RolesStorageWriteServerRoutesConfigurator import dev.inmo.postssystem.features.roles.server.RolesStorageWriteServerRoutesConfigurator
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
class RolesManagerRolesStorageServerRoutesConfigurator( class RolesManagerRolesStorageServerRoutesConfigurator(
storage: RolesStorage<RolesManagerRole>, storage: RolesStorage<RolesManagerRole>
unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element by RolesStorageWriteServerRoutesConfigurator( ) : ApplicationRoutingConfigurator.Element by RolesStorageWriteServerRoutesConfigurator(
storage, storage,
RolesManagerRole.serializer(), RolesManagerRole.serializer(),
RolesManagerRolesChecker.key, RolesManagerRolesChecker.key
unifiedRouter = unifiedRouter
) )

@ -12,8 +12,7 @@ class RolesStorageWriteServerRoutesConfigurator<T : Role>(
private val storage: WriteRolesStorage<T>, private val storage: WriteRolesStorage<T>,
private val serializer: KSerializer<T>, private val serializer: KSerializer<T>,
private val includeAuthKey: String, private val includeAuthKey: String,
private val excludeAuthKey: String = includeAuthKey, private val excludeAuthKey: String = includeAuthKey
private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
override fun Route.invoke() { override fun Route.invoke() {
route(usersRolesRootPathPart) { route(usersRolesRootPathPart) {

@ -11,8 +11,7 @@ import kotlinx.serialization.builtins.serializer
class RolesStorageReadServerRoutesConfigurator<T : Role>( class RolesStorageReadServerRoutesConfigurator<T : Role>(
private val storage: ReadRolesStorage<T>, private val storage: ReadRolesStorage<T>,
private val serializer: KSerializer<T>, private val serializer: KSerializer<T>
private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
private val userRolesSerializer = ListSerializer(serializer) private val userRolesSerializer = ListSerializer(serializer)
override fun Route.invoke() { override fun Route.invoke() {

@ -9,10 +9,10 @@ import kotlinx.serialization.builtins.nullable
class UsersStorageKtorClient( class UsersStorageKtorClient(
baseUrl: String, baseUrl: String,
unifiedRequester: UnifiedRequester client: HttpClient
) : ReadUsersStorage, ReadCRUDRepo<User, UserId> by KtorReadStandardCrudRepo( ) : ReadUsersStorage, ReadCRUDRepo<User, UserId> by KtorReadStandardCrudRepo(
buildStandardUrl(baseUrl, usersServerPathPart), buildStandardUrl(baseUrl, usersServerPathPart),
unifiedRequester, client,
User.serializer(), User.serializer(),
User.serializer().nullable, User.serializer().nullable,
UserId.serializer() UserId.serializer()

@ -1,28 +1,21 @@
package dev.inmo.postssystem.features.users.server package dev.inmo.postssystem.features.users.server
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.postssystem.features.users.common.* import dev.inmo.postssystem.features.users.common.*
import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator import dev.inmo.micro_utils.ktor.server.configurators.ApplicationRoutingConfigurator
import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadStandardCrudRepoRoutes import dev.inmo.micro_utils.repos.ktor.server.crud.configureReadCRUDRepoRoutes
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.routing.Route import io.ktor.server.routing.Route
import io.ktor.server.routing.route import io.ktor.server.routing.route
import kotlinx.serialization.builtins.nullable
class UsersStorageServerRoutesConfigurator( class UsersStorageServerRoutesConfigurator(
private val usersStorage: ReadUsersStorage, private val usersStorage: ReadUsersStorage
private val unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : ApplicationRoutingConfigurator.Element {
override fun Route.invoke() { override fun Route.invoke() {
authenticate { authenticate {
route(usersServerPathPart) { route(usersServerPathPart) {
configureReadStandardCrudRepoRoutes( configureReadCRUDRepoRoutes(
usersStorage, usersStorage
User.serializer(), ) { UserId(it.toLong()) }
User.serializer().nullable,
UserId.serializer(),
unifiedRouter
)
} }
} }
} }

@ -10,7 +10,7 @@ import kotlinx.serialization.builtins.serializer
class SimplePublicatorServiceClient( class SimplePublicatorServiceClient(
baseUrl: String, baseUrl: String,
private val unifiedRequester: UnifiedRequester private val client: HttpClient
) : SimplePublicatorService { ) : SimplePublicatorService {
private val fullUrl = buildStandardUrl( private val fullUrl = buildStandardUrl(
baseUrl, baseUrl,

@ -18,11 +18,10 @@ import dev.inmo.postssystem.features.status.server.StatusRoutingConfigurator
import dev.inmo.postssystem.features.users.common.ExposedUsersStorage import dev.inmo.postssystem.features.users.common.ExposedUsersStorage
import dev.inmo.postssystem.features.users.server.UsersStorageServerRoutesConfigurator import dev.inmo.postssystem.features.users.server.UsersStorageServerRoutesConfigurator
import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope
import dev.inmo.micro_utils.ktor.server.UnifiedRouter
import dev.inmo.micro_utils.ktor.server.configurators.* import dev.inmo.micro_utils.ktor.server.configurators.*
import dev.inmo.micro_utils.ktor.server.createKtorServer import dev.inmo.micro_utils.ktor.server.createKtorServer
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedOneToManyKeyValueRepo import dev.inmo.micro_utils.repos.exposed.onetomany.ExposedKeyValuesRepo
import dev.inmo.postssystem.features.common.common.* import dev.inmo.postssystem.features.common.common.*
import dev.inmo.postssystem.features.common.server.Qualifiers import dev.inmo.postssystem.features.common.server.Qualifiers
import dev.inmo.postssystem.features.content.common.* import dev.inmo.postssystem.features.content.common.*
@ -88,8 +87,6 @@ fun getDIModule(
} }
} }
single { UnifiedRouter(get()) }
singleWithBinds { config } singleWithBinds { config }
singleWithBinds { get<Config>().databaseConfig } singleWithBinds { get<Config>().databaseConfig }
singleWithBinds { get<Config>().authConfig } singleWithBinds { get<Config>().authConfig }
@ -101,7 +98,7 @@ fun getDIModule(
singleWithBinds { exposedUsersAuthenticator(get(), get()) } singleWithBinds { exposedUsersAuthenticator(get(), get()) }
factory<KeyValuesRolesOriginalRepo>(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) -> factory<KeyValuesRolesOriginalRepo>(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName) ExposedKeyValuesRepo(get(), { text("subject") }, { text("role") }, tableName)
} }
single { single {
RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) }) RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
@ -154,12 +151,12 @@ fun getDIModule(
} }
// Routing configurators // Routing configurators
singleWithBinds { FilesRoutingConfigurator(get(), null, get()) } singleWithBinds { FilesRoutingConfigurator(get(), null) }
singleWithBinds { StatusRoutingConfigurator } singleWithBinds { StatusRoutingConfigurator }
singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { UsersStorageServerRoutesConfigurator(get()) }
singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer, get()) } singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer) }
singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get()) }
singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get(), get()) } singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get()) }
singleWithBinds { ClientStaticRoutingConfiguration("web") } singleWithBinds { ClientStaticRoutingConfiguration("web") }
singleWithBinds { singleWithBinds {
@ -181,7 +178,7 @@ fun getDIModule(
get() get()
) )
} }
singleWithBinds { AuthenticationRoutingConfigurator(get(), get(), get()) } singleWithBinds { AuthenticationRoutingConfigurator(get(), get()) }
singleWithBinds { NotFoundStatusPageRedirectToIndex("/") } singleWithBinds { NotFoundStatusPageRedirectToIndex("/") }
if (config.debugMode) { if (config.debugMode) {

@ -5,7 +5,7 @@ import dev.inmo.postssystem.services.posts.common.*
class ClientPostsService( class ClientPostsService(
baseUrl: String, baseUrl: String,
unifiedRequester: UnifiedRequester client: HttpClient
) : PostsService, ) : PostsService,
ReadPostsService by ClientReadPostsService(baseUrl, unifiedRequester), ReadPostsService by ClientReadPostsService(baseUrl, client),
WritePostsService by ClientWritePostsService(baseUrl, unifiedRequester) WritePostsService by ClientWritePostsService(baseUrl, client)

@ -12,10 +12,10 @@ import kotlinx.serialization.builtins.nullable
class ClientReadPostsService( class ClientReadPostsService(
private val baseUrl: String, private val baseUrl: String,
private val unifiedRequester: UnifiedRequester private val client: HttpClient
) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo( ) : ReadPostsService, ReadCRUDRepo<RegisteredPost, PostId> by KtorReadStandardCrudRepo(
buildStandardUrl(baseUrl, postsRootPath), buildStandardUrl(baseUrl, postsRootPath),
unifiedRequester, client,
RegisteredPost.serializer(), RegisteredPost.serializer(),
RegisteredPost.serializer().nullable, RegisteredPost.serializer().nullable,
PostId.serializer() PostId.serializer()

@ -25,17 +25,17 @@ import kotlinx.serialization.modules.polymorphic
class ClientWritePostsService( class ClientWritePostsService(
private val baseUrl: String, private val baseUrl: String,
unifiedRequester: UnifiedRequester client: HttpClient
) : WritePostsService { ) : WritePostsService {
private val root = buildStandardUrl(baseUrl, postsRootPath) private val root = buildStandardUrl(baseUrl, postsRootPath)
private val unifiedRequester = UnifiedRequester( // private val unifiedRequester = UnifiedRequester(
unifiedRequester.client, // unifiedRequester.client,
unifiedRequester.serialFormat.createWithSerializerModuleExtension { // unifiedRequester.serialFormat.createWithSerializerModuleExtension {
polymorphic(Content::class) { // polymorphic(Content::class) {
subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer())) // subclass(BinaryContent::class, BinaryContentSerializer(TempFileIdentifierInputProvider::class, TempFileIdentifierInputProvider.serializer()))
} // }
} // }
) // )
private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer) private val contentEitherSerializer = EitherSerializer(ContentId.serializer(), ContentSerializer)
private val contentsEitherSerializer = ListSerializer(contentEitherSerializer) private val contentsEitherSerializer = ListSerializer(contentEitherSerializer)
@ -58,7 +58,7 @@ class ClientWritePostsService(
return (content as? BinaryContent) ?.let { return (content as? BinaryContent) ?.let {
when (val provider = it.inputProvider) { when (val provider = it.inputProvider) {
is FileBasedInputProvider -> { is FileBasedInputProvider -> {
val fileId = unifiedRequester.tempUpload( val fileId = client.tempUpload(
tempUploadFullPath, tempUploadFullPath,
provider.file 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.createRouting
import dev.inmo.micro_utils.repos.ktor.common.crud.updateRouting 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.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.common.common.FileBasedInputProvider
import dev.inmo.postssystem.features.content.common.* import dev.inmo.postssystem.features.content.common.*
import dev.inmo.postssystem.features.files.common.FileId 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.ApplicationCall
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.request.receive
import io.ktor.server.request.receiveMultipart import io.ktor.server.request.receiveMultipart
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.* import io.ktor.server.routing.*
@ -32,8 +33,6 @@ import io.ktor.utils.io.streams.asInput
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.builtins.*
import kotlinx.serialization.modules.polymorphic
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.attribute.FileTime import java.nio.file.attribute.FileTime
@ -42,19 +41,8 @@ import java.util.concurrent.TimeUnit
class ServerPostsServiceRoutingConfigurator( class ServerPostsServiceRoutingConfigurator(
private val readPostsService: ReadPostsService, private val readPostsService: ReadPostsService,
private val writePostsService: WritePostsService? = readPostsService as? WritePostsService, private val writePostsService: WritePostsService? = readPostsService as? WritePostsService,
private val scope: CoroutineScope, private val scope: CoroutineScope
unifiedRouter: UnifiedRouter
) : ApplicationRoutingConfigurator.Element { ) : 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 temporalFilesMap = mutableMapOf<FileId, MPPFile>()
private val temporalFilesMutex = Mutex() private val temporalFilesMutex = Mutex()
@ -97,68 +85,52 @@ class ServerPostsServiceRoutingConfigurator(
} }
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> { private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
return unifiedRouter.run { return call.receive<ContentsWrapper>().content.mapNotNull {
uniload(contentsSerializer).mapNotNull {
mapBinary(it as? BinaryContent ?: return@mapNotNull it) mapBinary(it as? BinaryContent ?: return@mapNotNull it)
} }
} }
}
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> { private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContentsEithers(): List<Either<ContentId, Content>> {
return unifiedRouter.run { return call.receive<ContentsEithersWrapper>().content.mapNotNull {
uniload(contentsEitherSerializer).mapNotNull {
it.mapOnSecond { it.mapOnSecond {
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either() mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
} ?: it } ?: it
} }
} }
}
override fun Route.invoke() { override fun Route.invoke() {
authenticate { authenticate {
route(postsRootPath) { route(postsRootPath) {
configureReadStandardCrudRepoRoutes( configureReadCRUDRepoRoutes(
readPostsService, readPostsService
RegisteredPost.serializer(), ) { PostId(it.toLong()) }
RegisteredPost.serializer().nullable,
PostId.serializer(),
unifiedRouter
)
writePostsService ?.let { writePostsService ?.let {
unifiedRouter.apply {
post(createRouting) { post(createRouting) {
val data = receiveContents() val data = receiveContents()
unianswer( call.respond(
RegisteredPost.serializer().nullable, writePostsService.create(FullNewPost(data)) ?: HttpStatusCode.NoContent
writePostsService.create(FullNewPost(data))
) )
} }
post(updateRouting) { post(updateRouting) {
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post call.respond(
val data = receiveContentsEithers()
unianswer(
RegisteredPost.serializer().nullable,
writePostsService.update( writePostsService.update(
postId, call.getQueryParameterOrSendError(postsPostIdParameter)?.toLong()?.let(::PostId) ?: return@post,
data receiveContentsEithers()
) ) ?: HttpStatusCode.NoContent
) )
} }
post(removeRoute) { post(removeRoute) {
val postId = uniload(PostId.serializer()) call.respond(
writePostsService.remove(
unianswer( call.receive()
Unit.serializer(), )
writePostsService.remove(postId)
) )
} }
@ -198,8 +170,6 @@ class ServerPostsServiceRoutingConfigurator(
} }
} }
}
} }
} }
} }