1use flawless::workflow::WorkflowTypeAlias;
2use reqwest::{
3 multipart::{Form, Part},
4 Client,
5};
6use serde::{Deserialize, Serialize};
7
8use crate::WorkflowRef;
9
10#[derive(Debug, Clone, Deserialize)]
12pub struct Server {
13 pub(crate) url: String,
14 pub(crate) auth_token: Option<String>,
15}
16
17impl Server {
18 pub fn new<A: ToString>(url: A, auth_token: Option<&str>) -> Self {
20 Server { url: url.to_string(), auth_token: auth_token.map(|t| t.to_string()) }
21 }
22
23 pub async fn deploy(&self, module: &'static [u8]) -> Result<DeployedModule, String> {
25 let deploy_url = format!("{}/api/module/deploy", self.url);
26
27 let client = Client::new();
28 let module = Part::stream(module).mime_str("application/wasm").unwrap();
29 let form = Form::new().part("module", module);
30
31 let mut request = client.post(deploy_url).multipart(form);
32
33 if let Some(auth_token) = &self.auth_token {
34 request = request.header("Authorization", &format!("Bearer {}", auth_token));
35 }
36
37 match request.send().await {
38 Ok(response) => {
39 let response = response.text().await.map_err(|_err| "Unable to read response".to_string())?;
40 let response: DeployResponse = serde_json::from_str(&response)
41 .map_err(|err| format!("Failed to parse flawless response as json. {err}"))?;
42 match response {
43 DeployResponse::Ok(mut deployed_module) => {
44 deployed_module.server = Some(self.clone());
45 Ok(deployed_module)
46 }
47 DeployResponse::Error(err) => Err(err),
48 }
49 }
50 Err(err) => Err(format!("Failed to send request to `{}`. {err}", self.url)),
51 }
52 }
53}
54
55#[derive(Debug, Deserialize)]
56pub enum DeployResponse {
57 #[serde(rename = "ok")]
58 Ok(DeployedModule),
59 #[serde(rename = "error")]
60 Error(String),
61}
62
63#[derive(Debug, Deserialize)]
64pub struct DeployedModule {
65 pub(crate) server: Option<Server>,
66 name: String,
67 version: String,
68}
69
70impl DeployedModule {
71 pub async fn start<W>(&self, input: W::InputArg) -> Result<WorkflowRef, String>
82 where
83 W: WorkflowTypeAlias,
84 {
85 self.start_by_name(W::NAME, input).await
86 }
87
88 pub async fn start_by_name<T>(&self, name: &str, input: T) -> Result<WorkflowRef, String>
90 where
91 T: Serialize,
92 {
93 let start_url = format!("{}/api/workflow/start", self.server.as_ref().unwrap().url);
94 let input = serde_json::to_string(&input).map_err(|err| err.to_string())?;
95 let workflow_start = WorkflowStart {
96 module: self.name.to_string(),
97 version: self.version.to_string(),
98 workflow: name.to_string(),
99 input,
100 };
101
102 let client = Client::new();
103 let mut request = client.post(start_url).json(&workflow_start);
104
105 if let Some(auth_token) = &self.server.as_ref().unwrap().auth_token {
106 request = request.header("Authorization", &format!("Bearer {}", auth_token));
107 }
108
109 match request.send().await {
110 Ok(response) => {
111 let response = response.text().await.map_err(|_err| "Unable to read response".to_string())?;
112 let response: WorkflowStartResponse = serde_json::from_str(&response)
113 .map_err(|err| format!("Failed to parse flawless response as json. {err}"))?;
114 match response {
115 WorkflowStartResponse::Ok(mut workflow) => {
116 workflow.server = self.server.clone();
117 Ok(workflow)
118 }
119 WorkflowStartResponse::Error(err) => Err(err),
120 }
121 }
122 Err(err) => {
123 Err(format!("Failed to send request to `{}`. {err}", self.server.as_ref().unwrap().url))
124 }
125 }
126 }
127}
128
129#[derive(Debug, Serialize)]
130struct WorkflowStart<T> {
131 module: String,
132 version: String,
133 workflow: String,
134 input: T,
135}
136
137#[derive(Debug, Deserialize)]
138enum WorkflowStartResponse {
139 #[serde(rename = "ok")]
140 Ok(WorkflowRef),
141 #[serde(rename = "error")]
142 Error(String),
143}