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

219 lines
9.4 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.ApplicationAuthenticationConfigurator
import dev.inmo.postssystem.features.files.common.*
import dev.inmo.postssystem.features.files.common.storage.*
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.common.server.Qualifiers
import dev.inmo.postssystem.features.content.common.*
import dev.inmo.postssystem.features.content.server.ServerContentStorageAggregator
import dev.inmo.postssystem.features.content.server.storage.*
import dev.inmo.postssystem.features.posts.server.*
import dev.inmo.postssystem.features.publication.server.PublicationManager
import dev.inmo.postssystem.services.posts.server.*
import io.ktor.server.application.pluginOrNull
import io.ktor.server.application.log
import io.ktor.server.routing.Route
import io.ktor.server.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.*
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.core.qualifier.named
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 configJsonElement = configJson.decodeFromString(JsonObject.serializer(), File(args.first()).readText())
val config = configJson.decodeFromJsonElement(Config.serializer(), configJsonElement)
return module {
singleWithRandomQualifier<ContentSerializersModuleConfigurator.Element> { OtherContentSerializerModuleConfigurator }
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(Qualifiers.filesFolderQualifier) { get<Config>().filesFolderFile }
singleWithBinds(Qualifiers.commonFilesFolderQualifier) { File(get<Config>().filesFolderFile, "common").apply { mkdirs() } }
singleWithBinds { get<DatabaseConfig>().database }
singleWithBinds { ExposedUsersStorage(get()) }
singleWithBinds { exposedUsersAuthenticator(get(), get()) }
factory<KeyValuesRolesOriginalRepo>(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) ->
ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName)
}
single {
RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) })
}
single<RolesStorage<RolesManagerRole>>(StringQualifier("RolesManagerRoleStorage")) { get<RolesManagerRoleStorage>() }
singleWithBinds {
RolesStorageHolder(
RolesManagerRole::class,
get<RolesManagerRoleStorage>()
)
}
singleWithBinds<RolesStorage<Role>> { RolesAggregator(getAll()) }
single(createdAtStart = true) { PublicationManager(getAll(), get(), get(), get()) }
// Roles checkers
single<RolesChecker<Role>>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker }
factory<CoroutineScope> { baseScope.LinkedSupervisorScope() }
// Content storages
single<ServerContentStorage<Content>> { ServerContentStorageAggregator(getAll(), get()) } binds arrayOf(
ServerReadContentStorage::class,
ServerWriteContentStorage::class
)
// Posts storage
single<ServerPostsStorage> { ExposedServerPostsStorage(get()) } binds arrayOf(
ServerReadPostsStorage::class,
ServerWritePostsStorage::class
)
singleWithBinds {
ServerPostsService(
DefaultExposedReadPostsService(get<ServerPostsStorage>()),
DefaultWritePostsService(get<ServerPostsStorage>(), get<ServerContentStorage<Content>>())
)
}
singleWithBinds<FilesStorage> {
val metasRepo = MetasKeyValueRepo(
get(),
ExposedKeyValueRepo(get(), { text("fileid") }, { text("metaInfo") }, "CommonFilesMetaInfoTable")
)
DefaultFilesStorage(
DiskReadFilesStorage(get(Qualifiers.commonFilesFolderQualifier), metasRepo),
WriteDistFilesStorage(get(Qualifiers.commonFilesFolderQualifier), metasRepo)
)
}
// 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(), get()) }
singleWithBinds { ClientStaticRoutingConfiguration("web") }
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()) }
singleWithBinds { NotFoundStatusPageRedirectToIndex("/") }
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) {
pluginOrNull(Routing) ?.print()
}
}
}
config.modules.forEach {
it.apply { load(configJsonElement) }
}
}
}