use flawless::workflow::WorkflowTypeAlias;
use reqwest::{
multipart::{Form, Part},
Client,
};
use serde::{Deserialize, Serialize};
use crate::WorkflowRef;
#[derive(Debug, Clone, Deserialize)]
pub struct Server {
pub(crate) url: String,
pub(crate) auth_token: Option<String>,
}
impl Server {
pub fn new<A: ToString>(url: A, auth_token: Option<&str>) -> Self {
Server { url: url.to_string(), auth_token: auth_token.map(|t| t.to_string()) }
}
pub async fn deploy(&self, module: &'static [u8]) -> Result<DeployedModule, String> {
let deploy_url = format!("{}/api/module/deploy", self.url);
let client = Client::new();
let module = Part::stream(module).mime_str("application/wasm").unwrap();
let form = Form::new().part("module", module);
let mut request = client.post(deploy_url).multipart(form);
if let Some(auth_token) = &self.auth_token {
request = request.header("Authorization", &format!("Bearer {}", auth_token));
}
match request.send().await {
Ok(response) => {
let response = response.text().await.map_err(|_err| format!("Unable to read response"))?;
let response: DeployResponse = serde_json::from_str(&response)
.map_err(|err| format!("Failed to parse flawless response as json. {err}"))?;
match response {
DeployResponse::Ok(mut deployed_module) => {
deployed_module.server = Some(self.clone());
Ok(deployed_module)
}
DeployResponse::Error(err) => Err(err),
}
}
Err(err) => Err(format!("Failed to send request to `{}`. {err}", self.url)),
}
}
}
#[derive(Debug, Deserialize)]
pub enum DeployResponse {
#[serde(rename = "ok")]
Ok(DeployedModule),
#[serde(rename = "error")]
Error(String),
}
#[derive(Debug, Deserialize)]
pub struct DeployedModule {
pub(crate) server: Option<Server>,
name: String,
version: String,
}
impl DeployedModule {
pub async fn start<W>(&self, input: W::InputArg) -> Result<WorkflowRef, String>
where
W: WorkflowTypeAlias,
{
self.start_by_name(W::NAME, input).await
}
pub async fn start_by_name<T>(&self, name: &str, input: T) -> Result<WorkflowRef, String>
where
T: Serialize,
{
let start_url = format!("{}/api/workflow/start", self.server.as_ref().unwrap().url);
let input = serde_json::to_string(&input).map_err(|err| err.to_string())?;
let workflow_start = WorkflowStart {
module: self.name.to_string(),
version: self.version.to_string(),
workflow: name.to_string(),
input,
};
let client = Client::new();
let mut request = client.post(start_url).json(&workflow_start);
if let Some(auth_token) = &self.server.as_ref().unwrap().auth_token {
request = request.header("Authorization", &format!("Bearer {}", auth_token));
}
match request.send().await {
Ok(response) => {
let response = response.text().await.map_err(|_err| format!("Unable to read response"))?;
let response: WorkflowStartResponse = serde_json::from_str(&response)
.map_err(|err| format!("Failed to parse flawless response as json. {err}"))?;
match response {
WorkflowStartResponse::Ok(mut workflow) => {
workflow.server = self.server.clone();
Ok(workflow)
}
WorkflowStartResponse::Error(err) => Err(err),
}
}
Err(err) => {
Err(format!("Failed to send request to `{}`. {err}", self.server.as_ref().unwrap().url))
}
}
}
}
#[derive(Debug, Serialize)]
struct WorkflowStart<T> {
module: String,
version: String,
workflow: String,
input: T,
}
#[derive(Debug, Deserialize)]
enum WorkflowStartResponse {
#[serde(rename = "ok")]
Ok(WorkflowRef),
#[serde(rename = "error")]
Error(String),
}