use serde::{Deserialize, Serialize};
use crate::client::VtaClient;
use crate::error::VtaError;
use crate::protocols::protocol_management;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[must_use]
pub struct EnableDidcommRequest {
pub mediator_did: String,
#[serde(default)]
pub force: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub handshake_timeout_secs: Option<u64>,
}
impl EnableDidcommRequest {
pub fn new(mediator_did: impl Into<String>) -> Self {
Self {
mediator_did: mediator_did.into(),
force: false,
handshake_timeout_secs: None,
}
}
pub fn force(mut self, force: bool) -> Self {
self.force = force;
self
}
pub fn handshake_timeout_secs(mut self, secs: u64) -> Self {
self.handshake_timeout_secs = Some(secs);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnableDidcommResponse {
pub new_version_id: String,
pub mediator_did: String,
pub mediator_endpoint: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DisableDidcommRequest {
pub drain_ttl_secs: u64,
}
impl DisableDidcommRequest {
pub fn new(drain_ttl_secs: u64) -> Self {
Self { drain_ttl_secs }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DisableDidcommResponse {
pub new_version_id: String,
pub prior_mediator_did: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub drains_until: Option<String>,
}
impl VtaClient {
pub async fn enable_didcomm(
&self,
req: EnableDidcommRequest,
) -> Result<EnableDidcommResponse, VtaError> {
self.rpc(
"services-management/1.0/enable-not-available-via-didcomm",
serde_json::to_value(&req)?,
"services-management/1.0/enable-not-available-via-didcomm-result",
30,
|c, url| c.post(format!("{url}/services/didcomm/enable")).json(&req),
)
.await
}
pub async fn disable_didcomm(
&self,
req: DisableDidcommRequest,
) -> Result<DisableDidcommResponse, VtaError> {
self.rpc(
protocol_management::DISABLE_DIDCOMM,
serde_json::to_value(&req)?,
protocol_management::DISABLE_DIDCOMM_RESULT,
30,
|c, url| c.post(format!("{url}/services/didcomm/disable")).json(&req),
)
.await
}
pub async fn migrate_mediator(
&self,
req: MigrateMediatorRequest,
) -> Result<MigrateMediatorResponse, VtaError> {
self.rpc(
protocol_management::MIGRATE_MEDIATOR,
serde_json::to_value(&req)?,
protocol_management::MIGRATE_MEDIATOR_RESULT,
120,
|c, url| c.post(format!("{url}/mediators/migrate")).json(&req),
)
.await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[must_use]
pub struct MigrateMediatorRequest {
pub new_mediator_did: String,
pub drain_ttl_secs: u64,
#[serde(default)]
pub force: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub handshake_timeout_secs: Option<u64>,
#[serde(default)]
pub rollback: bool,
}
impl MigrateMediatorRequest {
pub fn new(new_mediator_did: impl Into<String>, drain_ttl_secs: u64) -> Self {
Self {
new_mediator_did: new_mediator_did.into(),
drain_ttl_secs,
force: false,
handshake_timeout_secs: None,
rollback: false,
}
}
pub fn force(mut self, force: bool) -> Self {
self.force = force;
self
}
pub fn rollback(mut self, rollback: bool) -> Self {
self.rollback = rollback;
self
}
pub fn handshake_timeout_secs(mut self, secs: u64) -> Self {
self.handshake_timeout_secs = Some(secs);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MigrateMediatorResponse {
pub new_version_id: String,
pub prior_mediator_did: String,
pub active_mediator_did: String,
pub active_mediator_endpoint: String,
pub drains_until: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrainCancelRequest {
pub mediator_did: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrainCancelResponse {
pub mediator_did: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediatorStats {
pub mediator_did: String,
pub inbound_count: u64,
pub first_seen: String,
pub last_seen: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SenderLastSeen {
pub sender_did: String,
pub last_seen_mediator: String,
pub last_seen_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediatorReport {
#[serde(default)]
pub since: Option<String>,
pub until: String,
pub mediators: Vec<MediatorStats>,
pub senders: Vec<SenderLastSeen>,
}
impl VtaClient {
pub async fn drain_cancel(
&self,
req: DrainCancelRequest,
) -> Result<DrainCancelResponse, VtaError> {
self.rpc(
protocol_management::DRAIN_CANCEL,
serde_json::to_value(&req)?,
protocol_management::DRAIN_CANCEL_RESULT,
30,
|c, url| c.post(format!("{url}/mediators/drain/cancel")).json(&req),
)
.await
}
pub async fn mediator_report(
&self,
since: Option<&str>,
until: Option<&str>,
) -> Result<MediatorReport, VtaError> {
let since_owned = since.map(str::to_string);
let until_owned = until.map(str::to_string);
let qs = build_report_query(since_owned.as_deref(), until_owned.as_deref());
self.rpc(
protocol_management::MEDIATOR_REPORT,
serde_json::json!({
"since": since_owned,
"until": until_owned,
}),
protocol_management::MEDIATOR_REPORT_RESULT,
30,
move |c, url| {
let url = if qs.is_empty() {
format!("{url}/mediators/report")
} else {
format!("{url}/mediators/report?{qs}")
};
c.get(url)
},
)
.await
}
}
fn build_report_query(since: Option<&str>, until: Option<&str>) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(s) = since {
parts.push(format!("since={}", url_encode(s)));
}
if let Some(u) = until {
parts.push(format!("until={}", url_encode(u)));
}
parts.join("&")
}
fn url_encode(s: &str) -> String {
s.chars()
.flat_map(|c| match c {
':' => "%3A".chars().collect::<Vec<_>>(),
'+' => "%2B".chars().collect::<Vec<_>>(),
_ => vec![c],
})
.collect()
}