165 lines
6.7 KiB
Kotlin
165 lines
6.7 KiB
Kotlin
package com.jaytux.simd.server
|
|
|
|
import com.jaytux.simd.data.*
|
|
import com.jaytux.simd.server.RouteCache.register
|
|
import io.ktor.http.*
|
|
import io.ktor.http.content.*
|
|
import io.ktor.server.request.*
|
|
import io.ktor.server.response.*
|
|
import io.ktor.server.routing.*
|
|
import kotlinx.datetime.LocalDate
|
|
import kotlinx.serialization.Serializable
|
|
import kotlinx.serialization.json.Json
|
|
import org.jetbrains.exposed.dao.UUIDEntity
|
|
import org.jetbrains.exposed.dao.id.EntityID
|
|
import org.jetbrains.exposed.sql.*
|
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
|
|
import org.jetbrains.exposed.sql.transactions.transaction
|
|
import java.util.*
|
|
|
|
@Serializable
|
|
data class IntrinsicSummary(@Serializable(with = UUIDSerializer::class) val id: UUID, val name: String)
|
|
|
|
@Serializable
|
|
data class Param(val name: String, val type: String)
|
|
|
|
@Serializable
|
|
data class Instruction(val mnemonic: String, val xed: String, val form: String?)
|
|
|
|
@Serializable
|
|
data class PlatformPerformance(val platform: String, val latency: Float?, val throughput: Float?)
|
|
|
|
@Serializable
|
|
data class IntrinsicDetails(
|
|
@Serializable(with = UUIDSerializer::class) val id: UUID,
|
|
val name: String,
|
|
val returnType: String,
|
|
val returnVar: String?,
|
|
val description: String,
|
|
val operations: String?,
|
|
val category: String,
|
|
val cpuid: String?,
|
|
val tech: String,
|
|
val params: List<Param>,
|
|
val instructions: List<Instruction>?,
|
|
val performance: List<PlatformPerformance>?
|
|
)
|
|
|
|
@Serializable
|
|
data class Versioning(
|
|
val intelVersion: String, val intelUpdate: LocalDate, val scrapeDate: LocalDate
|
|
)
|
|
|
|
fun Routing.installGetAll() {
|
|
getPagedUrl("/all", "Get a quick overview of all endpoints", { 100 }, { IntrinsicSummary(it.id.value, it.mnemonic) }) {
|
|
Intrinsic.all().orderAsc(Intrinsics.mnemonic)
|
|
}
|
|
|
|
getPagedUrl("/cpuid", "Get a list of all CPUIDs", { 100 }, { it.name }) { CPUID.all().orderAsc(CPUIDs.name) }
|
|
getPagedUrl("/tech", "Get a list of all technologies", { 100 }, { it.name }) { Tech.all().orderAsc(Techs.name) }
|
|
getPagedUrl("/category", "Get a list of all intrinsic categories", { 100 }, { it.name }) { Category.all().orderAsc(Categories.name) }
|
|
getPagedUrl("/types", "Get a list of all used C/C++ types", { 100 }, { it.name }) { CppType.all().orderAsc(CppTypes.name) }
|
|
}
|
|
|
|
fun Routing.installSearch() {
|
|
getPagedRequest("/search", "Search for intrinsics matching certain filters", { 100 }, { IntrinsicSummary(it[Intrinsics.id].value, it[Intrinsics.mnemonic]) }) {
|
|
fun <T : UUIDEntity> resolveAny(key: String, finder: (String) -> SizedIterable<T>): List<EntityID<UUID>>? {
|
|
return call.request.queryParameters[key]?.let {
|
|
try {
|
|
val list = Json.decodeFromString<List<String>>(it)
|
|
list.map {
|
|
finder(it).firstOrNull()?.id
|
|
?: throw HttpError("Unknown $key: ${list.joinToString(", ")}")
|
|
}
|
|
}
|
|
catch(e: HttpError) {
|
|
throw e
|
|
}
|
|
catch(e: Exception) {
|
|
throw HttpError("Malformed $key parameter: $it")
|
|
}
|
|
}
|
|
}
|
|
|
|
val name = call.request.queryParameters["name"]
|
|
val returnType = call.request.queryParameters["return"]?.let {
|
|
CppType.find { CppTypes.name eq it }.firstOrNull()
|
|
?: throw HttpError("Unknown return type: $it")
|
|
}
|
|
val anyCpuid = resolveAny("cpuid") { CPUID.find { CPUIDs.name eq it } }
|
|
val anyTech = resolveAny("tech") { Tech.find { Techs.name eq it } }
|
|
val anyCat = resolveAny("category") { Category.find { Categories.name eq it } }
|
|
val desc = call.request.queryParameters["desc"]
|
|
|
|
var results = Intrinsics.selectAll().where {
|
|
val build = listOf(
|
|
name?.let { Intrinsics.mnemonic like "%$it%" },
|
|
returnType?.let { Intrinsics.returnType eq it.id },
|
|
anyCpuid?.let { Intrinsics.cpuid inList it },
|
|
anyTech?.let { Intrinsics.tech inList it },
|
|
anyCat?.let { Intrinsics.category inList it },
|
|
desc?.let { Intrinsics.description like "%$it%" }
|
|
).filterNotNull()
|
|
|
|
build.fold(Op.TRUE as Op<Boolean>, { acc, op -> op and acc })
|
|
}
|
|
|
|
results.orderAsc(Intrinsics.mnemonic)
|
|
}
|
|
}
|
|
|
|
fun Routing.installDetails() {
|
|
register(HttpMethod.Get, "/details/{id}", "Get details of an intrinsic by its ID")
|
|
get("/details/{id}") {
|
|
runCatching {
|
|
transaction {
|
|
val id = call.parameters["id"]?.let {
|
|
try {
|
|
UUID.fromString(it)
|
|
}
|
|
catch(e: IllegalArgumentException) {
|
|
throw HttpError("Invalid UUID: $it")
|
|
}
|
|
} ?: throw HttpError("Missing or invalid ID")
|
|
val intrinsic = Intrinsic.findById(id)
|
|
?: throw HttpError("Unknown intrinsic: $id")
|
|
|
|
IntrinsicDetails(
|
|
id = intrinsic.id.value,
|
|
name = intrinsic.mnemonic,
|
|
returnType = intrinsic.returnType.name,
|
|
returnVar = intrinsic.returnVar,
|
|
description = intrinsic.description,
|
|
operations = intrinsic.operations,
|
|
category = intrinsic.category.name,
|
|
cpuid = intrinsic.cpuid?.name,
|
|
tech = intrinsic.tech.name,
|
|
params = intrinsic.arguments.orderAsc(IntrinsicArguments.index)
|
|
.map { Param(it.name, it.type.name) },
|
|
instructions = intrinsic.instructions.emptyToNull()
|
|
?.map { Instruction(it.mnemonic, it.xed, it.form) },
|
|
performance = intrinsic.instructions.firstOrNull()?.let {
|
|
(Performances innerJoin Platforms).selectAll().where {
|
|
Performances.instruction eq it.id
|
|
}.map {
|
|
PlatformPerformance(
|
|
platform = it[Platforms.name],
|
|
latency = it[Performances.latency],
|
|
throughput = it[Performances.throughput]
|
|
)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Routing.installVersion() {
|
|
register(HttpMethod.Get, "/version", "Get the current version of the data")
|
|
get("/version") {
|
|
val upd = Loader.DatedVersion.fromPrefs()
|
|
call.respond(Versioning(upd.version.toString(), intelUpdate = upd.releaseDate, upd.updateDate))
|
|
}
|
|
} |