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 Persona {
37 name: String,
38 },
39}
40
41impl DispatchUri {
42 pub fn parse(raw: &str) -> Result<Self, DispatchUriError> {
43 let raw = raw.trim();
44 if raw.is_empty() {
45 return Err(DispatchUriError::Empty);
46 }
47 if let Some(target) = raw.strip_prefix("a2a://") {
48 if target.is_empty() {
49 return Err(DispatchUriError::MissingTarget {
50 scheme: "a2a".to_string(),
51 });
52 }
53 return Ok(Self::A2a {
54 target: target.to_string(),
55 allow_cleartext: false,
56 });
57 }
58 if let Some(queue) = raw.strip_prefix("worker://") {
59 if queue.is_empty() {
60 return Err(DispatchUriError::MissingTarget {
61 scheme: "worker".to_string(),
62 });
63 }
64 return Ok(Self::Worker {
65 queue: queue.to_string(),
66 });
67 }
68 if let Some(name) = raw.strip_prefix("persona://") {
69 if name.is_empty() {
70 return Err(DispatchUriError::MissingTarget {
71 scheme: "persona".to_string(),
72 });
73 }
74 return Ok(Self::Persona {
75 name: name.to_string(),
76 });
77 }
78 if let Some((scheme, _)) = raw.split_once("://") {
79 return Err(DispatchUriError::UnknownScheme(scheme.to_string()));
80 }
81 Ok(Self::Local {
82 raw: raw.to_string(),
83 })
84 }
85
86 pub fn kind(&self) -> &'static str {
87 match self {
88 Self::Local { .. } => "local",
89 Self::A2a { .. } => "a2a",
90 Self::Worker { .. } => "worker",
91 Self::Persona { .. } => "persona",
92 }
93 }
94
95 pub fn target_uri(&self) -> String {
96 match self {
97 Self::Local { raw } => raw.clone(),
98 Self::A2a { target, .. } => format!("a2a://{target}"),
99 Self::Worker { queue } => format!("worker://{queue}"),
100 Self::Persona { name } => format!("persona://{name}"),
101 }
102 }
103}
104
105impl From<&TriggerHandlerSpec> for DispatchUri {
106 fn from(value: &TriggerHandlerSpec) -> Self {
107 match value {
108 TriggerHandlerSpec::Local { raw, .. } => Self::Local { raw: raw.clone() },
109 TriggerHandlerSpec::A2a {
110 target,
111 allow_cleartext,
112 } => Self::A2a {
113 target: target.clone(),
114 allow_cleartext: *allow_cleartext,
115 },
116 TriggerHandlerSpec::Worker { queue } => Self::Worker {
117 queue: queue.clone(),
118 },
119 TriggerHandlerSpec::Persona { binding } => Self::Persona {
120 name: binding.name.clone(),
121 },
122 }
123 }
124}