refactor(#1375): type connector operation responses (#1388)

This commit is contained in:
m57 authored and GitHub committed 2026-09-29 21:28:40 +03:00
1 parent 8ae2ddbbee
commit c8edf3665f
12 files changed
+1168 -125

No files matched your search

@@ -7,6 +7,7 @@ import com.m57.hermescontrol.data.model.ConnectorCatalogEntry
import com.m57.hermescontrol.data.model.ConnectorError
import com.m57.hermescontrol.data.model.ConnectorPolicy
import com.m57.hermescontrol.data.model.ConnectorTool
import com.m57.hermescontrol.data.ws.contract.ConnectionRespondParams
import com.m57.hermescontrol.data.ws.contract.ConnectorOwner
import com.m57.hermescontrol.data.ws.contract.ConnectorsAccountsParams
import com.m57.hermescontrol.data.ws.contract.ConnectorsAccountsRemoveParams
@@ -61,10 +62,9 @@ interface AccountConnectorRepository {
expectedRevision: String,
): AccountConnectorResult<ConnectorPolicy>
suspend fun operationRequest(
method: String,
params: Map<String, Any>,
): Any?
suspend fun operationRespond(params: ConnectionRespondParams): Any?
suspend fun operationWake(params: ConnectorsOperationStatusParams): Any?
suspend fun operationStatus(
opId: String,
@@ -74,26 +74,8 @@ interface AccountConnectorRepository {
}
class HermesAccountConnectorRepository(
private val rpc: 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
} finally {
if (!deferred.isCompleted) deferred.cancel()
}
},
private val caller: TypedRpcCaller = HermesRpcCaller,
) : AccountConnectorRepository {
private suspend fun request(
method: String,
params: Map<String, Any> = emptyMap(),
) = rpc(method, params)
private suspend fun <T> guarded(block: suspend () -> T): AccountConnectorResult<T> =
try {
AccountConnectorResult.Success(block())
@@ -111,12 +93,6 @@ class HermesAccountConnectorRepository(
AccountConnectorResult.Failure(ConnectorError.NetworkError("Failed to communicate with gateway."))
}
private fun accountParams(params: Map<String, Any> = emptyMap()): Map<String, Any> =
buildMap {
putAll(params)
AuthManager.activeProfileId.value?.let { put("profile", it) }
}
private fun obj(value: Any?): JsonObject = ConnectorParser.toJsonElement(value).jsonObject
private fun JsonObject.str(k: String) = this[k]?.jsonPrimitive?.contentOrNull.orEmpty()
@@ -173,10 +149,23 @@ class HermesAccountConnectorRepository(
)
}
override suspend fun operationRequest(
method: String,
params: Map<String, Any>,
): Any? = request(method, accountParams(params + ("owner" to mapOf("type" to "account"))))
override suspend fun operationRespond(params: ConnectionRespondParams): Any? =
caller.call(
RpcMethods.CONNECTION_RESPOND,
params.copy(
owner = ConnectorOwner.account(),
profile = AuthManager.activeProfileId.value,
),
)
override suspend fun operationWake(params: ConnectorsOperationStatusParams): Any? =
caller.call(
RpcMethods.CONNECTORS_OPERATION_WAKE,
params.copy(
owner = ConnectorOwner.account(),
profile = AuthManager.activeProfileId.value,
),
)
override suspend fun operationStatus(opId: String) =
guarded {
@@ -0,0 +1,26 @@
package com.m57.hermescontrol.data.ws.contract
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ConnectionAnswerTarget(
@SerialName("name") val name: String,
@SerialName("status") val status: String,
@SerialName("detail") val detail: String? = null,
@SerialName("env") val env: Map<String, String>? = null,
)
@Serializable
data class ConnectionAnswer(
@SerialName("targets") val targets: List<ConnectionAnswerTarget>? = null,
@SerialName("settled_by") val settledBy: String? = null,
)
@Serializable
data class ConnectionRespondParams(
@SerialName("owner") val owner: ConnectorOwner,
@SerialName("op_id") val opId: String,
@SerialName("result") val result: ConnectionAnswer,
@SerialName("profile") val profile: String? = null,
)
@@ -315,6 +315,22 @@ object RpcMethods {
JsonElement.serializer(),
)
// Passthrough JsonElement results: callers keep their existing legacy parsers.
val CONNECTION_RESPOND: RpcMethod<ConnectionRespondParams, JsonElement> =
RpcMethod(
WsMethods.CONNECTION_RESPOND,
ConnectionRespondParams.serializer(),
JsonElement.serializer(),
)
// Passthrough JsonElement results: callers keep their existing legacy parsers.
val CONNECTORS_OPERATION_WAKE: RpcMethod<ConnectorsOperationStatusParams, JsonElement> =
RpcMethod(
WsMethods.CONNECTORS_OPERATION_WAKE,
ConnectorsOperationStatusParams.serializer(),
JsonElement.serializer(),
)
/** Every typed method. GatewayContractTest iterates this; future migrations append here. */
val all: List<RpcMethod<*, *>> =
listOf(
@@ -356,5 +372,7 @@ object RpcMethods {
CONNECTORS_POLICY_GET,
CONNECTORS_POLICY_SET,
CONNECTORS_TOOLS,
CONNECTION_RESPOND,
CONNECTORS_OPERATION_WAKE,
)
}