|
@@ -13,9 +13,9 @@ import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.withContext
|
|
import kotlinx.coroutines.withContext
|
|
import kotlinx.html.*
|
|
import kotlinx.html.*
|
|
import kotlinx.serialization.Serializable
|
|
import kotlinx.serialization.Serializable
|
|
-import kotlinx.serialization.builtins.ListSerializer
|
|
|
|
import kotlinx.serialization.encodeToString
|
|
import kotlinx.serialization.encodeToString
|
|
import kotlinx.serialization.json.Json
|
|
import kotlinx.serialization.json.Json
|
|
|
|
+import java.sql.Connection
|
|
import java.util.concurrent.ThreadLocalRandom
|
|
import java.util.concurrent.ThreadLocalRandom
|
|
|
|
|
|
@Serializable
|
|
@Serializable
|
|
@@ -28,9 +28,6 @@ data class World(val id: Int, var randomNumber: Int)
|
|
data class Fortune(val id: Int, var message: String)
|
|
data class Fortune(val id: Int, var message: String)
|
|
|
|
|
|
fun Application.main() {
|
|
fun Application.main() {
|
|
- val worldSerializer = World.serializer()
|
|
|
|
- val worldListSerializer = ListSerializer(World.serializer())
|
|
|
|
-
|
|
|
|
val dbRows = 10000
|
|
val dbRows = 10000
|
|
val poolSize = 48
|
|
val poolSize = 48
|
|
val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) }
|
|
val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) }
|
|
@@ -38,48 +35,61 @@ fun Application.main() {
|
|
|
|
|
|
install(DefaultHeaders)
|
|
install(DefaultHeaders)
|
|
|
|
|
|
- val okContent = TextContent("Hello, World!", ContentType.Text.Plain, HttpStatusCode.OK).also { it.contentLength }
|
|
|
|
|
|
+ val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain).also { it.contentLength }
|
|
|
|
|
|
routing {
|
|
routing {
|
|
get("/plaintext") {
|
|
get("/plaintext") {
|
|
- call.respond(okContent)
|
|
|
|
|
|
+ call.respond(helloWorldContent)
|
|
}
|
|
}
|
|
|
|
|
|
get("/json") {
|
|
get("/json") {
|
|
- call.respondText(
|
|
|
|
- Json.encodeToString(Message("Hello, world!")),
|
|
|
|
- ContentType.Application.Json,
|
|
|
|
- HttpStatusCode.OK
|
|
|
|
- )
|
|
|
|
|
|
+ call.respondText(Json.encodeToString(Message("Hello, world!")), ContentType.Application.Json)
|
|
}
|
|
}
|
|
|
|
|
|
get("/db") {
|
|
get("/db") {
|
|
val random = ThreadLocalRandom.current()
|
|
val random = ThreadLocalRandom.current()
|
|
- val queries = call.queries()
|
|
|
|
- val result = ArrayList<World>(queries ?: 1)
|
|
|
|
|
|
|
|
- withContext(databaseDispatcher) {
|
|
|
|
|
|
+ val world = withContext(databaseDispatcher) {
|
|
pool.connection.use { connection ->
|
|
pool.connection.use { connection ->
|
|
connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
|
|
connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
|
|
- for (i in 1..(queries ?: 1)) {
|
|
|
|
- statement.setInt(1, random.nextInt(dbRows) + 1)
|
|
|
|
- statement.executeQuery().use { rs ->
|
|
|
|
- while (rs.next()) {
|
|
|
|
- result += World(rs.getInt(1), rs.getInt(2))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ statement.setInt(1, random.nextInt(dbRows) + 1)
|
|
|
|
+
|
|
|
|
+ statement.executeQuery().use { rs ->
|
|
|
|
+ rs.next()
|
|
|
|
+ World(rs.getInt(1), rs.getInt(2))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- call.respondText(
|
|
|
|
- when (queries) {
|
|
|
|
- null -> Json.encodeToString(worldSerializer, result.single())
|
|
|
|
- else -> Json.encodeToString(worldListSerializer, result)
|
|
|
|
- },
|
|
|
|
- ContentType.Application.Json, HttpStatusCode.OK
|
|
|
|
- )
|
|
|
|
|
|
+ call.respondText(Json.encodeToString(world), ContentType.Application.Json)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fun Connection.selectWorlds(queries: Int, random: ThreadLocalRandom): List<World> {
|
|
|
|
+ val result = ArrayList<World>(queries)
|
|
|
|
+ prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
|
|
|
|
+ repeat(queries) {
|
|
|
|
+ statement.setInt(1, random.nextInt(dbRows) + 1)
|
|
|
|
+
|
|
|
|
+ statement.executeQuery().use { rs ->
|
|
|
|
+ rs.next()
|
|
|
|
+ result += World(rs.getInt(1), rs.getInt(2))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ get("/queries") {
|
|
|
|
+ val queries = call.queries()
|
|
|
|
+ val random = ThreadLocalRandom.current()
|
|
|
|
+
|
|
|
|
+ val result = withContext(databaseDispatcher) {
|
|
|
|
+ pool.connection.use { it.selectWorlds(queries, random) }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ call.respondText(Json.encodeToString(result), ContentType.Application.Json)
|
|
}
|
|
}
|
|
|
|
|
|
get("/fortunes") {
|
|
get("/fortunes") {
|
|
@@ -119,21 +129,11 @@ fun Application.main() {
|
|
get("/updates") {
|
|
get("/updates") {
|
|
val queries = call.queries()
|
|
val queries = call.queries()
|
|
val random = ThreadLocalRandom.current()
|
|
val random = ThreadLocalRandom.current()
|
|
- val result = ArrayList<World>(queries ?: 1)
|
|
|
|
|
|
+ val result: List<World>
|
|
|
|
|
|
withContext(databaseDispatcher) {
|
|
withContext(databaseDispatcher) {
|
|
pool.connection.use { connection ->
|
|
pool.connection.use { connection ->
|
|
- connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
|
|
|
|
- for (i in 1..(queries ?: 1)) {
|
|
|
|
- statement.setInt(1, random.nextInt(dbRows) + 1)
|
|
|
|
-
|
|
|
|
- statement.executeQuery().use { rs ->
|
|
|
|
- while (rs.next()) {
|
|
|
|
- result += World(rs.getInt(1), rs.getInt(2))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ result = connection.selectWorlds(queries, random)
|
|
|
|
|
|
result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 }
|
|
result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 }
|
|
|
|
|
|
@@ -149,13 +149,7 @@ fun Application.main() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- call.respondText(
|
|
|
|
- when (queries) {
|
|
|
|
- null -> Json.encodeToString(worldSerializer, result.single())
|
|
|
|
- else -> Json.encodeToString(worldListSerializer, result)
|
|
|
|
- },
|
|
|
|
- ContentType.Application.Json, HttpStatusCode.OK
|
|
|
|
- )
|
|
|
|
|
|
+ call.respondText(Json.encodeToString(result), ContentType.Application.Json)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -186,8 +180,5 @@ fun HikariConfig.configureMySql(poolSize: Int) {
|
|
configureCommon(poolSize)
|
|
configureCommon(poolSize)
|
|
}
|
|
}
|
|
|
|
|
|
-fun ApplicationCall.queries() = try {
|
|
|
|
- request.queryParameters["queries"]?.toInt()?.coerceIn(1, 500)
|
|
|
|
-} catch (nfe: NumberFormatException) {
|
|
|
|
- 1
|
|
|
|
-}
|
|
|
|
|
|
+fun ApplicationCall.queries() =
|
|
|
|
+ request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1
|