use super::{JSONRPC_VERSION, Message, ProgressToken};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::fmt::{Debug, Formatter};
#[cfg(feature = "server")]
use crate::Context;
#[cfg(feature = "http-server")]
use {crate::auth::DefaultClaims, volga::headers::HeaderMap};
#[cfg(feature = "tasks")]
use crate::types::RelatedTaskMetadata;
#[cfg(feature = "server")]
pub use from_request::FromRequest;
pub use request_id::RequestId;
#[cfg(feature = "server")]
mod from_request;
mod request_id;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
pub jsonrpc: String,
pub id: RequestId,
pub method: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<serde_json::Value>,
#[serde(skip)]
pub session_id: Option<uuid::Uuid>,
#[serde(skip)]
#[cfg(feature = "http-server")]
pub headers: HeaderMap,
#[serde(skip)]
#[cfg(feature = "http-server")]
pub claims: Option<Box<DefaultClaims>>,
}
#[derive(Default, Clone, Deserialize, Serialize)]
pub struct RequestParamsMeta {
#[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
pub progress_token: Option<ProgressToken>,
#[serde(
rename = "io.modelcontextprotocol/related-task",
skip_serializing_if = "Option::is_none"
)]
#[cfg(feature = "tasks")]
pub(crate) task: Option<RelatedTaskMetadata>,
#[serde(skip)]
#[cfg(feature = "server")]
pub(crate) context: Option<Context>,
}
impl Debug for RequestParamsMeta {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("RequestParamsMeta")
.field("progress_token", &self.progress_token)
.finish()
}
}
impl From<Request> for Message {
#[inline]
fn from(request: Request) -> Self {
Self::Request(request)
}
}
impl RequestParamsMeta {
pub fn new(id: &RequestId) -> Self {
Self {
progress_token: Some(ProgressToken::from(id)),
#[cfg(feature = "tasks")]
task: None,
#[cfg(feature = "server")]
context: None,
}
}
}
impl Request {
pub fn new<T: Serialize>(
id: Option<RequestId>,
method: impl Into<String>,
params: Option<T>,
) -> Self {
Self {
jsonrpc: JSONRPC_VERSION.into(),
session_id: None,
id: id.unwrap_or_default(),
method: method.into(),
params: params.and_then(|p| serde_json::to_value(p).ok()),
#[cfg(feature = "http-server")]
headers: HeaderMap::with_capacity(8),
#[cfg(feature = "http-server")]
claims: None,
}
}
pub fn id(&self) -> RequestId {
self.id.clone()
}
pub fn full_id(&self) -> RequestId {
let id = self.id.clone();
if let Some(session_id) = self.session_id {
id.concat(RequestId::Uuid(session_id))
} else {
id
}
}
pub fn meta(&self) -> Option<RequestParamsMeta> {
self.params
.as_ref()?
.get("_meta")
.cloned()
.and_then(|meta| serde_json::from_value(meta).ok())
}
}
#[cfg(test)]
mod tests {}