azure_functions_durable/
endpoint.rs1use std::fmt::Write;
2use url::Url;
3
4#[derive(Debug, Clone)]
6pub struct Endpoint {
7 base_uri: Url,
8 task_hub: String,
9 connection: String,
10 code: String,
11}
12
13impl Endpoint {
14 pub fn new(status_query_url: Url) -> Self {
16 let mut task_hub = None;
17 let mut connection = None;
18 let mut code = None;
19
20 for (k, v) in status_query_url.query_pairs() {
21 match k.to_ascii_lowercase().as_ref() {
22 "taskhub" => task_hub = Some(v.into_owned()),
23 "connection" => connection = Some(v.into_owned()),
24 "code" => code = Some(v.into_owned()),
25 _ => {}
26 };
27 }
28
29 Self {
30 base_uri: status_query_url,
31 task_hub: task_hub.expect("expected a taskhub parameter"),
32 connection: connection.expect("expected a connection parameter"),
33 code: code.expect("expected a code parameter"),
34 }
35 }
36
37 pub fn task_hub(&self) -> &str {
39 &self.task_hub
40 }
41
42 pub fn create_new_instance_url(&self, function_name: &str, instance_id: Option<&str>) -> Url {
44 let mut url = self.base_uri.clone();
45
46 let path = match instance_id {
47 Some(id) => format!(
48 "/runtime/webhooks/durabletask/orchestrators/{}/{}",
49 function_name, id
50 ),
51 None => format!(
52 "/runtime/webhooks/durabletask/orchestrators/{}",
53 function_name
54 ),
55 };
56
57 url.set_path(&path);
58
59 url.query_pairs_mut()
60 .clear()
61 .append_pair("code", &self.code);
62
63 url
64 }
65
66 pub fn status_query_url(&self, instance_id: Option<&str>) -> Url {
68 self.build_query_url(instance_id, None)
69 }
70
71 pub fn purge_history_url(&self, instance_id: Option<&str>) -> Url {
73 self.build_query_url(instance_id, None)
74 }
75
76 pub fn rewind_url(&self, instance_id: &str, reason: &str) -> Url {
78 let mut url = self.build_query_url(Some(instance_id), Some("rewind"));
79 url.query_pairs_mut().append_pair("reason", reason);
80 url
81 }
82
83 pub fn raise_event_url(&self, instance_id: &str, event_name: &str) -> Url {
85 self.build_query_url(
86 Some(instance_id),
87 Some(&format!("raiseEvent/{}", event_name)),
88 )
89 }
90
91 pub fn terminate_url(&self, instance_id: &str, reason: &str) -> Url {
93 let mut url = self.build_query_url(Some(instance_id), Some("terminate"));
94 url.query_pairs_mut().append_pair("reason", reason);
95 url
96 }
97
98 fn build_query_url(&self, instance_id: Option<&str>, action: Option<&str>) -> Url {
99 let mut url = self.base_uri.clone();
100 let mut path = "/runtime/webhooks/durabletask/instances".to_string();
101
102 if let Some(id) = instance_id {
103 write!(&mut path, "/{}", id).unwrap();
104 }
105
106 if let Some(action) = action {
107 write!(&mut path, "/{}", action).unwrap();
108 }
109
110 url.set_path(&path);
111
112 url.query_pairs_mut()
113 .clear()
114 .append_pair("taskHub", &self.task_hub)
115 .append_pair("connection", &self.connection)
116 .append_pair("code", &self.code);
117
118 url
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_endpoint_parsing() {
128 let endpoint = Endpoint::new(Url::parse("http://localhost:7071/runtime/webhooks/durabletask/instances/INSTANCEID?taskHub=myHub&connection=Storage&code=myCode").unwrap());
129 assert_eq!(endpoint.code, "myCode");
130
131 let rewind_result = "http://localhost:7071/runtime/webhooks/durabletask/instances/1234/rewind?taskHub=myHub&connection=Storage&code=myCode&reason=myReason";
132 let rewind_url = endpoint.rewind_url("1234", "myReason");
133 assert_eq!(rewind_url.to_string(), rewind_result);
134 }
135
136 #[test]
137 #[should_panic]
138 fn test_bad_endpoint() {
139 Endpoint::new(
140 Url::parse("http://localhost:7071/runtime/webhooks/durabletask/instances/INSTANC")
141 .unwrap(),
142 );
143 }
144}