Skip to content

Commit 16b449e

Browse files
committed
Add OpenAPI docs
1 parent 61e46b9 commit 16b449e

10 files changed

Lines changed: 235 additions & 103 deletions

File tree

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,67 @@
1+
@file:OptIn(ExperimentalSerializationApi::class)
2+
13
package org.sinytra.probe.base
24

35
import kotlinx.datetime.LocalDateTime
6+
import kotlinx.serialization.ExperimentalSerializationApi
7+
import kotlinx.serialization.SerialName
48
import kotlinx.serialization.Serializable
9+
import kotlinx.serialization.json.JsonClassDiscriminator
510
import org.sinytra.probe.base.db.ProjectPlatform
611

12+
713
@Serializable
814
data class TestRequestBody(
915
val platform: ProjectPlatform,
1016
val id: String,
1117
val gameVersion: String
1218
)
1319

14-
interface ResponseBase {
20+
@Serializable
21+
@JsonClassDiscriminator("type")
22+
sealed interface TestResponseBody {
1523
val project: TestProjectDTO
1624
val type: ResultType
25+
26+
@Serializable
27+
data class Tested(
28+
val modid: String?,
29+
val versionNumber: String?,
30+
val versionId: String?,
31+
val passing: Boolean,
32+
33+
val environment: TestEnvironmentDTO,
34+
val createdAt: LocalDateTime,
35+
36+
override val project: TestProjectDTO,
37+
override val type: ResultType = ResultType.TESTED
38+
) : TestResponseBody
39+
40+
@Serializable
41+
data class Unavailable(
42+
val loader: String,
43+
val gameVersion: String,
44+
45+
override val project: TestProjectDTO,
46+
override val type: ResultType = ResultType.UNAVAILABLE
47+
) : TestResponseBody
48+
49+
@Serializable
50+
data class Skipped(
51+
val gameVersion: String,
52+
53+
override val project: TestProjectDTO,
54+
override val type: ResultType = ResultType.NATIVE
55+
) : TestResponseBody
1756
}
1857

1958
@Serializable
2059
enum class ResultType {
60+
@SerialName("tested")
2161
TESTED,
62+
@SerialName("native")
2263
NATIVE,
64+
@SerialName("unavailable")
2365
UNAVAILABLE
2466
}
2567

@@ -34,40 +76,9 @@ data class TestProjectDTO(
3476
val platform: ProjectPlatform
3577
)
3678

37-
@Serializable
38-
data class UnavailableResponseBody(
39-
val loader: String,
40-
val gameVersion: String,
41-
42-
override val project: TestProjectDTO,
43-
override val type: ResultType
44-
) : ResponseBase
45-
4679
@Serializable
4780
data class TestEnvironmentDTO(
4881
val connectorVersion: String,
4982
val gameVersion: String,
5083
val neoforgeVersion: String
51-
)
52-
53-
@Serializable
54-
data class TestResponseBody(
55-
val modid: String?,
56-
val versionNumber: String?,
57-
val versionId: String?,
58-
val passing: Boolean,
59-
60-
val environment: TestEnvironmentDTO,
61-
val createdAt: LocalDateTime,
62-
63-
override val project: TestProjectDTO,
64-
override val type: ResultType
65-
) : ResponseBase
66-
67-
@Serializable
68-
data class SkippedResponseBody(
69-
val gameVersion: String,
70-
71-
override val project: TestProjectDTO,
72-
override val type: ResultType
73-
) : ResponseBase
84+
)

base/src/main/kotlin/org/sinytra/probe/base/db/Project.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package org.sinytra.probe.base.db
22

3+
import kotlinx.serialization.SerialName
34
import kotlinx.serialization.Serializable
45

6+
// WARNING: STABLE API
7+
@Serializable
58
enum class ProjectPlatform {
9+
@SerialName("curseforge")
610
CURSEFORGE,
11+
@SerialName("modrinth")
712
MODRINTH
813
}
914

discord/src/main/kotlin/CheckCompatCommandBase.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import dev.kord.rest.builder.message.embed
77
import kotlinx.datetime.format.FormatStringsInDatetimeFormats
88
import kotlinx.datetime.toJavaLocalDateTime
99
import org.sinytra.probe.base.ResultType
10-
import org.sinytra.probe.base.SkippedResponseBody
1110
import org.sinytra.probe.base.TestResponseBody
12-
import org.sinytra.probe.base.UnavailableResponseBody
1311
import org.slf4j.LoggerFactory
1412
import java.time.format.DateTimeFormatter
1513
import java.time.format.FormatStyle
@@ -56,24 +54,24 @@ abstract class CheckCompatCommandBase(private val gameVersion: String) {
5654

5755
when (result.type) {
5856
ResultType.TESTED -> {
59-
response.respondTestResult(result as TestResponseBody)
57+
response.respondTestResult(result as TestResponseBody.Tested)
6058
}
6159
ResultType.UNAVAILABLE -> {
62-
response.respondUnavailableResult(result as UnavailableResponseBody)
60+
response.respondUnavailableResult(result as TestResponseBody.Unavailable)
6361
}
6462
else -> {
65-
response.respondSkippedTest(result as SkippedResponseBody)
63+
response.respondSkippedTest(result as TestResponseBody.Skipped)
6664
}
6765
}
6866
}
6967

70-
private suspend fun DeferredMessageInteractionResponseBehavior.respondUnavailableResult(result: UnavailableResponseBody) {
68+
private suspend fun DeferredMessageInteractionResponseBehavior.respondUnavailableResult(result: TestResponseBody.Unavailable) {
7169
respond {
7270
content = ":warning: Project `${result.project.slug}` is not available for ${result.loader.capitalize()} on ${result.gameVersion}"
7371
}
7472
}
7573

76-
private suspend fun DeferredMessageInteractionResponseBehavior.respondTestResult(result: TestResponseBody) {
74+
private suspend fun DeferredMessageInteractionResponseBehavior.respondTestResult(result: TestResponseBody.Tested) {
7775
val green = Color(0, 255, 0)
7876
val red = Color(255, 0, 0)
7977
val link = result.project.url
@@ -123,7 +121,7 @@ abstract class CheckCompatCommandBase(private val gameVersion: String) {
123121
}
124122
}
125123

126-
suspend fun DeferredMessageInteractionResponseBehavior.respondSkippedTest(result: SkippedResponseBody) {
124+
suspend fun DeferredMessageInteractionResponseBehavior.respondSkippedTest(result: TestResponseBody.Skipped) {
127125
val neoOrange = Color(215, 116, 47)
128126
val link = result.project.url
129127

discord/src/main/kotlin/TransformRunner.kt

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,31 @@
11
package org.sinytra
22

33
import io.ktor.client.*
4-
import io.ktor.client.call.body
4+
import io.ktor.client.call.*
55
import io.ktor.client.plugins.*
66
import io.ktor.client.plugins.contentnegotiation.*
7-
import io.ktor.client.request.post
8-
import io.ktor.client.request.setBody
9-
import io.ktor.http.ContentType
10-
import io.ktor.http.HttpStatusCode
11-
import io.ktor.http.contentType
7+
import io.ktor.client.request.*
8+
import io.ktor.http.*
129
import io.ktor.serialization.kotlinx.json.*
1310
import kotlinx.serialization.Serializable
1411
import kotlinx.serialization.json.Json
1512
import kotlinx.serialization.json.JsonNamingStrategy
16-
import org.sinytra.probe.base.ResponseBase
1713
import org.sinytra.probe.base.ResultType
18-
import org.sinytra.probe.base.SkippedResponseBody
1914
import org.sinytra.probe.base.TestProjectDTO
2015
import org.sinytra.probe.base.TestRequestBody
2116
import org.sinytra.probe.base.TestResponseBody
22-
import org.sinytra.probe.base.UnavailableResponseBody
2317
import org.sinytra.probe.base.db.ProjectPlatform
2418

2519
@Serializable
2620
data class ResponseBaseData(
27-
override val project: TestProjectDTO,
28-
override val type: ResultType
29-
) : ResponseBase
21+
val project: TestProjectDTO,
22+
val type: ResultType
23+
)
3024

3125
class ProjectNotFoundException(message: String) : Exception(message)
3226

3327
object TransformRunner {
34-
suspend fun runTransformation(platform: String, slug: String, gameVersion: String): ResponseBase {
28+
suspend fun runTransformation(platform: String, slug: String, gameVersion: String): TestResponseBody {
3529
val endpoint = System.getenv("CORE_API_URL") ?: "localhost:8080"
3630

3731
val client = HttpClient {
@@ -65,9 +59,9 @@ object TransformRunner {
6559

6660
val base = resp.body<ResponseBaseData>()
6761
return when (base.type) {
68-
ResultType.TESTED -> resp.body<TestResponseBody>()
69-
ResultType.UNAVAILABLE -> resp.body<UnavailableResponseBody>()
70-
else -> resp.body<SkippedResponseBody>()
62+
ResultType.TESTED -> resp.body<TestResponseBody.Tested>()
63+
ResultType.UNAVAILABLE -> resp.body<TestResponseBody.Unavailable>()
64+
else -> resp.body<TestResponseBody.Skipped>()
7165
}
7266
}
7367
}

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jib-version = "3.4.5"
1616
gradleutils-version = "3.0.0"
1717
md-gen-version = "1.3.2"
1818
picocli-version = "4.7.7"
19+
ktor-openapi = "5.1.0"
1920

2021
[libraries]
2122
ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor-version" }
@@ -50,6 +51,8 @@ kotlinx-serialization-hocon = { module = "org.jetbrains.kotlinx:kotlinx-serializ
5051
markdown-generator = { module = "com.github.Steppschuh:Java-Markdown-Generator", version.ref = "md-gen-version" }
5152
picocli = { module = "info.picocli:picocli", version.ref = "picocli-version" }
5253
picocli-codegen = { module = "info.picocli:picocli-codegen", version.ref = "picocli-version" }
54+
ktor-openapi = { module = "io.github.smiley4:ktor-openapi", version.ref = "ktor-openapi" }
55+
ktor-swagger-ui = { module = "io.github.smiley4:ktor-swagger-ui", version.ref = "ktor-openapi" }
5356

5457
[plugins]
5558
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }

service/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ plugins {
66

77
group = "org.sinytra.probe"
88

9-
val neoForgeVersion: String by rootProject
109
val gameVersion: String by rootProject
1110
val dockerImage = "sinytra/probe/service"
1211

@@ -59,6 +58,8 @@ dependencies {
5958
implementation(libs.ktor.server.content.negotiation)
6059
implementation(libs.ktor.server.auth)
6160
implementation(libs.ktor.server.cors)
61+
implementation(libs.ktor.openapi)
62+
implementation(libs.ktor.swagger.ui)
6263
implementation(libs.postgresql)
6364
implementation(libs.h2)
6465
implementation(libs.lettuce)

service/src/main/kotlin/org/sinytra/probe/service/Application.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ import org.sinytra.probe.core.model.PostgresTestEnvironmentRepository
1818
import org.sinytra.probe.core.model.PostgresTestResultRepository
1919
import org.sinytra.probe.core.platform.GlobalPlatformService
2020
import org.sinytra.probe.core.platform.ModrinthPlatform
21+
import org.sinytra.probe.core.service.AsyncTransformationRunner
2122
import org.sinytra.probe.core.service.CacheService
2223
import org.sinytra.probe.core.service.PersistenceService
2324
import org.sinytra.probe.core.service.SetupService
2425
import org.sinytra.probe.core.service.TransformationService
26+
import org.sinytra.probe.service.api.configureInternalRouting
2527
import org.sinytra.probe.service.api.configureStableRouting
28+
import org.sinytra.probe.service.impl.RoutingImpl
2629
import kotlin.io.path.Path
2730
import kotlin.io.path.createDirectories
2831
import kotlin.io.path.div
@@ -64,6 +67,10 @@ fun Application.module() {
6467
testResultsRepository,
6568
testEnvironmentRepository
6669
)
70+
71+
val maxThreadCount = System.getenv("org.sinytra.probe.max_threads")?.toIntOrNull() ?: 10
72+
val asyncTransform = AsyncTransformationRunner(transformation, persistence, maxThreadCount)
73+
val routingImpl = RoutingImpl(setup, platforms, persistence, asyncTransform)
6774

6875
install(Authentication) {
6976
bearer("api-key") {
@@ -92,7 +99,8 @@ fun Application.module() {
9299

93100
configureSerialization()
94101
configureDatabases()
95-
configureStableRouting(setup, platforms, transformation, persistence)
102+
configureStableRouting(setup, routingImpl)
103+
configureInternalRouting(routingImpl)
96104

97105
transaction {
98106
SchemaUtils.create(TestEnvironmentTable)

0 commit comments

Comments
 (0)