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.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,84 +25,72 @@ 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( {
{ // TODO:: add error info
// TODO:: add error info it.printStackTrace()
it.printStackTrace() call.respond(
call.respond( HttpStatusCode.InternalServerError,
HttpStatusCode.InternalServerError, "Something went wrong"
"Something went wrong"
)
}
) {
val creds = uniload(AuthCreds.serializer())
val tokenInfo = authFeature.auth(creds)
if (tokenInfo == null) {
if (call.response.status() == null) {
call.respond(HttpStatusCode.Forbidden)
}
} else {
call.sessions.set(tokenSessionKey, tokenInfo.token)
unianswer(
AuthTokenInfo.serializer().nullable,
tokenInfo
)
}
}
}
post (authRefreshPathPart) {
safely(
{
// TODO:: add error info
call.respond(
HttpStatusCode.InternalServerError,
"Something went wrong"
)
}
) {
val refreshToken = uniload(RefreshToken.serializer())
val tokenInfo = authFeature.refresh(refreshToken)
if (tokenInfo == null) {
if (call.response.status() == null) {
call.respond(HttpStatusCode.Forbidden)
}
} else {
call.sessions.set(tokenSessionKey, tokenInfo.token)
unianswer(
AuthTokenInfo.serializer().nullable,
tokenInfo
)
}
}
}
post(authGetMePathPart) {
safely(
{
// TODO:: add error info
call.respond(
HttpStatusCode.InternalServerError,
"Something went wrong"
)
}
) {
unianswer(
User.serializer().nullable,
authFeature.getMe(
uniload(AuthToken.serializer())
)
) )
} }
) {
val creds = call.receive<AuthCreds>()
val tokenInfo = authFeature.auth(creds)
if (tokenInfo == null) {
if (call.response.status() == null) {
call.respond(HttpStatusCode.Forbidden)
}
} else {
call.sessions.set(tokenSessionKey, tokenInfo.token)
call.respond(tokenInfo)
}
}
}
post (authRefreshPathPart) {
safely(
{
// TODO:: add error info
call.respond(
HttpStatusCode.InternalServerError,
"Something went wrong"
)
}
) {
val refreshToken = call.receive<RefreshToken>()
val tokenInfo = authFeature.refresh(refreshToken)
if (tokenInfo == null) {
if (call.response.status() == null) {
call.respond(HttpStatusCode.Forbidden)
}
} else {
call.sessions.set(tokenSessionKey, tokenInfo.token)
call.respond(tokenInfo)
}
}
}
post(authGetMePathPart) {
safely(
{
// TODO:: add error info
call.respond(
HttpStatusCode.InternalServerError,
"Something went wrong"
)
}
) {
call.respond(
authFeature.getMe(call.receive()) ?: HttpStatusCode.NoContent
)
} }
} }
} }

View File

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

View File

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

View File

@ -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( call.receive()
uniload(FileId.serializer())
)
) )
} )
get(filesGetFullFileInfoPathPart) { }
unianswer( get(filesGetFullFileInfoPathPart) {
FullFileInfoStorageWrapper.serializer().nullable, call.respond(
filesStorage.getFullFileInfo( 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>( 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
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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.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) {

View File

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

View File

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

View File

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

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.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,20 +85,16 @@ 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
}
} }
} }
@ -119,84 +103,70 @@ class ServerPostsServiceRoutingConfigurator(
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) {
val data = receiveContents()
post(createRouting) { call.respond(
val data = receiveContents() writePostsService.create(FullNewPost(data)) ?: HttpStatusCode.NoContent
)
}
unianswer( post(updateRouting) {
RegisteredPost.serializer().nullable, call.respond(
writePostsService.create(FullNewPost(data)) writePostsService.update(
call.getQueryParameterOrSendError(postsPostIdParameter)?.toLong()?.let(::PostId) ?: return@post,
receiveContentsEithers()
) ?: HttpStatusCode.NoContent
)
}
post(removeRoute) {
call.respond(
writePostsService.remove(
call.receive()
) )
} )
}
post(updateRouting) { post(postsCreateTempPathPart) {
val postId = call.decodeUrlQueryValueOrSendError(postsPostIdParameter, PostId.serializer()) ?: return@post val multipart = call.receiveMultipart()
val data = receiveContentsEithers()
unianswer( var fileInfo: Pair<FileId, MPPFile>? = null
RegisteredPost.serializer().nullable, var part = multipart.readPart()
writePostsService.update( while (part != null) {
postId, if (part is PartData.FileItem) {
data break
)
)
}
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()
} }
part ?.let { part = multipart.readPart()
if (it is PartData.FileItem) { }
val fileId = FileId(uuid4().toString()) part ?.let {
val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let if (it is PartData.FileItem) {
fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply { val fileId = FileId(uuid4().toString())
outputStream().use { outputStream -> val fileName = it.originalFileName ?.let { FileName(it) } ?: return@let
it.streamProvider().use { fileInfo = fileId to File.createTempFile(fileId.string, ".${fileName.extension}").apply {
it.copyTo(outputStream) 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)
} }
} }