use anyhow::Result; mod progenitor_support { use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; #[allow(dead_code)] const PATH_SET: &AsciiSet = &CONTROLS .add(b' ') .add(b'"') .add(b'#') .add(b'<') .add(b'>') .add(b'?') .add(b'`') .add(b'{') .add(b'}'); #[allow(dead_code)] pub(crate) fn encode_path(pc: &str) -> String { utf8_percent_encode(pc, PATH_SET).to_string() } } pub mod types { use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Task { pub id: String, pub name: String, pub output_rules: Vec, pub script: String, pub state: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct TaskEvent { pub payload: String, pub seq: u32, pub stream: String, pub time: chrono::DateTime, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct TaskOutput { pub id: String, pub path: String, pub size: u64, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct TaskSubmit { pub name: String, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub output_rules: Vec, pub script: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct TaskSubmitResult { pub id: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UploadedChunk { pub id: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UserCreate { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UserCreateResult { pub id: String, pub name: String, pub token: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WhoamiResult { pub id: String, pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Worker { pub deleted: bool, pub id: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub instance_id: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub lastping: Option>, pub recycle: bool, pub tasks: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerAddOutput { pub chunks: Vec, pub path: String, pub size: i64, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerAppendTask { pub payload: String, pub stream: String, pub time: chrono::DateTime, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerBootstrap { pub bootstrap: String, pub token: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerBootstrapResult { pub id: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerCompleteTask { pub failed: bool, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerPingResult { pub poweroff: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub task: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerPingTask { pub id: String, pub output_rules: Vec, pub script: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkerTask { pub id: String, pub name: String, pub owner: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct WorkersResult { pub workers: Vec, } } #[derive(Clone)] pub struct Client { baseurl: String, client: reqwest::Client, } impl Client { pub fn new(baseurl: &str) -> Self { let dur = std::time::Duration::from_secs(15); let client = reqwest::ClientBuilder::new() .connect_timeout(dur) .timeout(dur) .build() .unwrap(); Self::new_with_client(baseurl, client) } pub fn new_with_client(baseurl: &str, client: reqwest::Client) -> Self { Self { baseurl: baseurl.to_string(), client, } } pub fn baseurl(&self) -> &String { &self.baseurl } pub fn client(&self) -> &reqwest::Client { &self.client } #[doc = "control_hold: POST /v1/control/hold"] pub async fn control_hold(&self) -> Result<()> { let url = format!("{}/v1/control/hold", self.baseurl,); let request = self.client.post(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "control_resume: POST /v1/control/resume"] pub async fn control_resume(&self) -> Result<()> { let url = format!("{}/v1/control/resume", self.baseurl,); let request = self.client.post(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(()) } #[doc = "task_get: GET /v1/task/{task}"] pub async fn task_get(&self, task: &str) -> Result { let url = format!( "{}/v1/task/{}", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "tasks_get: GET /v1/tasks"] pub async fn tasks_get(&self) -> Result> { let url = format!("{}/v1/tasks", self.baseurl,); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "task_submit: POST /v1/tasks"] pub async fn task_submit(&self, body: &types::TaskSubmit) -> Result { let url = format!("{}/v1/tasks", self.baseurl,); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "task_events_get: GET /v1/tasks/{task}/events"] pub async fn task_events_get( &self, task: &str, minseq: Option, ) -> Result> { let url = format!( "{}/v1/tasks/{}/events", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let mut query = Vec::new(); if let Some(v) = &minseq { query.push(("minseq", v.to_string())); } let request = self.client.get(url).query(&query).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "task_outputs_get: GET /v1/tasks/{task}/outputs"] pub async fn task_outputs_get(&self, task: &str) -> Result> { let url = format!( "{}/v1/tasks/{}/outputs", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "task_output_download: GET /v1/tasks/{task}/outputs/{output}"] pub async fn task_output_download( &self, task: &str, output: &str, ) -> Result { let url = format!( "{}/v1/tasks/{}/outputs/{}", self.baseurl, progenitor_support::encode_path(&task.to_string()), progenitor_support::encode_path(&output.to_string()), ); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res) } #[doc = "user_create: POST /v1/users"] pub async fn user_create(&self, body: &types::UserCreate) -> Result { let url = format!("{}/v1/users", self.baseurl,); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "whoami: GET /v1/whoami"] pub async fn whoami(&self) -> Result { let url = format!("{}/v1/whoami", self.baseurl,); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "worker_bootstrap: POST /v1/worker/bootstrap"] pub async fn worker_bootstrap( &self, body: &types::WorkerBootstrap, ) -> Result { let url = format!("{}/v1/worker/bootstrap", self.baseurl,); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "worker_ping: GET /v1/worker/ping"] pub async fn worker_ping(&self) -> Result { let url = format!("{}/v1/worker/ping", self.baseurl,); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "worker_task_append: POST /v1/worker/task/{task}/append"] pub async fn worker_task_append( &self, task: &str, body: &types::WorkerAppendTask, ) -> Result<()> { let url = format!( "{}/v1/worker/task/{}/append", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(()) } #[doc = "worker_task_upload_chunk: POST /v1/worker/task/{task}/chunk"] pub async fn worker_task_upload_chunk>( &self, task: &str, body: B, ) -> Result { let url = format!( "{}/v1/worker/task/{}/chunk", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.post(url).body(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "worker_task_complete: POST /v1/worker/task/{task}/complete"] pub async fn worker_task_complete( &self, task: &str, body: &types::WorkerCompleteTask, ) -> Result<()> { let url = format!( "{}/v1/worker/task/{}/complete", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(()) } #[doc = "worker_task_add_output: POST /v1/worker/task/{task}/output"] pub async fn worker_task_add_output( &self, task: &str, body: &types::WorkerAddOutput, ) -> Result<()> { let url = format!( "{}/v1/worker/task/{}/output", self.baseurl, progenitor_support::encode_path(&task.to_string()), ); let request = self.client.post(url).json(body).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(()) } #[doc = "workers_list: GET /v1/workers"] pub async fn workers_list(&self) -> Result { let url = format!("{}/v1/workers", self.baseurl,); let request = self.client.get(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(res.json().await?) } #[doc = "workers_recycle: POST /v1/workers/recycle"] pub async fn workers_recycle(&self) -> Result<()> { let url = format!("{}/v1/workers/recycle", self.baseurl,); let request = self.client.post(url).build()?; let result = self.client.execute(request).await; let res = result?.error_for_status()?; Ok(()) } }