use super::{config::Seat, tools::Identity};
use crate::{
client::{Client, Ended, Reply},
mcp::adapter::{Sender, ServiceRefusal},
serve::{cli::Config, protocol::Operation},
};
use serde::Deserialize;
use serde_json::{Value, json, value::RawValue};
use std::{path::PathBuf, time::Duration};
pub(super) struct Native {
pub page: u32,
socket: PathBuf,
timeout: Duration,
issuer: String,
agent: String,
proof: String,
bound: usize,
}
#[derive(Deserialize)]
struct Wire {
method: String,
params: Option<Box<RawValue>>,
}
impl Native {
pub fn new(seat: &Seat, identity: &Identity) -> anyhow::Result<Self> {
let config: Config = serde_json::from_slice(&std::fs::read(&seat.serve_config)?)
.map_err(|_| anyhow::anyhow!("assistant_serve_config_invalid"))?;
let endpoint = config.endpoint(false)?;
anyhow::ensure!(endpoint.name == seat.store, "assistant_serve_store_differs");
Ok(Self {
page: config.max_page.get(),
socket: endpoint.socket,
timeout: Duration::from_millis(config.timeout_ms.get()),
issuer: seat.issuer.clone(),
agent: identity.agent.clone(),
proof: identity.launch.clone(),
bound: seat.harness.issuer_response_bytes,
})
}
pub fn read(&mut self, method: &str, params: &Value) -> Result<Value, ServiceRefusal> {
let request = serde_json::from_value(json!({"method":method,"params":params}))
.map_err(|error| encoding(&error))?;
serde_json::from_str(self.send(request)?.get()).map_err(|error| encoding(&error))
}
}
impl Sender for Native {
fn send(&mut self, request: Operation) -> Result<Box<RawValue>, ServiceRefusal> {
let pass = super::tools::acquire(&self.issuer, &self.agent, &self.proof, self.bound)
.map_err(|_| ServiceRefusal {
code: "assistant_record_pass_refused".to_owned(),
message: "could not acquire the agent's record pass".to_owned(),
receipt: None,
})?;
let mut client = Client::connect(&self.socket, self.timeout).map_err(ended)?;
let raw = serde_json::value::to_raw_value(&json!({"pass":pass}))
.map_err(|error| encoding(&error))?;
answered(client.call("session.pass", Some(&raw)).map_err(ended)?)?;
let raw = serde_json::value::to_raw_value(&request).map_err(|error| encoding(&error))?;
let operation: Wire = serde_json::from_str(raw.get()).map_err(|error| encoding(&error))?;
answered(
client
.call(&operation.method, operation.params.as_deref())
.map_err(ended)?,
)
}
}
fn answered(reply: Reply) -> Result<Box<RawValue>, ServiceRefusal> {
match reply {
Reply::Answered(raw) => Ok(raw),
Reply::Refused(error) => Err(ServiceRefusal {
code: error.code,
message: error.message,
receipt: error.verified.map(|receipt| receipt.raw().to_owned()),
}),
}
}
fn encoding(error: &serde_json::Error) -> ServiceRefusal {
ServiceRefusal {
code: "assistant_record_encoding_failed".to_owned(),
message: error.to_string(),
receipt: None,
}
}
fn ended(error: Ended) -> ServiceRefusal {
let (code, message, receipt) = match error {
Ended::Usage(why) | Ended::NotAsked(why) => ("assistant_record_not_asked", why, None),
Ended::Unknown(why) => ("assistant_record_outcome_unknown", why, None),
Ended::Received { why, receipt } => (
"assistant_record_outcome_unknown",
why,
Some(receipt.raw().to_owned()),
),
};
ServiceRefusal {
code: code.to_owned(),
message,
receipt,
}
}