use serde::{Deserialize, Serialize, de::DeserializeOwned};
use super::{Sender, ServiceRefusal, ToolResult, result};
use crate::mcp::types;
use crate::serve::protocol;
#[derive(Deserialize, Serialize)]
pub(super) struct Snapshot {
pub(super) branch: String,
pub(super) version: types::Version,
}
impl Snapshot {
pub(super) fn selection(&self) -> protocol::Selection {
protocol::Selection {
branch: self.branch.clone(),
version: Some(self.version.0),
}
}
pub(super) fn output(self) -> types::Snapshot {
types::Snapshot {
branch: self.branch,
version: self.version,
}
}
pub(super) fn require(&self, other: &Self) -> Result<(), ServiceRefusal> {
if self.branch == other.branch && self.version.0 == other.version.0 {
Ok(())
} else {
Err(failure(
"mcp_service_snapshot_mismatch",
"The served pages do not identify the same captured version",
))
}
}
pub(super) fn requested(&self, asked: &types::Selection) -> Result<(), ServiceRefusal> {
if self.branch == asked.branch
&& asked
.version
.is_none_or(|version| version.0 == self.version.0)
{
Ok(())
} else {
Err(failure(
"mcp_service_snapshot_mismatch",
"The service did not answer the requested captured version",
))
}
}
}
pub(super) fn failure(code: &str, message: impl Into<String>) -> ServiceRefusal {
ServiceRefusal {
code: code.to_owned(),
message: message.into(),
receipt: None,
}
}
pub(super) fn call<T: DeserializeOwned>(
sender: &mut impl Sender,
operation: protocol::Operation,
) -> Result<T, ServiceRefusal> {
let raw = sender.send(operation)?;
serde_json::from_str(raw.get())
.map_err(|error| failure("mcp_service_answer_invalid", error.to_string()))
}
pub(super) fn bounded(body: &impl Serialize, bytes: u64) -> Result<ToolResult, ServiceRefusal> {
let output = result(body, false)
.map_err(|error| failure("mcp_result_encoding_failed", error.to_string()))?;
let size = u64::try_from(output.structured_content.get().len()).map_err(|_| {
failure(
"mcp_page_bytes_unrepresentable",
"The answer length is not representable",
)
})?;
if size > bytes {
return Err(failure(
"mcp_page_bytes_exceeded",
"The complete answer exceeds the requested byte limit; increase it or reduce rows",
));
}
Ok(output)
}