Skip to content

Commit

Permalink
Clean up Kotlin code and add GET history and GET available
Browse files Browse the repository at this point in the history
  • Loading branch information
starscouts committed Aug 28, 2024
1 parent adb4acf commit d5915b0
Show file tree
Hide file tree
Showing 20 changed files with 208 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ server/includes/recaptcha
client/.vercel
serverkt/config.json
serverkt/tokens
serverkt/data
serverkt/.gradle
serverkt/build
serverkt/out
Expand Down
8 changes: 8 additions & 0 deletions serverkt/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions serverkt/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("PropertyName")

val kotlin_version: String by project
val logback_version: String by project
val ktor_version = "2.3.12"
Expand Down
4 changes: 2 additions & 2 deletions serverkt/resources/views/docs-v2.vl
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ output: any|null
</tr>
<tr>
<td><code>GET</code></td>
<td>v2/available</td>
<td>v2/available<br><span class="badge bg-secondary-subtle">Kotlin</span></td>
<td>-</td>
<td>Check if enqueing a new generation is possible.</td>
<td><pre>{
Expand All @@ -176,7 +176,7 @@ output: any|null
</tr>
<tr>
<td><code>GET</code></td>
<td>v2/history</td>
<td>v2/history<br><span class="badge bg-secondary-subtle">Kotlin</span></td>
<td>URL: <code>amount</code>: number (optional)</td>
<td>Get previous generations associated with this account.</td>
<td><pre>[
Expand Down
8 changes: 8 additions & 0 deletions serverkt/serverkt.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<excludeFolder url="file://$MODULE_DIR$/data/generations" />
</content>
</component>
</module>
8 changes: 4 additions & 4 deletions serverkt/src/main/kotlin/fi/floo/voice/Utility.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fun getSession(call: ApplicationCall): UserData? {

if (sessionCookie != null && !sessionCookie.contains('/') && !sessionCookie.contains('\\') &&
!sessionCookie.contains('.')) {
val file = File("tokens/session/$sessionCookie")
val file = File("data/session/$sessionCookie")

if (file.exists()) {
val dataString = file.readText()
Expand All @@ -62,11 +62,11 @@ fun getSession(call: ApplicationCall): UserData? {
!authenticationHeader.contains("..")) {
if (authenticationHeader.startsWith("Bearer ")) {
val key = authenticationHeader.substring(7)
val idFile = File("tokens/keys/$key")
val idFile = File("data/keys/$key")

if (idFile.exists()) {
val id = idFile.readText().trim()
val dataFile = File("tokens/users/$id")
val dataFile = File("data/users/$id")

if (dataFile.exists()) {
val dataString = dataFile.readText()
Expand All @@ -84,7 +84,7 @@ fun getSession(call: ApplicationCall): UserData? {
}

fun getAPIKey(id: String): String {
val file = File("tokens/keys/$id")
val file = File("data/keys/$id")

if (!file.exists()) {
file.writer().use { f ->
Expand Down
21 changes: 21 additions & 0 deletions serverkt/src/main/kotlin/fi/floo/voice/routing/api/v2/available.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package fi.floo.voice.routing.api.v2

import fi.floo.voice.getAuthenticationData
import fi.floo.voice.types.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*

suspend fun apiV2Available(call: ApplicationCall) {
val auth = getAuthenticationData(call, AuthenticationMode.Enforced)
if (!auth.authenticated || auth.userData == null) return

val list: GenerationList = Generation.forUser(auth.userData)
val items = list.inner
.map { it.data.status == "generating" || it.data.status == "queued" }

call.respond(HttpStatusCode.OK, APIResponse(
error = null,
output = APIResponseAvailable(!items.contains(true))
))
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
package fi.floo.voice.routing.api.v2

import fi.floo.voice.config
import fi.floo.voice.getAuthenticationData
import fi.floo.voice.httpCodeToError
import fi.floo.voice.types.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Period
import kotlin.time.Duration

suspend fun apiV2Handoff(call: ApplicationCall) {
val handoffRequestData = call.receive<HandoffRequestData>()

val file = File("tokens/handoff/${handoffRequestData.token}")
val file = File("data/handoff/${handoffRequestData.token}")

if (file.exists()) {
val dataString = file.readText()
Expand Down
23 changes: 23 additions & 0 deletions serverkt/src/main/kotlin/fi/floo/voice/routing/api/v2/history.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fi.floo.voice.routing.api.v2

import fi.floo.voice.getAuthenticationData
import fi.floo.voice.types.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*

suspend fun apiV2History(call: ApplicationCall) {
val auth = getAuthenticationData(call, AuthenticationMode.Enforced)
if (!auth.authenticated || auth.userData == null) return

val list: GenerationList = Generation.forUser(auth.userData)
list.inner = list.inner
.filter { it.data.status != "blocked" }
.filter { it.data.status != "removed" }
.toMutableList()

call.respond(HttpStatusCode.OK, APIResponse(
error = null,
output = list.flatten()
))
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import fi.floo.voice.types.AuthenticationMode
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

suspend fun apiV2Models(call: ApplicationCall) {
val auth = getAuthenticationData(call, AuthenticationMode.Enforced)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package fi.floo.voice.routing.api.v2

import fi.floo.voice.config
import fi.floo.voice.getAuthenticationData
import fi.floo.voice.types.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

suspend fun apiV2Status(call: ApplicationCall) {
val auth = getAuthenticationData(call, AuthenticationMode.Enforced)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import kotlinx.serialization.json.Json
import java.io.File
import java.net.URLEncoder
import java.time.Instant
import java.time.format.DateTimeFormatter
import java.util.*

suspend fun authCallback(call: ApplicationCall) {
Expand Down Expand Up @@ -68,11 +67,11 @@ suspend fun authCallback(call: ApplicationCall) {
val userDataString = response.body<String>()
val sessionToken = generateToken(96)

File("tokens/session/$sessionToken").writer().use { f ->
File("data/session/$sessionToken").writer().use { f ->
f.write(userDataString)
}

File("tokens/users/${userData.id}").writer().use { f ->
File("data/users/${userData.id}").writer().use { f ->
f.write(userDataString)
}

Expand All @@ -84,7 +83,7 @@ suspend fun authCallback(call: ApplicationCall) {
if (config.development) {
val handoffToken = generateToken(32)
val handoffData = HandoffData(sessionToken, Instant.now().toEpochMilli())
File("tokens/handoff/$handoffToken").writer().use { f ->
File("data/handoff/$handoffToken").writer().use { f ->
f.write(Json.encodeToString(handoffData))
}

Expand Down
11 changes: 6 additions & 5 deletions serverkt/src/main/kotlin/fi/floo/voice/server/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import java.nio.file.Files
import java.nio.file.Paths

fun loadConfig(): Config {
Files.createDirectories(Paths.get("tokens"))
Files.createDirectories(Paths.get("tokens/handoff"))
Files.createDirectories(Paths.get("tokens/session"))
Files.createDirectories(Paths.get("tokens/users"))
Files.createDirectories(Paths.get("tokens/keys"))
Files.createDirectories(Paths.get("data"))
Files.createDirectories(Paths.get("data/generations"))
Files.createDirectories(Paths.get("data/handoff"))
Files.createDirectories(Paths.get("data/session"))
Files.createDirectories(Paths.get("data/users"))
Files.createDirectories(Paths.get("data/keys"))

val file = File("config.json")
return Json.decodeFromString(file.readText())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.plugins.statuspages.*
import io.ktor.server.response.*
import io.ktor.server.velocity.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

fun getServer(): NettyApplicationEngine {
return embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
Expand Down
8 changes: 3 additions & 5 deletions serverkt/src/main/kotlin/fi/floo/voice/server/Routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package fi.floo.voice.server
import fi.floo.voice.routing.auth.*
import fi.floo.voice.routing.docs.*
import fi.floo.voice.routing.*
import fi.floo.voice.routing.api.v2.apiV2Handoff
import fi.floo.voice.routing.api.v2.apiV2Models
import fi.floo.voice.routing.api.v2.apiV2Status
import fi.floo.voice.routing.api.v2.*
import io.ktor.server.application.*
import io.ktor.server.http.content.*
import io.ktor.server.routing.*
Expand All @@ -26,8 +24,8 @@ fun Application.configureRouting() {

get("/api/v2/models") { apiV2Models(call) }
get("/api/v2/status") { apiV2Status(call) }
// TODO: GET available
// TODO: GET history
get("/api/v2/available") { apiV2Available(call) }
get("/api/v2/history") { apiV2History(call) }
// TODO: GET history/:id
// TODO: DELETE history
// TODO: POST generate
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fi.floo.voice.types

import kotlinx.serialization.Serializable

@Serializable
data class APIResponseAvailable(
val available: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fi.floo.voice.types

import kotlinx.serialization.Serializable

@Suppress("PropertyName")
@Serializable
data class AccessToken(
val access_token: String,
Expand Down
86 changes: 86 additions & 0 deletions serverkt/src/main/kotlin/fi/floo/voice/types/Generation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package fi.floo.voice.types

import java.io.File
import java.time.Instant
import java.time.format.DateTimeFormatter
import java.util.*

class Generation(val data: GenerationData) {
val time = Date(data.timeTs)

companion object {
fun forUser(user: UserData): GenerationList {
val list = GenerationList(mutableListOf())
val directory = File("data/generations")
val files = directory.listFiles()?.filter { it.isDirectory }

if (files != null) {
for (file in files) {
list.inner.add(fromDirectory(file))
list.inner.sortBy { it.time }
list.inner = list.inner
.filter { it.data.version != "0" }
.filter { it.data.model != "" }
.filter { it.data.author == user.id }
.toMutableList()
}
}

return list
}

private fun fromDirectory(directory: File): Generation {
val author = File("${directory.absolutePath}/author.txt").readText()
val complete = File("${directory.absolutePath}/complete.txt").exists()
val blocked = File("${directory.absolutePath}/blocked.txt").exists()
val input = File("${directory.absolutePath}/input_orig.txt").readText()
val process = File("${directory.absolutePath}/process.txt").exists()
val removed = File("${directory.absolutePath}/removed.txt").exists()
val timestamp = File("${directory.absolutePath}/timestamp.txt").readText()

val versionFile = File("${directory.absolutePath}/version.txt")
val version = if (versionFile.exists()) {
versionFile.readText()
} else {
"0"
}

val modelFile = File("${directory.absolutePath}/model.txt")
val model = if (modelFile.exists()) {
modelFile.readText()
} else {
""
}

val timeTs = timestamp.toLong()
val timeInstant = Instant.ofEpochSecond(timeTs)
val dateIso = DateTimeFormatter.ISO_INSTANT.format(timeInstant)

val status = if (blocked) {
"blocked"
} else if (removed) {
"removed"
} else if (complete) {
"processed"
} else if (process) {
"generating"
} else {
"queued"
}

val data = GenerationData(
id = directory.name,
model = model,
version = version,
author = author,
time = dateIso,
timeTs = timeTs,
audioUrl = "",
input = input,
status = status
)

return Generation(data)
}
}
}
16 changes: 16 additions & 0 deletions serverkt/src/main/kotlin/fi/floo/voice/types/GenerationData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package fi.floo.voice.types

import kotlinx.serialization.Serializable

@Serializable
data class GenerationData(
val id: String,
val model: String,
val version: String,
val author: String,
val time: String,
val timeTs: Long,
val audioUrl: String,
val input: String,
var status: String
)
Loading

0 comments on commit d5915b0

Please sign in to comment.