start migration onto ktor-based serialization of data

This commit is contained in:
InsanusMokrassar 2022-06-12 18:54:28 +06:00
parent 399405a4fb
commit ff973e63fc
19 changed files with 201 additions and 257 deletions

View File

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

View File

@ -1,7 +1,6 @@
package dev.inmo.postssystem.features.content.common
import dev.inmo.micro_utils.common.FileName
import dev.inmo.micro_utils.common.MPPFile
import dev.inmo.micro_utils.common.*
import dev.inmo.micro_utils.mime_types.MimeType
import dev.inmo.postssystem.features.common.common.SimpleInputProvider
import kotlinx.serialization.PolymorphicSerializer
@ -30,6 +29,18 @@ data class BinaryContent(
) : Content
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,28 +1,21 @@
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.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.routing.Route
import io.ktor.server.routing.route
import kotlinx.serialization.builtins.nullable
class UsersStorageServerRoutesConfigurator(
private val usersStorage: ReadUsersStorage,
private val unifiedRouter: UnifiedRouter
private val usersStorage: ReadUsersStorage
) : ApplicationRoutingConfigurator.Element {
override fun Route.invoke() {
authenticate {
route(usersServerPathPart) {
configureReadStandardCrudRepoRoutes(
usersStorage,
User.serializer(),
User.serializer().nullable,
UserId.serializer(),
unifiedRouter
)
configureReadCRUDRepoRoutes(
usersStorage
) { UserId(it.toLong()) }
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View 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,68 +85,52 @@ class ServerPostsServiceRoutingConfigurator(
}
private suspend fun PipelineContext<Unit, ApplicationCall>.receiveContents(): List<Content> {
return unifiedRouter.run {
uniload(contentsSerializer).mapNotNull {
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 {
return call.receive<ContentsEithersWrapper>().content.mapNotNull {
it.mapOnSecond {
mapBinary(it as? BinaryContent ?: return@mapOnSecond null) ?.either()
} ?: it
}
}
}
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()
unianswer(
RegisteredPost.serializer().nullable,
writePostsService.create(FullNewPost(data))
call.respond(
writePostsService.create(FullNewPost(data)) ?: HttpStatusCode.NoContent
)
}
post(updateRouting) {
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post
val data = receiveContentsEithers()
unianswer(
RegisteredPost.serializer().nullable,
call.respond(
writePostsService.update(
postId,
data
)
call.getQueryParameterOrSendError(postsPostIdParameter)?.toLong()?.let(::PostId) ?: return@post,
receiveContentsEithers()
) ?: HttpStatusCode.NoContent
)
}
post(removeRoute) {
val postId = uniload(PostId.serializer())
unianswer(
Unit.serializer(),
writePostsService.remove(postId)
call.respond(
writePostsService.remove(
call.receive()
)
)
}
@ -198,8 +170,6 @@ class ServerPostsServiceRoutingConfigurator(
}
}
}
}
}
}