feat: add :backend:config module with ConfigApiClient (Step 3)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0ede5c690b
commit
ea460f7ef0
5 changed files with 129 additions and 0 deletions
|
|
@ -64,6 +64,8 @@ dependencies {
|
|||
implementation(project(":core:domain"))
|
||||
implementation(project(":core:data"))
|
||||
implementation(project(":core:ui"))
|
||||
implementation(project(":backend:api"))
|
||||
implementation(project(":backend:config"))
|
||||
|
||||
implementation(platform(libs.compose.bom))
|
||||
implementation(libs.compose.ui)
|
||||
|
|
|
|||
45
android/backend/config/build.gradle.kts
Normal file
45
android/backend/config/build.gradle.kts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.compose.compiler)
|
||||
alias(libs.plugins.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.clawdroid.backend.config"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":backend:api"))
|
||||
implementation(project(":core:ui"))
|
||||
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
implementation(libs.ktor.client.content.negotiation)
|
||||
implementation(libs.ktor.serialization.json)
|
||||
implementation(libs.serialization.json)
|
||||
|
||||
implementation(platform(libs.compose.bom))
|
||||
implementation(libs.compose.ui)
|
||||
implementation(libs.compose.material3)
|
||||
implementation(libs.navigation.compose)
|
||||
|
||||
implementation(libs.koin.android)
|
||||
implementation(libs.koin.compose)
|
||||
|
||||
implementation(libs.coroutines.android)
|
||||
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
}
|
||||
2
android/backend/config/src/main/AndroidManifest.xml
Normal file
2
android/backend/config/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package io.clawdroid.backend.config
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.engine.okhttp.OkHttp
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.put
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.contentType
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import java.io.Closeable
|
||||
import java.io.IOException
|
||||
|
||||
@Serializable
|
||||
data class ConfigSchema(val sections: List<SchemaSection>)
|
||||
|
||||
@Serializable
|
||||
data class SchemaSection(val key: String, val label: String, val fields: List<SchemaField>)
|
||||
|
||||
@Serializable
|
||||
data class SchemaField(
|
||||
val key: String,
|
||||
val label: String,
|
||||
val type: String,
|
||||
val secret: Boolean = false,
|
||||
val default: JsonElement = Json.parseToJsonElement("null"),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SaveConfigResult(
|
||||
val status: String? = null,
|
||||
val restart: Boolean = false,
|
||||
val error: String? = null,
|
||||
)
|
||||
|
||||
class ConfigApiClient : Closeable {
|
||||
private val baseUrl: String get() = "http://127.0.0.1:18790"
|
||||
|
||||
private val client = HttpClient(OkHttp) {
|
||||
install(ContentNegotiation) {
|
||||
json(Json { ignoreUnknownKeys = true; isLenient = true })
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getSchema(): ConfigSchema {
|
||||
return client.get("$baseUrl/api/config/schema").ensureSuccess().body()
|
||||
}
|
||||
|
||||
suspend fun getConfig(): JsonObject {
|
||||
return client.get("$baseUrl/api/config").ensureSuccess().body()
|
||||
}
|
||||
|
||||
suspend fun saveConfig(config: JsonObject): SaveConfigResult {
|
||||
return client.put("$baseUrl/api/config") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(config)
|
||||
}.ensureSuccess().body()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
client.close()
|
||||
}
|
||||
|
||||
private suspend fun HttpResponse.ensureSuccess(): HttpResponse {
|
||||
if (!status.isSuccess()) {
|
||||
val error = runCatching { body<SaveConfigResult>().error }.getOrNull()
|
||||
throw IOException("HTTP ${status.value}: ${error ?: "request failed"}")
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
@ -19,3 +19,4 @@ include(":core:domain")
|
|||
include(":core:data")
|
||||
include(":core:ui")
|
||||
include(":backend:api")
|
||||
include(":backend:config")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue