diff options
Diffstat (limited to 'server/core')
3 files changed, 109 insertions, 17 deletions
diff --git a/server/core/build.gradle.kts b/server/core/build.gradle.kts index 87f613a..6300a4b 100644 --- a/server/core/build.gradle.kts +++ b/server/core/build.gradle.kts @@ -2,19 +2,21 @@ plugins { kotlin("jvm") kotlin("plugin.serialization") application + id("com.github.gmazzo.buildconfig") } -val ktor_version = "3.0.3" dependencies { - implementation(platform("io.ktor:ktor-bom:$ktor_version")) - implementation("io.ktor:ktor-server-netty") - implementation("io.ktor:ktor-server-status-pages") - implementation("io.ktor:ktor-server-content-negotiation") - implementation("io.ktor:ktor-server-openapi") - implementation("io.ktor:ktor-serialization-kotlinx-json") - implementation("io.ktor:ktor-server-compression") - implementation(project(":database:impl")) + declareKtorVersion() + api("io.ktor:ktor-server-netty") + api("io.ktor:ktor-server-status-pages") + api("io.ktor:ktor-server-content-negotiation") + api("io.ktor:ktor-serialization-kotlinx-json") + api("io.ktor:ktor-server-compression") + api("io.ktor:ktor-server-cors") + api("sh.ondr:kotlin-json-schema:0.1.1") + api(project(":database:impl")) + api(project(":server:swagger")) runtimeOnly("ch.qos.logback:logback-classic:1.5.16") runtimeOnly("org.xerial:sqlite-jdbc:3.45.3.0") @@ -29,3 +31,6 @@ application { "-Dledger.databasefolder=${project(":mod").file("run/money-ledger").absoluteFile}") mainClass.set("moe.nea.ledger.server.core.ApplicationKt") } +buildConfig { + packageName("moe.nea.ledger.gen") +} diff --git a/server/core/src/main/kotlin/moe/nea/ledger/server/core/Application.kt b/server/core/src/main/kotlin/moe/nea/ledger/server/core/Application.kt index 0ea6ed3..23b2a6a 100644 --- a/server/core/src/main/kotlin/moe/nea/ledger/server/core/Application.kt +++ b/server/core/src/main/kotlin/moe/nea/ledger/server/core/Application.kt @@ -6,29 +6,76 @@ import io.ktor.server.application.install import io.ktor.server.netty.EngineMain import io.ktor.server.plugins.compression.Compression import io.ktor.server.plugins.contentnegotiation.ContentNegotiation +import io.ktor.server.plugins.cors.routing.CORS +import io.ktor.server.response.respondRedirect +import io.ktor.server.routing.Routing +import io.ktor.server.routing.get import io.ktor.server.routing.route import io.ktor.server.routing.routing +import kotlinx.serialization.json.Json import moe.nea.ledger.database.Database +import moe.nea.ledger.gen.BuildConfig +import moe.nea.ledger.server.core.api.Documentation +import moe.nea.ledger.server.core.api.Info +import moe.nea.ledger.server.core.api.Server import moe.nea.ledger.server.core.api.apiRouting +import moe.nea.ledger.server.core.api.openApiDocsJson +import moe.nea.ledger.server.core.api.openApiUi +import moe.nea.ledger.server.core.api.setApiRoot import java.io.File fun main(args: Array<String>) { EngineMain.main(args) } +interface AIOProvider { + fun Routing.installExtraRouting() + fun Application.module() +} fun Application.module() { + val aio = runCatching { + Class.forName("moe.nea.ledger.server.aio.AIO") + .newInstance() as AIOProvider + }.getOrNull() + aio?.run { module() } install(Compression) + install(Documentation) { + info = Info( + "Ledger Analysis Server", + "Your local API for loading ledger data", + BuildConfig.VERSION + ) + servers.add( + Server("http://localhost:8080/api", "Your Local Server") + ) + } install(ContentNegotiation) { - json() + json(Json { + this.explicitNulls = false + this.encodeDefaults = true + }) // cbor() } - val database = Database(File(System.getProperty("ledger.databasefolder"))) + install(CORS) { + anyHost() + } + val database = Database(File(System.getProperty("ledger.databasefolder", + "/home/nea/.local/share/PrismLauncher/instances/Skyblock/.minecraft/money-ledger"))) database.loadAndUpgrade() routing { route("/api") { - this.apiRouting(database) + setApiRoot() + get { call.respondRedirect("/openapi/") } + apiRouting(database) + } + route("/api.json") { + openApiDocsJson() + } + route("/openapi") { + openApiUi("/api.json") } + aio?.run { installExtraRouting() } } } diff --git a/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt b/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt index 264f74b..c58763f 100644 --- a/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt +++ b/server/core/src/main/kotlin/moe/nea/ledger/server/core/api/BaseApi.kt @@ -1,18 +1,21 @@ package moe.nea.ledger.server.core.api +import io.ktor.http.Url +import io.ktor.http.toURI import io.ktor.server.response.respond -import io.ktor.server.response.respondText import io.ktor.server.routing.Route -import io.ktor.server.routing.Routing import io.ktor.server.routing.get +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream import moe.nea.ledger.database.DBLogEntry import moe.nea.ledger.database.Database import moe.nea.ledger.server.core.Profile +import sh.ondr.jsonschema.jsonSchema fun Route.apiRouting(database: Database) { - get("/") { - call.respondText("K") - } get("/profiles") { val profiles = DBLogEntry.from(database.connection) .select(DBLogEntry.playerId, DBLogEntry.profileId) @@ -21,5 +24,42 @@ fun Route.apiRouting(database: Database) { Profile(it[DBLogEntry.playerId], it[DBLogEntry.profileId]) } call.respond(profiles) + }.docs { + summary = "List all profiles and players known to ledger" + operationId = "listProfiles" + tag(Tags.PROFILE) + respondsOk { + schema<List<Profile>>() + } + } + @OptIn(DelicateCoroutinesApi::class) + val itemNames = GlobalScope.async { + val itemNamesUrl = + Url("https://github.com/nea89o/ledger-auxiliary-data/raw/refs/heads/master/data/item_names.json") + Json.decodeFromStream<Map<String, String>>(itemNamesUrl.toURI().toURL().openStream()) + } + get("/item") { + val itemIds = call.queryParameters.getAll("itemId")?.toSet() ?: emptySet() + val itemNameMap = itemNames.await() + call.respond(itemIds.associateWith { itemNameMap[it] }) + }.docs { + summary = "Get item names for item ids" + operationId = "getItemNames" + tag(Tags.HYPIXEL) + queryParameter<List<String>>("itemId") + respondsOk { + schema<Map<String, String?>>() + } } } + +enum class Tags : IntoTag { + PROFILE, + HYPIXEL, + MANAGEMENT, + ; + + override fun intoTag(): String { + return name + } +}
\ No newline at end of file |