use async_trait::async_trait;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value;
use crate::envelope::{JsonRpcRequest, JsonRpcResponse, RequestId};
use crate::error::{ControlError, ControlErrorCode};
use crate::method::ControlMethod;
use crate::params;
use crate::results;
pub trait ControlCall: Serialize {
const METHOD: ControlMethod;
type Output: DeserializeOwned;
}
fn params_value<C: ControlCall>(call: &C) -> Value {
match serde_json::to_value(call) {
Ok(Value::Null) => Value::Object(Default::default()),
Ok(v) => v,
Err(_) => Value::Object(Default::default()),
}
}
pub fn build_request<C: ControlCall>(id: RequestId, call: &C) -> JsonRpcRequest {
JsonRpcRequest::new(id, C::METHOD.name(), params_value(call))
}
pub fn parse_response<C: ControlCall>(
response: JsonRpcResponse,
) -> Result<C::Output, ControlError> {
let value = response.into_result()?;
serde_json::from_value(value).map_err(|e| {
ControlError::of(
ControlErrorCode::ControlError,
format!("failed to parse {} result: {e}", C::METHOD.name()),
)
})
}
pub trait ControlClient {
fn build_request<C: ControlCall>(&self, id: RequestId, call: &C) -> JsonRpcRequest {
build_request(id, call)
}
fn parse_response<C: ControlCall>(
&self,
response: JsonRpcResponse,
) -> Result<C::Output, ControlError> {
parse_response::<C>(response)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultControlClient;
impl ControlClient for DefaultControlClient {}
#[async_trait]
pub trait ControlHandler: Sync {
async fn status(&self) -> Result<results::StatusResult, ControlError>;
async fn config_get(&self) -> Result<results::ConfigResult, ControlError>;
async fn config_set_upstream(
&self,
params: params::SetUpstreamParams,
) -> Result<results::SetUpstreamResult, ControlError>;
async fn log_set_level(
&self,
params: params::SetLevelParams,
) -> Result<results::SetLevelResult, ControlError>;
async fn cache_get(&self) -> Result<results::CacheView, ControlError>;
async fn cache_set_cap(
&self,
params: params::SetCapParams,
) -> Result<results::SetCapResult, ControlError>;
async fn cache_clear(&self) -> Result<results::CacheClearResult, ControlError>;
async fn hosted_stores_list(&self) -> Result<results::HostedStoresListResult, ControlError>;
async fn hosted_stores_pin(
&self,
params: params::PinParams,
) -> Result<results::PinResult, ControlError>;
async fn hosted_stores_unpin(
&self,
params: params::UnpinParams,
) -> Result<results::UnpinResult, ControlError>;
async fn hosted_stores_status(
&self,
params: params::HostedStoreStatusParams,
) -> Result<results::HostedStoreStatusResult, ControlError>;
async fn sync_status(&self) -> Result<results::SyncStatusResult, ControlError>;
async fn sync_trigger(
&self,
params: params::SyncTriggerParams,
) -> Result<results::SyncTriggerResult, ControlError>;
async fn updater_status(&self) -> Result<Value, ControlError>;
async fn updater_set_channel(
&self,
params: params::SetChannelParams,
) -> Result<Value, ControlError>;
async fn updater_pause(&self, params: params::PauseParams) -> Result<Value, ControlError>;
async fn updater_resume(&self) -> Result<Value, ControlError>;
async fn updater_check_now(&self) -> Result<Value, ControlError>;
async fn pairing_list(&self) -> Result<Value, ControlError>;
async fn pairing_approve(
&self,
params: params::ApproveParams,
) -> Result<results::PairingApproveResult, ControlError>;
async fn pairing_revoke(
&self,
params: params::RevokeParams,
) -> Result<results::PairingRevokeResult, ControlError>;
async fn peer_status(&self) -> Result<Value, ControlError>;
async fn peers_connect(
&self,
params: params::PeersConnectParams,
) -> Result<results::PeersConnectResult, ControlError>;
async fn peers_disconnect(
&self,
params: params::PeersDisconnectParams,
) -> Result<results::PeersDisconnectResult, ControlError>;
async fn subscribe(
&self,
params: params::SubscribeParams,
) -> Result<results::SubscribeResult, ControlError>;
async fn unsubscribe(
&self,
params: params::UnsubscribeParams,
) -> Result<results::UnsubscribeResult, ControlError>;
async fn list_subscriptions(&self) -> Result<results::ListSubscriptionsResult, ControlError>;
async fn pairing_request(
&self,
params: params::RequestParams,
) -> Result<results::PairingRequestResult, ControlError>;
async fn pairing_poll(
&self,
params: params::PollParams,
) -> Result<results::PairingPollResult, ControlError>;
async fn dispatch(&self, request: JsonRpcRequest) -> JsonRpcResponse {
let id = request.id.clone();
let Some(method) = ControlMethod::from_name(&request.method) else {
return JsonRpcResponse::error(
id,
ControlError::of(
ControlErrorCode::MethodNotFound,
format!("unknown control method: {}", request.method),
),
);
};
match self.dispatch_method(method, request.params).await {
Ok(result) => JsonRpcResponse::success(id, result),
Err(err) => JsonRpcResponse::error(id, err),
}
}
#[doc(hidden)]
async fn dispatch_method(
&self,
method: ControlMethod,
params: Value,
) -> Result<Value, ControlError> {
fn decode<T: DeserializeOwned>(params: Value) -> Result<T, ControlError> {
serde_json::from_value(params)
.map_err(|e| ControlError::of(ControlErrorCode::InvalidParams, e.to_string()))
}
fn encode<T: Serialize>(value: T) -> Result<Value, ControlError> {
serde_json::to_value(value)
.map_err(|e| ControlError::of(ControlErrorCode::ControlError, e.to_string()))
}
match method {
ControlMethod::Status => encode(self.status().await?),
ControlMethod::ConfigGet => encode(self.config_get().await?),
ControlMethod::ConfigSetUpstream => {
encode(self.config_set_upstream(decode(params)?).await?)
}
ControlMethod::LogSetLevel => encode(self.log_set_level(decode(params)?).await?),
ControlMethod::CacheGet => encode(self.cache_get().await?),
ControlMethod::CacheSetCap => encode(self.cache_set_cap(decode(params)?).await?),
ControlMethod::CacheClear => encode(self.cache_clear().await?),
ControlMethod::HostedStoresList => encode(self.hosted_stores_list().await?),
ControlMethod::HostedStoresPin => {
encode(self.hosted_stores_pin(decode(params)?).await?)
}
ControlMethod::HostedStoresUnpin => {
encode(self.hosted_stores_unpin(decode(params)?).await?)
}
ControlMethod::HostedStoresStatus => {
encode(self.hosted_stores_status(decode(params)?).await?)
}
ControlMethod::SyncStatus => encode(self.sync_status().await?),
ControlMethod::SyncTrigger => encode(self.sync_trigger(decode(params)?).await?),
ControlMethod::UpdaterStatus => self.updater_status().await,
ControlMethod::UpdaterSetChannel => self.updater_set_channel(decode(params)?).await,
ControlMethod::UpdaterPause => self.updater_pause(decode(params)?).await,
ControlMethod::UpdaterResume => self.updater_resume().await,
ControlMethod::UpdaterCheckNow => self.updater_check_now().await,
ControlMethod::PairingList => self.pairing_list().await,
ControlMethod::PairingApprove => encode(self.pairing_approve(decode(params)?).await?),
ControlMethod::PairingRevoke => encode(self.pairing_revoke(decode(params)?).await?),
ControlMethod::PeerStatus => self.peer_status().await,
ControlMethod::PeersConnect => encode(self.peers_connect(decode(params)?).await?),
ControlMethod::PeersDisconnect => encode(self.peers_disconnect(decode(params)?).await?),
ControlMethod::Subscribe => encode(self.subscribe(decode(params)?).await?),
ControlMethod::Unsubscribe => encode(self.unsubscribe(decode(params)?).await?),
ControlMethod::ListSubscriptions => encode(self.list_subscriptions().await?),
ControlMethod::PairingRequest => encode(self.pairing_request(decode(params)?).await?),
ControlMethod::PairingPoll => encode(self.pairing_poll(decode(params)?).await?),
}
}
}