harn_vm/triggers/dispatcher/
uri.rs1use crate::triggers::TriggerHandlerSpec;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub enum DispatchUriError {
5 Empty,
6 MissingTarget { scheme: String },
7 UnknownScheme(String),
8}
9
10impl std::fmt::Display for DispatchUriError {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 match self {
13 Self::Empty => f.write_str("handler URI cannot be empty"),
14 Self::MissingTarget { scheme } => {
15 write!(f, "{scheme} handler URI target cannot be empty")
16 }
17 Self::UnknownScheme(scheme) => write!(f, "unsupported handler URI scheme '{scheme}'"),
18 }
19 }
20}
21
22impl std::error::Error for DispatchUriError {}
23
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum DispatchUri {
26 Local {
27 raw: String,
28 },
29 A2a {
30 target: String,
31 allow_cleartext: bool,
32 },
33 Worker {
34 queue: String,
35 },
36}
37
38impl DispatchUri {
39 pub fn parse(raw: &str) -> Result<Self, DispatchUriError> {
40 let raw = raw.trim();
41 if raw.is_empty() {
42 return Err(DispatchUriError::Empty);
43 }
44 if let Some(target) = raw.strip_prefix("a2a://") {
45 if target.is_empty() {
46 return Err(DispatchUriError::MissingTarget {
47 scheme: "a2a".to_string(),
48 });
49 }
50 return Ok(Self::A2a {
51 target: target.to_string(),
52 allow_cleartext: false,
53 });
54 }
55 if let Some(queue) = raw.strip_prefix("worker://") {
56 if queue.is_empty() {
57 return Err(DispatchUriError::MissingTarget {
58 scheme: "worker".to_string(),
59 });
60 }
61 return Ok(Self::Worker {
62 queue: queue.to_string(),
63 });
64 }
65 if let Some((scheme, _)) = raw.split_once("://") {
66 return Err(DispatchUriError::UnknownScheme(scheme.to_string()));
67 }
68 Ok(Self::Local {
69 raw: raw.to_string(),
70 })
71 }
72
73 pub fn kind(&self) -> &'static str {
74 match self {
75 Self::Local { .. } => "local",
76 Self::A2a { .. } => "a2a",
77 Self::Worker { .. } => "worker",
78 }
79 }
80
81 pub fn target_uri(&self) -> String {
82 match self {
83 Self::Local { raw } => raw.clone(),
84 Self::A2a { target, .. } => format!("a2a://{target}"),
85 Self::Worker { queue } => format!("worker://{queue}"),
86 }
87 }
88}
89
90impl From<&TriggerHandlerSpec> for DispatchUri {
91 fn from(value: &TriggerHandlerSpec) -> Self {
92 match value {
93 TriggerHandlerSpec::Local { raw, .. } => Self::Local { raw: raw.clone() },
94 TriggerHandlerSpec::A2a {
95 target,
96 allow_cleartext,
97 } => Self::A2a {
98 target: target.clone(),
99 allow_cleartext: *allow_cleartext,
100 },
101 TriggerHandlerSpec::Worker { queue } => Self::Worker {
102 queue: queue.clone(),
103 },
104 }
105 }
106}