core/server/src/main/java/dev/inmo/postssystem/server/DI.kt

245 lines
12 KiB
Kotlin

package dev.inmo.postssystem.server
import dev.inmo.postssystem.features.auth.server.AuthenticationRoutingConfigurator
import dev.inmo.postssystem.features.auth.server.SessionAuthenticationConfigurator
import dev.inmo.postssystem.features.auth.server.tokens.*
import dev.inmo.postssystem.features.common.server.sessions.ApplicationAuthenticationConfigurator
import dev.inmo.postssystem.features.files.common.*
import dev.inmo.postssystem.features.files.common.storage.*
import dev.inmo.postssystem.features.files.common.storage.WriteFilesStorage
import dev.inmo.postssystem.features.files.server.FilesRoutingConfigurator
import dev.inmo.postssystem.features.roles.common.*
import dev.inmo.postssystem.features.roles.common.keyvalue.KeyValuesRolesOriginalRepo
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRole
import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleStorage
import dev.inmo.postssystem.features.roles.manager.server.RolesManagerRolesChecker
import dev.inmo.postssystem.features.roles.manager.server.RolesManagerRolesStorageServerRoutesConfigurator
import dev.inmo.postssystem.features.roles.server.*
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.postssystem.features.common.common.*
import dev.inmo.postssystem.features.content.binary.server.BinaryServerContentStorage
import dev.inmo.postssystem.features.content.common.*
import dev.inmo.postssystem.features.content.server.storage.ServerContentStorage
import dev.inmo.postssystem.features.content.server.ServerContentStorageAggregator
import dev.inmo.postssystem.features.content.text.common.TextContentSerializerModuleConfigurator
import dev.inmo.postssystem.features.content.text.server.TextServerContentStorage
import dev.inmo.postssystem.features.posts.server.ExposedServerPostsStorage
import dev.inmo.postssystem.features.posts.server.ServerPostsStorage
import dev.inmo.postssystem.features.publication.server.PublicationManager
import dev.inmo.postssystem.features.publication.server.PublicationTarget
import dev.inmo.postssystem.services.posts.server.*
import dev.inmo.postssystem.targets.telegram.publication.server.PublicationTargetTelegram
import io.ktor.application.featureOrNull
import io.ktor.application.log
import io.ktor.routing.Route
import io.ktor.routing.Routing
import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.netty.Netty
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.serialization.BinaryFormat
import kotlinx.serialization.StringFormat
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import org.jetbrains.exposed.sql.Database
import org.koin.core.module.Module
import org.koin.core.parameter.ParametersHolder
import org.koin.core.qualifier.StringQualifier
import org.koin.dsl.*
import java.io.File
private fun Route.print() {
println(this)
children.forEach {
it.print()
}
}
fun getDIModule(
vararg args: String,
baseScope: CoroutineScope = CoroutineScope(Dispatchers.IO)
): Module {
val configJson = Json {
ignoreUnknownKeys = true
}
val config = configJson.decodeFromString(Config.serializer(), File(args.first()).readText())
val originalFilesMetasKeyValueRepoQualifier = StringQualifier("OriginalFilesMetaKV")
val binaryOriginalFilesMetasKeyValueRepoQualifier = StringQualifier("BinaryOriginalFilesMetaKV")
val commonFilesMetasKeyValueRepoQualifier = StringQualifier("CommonFilesMetaKV")
val binaryFilesMetasKeyValueRepoQualifier = StringQualifier("BinaryFilesMetaKV")
val filesFolderQualifier = StringQualifier("rootFilesFolder")
val commonFilesFolderQualifier = StringQualifier("commonFilesFolder")
val binaryFilesFolderQualifier = StringQualifier("binaryFilesFolder")
val usersRolesKeyValueFactoryQualifier = StringQualifier("usersRolesKeyValueFactory")
return module {
singleWithRandomQualifier<ContentSerializersModuleConfigurator.Element> { OtherContentSerializerModuleConfigurator }
singleWithRandomQualifier<ContentSerializersModuleConfigurator.Element> { TextContentSerializerModuleConfigurator }
singleWithRandomQualifier<SerializersModuleConfigurator.Element> { ContentSerializersModuleConfigurator(getAll()) }
single { SerializersModuleConfigurator(getAll()) }
single {
Json {
ignoreUnknownKeys = true
serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } }
}
}
single<StringFormat> { get<Json>() }
single<BinaryFormat> {
Cbor {
serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } }
}
}
single { UnifiedRouter(get()) }
singleWithBinds { config }
singleWithBinds { get<Config>().databaseConfig }
singleWithBinds { get<Config>().authConfig }
singleWithBinds(filesFolderQualifier) { get<Config>().filesFolderFile }
singleWithBinds(commonFilesFolderQualifier) { get<Config>().commonFilesFolder }
singleWithBinds(binaryFilesFolderQualifier) { get<Config>().binaryFilesFolder }
singleWithBinds { get<DatabaseConfig>().database }
singleWithBinds(originalFilesMetasKeyValueRepoQualifier) {
ExposedKeyValueRepo(get(), { text("fileid") }, { text("metaInfo") }, "FileIdsToMetas")
}
singleWithBinds(binaryOriginalFilesMetasKeyValueRepoQualifier) {
ExposedKeyValueRepo(get(), { text("fileid") }, { text("metaInfo") }, "BinaryContentFileIdsToMetas")
}
singleWithBinds(commonFilesMetasKeyValueRepoQualifier) {
MetasKeyValueRepo(
get(),
get(originalFilesMetasKeyValueRepoQualifier)
)
}
single<ReadFilesStorage> { DiskReadFilesStorage(get(commonFilesFolderQualifier), get(commonFilesMetasKeyValueRepoQualifier)) }
single<WriteFilesStorage> { WriteDistFilesStorage(get(commonFilesFolderQualifier), get(commonFilesMetasKeyValueRepoQualifier)) }
single<FilesStorage> { DefaultFilesStorage(get(), get()) }
singleWithBinds { ExposedUsersStorage(get()) }
singleWithBinds { exposedUsersAuthenticator(get(), get()) }
factory<KeyValuesRolesOriginalRepo>(usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName)
}
single {
RolesManagerRoleStorage(get(usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
}
single<RolesStorage<RolesManagerRole>>(StringQualifier("RolesManagerRoleStorage")) { get<RolesManagerRoleStorage>() }
singleWithBinds {
RolesStorageHolder(
RolesManagerRole::class,
get<RolesManagerRoleStorage>()
)
}
singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) }
// Publication targets
singleWithRandomQualifier<PublicationTarget> { PublicationTargetTelegram(get(), get()) }
single { PublicationManager(getAll(), get(), get(), get()) }
// Roles checkers
single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker }
factory<CoroutineScope> { baseScope.LinkedSupervisorScope() }
// Content storages
val binaryStorageFilesQualifier = StringQualifier("binaryContentFiles")
singleWithBinds(binaryFilesMetasKeyValueRepoQualifier) {
MetasKeyValueRepo(
get(),
get(binaryOriginalFilesMetasKeyValueRepoQualifier)
)
}
single<FilesStorage>(binaryStorageFilesQualifier) {
DefaultFilesStorage(
DiskReadFilesStorage(get(binaryFilesFolderQualifier), get(binaryFilesMetasKeyValueRepoQualifier)),
WriteDistFilesStorage(get(binaryFilesFolderQualifier), get(binaryFilesMetasKeyValueRepoQualifier))
)
}
singleWithRandomQualifier { BinaryServerContentStorage(get(binaryStorageFilesQualifier)) }
singleWithRandomQualifier { TextServerContentStorage(get()) }
single<ServerContentStorage<Content>> { ServerContentStorageAggregator(getAll(), get()) }
// Posts storage
single<ServerPostsStorage> { ExposedServerPostsStorage(get()) }
singleWithBinds {
ServerPostsService(
DefaultExposedReadPostsService(get<ServerPostsStorage>()),
DefaultWritePostsService(get<ServerPostsStorage>(), get<ServerContentStorage<Content>>())
)
}
// Routing configurators
singleWithBinds { FilesRoutingConfigurator(get(), null, get()) }
singleWithBinds { StatusRoutingConfigurator }
singleWithBinds { UsersStorageServerRoutesConfigurator(get(), get()) }
singleWithBinds { RolesStorageReadServerRoutesConfigurator<Role>(get(), RoleSerializer, get()) }
singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get(), get()) }
singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get()) }
singleWithBinds { ClientStaticRoutingConfiguration(get<Config>().clientStatic) }
singleWithBinds {
RolesAuthenticationConfigurator<Role>(
get(),
get(),
getAll()
)
}
// Session and auth configurators
singleWithBinds { SessionAuthenticationConfigurator(get<AuthConfig>().sessionAge) }
singleWithBinds {
DefaultAuthTokensService(
get<Database>(),
get(),
get(),
get<AuthConfig>().sessionAge,
get()
)
}
singleWithBinds { AuthenticationRoutingConfigurator(get(), get(), get()) }
if (config.debugMode) {
single<ApplicationRoutingConfigurator.Element>(StringQualifier("Tracer")) { ApplicationRoutingConfigurator.Element {(this as Routing).trace { application.log.trace(it.buildText()) } } }
}
singleWithBinds { ApplicationRoutingConfigurator(getAllDistinct()) }
singleWithBinds { ApplicationCachingHeadersConfigurator(getAllDistinct()) }
singleWithBinds { ApplicationSessionsConfigurator(getAllDistinct()) }
singleWithBinds { StatusPagesConfigurator(getAllDistinct()) }
singleWithBinds { ApplicationAuthenticationConfigurator(getAllDistinct()) }
singleWithBinds { WebSocketsConfigurator }
factory<ApplicationEngine> {
val config = get<Config>()
createKtorServer(
Netty,
config.host,
config.port
) {
getAllDistinct<KtorApplicationConfigurator>().also(::println).forEach {
it.apply { configure() }
}
if (config.debugMode) {
featureOrNull(Routing) ?.print()
}
}
}
}
}