diff --git a/apps/documentViewerKorge/src/jvmMain/kotlin/de/itkl/documentViewerKorge/main.kt b/apps/documentViewerKorge/src/jvmMain/kotlin/de/itkl/documentViewerKorge/main.kt index ca38ef0..b998e54 100644 --- a/apps/documentViewerKorge/src/jvmMain/kotlin/de/itkl/documentViewerKorge/main.kt +++ b/apps/documentViewerKorge/src/jvmMain/kotlin/de/itkl/documentViewerKorge/main.kt @@ -12,6 +12,7 @@ import korlibs.korge.input.* import korlibs.korge.tween.get import korlibs.korge.tween.tween import korlibs.korge.ui.tooltip +import korlibs.korge.ui.uiCheckBox import korlibs.logger.AnsiEscape import korlibs.math.geom.* import korlibs.math.geom.shape.toShape2D @@ -89,6 +90,8 @@ class ViewDocument(private val document: Document) : Scene() { val imageFile = localCurrentDirVfs["assets/xs-reg/00001.jpg"].readBitmap() image(imageFile) + uiCheckBox { text = "foo" } + document.retrieveOcrPages().first().words.forEach { word -> solidRect( width = word.rectangle.width, diff --git a/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt b/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt index 1038b6c..fad2380 100644 --- a/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt +++ b/apps/xsCli/src/main/kotlin/de/itkl/xsCli/App.kt @@ -4,6 +4,7 @@ import com.github.ajalt.clikt.parameters.options.convert import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.required import com.github.ajalt.clikt.parameters.types.int +import de.itkl.httpClient.clients.TaskWaitStatus import de.itkl.httpClient.clients.XsClient import de.itkl.httpClient.httpClientModule import kotlinx.coroutines.* @@ -15,6 +16,7 @@ import org.koin.core.context.GlobalContext.startKoin import java.io.File import java.nio.file.Path import java.nio.file.Paths +import kotlin.time.Duration.Companion.minutes class Cli : CliktCommand() { override fun run() {} @@ -36,10 +38,14 @@ class XsCli : KoinComponent { private val xsClient: XsClient by inject() suspend fun run(tasks: Int, inputDirectory: Path) = coroutineScope { - val files = inputDirectory.toFile().listFiles()!!.toList().filter { it.isFile }.filter { it.extension in listOf("pdf", "ttf", "jpg", "jpeg") } + val files = inputDirectory.toFile() + .listFiles()!! + .toList() + .filter { it.isFile }.filter { it.extension in listOf("pdf", "ttf", "jpg", "jpeg") } + .filter { !it.name.startsWith(".") } val random = Random() - (0..tasks) + val (success, error) = (0..) { startKoin { modules(httpClientModule) } - XsCli().run(tasks = 1, inputDirectory = Paths.get("assets/xs-reg")) -// Cli().main(args) + XsCli().run(tasks = 100, inputDirectory = Paths.get("assets/xs-reg")) } \ No newline at end of file diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt index 7f4913a..3be1cf5 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/clients/XsClient.kt @@ -29,16 +29,27 @@ private val Log = KotlinLogging.logger { } class XsClient : KoinComponent { private val httpClient by inject() - - suspend fun waitFor(task: XsTask) { + suspend fun waitFor(task: XsTask): WaitForResponse { Log.info { "Wait for competition: $task" } val response = httpClient.get { url("http://localhost:8080/api/v1/analyse/tasks/wait/${task.xsTaskId.taskId}") user = "xs.dev.klara" } - val responseText = response.bodyAsText() - Log.info { "Waiting done for task $task: ${response.status}: $responseText" } + val result = response.body() + Log.info { "Waiting done for task $task: ${response.status}: $result" } + return result + } + suspend fun analyseResult(task: XsTask) { + val response = httpClient.get { + url("http://localhost:8080/api/v1/analyse-async-result/${task.xsTaskId.taskId}") + user = "xs.dev.klara" + } + check(response.status.isSuccess()) { + "HTTP Error" + } + val text = response.bodyAsText() + println(text) } suspend fun analyse(image: Path): TaskReference { Log.info { "Starting analysis for image at path: $image" } @@ -105,6 +116,18 @@ data class XsTaskId(val tenantId: String, val taskId: String) { } } +@Serializable +data class WaitForResponse( + val xsTaskId: XsTaskId, + val status: TaskWaitStatus, +) + +@Serializable +enum class TaskWaitStatus { + ERROR, + SUCCESS +} + fun Path.toChannelProvider(): ChannelProvider { val file = toFile() return ChannelProvider(file.length()) { file.readChannel() } diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt index edc2dae..3f88251 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/createHttpClient.kt @@ -16,7 +16,7 @@ fun createHttpClient(): HttpClient { } install(smartCloudAuthPlugin) install(HttpTimeout) { - requestTimeoutMillis = 1.minutes.inWholeMilliseconds + requestTimeoutMillis = 30.minutes.inWholeMilliseconds } engine { diff --git a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt index 6546105..fd95407 100644 --- a/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt +++ b/libraries/httpClient/src/main/kotlin/de/itkl/httpClient/implementation/SmartCloudAuthStrategy.kt @@ -3,6 +3,7 @@ package de.itkl.httpClient.implementation import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Cache import de.itkl.httpClient.auth.* +import de.itkl.httpClient.clients.user import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.client.* import io.ktor.client.call.* @@ -13,12 +14,16 @@ import io.ktor.util.* import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.util.concurrent.TimeUnit +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock private val Log = KotlinLogging.logger { } class SmartCloudAuthStrategy : AuthStrategy, KoinComponent { private val credentialsProvider: CredentialsProvider by inject() + private val loginMutex = Mutex() + // Cache Helpers private val tokenCache: Cache = Caffeine.newBuilder() .expireAfterWrite(1, TimeUnit.HOURS) @@ -31,31 +36,37 @@ class SmartCloudAuthStrategy : AuthStrategy, KoinComponent { return null } - // Return cached token if present tokenCache.getIfPresent(user)?.let { Log.info { "Returning cached token for user: $user" } return it } - val credentials: Credentials = credentialsProvider.lookupByUsername(user) ?: error("No credentials found for user: $user") - val loginAndPassword: Credentials.LoginAndPassword = credentials as? Credentials.LoginAndPassword ?: error("Only username and password is supported by smartcloud auth login") + return loginMutex.withLock { + tokenCache.getIfPresent(user)?.let { + Log.info { "Returning cached token for user: $user" } + return it + } - Log.debug { "User: $user, using smartcloud auth login" } + val credentials: Credentials = credentialsProvider.lookupByUsername(user) ?: error("No credentials found for user: $user") + val loginAndPassword: Credentials.LoginAndPassword = credentials as? Credentials.LoginAndPassword ?: error("Only username and password is supported by smartcloud auth login") - val response = httpClient.post { - url("https://api.internal.insiders.cloud/1/rest/accounts/authentication/requesttoken") - contentType(ContentType.Application.Json) - setBody(loginAndPassword) + Log.debug { "User: $user, using smartcloud auth login" } + + val response = httpClient.post { + url("https://api.internal.insiders.cloud/1/rest/accounts/authentication/requesttoken") + contentType(ContentType.Application.Json) + setBody(loginAndPassword) + } + check(response.status.isSuccess()) { + "could not login into smart cloud: ${response.bodyAsText()}" + } + val token = response.body() + Log.info { "Login successful. Valid until: ${token.validUntil}" } + + // Cache the token after successful login + tokenCache.put(user, token) + + token } - check(response.status.isSuccess()) { - "could not login into smart cloud: ${response.bodyAsText()}" - } - val token = response.body() - Log.info { "Login successful. Valid until: ${token.validUntil}" } - - // Cache the token after successful login - tokenCache.put(user, token) - - return token } } \ No newline at end of file