This commit is contained in:
11 files changed
+175
-73
No files matched your search
@@ -1,8 +1,10 @@
|
||||
package com.m57.hermescontrol.data.ws
|
||||
|
||||
import com.m57.hermescontrol.data.remote.OkHttpProvider
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.serialization.json.Json
|
||||
import com.m57.hermescontrol.data.ws.contract.HermesRpcCaller
|
||||
import com.m57.hermescontrol.data.ws.contract.PluginsManageParams
|
||||
import com.m57.hermescontrol.data.ws.contract.RpcMethods
|
||||
import com.m57.hermescontrol.data.ws.contract.TypedRpcCaller
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
@@ -11,23 +13,14 @@ import kotlinx.serialization.json.decodeFromJsonElement
|
||||
* Manages plugin settings and inspection through the gateway's canonical `plugins.manage` RPC.
|
||||
*/
|
||||
class PluginManageRepository(
|
||||
private val rpcRequest: suspend (String, Map<String, Any?>) -> Any? = { method, params ->
|
||||
val deferred = HermesWsClient.request(method, params.filterValues { it != null }.mapValues { it.value ?: "" })
|
||||
try {
|
||||
deferred.await()
|
||||
} catch (e: CancellationException) {
|
||||
deferred.cancel(e)
|
||||
throw e
|
||||
}
|
||||
},
|
||||
private val caller: TypedRpcCaller = HermesRpcCaller,
|
||||
) {
|
||||
suspend fun listPlugins(profile: String? = null): List<AgentPluginRow> {
|
||||
val params = mutableMapOf<String, Any?>("action" to "list")
|
||||
if (!profile.isNullOrBlank()) {
|
||||
params["profile"] = profile
|
||||
}
|
||||
val result = rpcRequest(WsMethods.PLUGINS_MANAGE, params)
|
||||
val element = result.toJsonElement()
|
||||
val element =
|
||||
caller.call(
|
||||
RpcMethods.PLUGINS_MANAGE,
|
||||
PluginsManageParams(action = "list", profile = profile.orNullIfBlank()),
|
||||
)
|
||||
val pluginsElement = (element as? JsonObject)?.get("plugins") ?: return emptyList()
|
||||
return OkHttpProvider.json.decodeFromJsonElement<List<AgentPluginRow>>(pluginsElement)
|
||||
}
|
||||
@@ -38,15 +31,15 @@ class PluginManageRepository(
|
||||
profile: String? = null,
|
||||
): PluginsManageSettingsResult {
|
||||
val params =
|
||||
mutableMapOf<String, Any?>(
|
||||
"action" to "settings",
|
||||
"key" to key,
|
||||
"values" to JsonObject(values),
|
||||
PluginsManageParams(
|
||||
action = "settings",
|
||||
key = key,
|
||||
values = JsonObject(values),
|
||||
profile = profile.orNullIfBlank(),
|
||||
)
|
||||
if (!profile.isNullOrBlank()) {
|
||||
params["profile"] = profile
|
||||
}
|
||||
val result = rpcRequest(WsMethods.PLUGINS_MANAGE, params)
|
||||
return OkHttpProvider.json.decodeFromJsonElement<PluginsManageSettingsResult>(result.toJsonElement())
|
||||
val result = caller.call(RpcMethods.PLUGINS_MANAGE, params)
|
||||
return OkHttpProvider.json.decodeFromJsonElement<PluginsManageSettingsResult>(result)
|
||||
}
|
||||
|
||||
private fun String?.orNullIfBlank(): String? = this?.takeIf { it.isNotBlank() }
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.m57.hermescontrol.data.ws
|
||||
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import com.m57.hermescontrol.data.ws.contract.HermesRpcCaller
|
||||
import com.m57.hermescontrol.data.ws.contract.PluginsManageParams
|
||||
import com.m57.hermescontrol.data.ws.contract.RpcMethods
|
||||
import com.m57.hermescontrol.data.ws.contract.TypedRpcCaller
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
@@ -14,18 +17,10 @@ data class PluginRemovalResult(
|
||||
|
||||
/** Removes a user-installed plugin through the gateway's canonical plugin manager. */
|
||||
class PluginRemovalRepository(
|
||||
private val rpcRequest: suspend (String, Map<String, Any>) -> Any? = { method, params ->
|
||||
val deferred = HermesWsClient.request(method, params)
|
||||
try {
|
||||
deferred.await()
|
||||
} catch (e: CancellationException) {
|
||||
deferred.cancel(e)
|
||||
throw e
|
||||
}
|
||||
},
|
||||
private val caller: TypedRpcCaller = HermesRpcCaller,
|
||||
) {
|
||||
suspend fun remove(name: String): PluginRemovalResult {
|
||||
val result = rpcRequest(WsMethods.PLUGINS_MANAGE, mapOf("action" to "remove", "name" to name))
|
||||
return Json.decodeFromJsonElement<PluginRemovalResult>(result.toJsonElement())
|
||||
val result = caller.call(RpcMethods.PLUGINS_MANAGE, PluginsManageParams(action = "remove", name = name))
|
||||
return Json.decodeFromJsonElement<PluginRemovalResult>(result)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,10 @@ package com.m57.hermescontrol.data.ws
|
||||
import com.m57.hermescontrol.data.model.ProjectInfo
|
||||
import com.m57.hermescontrol.data.model.ProjectsListResponse
|
||||
import com.m57.hermescontrol.data.remote.OkHttpProvider
|
||||
import com.m57.hermescontrol.data.ws.contract.HermesRpcCaller
|
||||
import com.m57.hermescontrol.data.ws.contract.ProjectsListParams
|
||||
import com.m57.hermescontrol.data.ws.contract.RpcMethods
|
||||
import com.m57.hermescontrol.data.ws.contract.TypedRpcCaller
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
||||
@@ -17,14 +21,12 @@ class HermesProjectsSource(
|
||||
// Only ask a live socket: an offline request would be queued and force a reconnect on
|
||||
// every refresh. The view model refetches when the connection comes back.
|
||||
private val isConnected: () -> Boolean = { HermesWsClient.connectionStatus.value == ConnectionStatus.CONNECTED },
|
||||
private val rpcRequest: suspend (method: String, params: Map<String, Any>) -> Any? = { method, params ->
|
||||
HermesWsClient.request(method, params).await()
|
||||
},
|
||||
private val caller: TypedRpcCaller = HermesRpcCaller,
|
||||
) : ProjectsSource {
|
||||
override suspend fun fetchProjects(): List<ProjectInfo>? {
|
||||
if (!isConnected()) return null
|
||||
return try {
|
||||
val element = SessionLiveStatusDecoder.anyToJsonElement(rpcRequest(WsMethods.PROJECTS_LIST, emptyMap()))
|
||||
val element = caller.call(RpcMethods.PROJECTS_LIST, ProjectsListParams)
|
||||
if (element is JsonObject && element.containsKey("projects")) {
|
||||
OkHttpProvider.json.decodeFromJsonElement(ProjectsListResponse.serializer(), element).projects
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.m57.hermescontrol.data.ws.contract
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
||||
/**
|
||||
* `plugins.manage` params. [action] has no default so it is always encoded; every other field is
|
||||
* omitted when null. [profile] is an explicit override only; otherwise WsProfileParams injects it.
|
||||
*/
|
||||
@Serializable
|
||||
data class PluginsManageParams(
|
||||
@SerialName("action") val action: String,
|
||||
@SerialName("profile") val profile: String? = null,
|
||||
@SerialName("key") val key: String? = null,
|
||||
@SerialName("name") val name: String? = null,
|
||||
@SerialName("enable") val enable: Boolean? = null,
|
||||
@SerialName("identifier") val identifier: String? = null,
|
||||
@SerialName("repo") val repo: String? = null,
|
||||
@SerialName("catalog_name") val catalogName: String? = null,
|
||||
@SerialName("force") val force: Boolean? = null,
|
||||
@SerialName("ref") val ref: String? = null,
|
||||
@SerialName("accept_capabilities") val acceptCapabilities: Boolean? = null,
|
||||
@SerialName("values") val values: JsonObject? = null,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.m57.hermescontrol.data.ws.contract
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/** `projects.list` takes no explicit params; the active profile is injected by WsProfileParams. */
|
||||
@Serializable
|
||||
data object ProjectsListParams
|
||||
@@ -363,6 +363,22 @@ object RpcMethods {
|
||||
JsonElement.serializer(),
|
||||
)
|
||||
|
||||
// Passthrough JsonElement results: callers keep their existing legacy decoders.
|
||||
val PLUGINS_MANAGE: RpcMethod<PluginsManageParams, JsonElement> =
|
||||
RpcMethod(
|
||||
WsMethods.PLUGINS_MANAGE,
|
||||
PluginsManageParams.serializer(),
|
||||
JsonElement.serializer(),
|
||||
)
|
||||
|
||||
// Passthrough JsonElement results: callers keep their existing legacy decoders.
|
||||
val PROJECTS_LIST: RpcMethod<ProjectsListParams, JsonElement> =
|
||||
RpcMethod(
|
||||
WsMethods.PROJECTS_LIST,
|
||||
ProjectsListParams.serializer(),
|
||||
JsonElement.serializer(),
|
||||
)
|
||||
|
||||
/** Every typed method. GatewayContractTest iterates this; future migrations append here. */
|
||||
val all: List<RpcMethod<*, *>> =
|
||||
listOf(
|
||||
@@ -410,5 +426,7 @@ object RpcMethods {
|
||||
SUBAGENT_TAIL,
|
||||
PROCESS_LIST,
|
||||
PROCESS_KILL,
|
||||
PLUGINS_MANAGE,
|
||||
PROJECTS_LIST,
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user