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 { OtherContentSerializerModuleConfigurator } singleWithRandomQualifier { ContentSerializersModuleConfigurator(getAll()) } single { SerializersModuleConfigurator(getAll()) } single { Json { ignoreUnknownKeys = true serializersModule = SerializersModule { get().apply { invoke() } } } } single { get() } single { Cbor { serializersModule = SerializersModule { get().apply { invoke() } } } } single { UnifiedRouter(get()) } singleWithBinds { config } singleWithBinds { get().databaseConfig } singleWithBinds { get().authConfig } singleWithBinds(Qualifiers.filesFolderQualifier) { get().filesFolderFile } singleWithBinds(Qualifiers.commonFilesFolderQualifier) { File(get().filesFolderFile, "common").apply { mkdirs() } } singleWithBinds { get().database } singleWithBinds { ExposedUsersStorage(get()) } singleWithBinds { exposedUsersAuthenticator(get(), get()) } factory(Qualifiers.usersRolesKeyValueFactoryQualifier) { (tableName: String) -> ExposedOneToManyKeyValueRepo(get(), { text("subject") }, { text("role") }, tableName) } single { RolesManagerRoleStorage(get(Qualifiers.usersRolesKeyValueFactoryQualifier) { ParametersHolder(mutableListOf("rolesManager")) }) } single>(StringQualifier("RolesManagerRoleStorage")) { get() } singleWithBinds { RolesStorageHolder( RolesManagerRole::class, get() ) } singleWithBinds> { RolesAggregator(getAll()) } single(createdAtStart = true) { PublicationManager(getAll(), get(), get(), get()) } // Roles checkers single>(StringQualifier(RolesManagerRolesChecker.key)) { RolesManagerRolesChecker } factory { baseScope.LinkedSupervisorScope() } // Content storages single> { ServerContentStorageAggregator(getAll(), get()) } binds arrayOf( ServerReadContentStorage::class, ServerWriteContentStorage::class ) // Posts storage single { ExposedServerPostsStorage(get()) } binds arrayOf( ServerReadPostsStorage::class, ServerWritePostsStorage::class ) singleWithBinds { ServerPostsService( DefaultExposedReadPostsService(get()), DefaultWritePostsService(get(), get>()) ) } singleWithBinds { 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(get(), RoleSerializer, get()) } singleWithBinds { RolesManagerRolesStorageServerRoutesConfigurator(get(), get()) } singleWithBinds { ServerPostsServiceRoutingConfigurator(get(), get(), get(), get()) } singleWithBinds { ClientStaticRoutingConfiguration("web") } singleWithBinds { RolesAuthenticationConfigurator( get(), get(), getAll() ) } // Session and auth configurators singleWithBinds { SessionAuthenticationConfigurator(get().sessionAge) } singleWithBinds { DefaultAuthTokensService( get(), get(), get(), get().sessionAge, get() ) } singleWithBinds { AuthenticationRoutingConfigurator(get(), get(), get()) } singleWithBinds { NotFoundStatusPageRedirectToIndex("/") } if (config.debugMode) { single(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 { val config = get() createKtorServer( Netty, config.host, config.port ) { getAllDistinct().also(::println).forEach { it.apply { configure() } } if (config.debugMode) { pluginOrNull(Routing) ?.print() } } } config.modules.forEach { it.apply { load(configJsonElement) } } } }