1pub mod matching;
16pub mod services;
17
18use serde::{Deserialize, Serialize};
19
20#[cfg(feature = "client")]
21use crate::client::VtaClient;
22#[cfg(feature = "client")]
23use crate::error::VtaError;
24#[cfg(feature = "client")]
25use crate::protocols::protocol_management;
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29#[must_use]
30pub struct EnableDidcommRequest {
31 pub mediator_did: String,
32 #[serde(default)]
35 pub force: bool,
36 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub handshake_timeout_secs: Option<u64>,
39}
40
41impl EnableDidcommRequest {
42 pub fn new(mediator_did: impl Into<String>) -> Self {
43 Self {
44 mediator_did: mediator_did.into(),
45 force: false,
46 handshake_timeout_secs: None,
47 }
48 }
49
50 pub fn force(mut self, force: bool) -> Self {
51 self.force = force;
52 self
53 }
54
55 pub fn handshake_timeout_secs(mut self, secs: u64) -> Self {
56 self.handshake_timeout_secs = Some(secs);
57 self
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct EnableDidcommResponse {
63 pub new_version_id: String,
64 pub mediator_did: String,
65 pub mediator_endpoint: String,
66 #[serde(default, skip_serializing_if = "String::is_empty")]
72 pub vta_did: String,
73 #[serde(default)]
78 pub serverless: bool,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
84pub struct DidcommStatusResponse {
85 pub enabled: bool,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub mediator_did: Option<String>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub websocket_status: Option<String>,
90}
91
92#[derive(Debug, Clone, Deserialize)]
95pub struct EnableDidcommConflictBody {
96 pub error: String,
97 #[serde(default)]
98 pub mediator_did: Option<String>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct DisableDidcommRequest {
104 pub drain_ttl_secs: u64,
107}
108
109impl DisableDidcommRequest {
110 pub fn new(drain_ttl_secs: u64) -> Self {
111 Self { drain_ttl_secs }
112 }
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct DisableDidcommResponse {
117 pub new_version_id: String,
118 pub prior_mediator_did: String,
119 #[serde(default, skip_serializing_if = "Option::is_none")]
122 pub drains_until: Option<String>,
123 #[serde(default, skip_serializing_if = "String::is_empty")]
125 pub vta_did: String,
126 #[serde(default)]
129 pub serverless: bool,
130}
131
132#[cfg(feature = "client")]
133impl VtaClient {
134 pub async fn enable_didcomm(
151 &self,
152 req: EnableDidcommRequest,
153 ) -> Result<EnableDidcommResponse, VtaError> {
154 match &self.transport {
155 crate::client::Transport::Rest {
156 client,
157 base_url,
158 auth,
159 } => {
160 Self::ensure_token_valid(client, base_url, auth).await?;
161 let token = auth.lock().await.token.clone();
162 let req = client
163 .post(format!("{base_url}/services/didcomm/enable"))
164 .json(&req);
165 let resp = Self::with_auth_token(req, &token).send().await?;
166 Self::handle_response(resp).await
167 }
168 #[cfg(feature = "session")]
169 crate::client::Transport::DIDComm { .. } => Err(VtaError::UnsupportedTransport(
170 "enable_didcomm is REST-only".into(),
171 )),
172 #[cfg(feature = "tsp")]
173 crate::client::Transport::Tsp { .. } => Err(VtaError::UnsupportedTransport(
174 "enable_didcomm is REST-only".into(),
175 )),
176 }
177 }
178
179 pub async fn didcomm_status(&self) -> Result<DidcommStatusResponse, VtaError> {
182 match &self.transport {
183 crate::client::Transport::Rest {
184 client,
185 base_url,
186 auth,
187 } => {
188 crate::client::VtaClient::ensure_token_valid(client, base_url, auth).await?;
189 let token = auth.lock().await.token.clone();
190 let req = client.get(format!("{base_url}/services/didcomm"));
191 let resp = crate::client::VtaClient::with_auth_token(req, &token)
192 .send()
193 .await?;
194 crate::client::VtaClient::handle_response(resp).await
195 }
196 #[cfg(feature = "session")]
197 crate::client::Transport::DIDComm { .. } => Err(VtaError::UnsupportedTransport(
198 "didcomm status is REST-only in the SDK".into(),
199 )),
200 #[cfg(feature = "tsp")]
201 crate::client::Transport::Tsp { .. } => Err(VtaError::UnsupportedTransport(
202 "didcomm status is REST-only in the SDK".into(),
203 )),
204 }
205 }
206
207 pub async fn disable_didcomm(
213 &self,
214 req: DisableDidcommRequest,
215 ) -> Result<DisableDidcommResponse, VtaError> {
216 self.rpc(
217 protocol_management::DISABLE_DIDCOMM,
218 serde_json::to_value(&req)?,
219 protocol_management::DISABLE_DIDCOMM_RESULT,
220 30,
221 |c, url| c.post(format!("{url}/services/didcomm/disable")).json(&req),
222 )
223 .await
224 }
225
226 pub async fn update_didcomm(
235 &self,
236 req: UpdateDidcommRequest,
237 ) -> Result<UpdateDidcommResponse, VtaError> {
238 self.rpc(
239 protocol_management::UPDATE_DIDCOMM,
240 serde_json::to_value(&req)?,
241 protocol_management::UPDATE_DIDCOMM_RESULT,
242 120,
243 |c, url| c.post(format!("{url}/services/didcomm/update")).json(&req),
244 )
245 .await
246 }
247
248 pub async fn enable_rest(
254 &self,
255 req: services::EnableRestRequest,
256 ) -> Result<services::ServiceMutationResponse, VtaError> {
257 self.rpc(
258 protocol_management::ENABLE_REST,
259 serde_json::to_value(&req)?,
260 protocol_management::ENABLE_REST_RESULT,
261 30,
262 |c, url| c.post(format!("{url}/services/rest/enable")).json(&req),
263 )
264 .await
265 }
266
267 pub async fn update_rest(
269 &self,
270 req: services::UpdateRestRequest,
271 ) -> Result<services::ServiceMutationResponse, VtaError> {
272 self.rpc(
273 protocol_management::UPDATE_REST,
274 serde_json::to_value(&req)?,
275 protocol_management::UPDATE_REST_RESULT,
276 30,
277 |c, url| c.post(format!("{url}/services/rest/update")).json(&req),
278 )
279 .await
280 }
281
282 pub async fn disable_rest(
285 &self,
286 req: services::DisableRestRequest,
287 ) -> Result<services::ServiceMutationResponse, VtaError> {
288 self.rpc(
289 protocol_management::DISABLE_REST,
290 serde_json::to_value(&req)?,
291 protocol_management::DISABLE_REST_RESULT,
292 30,
293 |c, url| c.post(format!("{url}/services/rest/disable")).json(&req),
294 )
295 .await
296 }
297
298 pub async fn rollback_rest(
304 &self,
305 req: services::RollbackRestRequest,
306 ) -> Result<services::RollbackResponse, VtaError> {
307 self.rpc(
308 protocol_management::ROLLBACK_REST,
309 serde_json::to_value(&req)?,
310 protocol_management::ROLLBACK_REST_RESULT,
311 60,
312 |c, url| c.post(format!("{url}/services/rest/rollback")).json(&req),
313 )
314 .await
315 }
316
317 pub async fn enable_tsp(
330 &self,
331 req: services::EnableTspRequest,
332 ) -> Result<services::ServiceMutationResponse, VtaError> {
333 self.rpc(
334 protocol_management::ENABLE_TSP,
335 serde_json::to_value(&req)?,
336 protocol_management::ENABLE_TSP_RESULT,
337 30,
338 |c, url| c.post(format!("{url}/services/tsp/enable")).json(&req),
339 )
340 .await
341 }
342
343 pub async fn update_tsp(
345 &self,
346 req: services::UpdateTspRequest,
347 ) -> Result<services::ServiceMutationResponse, VtaError> {
348 self.rpc(
349 protocol_management::UPDATE_TSP,
350 serde_json::to_value(&req)?,
351 protocol_management::UPDATE_TSP_RESULT,
352 30,
353 |c, url| c.post(format!("{url}/services/tsp/update")).json(&req),
354 )
355 .await
356 }
357
358 pub async fn disable_tsp(
362 &self,
363 req: services::DisableTspRequest,
364 ) -> Result<services::ServiceMutationResponse, VtaError> {
365 self.rpc(
366 protocol_management::DISABLE_TSP,
367 serde_json::to_value(&req)?,
368 protocol_management::DISABLE_TSP_RESULT,
369 30,
370 |c, url| c.post(format!("{url}/services/tsp/disable")).json(&req),
371 )
372 .await
373 }
374
375 pub async fn rollback_tsp(
378 &self,
379 req: services::RollbackTspRequest,
380 ) -> Result<services::RollbackResponse, VtaError> {
381 self.rpc(
382 protocol_management::ROLLBACK_TSP,
383 serde_json::to_value(&req)?,
384 protocol_management::ROLLBACK_TSP_RESULT,
385 60,
386 |c, url| c.post(format!("{url}/services/tsp/rollback")).json(&req),
387 )
388 .await
389 }
390
391 pub async fn enable_webauthn(
396 &self,
397 req: services::EnableWebauthnRequest,
398 ) -> Result<services::ServiceMutationResponse, VtaError> {
399 self.rpc(
400 protocol_management::ENABLE_WEBAUTHN,
401 serde_json::to_value(&req)?,
402 protocol_management::ENABLE_WEBAUTHN_RESULT,
403 30,
404 |c, url| c.post(format!("{url}/services/webauthn/enable")).json(&req),
405 )
406 .await
407 }
408
409 pub async fn update_webauthn(
411 &self,
412 req: services::UpdateWebauthnRequest,
413 ) -> Result<services::ServiceMutationResponse, VtaError> {
414 self.rpc(
415 protocol_management::UPDATE_WEBAUTHN,
416 serde_json::to_value(&req)?,
417 protocol_management::UPDATE_WEBAUTHN_RESULT,
418 30,
419 |c, url| c.post(format!("{url}/services/webauthn/update")).json(&req),
420 )
421 .await
422 }
423
424 pub async fn disable_webauthn(
429 &self,
430 req: services::DisableWebauthnRequest,
431 ) -> Result<services::ServiceMutationResponse, VtaError> {
432 self.rpc(
436 protocol_management::DISABLE_WEBAUTHN,
437 serde_json::to_value(&req)?,
438 protocol_management::DISABLE_WEBAUTHN_RESULT,
439 300,
440 |c, url| {
441 c.post(format!("{url}/services/webauthn/disable"))
442 .json(&req)
443 },
444 )
445 .await
446 }
447
448 pub async fn rollback_webauthn(
451 &self,
452 req: services::RollbackWebauthnRequest,
453 ) -> Result<services::RollbackResponse, VtaError> {
454 self.rpc(
455 protocol_management::ROLLBACK_WEBAUTHN,
456 serde_json::to_value(&req)?,
457 protocol_management::ROLLBACK_WEBAUTHN_RESULT,
458 300,
459 |c, url| {
460 c.post(format!("{url}/services/webauthn/rollback"))
461 .json(&req)
462 },
463 )
464 .await
465 }
466
467 pub async fn rollback_didcomm(
471 &self,
472 req: services::RollbackDidcommRequest,
473 ) -> Result<services::RollbackResponse, VtaError> {
474 self.rpc(
475 protocol_management::ROLLBACK_DIDCOMM,
476 serde_json::to_value(&req)?,
477 protocol_management::ROLLBACK_DIDCOMM_RESULT,
478 120,
479 |c, url| {
480 c.post(format!("{url}/services/didcomm/rollback"))
481 .json(&req)
482 },
483 )
484 .await
485 }
486
487 pub async fn list_services(&self) -> Result<services::ServicesListResponse, VtaError> {
493 self.rpc(
494 protocol_management::LIST_SERVICES,
495 serde_json::Value::Null,
496 protocol_management::LIST_SERVICES_RESULT,
497 30,
498 |c, url| c.get(format!("{url}/services")),
499 )
500 .await
501 }
502
503 pub async fn list_drain(&self) -> Result<services::DrainListResponse, VtaError> {
505 self.rpc(
506 protocol_management::LIST_DRAIN,
507 serde_json::Value::Null,
508 protocol_management::LIST_DRAIN_RESULT,
509 30,
510 |c, url| c.get(format!("{url}/services/didcomm/drain")),
511 )
512 .await
513 }
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize)]
518#[must_use]
519pub struct UpdateDidcommRequest {
520 pub new_mediator_did: String,
521 pub drain_ttl_secs: u64,
522 #[serde(default)]
523 pub force: bool,
524 #[serde(default, skip_serializing_if = "Option::is_none")]
525 pub handshake_timeout_secs: Option<u64>,
526 #[serde(default)]
528 pub rollback: bool,
529}
530
531impl UpdateDidcommRequest {
532 pub fn new(new_mediator_did: impl Into<String>, drain_ttl_secs: u64) -> Self {
533 Self {
534 new_mediator_did: new_mediator_did.into(),
535 drain_ttl_secs,
536 force: false,
537 handshake_timeout_secs: None,
538 rollback: false,
539 }
540 }
541
542 pub fn force(mut self, force: bool) -> Self {
543 self.force = force;
544 self
545 }
546
547 pub fn rollback(mut self, rollback: bool) -> Self {
548 self.rollback = rollback;
549 self
550 }
551
552 pub fn handshake_timeout_secs(mut self, secs: u64) -> Self {
553 self.handshake_timeout_secs = Some(secs);
554 self
555 }
556}
557
558#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct UpdateDidcommResponse {
560 pub new_version_id: String,
561 pub prior_mediator_did: String,
562 pub active_mediator_did: String,
563 pub active_mediator_endpoint: String,
564 pub drains_until: String,
565 #[serde(default, skip_serializing_if = "String::is_empty")]
567 pub vta_did: String,
568 #[serde(default)]
571 pub serverless: bool,
572}
573
574#[derive(Debug, Clone, Serialize, Deserialize)]
576pub struct DrainCancelRequest {
577 pub mediator_did: String,
578}
579
580#[derive(Debug, Clone, Serialize, Deserialize)]
581pub struct DrainCancelResponse {
582 pub mediator_did: String,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
586pub struct MediatorStats {
587 pub mediator_did: String,
588 pub inbound_count: u64,
589 pub first_seen: String,
590 pub last_seen: String,
591}
592
593#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct SenderLastSeen {
595 pub sender_did: String,
596 pub last_seen_mediator: String,
597 pub last_seen_at: String,
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
601pub struct MediatorReport {
602 #[serde(default)]
603 pub since: Option<String>,
604 pub until: String,
605 pub mediators: Vec<MediatorStats>,
606 pub senders: Vec<SenderLastSeen>,
607}
608
609#[cfg(feature = "client")]
610impl VtaClient {
611 pub async fn drain_cancel(
616 &self,
617 req: DrainCancelRequest,
618 ) -> Result<DrainCancelResponse, VtaError> {
619 self.rpc(
620 protocol_management::DRAIN_CANCEL,
621 serde_json::to_value(&req)?,
622 protocol_management::DRAIN_CANCEL_RESULT,
623 30,
624 |c, url| c.post(format!("{url}/mediators/drain/cancel")).json(&req),
625 )
626 .await
627 }
628
629 pub async fn mediator_report(
635 &self,
636 since: Option<&str>,
637 until: Option<&str>,
638 ) -> Result<MediatorReport, VtaError> {
639 let since_owned = since.map(str::to_string);
640 let until_owned = until.map(str::to_string);
641 let qs = build_report_query(since_owned.as_deref(), until_owned.as_deref());
642 self.rpc(
643 protocol_management::MEDIATOR_REPORT,
644 serde_json::json!({
645 "since": since_owned,
646 "until": until_owned,
647 }),
648 protocol_management::MEDIATOR_REPORT_RESULT,
649 30,
650 move |c, url| {
651 let url = if qs.is_empty() {
652 format!("{url}/mediators/report")
653 } else {
654 format!("{url}/mediators/report?{qs}")
655 };
656 c.get(url)
657 },
658 )
659 .await
660 }
661}
662
663#[cfg(feature = "client")]
664fn build_report_query(since: Option<&str>, until: Option<&str>) -> String {
665 let mut parts: Vec<String> = Vec::new();
666 if let Some(s) = since {
667 parts.push(format!("since={}", url_encode(s)));
668 }
669 if let Some(u) = until {
670 parts.push(format!("until={}", url_encode(u)));
671 }
672 parts.join("&")
673}
674
675#[cfg(feature = "client")]
676fn url_encode(s: &str) -> String {
677 s.chars()
682 .flat_map(|c| match c {
683 ':' => "%3A".chars().collect::<Vec<_>>(),
684 '+' => "%2B".chars().collect::<Vec<_>>(),
685 _ => vec![c],
686 })
687 .collect()
688}