Skip to main content

tapis_workflows/
client.rs

1use crate::apis::{
2    archives_api, cicd_api, configuration, etl_api, general_api, group_secrets_api, groups_api,
3    identities_api, pipeline_archives_api, pipeline_locks_api, pipeline_runs_api, pipelines_api,
4    secrets_api, task_executions_api, tasks_api, users_api, Error,
5};
6use crate::models;
7use http::header::{HeaderMap, HeaderValue};
8use reqwest::{Client, Request, Response};
9use reqwest_middleware::{ClientBuilder, Middleware, Next, Result as MiddlewareResult};
10use std::sync::Arc;
11use tapis_core::TokenProvider;
12
13tokio::task_local! {
14    /// Extra headers to inject into every request within a [`with_headers`] scope.
15    static EXTRA_HEADERS: HeaderMap;
16}
17
18/// Run an async call with additional HTTP headers injected into every request
19/// made within the future `f`. Headers are scoped to this task only, so
20/// concurrent calls with different headers are safe.
21pub async fn with_headers<F, T>(headers: HeaderMap, f: F) -> T
22where
23    F: std::future::Future<Output = T>,
24{
25    EXTRA_HEADERS.scope(headers, f).await
26}
27
28#[derive(Debug)]
29struct LoggingMiddleware;
30
31#[derive(Debug)]
32struct HeaderInjectionMiddleware;
33
34#[async_trait::async_trait]
35impl Middleware for LoggingMiddleware {
36    async fn handle(
37        &self,
38        req: Request,
39        extensions: &mut http::Extensions,
40        next: Next<'_>,
41    ) -> MiddlewareResult<Response> {
42        let method = req.method().clone();
43        let url = req.url().clone();
44        println!("Tapis SDK request: {} {}", method, url);
45        next.run(req, extensions).await
46    }
47}
48
49#[async_trait::async_trait]
50impl Middleware for HeaderInjectionMiddleware {
51    async fn handle(
52        &self,
53        mut req: Request,
54        extensions: &mut http::Extensions,
55        next: Next<'_>,
56    ) -> MiddlewareResult<Response> {
57        let _ = EXTRA_HEADERS.try_with(|headers| {
58            for (k, v) in headers {
59                req.headers_mut().insert(k, v.clone());
60            }
61        });
62        next.run(req, extensions).await
63    }
64}
65
66fn validate_tracking_id(tracking_id: &str) -> Result<(), String> {
67    if !tracking_id.is_ascii() {
68        return Err("X-Tapis-Tracking-ID must be an entirely ASCII string.".to_string());
69    }
70    if tracking_id.len() > 126 {
71        return Err("X-Tapis-Tracking-ID must be less than 126 characters.".to_string());
72    }
73    if tracking_id.matches('.').count() != 1 {
74        return Err("X-Tapis-Tracking-ID must contain exactly one '.' (format: <namespace>.<unique_identifier>).".to_string());
75    }
76    if tracking_id.starts_with('.') || tracking_id.ends_with('.') {
77        return Err("X-Tapis-Tracking-ID cannot start or end with '.'.".to_string());
78    }
79    let (namespace, unique_id) = tracking_id.split_once('.').unwrap();
80    if !namespace.chars().all(|c| c.is_alphanumeric() || c == '_') {
81        return Err("X-Tapis-Tracking-ID namespace must contain only alphanumeric characters and underscores.".to_string());
82    }
83    if !unique_id.chars().all(|c| c.is_alphanumeric() || c == '-') {
84        return Err("X-Tapis-Tracking-ID unique identifier must contain only alphanumeric characters and hyphens.".to_string());
85    }
86    Ok(())
87}
88
89#[derive(Debug)]
90struct TrackingIdMiddleware;
91
92#[async_trait::async_trait]
93impl Middleware for TrackingIdMiddleware {
94    async fn handle(
95        &self,
96        mut req: Request,
97        extensions: &mut http::Extensions,
98        next: Next<'_>,
99    ) -> MiddlewareResult<Response> {
100        let tracking_key = req
101            .headers()
102            .keys()
103            .find(|k| {
104                let s = k.as_str();
105                s.eq_ignore_ascii_case("x-tapis-tracking-id")
106                    || s.eq_ignore_ascii_case("x_tapis_tracking_id")
107            })
108            .cloned();
109        if let Some(key) = tracking_key {
110            let tracking_id = req
111                .headers()
112                .get(&key)
113                .and_then(|v| v.to_str().ok())
114                .map(|s| s.to_owned());
115            if let Some(id) = tracking_id {
116                req.headers_mut().remove(&key);
117                validate_tracking_id(&id)
118                    .map_err(|e| reqwest_middleware::Error::Middleware(anyhow::anyhow!(e)))?;
119                let name = reqwest::header::HeaderName::from_static("x-tapis-tracking-id");
120                let value = reqwest::header::HeaderValue::from_str(&id)
121                    .map_err(|e| reqwest_middleware::Error::Middleware(anyhow::anyhow!(e)))?;
122                req.headers_mut().insert(name, value);
123            }
124        }
125        next.run(req, extensions).await
126    }
127}
128
129/// Decode a base64url-encoded segment (no padding required) into raw bytes.
130fn decode_base64url(s: &str) -> Option<Vec<u8>> {
131    fn val(c: u8) -> Option<u8> {
132        match c {
133            b'A'..=b'Z' => Some(c - b'A'),
134            b'a'..=b'z' => Some(c - b'a' + 26),
135            b'0'..=b'9' => Some(c - b'0' + 52),
136            b'-' | b'+' => Some(62),
137            b'_' | b'/' => Some(63),
138            _ => None,
139        }
140    }
141    let chars: Vec<u8> = s.bytes().filter(|&b| b != b'=').collect();
142    let mut out = Vec::with_capacity(chars.len() * 3 / 4 + 1);
143    let mut i = 0;
144    while i < chars.len() {
145        let a = val(chars[i])?;
146        let b = val(*chars.get(i + 1)?)?;
147        out.push((a << 2) | (b >> 4));
148        if let Some(&c3) = chars.get(i + 2) {
149            let c = val(c3)?;
150            out.push(((b & 0x0f) << 4) | (c >> 2));
151            if let Some(&c4) = chars.get(i + 3) {
152                let d = val(c4)?;
153                out.push(((c & 0x03) << 6) | d);
154            }
155        }
156        i += 4;
157    }
158    Some(out)
159}
160
161/// Extract the `exp` (expiration) claim from a JWT without verifying the signature.
162fn extract_jwt_exp(token: &str) -> Option<i64> {
163    let payload_b64 = token.split('.').nth(1)?;
164    let bytes = decode_base64url(payload_b64)?;
165    let claims: serde_json::Value = serde_json::from_slice(&bytes).ok()?;
166    claims.get("exp")?.as_i64()
167}
168
169struct RefreshMiddleware {
170    token_provider: Arc<dyn TokenProvider>,
171}
172
173#[async_trait::async_trait]
174impl Middleware for RefreshMiddleware {
175    async fn handle(
176        &self,
177        mut req: Request,
178        extensions: &mut http::Extensions,
179        next: Next<'_>,
180    ) -> MiddlewareResult<Response> {
181        let is_token_endpoint = {
182            let url = req.url().as_str();
183            url.contains("/oauth2/tokens") || url.contains("/v3/tokens")
184        };
185        if !is_token_endpoint {
186            let needs_refresh = req
187                .headers()
188                .get("x-tapis-token")
189                .and_then(|v| v.to_str().ok())
190                .and_then(extract_jwt_exp)
191                .map(|exp| {
192                    let now = std::time::SystemTime::now()
193                        .duration_since(std::time::UNIX_EPOCH)
194                        .map(|d| d.as_secs() as i64)
195                        .unwrap_or(0);
196                    exp - now < 5
197                })
198                .unwrap_or(false);
199            if needs_refresh {
200                if let Some(new_token) = self.token_provider.get_token().await {
201                    let value = HeaderValue::from_str(&new_token)
202                        .map_err(|e| reqwest_middleware::Error::Middleware(anyhow::anyhow!(e)))?;
203                    req.headers_mut().insert("x-tapis-token", value);
204                }
205            }
206        }
207        next.run(req, extensions).await
208    }
209}
210
211#[derive(Clone)]
212pub struct TapisWorkflows {
213    config: Arc<configuration::Configuration>,
214    pub archives: ArchivesClient,
215    pub cicd: CicdClient,
216    pub etl: EtlClient,
217    pub general: GeneralClient,
218    pub group_secrets: GroupSecretsClient,
219    pub groups: GroupsClient,
220    pub identities: IdentitiesClient,
221    pub pipeline_archives: PipelineArchivesClient,
222    pub pipeline_locks: PipelineLocksClient,
223    pub pipeline_runs: PipelineRunsClient,
224    pub pipelines: PipelinesClient,
225    pub secrets: SecretsClient,
226    pub task_executions: TaskExecutionsClient,
227    pub tasks: TasksClient,
228    pub users: UsersClient,
229}
230
231impl TapisWorkflows {
232    pub fn new(
233        base_url: &str,
234        jwt_token: Option<&str>,
235    ) -> Result<Self, Box<dyn std::error::Error>> {
236        Self::build(base_url, jwt_token, None)
237    }
238
239    /// Create a client with a [`TokenProvider`] for automatic token refresh.
240    /// `RefreshMiddleware` is added to the middleware chain and will call
241    /// `provider.get_token()` transparently whenever the JWT is about to expire.
242    pub fn with_token_provider(
243        base_url: &str,
244        jwt_token: Option<&str>,
245        provider: Arc<dyn TokenProvider>,
246    ) -> Result<Self, Box<dyn std::error::Error>> {
247        Self::build(base_url, jwt_token, Some(provider))
248    }
249
250    fn build(
251        base_url: &str,
252        jwt_token: Option<&str>,
253        token_provider: Option<Arc<dyn TokenProvider>>,
254    ) -> Result<Self, Box<dyn std::error::Error>> {
255        let mut headers = HeaderMap::new();
256        if let Some(token) = jwt_token {
257            headers.insert("X-Tapis-Token", HeaderValue::from_str(token)?);
258        }
259
260        let reqwest_client = Client::builder().default_headers(headers).build()?;
261
262        let mut builder = ClientBuilder::new(reqwest_client)
263            .with(LoggingMiddleware)
264            .with(HeaderInjectionMiddleware)
265            .with(TrackingIdMiddleware);
266
267        if let Some(provider) = token_provider {
268            builder = builder.with(RefreshMiddleware {
269                token_provider: provider,
270            });
271        }
272
273        let client = builder.build();
274
275        let config = Arc::new(configuration::Configuration {
276            base_path: base_url.to_string(),
277            client,
278            ..Default::default()
279        });
280
281        Ok(Self {
282            config: config.clone(),
283            archives: ArchivesClient {
284                config: config.clone(),
285            },
286            cicd: CicdClient {
287                config: config.clone(),
288            },
289            etl: EtlClient {
290                config: config.clone(),
291            },
292            general: GeneralClient {
293                config: config.clone(),
294            },
295            group_secrets: GroupSecretsClient {
296                config: config.clone(),
297            },
298            groups: GroupsClient {
299                config: config.clone(),
300            },
301            identities: IdentitiesClient {
302                config: config.clone(),
303            },
304            pipeline_archives: PipelineArchivesClient {
305                config: config.clone(),
306            },
307            pipeline_locks: PipelineLocksClient {
308                config: config.clone(),
309            },
310            pipeline_runs: PipelineRunsClient {
311                config: config.clone(),
312            },
313            pipelines: PipelinesClient {
314                config: config.clone(),
315            },
316            secrets: SecretsClient {
317                config: config.clone(),
318            },
319            task_executions: TaskExecutionsClient {
320                config: config.clone(),
321            },
322            tasks: TasksClient {
323                config: config.clone(),
324            },
325            users: UsersClient {
326                config: config.clone(),
327            },
328        })
329    }
330
331    pub fn config(&self) -> &configuration::Configuration {
332        &self.config
333    }
334}
335
336#[derive(Clone)]
337pub struct ArchivesClient {
338    config: Arc<configuration::Configuration>,
339}
340
341impl ArchivesClient {
342    pub async fn create_archive(
343        &self,
344        group_id: &str,
345        req_archive: models::ReqArchive,
346    ) -> Result<models::RespResourceUrl, Error<archives_api::CreateArchiveError>> {
347        archives_api::create_archive(&self.config, group_id, req_archive).await
348    }
349
350    pub async fn get_archive(
351        &self,
352        group_id: &str,
353        archive_id: &str,
354    ) -> Result<models::RespArchive, Error<archives_api::GetArchiveError>> {
355        archives_api::get_archive(&self.config, group_id, archive_id).await
356    }
357
358    pub async fn list_archives(
359        &self,
360        group_id: &str,
361    ) -> Result<models::RespArchiveList, Error<archives_api::ListArchivesError>> {
362        archives_api::list_archives(&self.config, group_id).await
363    }
364}
365
366#[derive(Clone)]
367pub struct CicdClient {
368    config: Arc<configuration::Configuration>,
369}
370
371impl CicdClient {
372    pub async fn create_ci_pipeline(
373        &self,
374        group_id: &str,
375        req_ci_pipeline: models::ReqCiPipeline,
376    ) -> Result<models::RespResourceUrl, Error<cicd_api::CreateCiPipelineError>> {
377        cicd_api::create_ci_pipeline(&self.config, group_id, req_ci_pipeline).await
378    }
379}
380
381#[derive(Clone)]
382pub struct EtlClient {
383    config: Arc<configuration::Configuration>,
384}
385
386impl EtlClient {
387    pub async fn create_etl_pipeline(
388        &self,
389        group_id: &str,
390        req_create_etl_pipeline: models::ReqCreateEtlPipeline,
391    ) -> Result<models::RespResourceUrl, Error<etl_api::CreateEtlPipelineError>> {
392        etl_api::create_etl_pipeline(&self.config, group_id, req_create_etl_pipeline).await
393    }
394}
395
396#[derive(Clone)]
397pub struct GeneralClient {
398    config: Arc<configuration::Configuration>,
399}
400
401impl GeneralClient {
402    pub async fn health_check(
403        &self,
404    ) -> Result<models::RespBase, Error<general_api::HealthCheckError>> {
405        general_api::health_check(&self.config).await
406    }
407}
408
409#[derive(Clone)]
410pub struct GroupSecretsClient {
411    config: Arc<configuration::Configuration>,
412}
413
414impl GroupSecretsClient {
415    pub async fn add_group_secret(
416        &self,
417        group_id: &str,
418        req_group_secret: models::ReqGroupSecret,
419    ) -> Result<models::RespGroupSecret, Error<group_secrets_api::AddGroupSecretError>> {
420        group_secrets_api::add_group_secret(&self.config, group_id, req_group_secret).await
421    }
422
423    pub async fn get_group_secret(
424        &self,
425        group_id: &str,
426        group_secret_id: &str,
427    ) -> Result<models::RespGroupSecret, Error<group_secrets_api::GetGroupSecretError>> {
428        group_secrets_api::get_group_secret(&self.config, group_id, group_secret_id).await
429    }
430
431    pub async fn list_group_secrets(
432        &self,
433        group_id: &str,
434    ) -> Result<models::RespGroupSecretList, Error<group_secrets_api::ListGroupSecretsError>> {
435        group_secrets_api::list_group_secrets(&self.config, group_id).await
436    }
437
438    pub async fn remove_group_secret(
439        &self,
440        group_id: &str,
441        group_secret_id: &str,
442    ) -> Result<models::RespBase, Error<group_secrets_api::RemoveGroupSecretError>> {
443        group_secrets_api::remove_group_secret(&self.config, group_id, group_secret_id).await
444    }
445}
446
447#[derive(Clone)]
448pub struct GroupsClient {
449    config: Arc<configuration::Configuration>,
450}
451
452impl GroupsClient {
453    pub async fn create_group(
454        &self,
455        req_group: models::ReqGroup,
456    ) -> Result<models::RespResourceUrl, Error<groups_api::CreateGroupError>> {
457        groups_api::create_group(&self.config, req_group).await
458    }
459
460    pub async fn delete_group(
461        &self,
462        group_id: &str,
463    ) -> Result<models::RespString, Error<groups_api::DeleteGroupError>> {
464        groups_api::delete_group(&self.config, group_id).await
465    }
466
467    pub async fn get_group(
468        &self,
469        group_id: &str,
470    ) -> Result<models::RespGroupDetail, Error<groups_api::GetGroupError>> {
471        groups_api::get_group(&self.config, group_id).await
472    }
473
474    pub async fn list_groups(
475        &self,
476    ) -> Result<models::RespGroupList, Error<groups_api::ListGroupsError>> {
477        groups_api::list_groups(&self.config).await
478    }
479}
480
481#[derive(Clone)]
482pub struct IdentitiesClient {
483    config: Arc<configuration::Configuration>,
484}
485
486impl IdentitiesClient {
487    pub async fn create_identity(
488        &self,
489        req_identity: models::ReqIdentity,
490    ) -> Result<models::RespResourceUrl, Error<identities_api::CreateIdentityError>> {
491        identities_api::create_identity(&self.config, req_identity).await
492    }
493
494    pub async fn delete_identity(
495        &self,
496        identity_uuid: &str,
497    ) -> Result<models::RespString, Error<identities_api::DeleteIdentityError>> {
498        identities_api::delete_identity(&self.config, identity_uuid).await
499    }
500
501    pub async fn get_identity(
502        &self,
503        identity_uuid: &str,
504    ) -> Result<models::RespIdentity, Error<identities_api::GetIdentityError>> {
505        identities_api::get_identity(&self.config, identity_uuid).await
506    }
507
508    pub async fn list_identities(
509        &self,
510    ) -> Result<models::RespIdentityList, Error<identities_api::ListIdentitiesError>> {
511        identities_api::list_identities(&self.config).await
512    }
513}
514
515#[derive(Clone)]
516pub struct PipelineArchivesClient {
517    config: Arc<configuration::Configuration>,
518}
519
520impl PipelineArchivesClient {
521    pub async fn list_pipeline_archives(
522        &self,
523        group_id: &str,
524        pipeline_id: &str,
525    ) -> Result<models::RespArchiveList, Error<pipeline_archives_api::ListPipelineArchivesError>>
526    {
527        pipeline_archives_api::list_pipeline_archives(&self.config, group_id, pipeline_id).await
528    }
529}
530
531#[derive(Clone)]
532pub struct PipelineLocksClient {
533    config: Arc<configuration::Configuration>,
534}
535
536impl PipelineLocksClient {
537    pub async fn get_pipeline_lock(
538        &self,
539        group_id: &str,
540        pipeline_id: &str,
541        pipeline_lock_uuid: &str,
542    ) -> Result<models::RespPipelineLock, Error<pipeline_locks_api::GetPipelineLockError>> {
543        pipeline_locks_api::get_pipeline_lock(
544            &self.config,
545            group_id,
546            pipeline_id,
547            pipeline_lock_uuid,
548        )
549        .await
550    }
551
552    pub async fn list_pipeline_locks(
553        &self,
554        group_id: &str,
555        pipeline_id: &str,
556    ) -> Result<models::RespPipelineLockList, Error<pipeline_locks_api::ListPipelineLocksError>>
557    {
558        pipeline_locks_api::list_pipeline_locks(&self.config, group_id, pipeline_id).await
559    }
560
561    pub async fn release_pipeline_lock(
562        &self,
563        group_id: &str,
564        pipeline_id: &str,
565        pipeline_run_uuid: &str,
566    ) -> Result<(), Error<pipeline_locks_api::ReleasePipelineLockError>> {
567        pipeline_locks_api::release_pipeline_lock(
568            &self.config,
569            group_id,
570            pipeline_id,
571            pipeline_run_uuid,
572        )
573        .await
574    }
575}
576
577#[derive(Clone)]
578pub struct PipelineRunsClient {
579    config: Arc<configuration::Configuration>,
580}
581
582impl PipelineRunsClient {
583    pub async fn acquire_pipeline_lock(
584        &self,
585        group_id: &str,
586        pipeline_id: &str,
587        pipeline_run_uuid: &str,
588        req_pipeline_lock: models::ReqPipelineLock,
589    ) -> Result<
590        models::RespPipelineLockAcquisition,
591        Error<pipeline_runs_api::AcquirePipelineLockError>,
592    > {
593        pipeline_runs_api::acquire_pipeline_lock(
594            &self.config,
595            group_id,
596            pipeline_id,
597            pipeline_run_uuid,
598            req_pipeline_lock,
599        )
600        .await
601    }
602
603    pub async fn get_pipeline_run(
604        &self,
605        group_id: &str,
606        pipeline_id: &str,
607        pipeline_run_uuid: &str,
608    ) -> Result<models::RespPipelineRun, Error<pipeline_runs_api::GetPipelineRunError>> {
609        pipeline_runs_api::get_pipeline_run(&self.config, group_id, pipeline_id, pipeline_run_uuid)
610            .await
611    }
612
613    pub async fn list_pipeline_runs(
614        &self,
615        group_id: &str,
616        pipeline_id: &str,
617    ) -> Result<models::RespPipelineRunList, Error<pipeline_runs_api::ListPipelineRunsError>> {
618        pipeline_runs_api::list_pipeline_runs(&self.config, group_id, pipeline_id).await
619    }
620
621    pub async fn terminate_pipeline(
622        &self,
623        group_id: &str,
624        pipeline_id: &str,
625        pipeline_run_uuid: &str,
626    ) -> Result<models::RespPipelineRun, Error<pipeline_runs_api::TerminatePipelineError>> {
627        pipeline_runs_api::terminate_pipeline(
628            &self.config,
629            group_id,
630            pipeline_id,
631            pipeline_run_uuid,
632        )
633        .await
634    }
635
636    pub async fn update_pipeline_run_status(
637        &self,
638        x_workflow_executor_token: &str,
639        pipeline_run_uuid: &str,
640        status: models::EnumRunStatus,
641        req_patch_pipeline_run: Option<models::ReqPatchPipelineRun>,
642    ) -> Result<models::RespString, Error<pipeline_runs_api::UpdatePipelineRunStatusError>> {
643        pipeline_runs_api::update_pipeline_run_status(
644            &self.config,
645            x_workflow_executor_token,
646            pipeline_run_uuid,
647            status,
648            req_patch_pipeline_run,
649        )
650        .await
651    }
652}
653
654#[derive(Clone)]
655pub struct PipelinesClient {
656    config: Arc<configuration::Configuration>,
657}
658
659impl PipelinesClient {
660    pub async fn add_pipeline_archive(
661        &self,
662        group_id: &str,
663        pipeline_id: &str,
664    ) -> Result<models::RespBase, Error<pipelines_api::AddPipelineArchiveError>> {
665        pipelines_api::add_pipeline_archive(&self.config, group_id, pipeline_id).await
666    }
667
668    pub async fn change_pipeline_owner(
669        &self,
670        group_id: &str,
671        pipeline_id: &str,
672        username: &str,
673    ) -> Result<models::RespBase, Error<pipelines_api::ChangePipelineOwnerError>> {
674        pipelines_api::change_pipeline_owner(&self.config, group_id, pipeline_id, username).await
675    }
676
677    pub async fn create_pipeline(
678        &self,
679        group_id: &str,
680        req_pipeline: models::ReqPipeline,
681    ) -> Result<models::RespResourceUrl, Error<pipelines_api::CreatePipelineError>> {
682        pipelines_api::create_pipeline(&self.config, group_id, req_pipeline).await
683    }
684
685    pub async fn delete_pipeline(
686        &self,
687        group_id: &str,
688        pipeline_id: &str,
689    ) -> Result<models::RespString, Error<pipelines_api::DeletePipelineError>> {
690        pipelines_api::delete_pipeline(&self.config, group_id, pipeline_id).await
691    }
692
693    pub async fn get_pipeline(
694        &self,
695        group_id: &str,
696        pipeline_id: &str,
697    ) -> Result<models::RespPipeline, Error<pipelines_api::GetPipelineError>> {
698        pipelines_api::get_pipeline(&self.config, group_id, pipeline_id).await
699    }
700
701    pub async fn list_pipelines(
702        &self,
703        group_id: &str,
704    ) -> Result<models::RespPipelineList, Error<pipelines_api::ListPipelinesError>> {
705        pipelines_api::list_pipelines(&self.config, group_id).await
706    }
707
708    pub async fn remove_pipeline_archive(
709        &self,
710        group_id: &str,
711        pipeline_id: &str,
712    ) -> Result<models::RespBase, Error<pipelines_api::RemovePipelineArchiveError>> {
713        pipelines_api::remove_pipeline_archive(&self.config, group_id, pipeline_id).await
714    }
715
716    pub async fn run_pipeline(
717        &self,
718        group_id: &str,
719        pipeline_id: &str,
720        req_run_pipeline: models::ReqRunPipeline,
721    ) -> Result<models::RespPipelineRun, Error<pipelines_api::RunPipelineError>> {
722        pipelines_api::run_pipeline(&self.config, group_id, pipeline_id, req_run_pipeline).await
723    }
724}
725
726#[derive(Clone)]
727pub struct SecretsClient {
728    config: Arc<configuration::Configuration>,
729}
730
731impl SecretsClient {
732    pub async fn create_secret(
733        &self,
734        req_create_secret: models::ReqCreateSecret,
735    ) -> Result<models::RespSecret, Error<secrets_api::CreateSecretError>> {
736        secrets_api::create_secret(&self.config, req_create_secret).await
737    }
738
739    pub async fn delete_secret(
740        &self,
741        secret_id: &str,
742    ) -> Result<models::RespString, Error<secrets_api::DeleteSecretError>> {
743        secrets_api::delete_secret(&self.config, secret_id).await
744    }
745
746    pub async fn get_secret(
747        &self,
748        secret_id: &str,
749    ) -> Result<models::RespSecret, Error<secrets_api::GetSecretError>> {
750        secrets_api::get_secret(&self.config, secret_id).await
751    }
752
753    pub async fn list_secrets(
754        &self,
755    ) -> Result<models::RespSecretList, Error<secrets_api::ListSecretsError>> {
756        secrets_api::list_secrets(&self.config).await
757    }
758}
759
760#[derive(Clone)]
761pub struct TaskExecutionsClient {
762    config: Arc<configuration::Configuration>,
763}
764
765impl TaskExecutionsClient {
766    pub async fn create_task_execution(
767        &self,
768        x_workflow_executor_token: &str,
769        pipeline_run_uuid: &str,
770        req_create_task_execution: models::ReqCreateTaskExecution,
771    ) -> Result<models::RespResourceUrl, Error<task_executions_api::CreateTaskExecutionError>> {
772        task_executions_api::create_task_execution(
773            &self.config,
774            x_workflow_executor_token,
775            pipeline_run_uuid,
776            req_create_task_execution,
777        )
778        .await
779    }
780
781    pub async fn get_task_execution(
782        &self,
783        group_id: &str,
784        pipeline_id: &str,
785        pipeline_run_uuid: &str,
786        task_execution_uuid: &str,
787    ) -> Result<models::RespTaskExecution, Error<task_executions_api::GetTaskExecutionError>> {
788        task_executions_api::get_task_execution(
789            &self.config,
790            group_id,
791            pipeline_id,
792            pipeline_run_uuid,
793            task_execution_uuid,
794        )
795        .await
796    }
797
798    pub async fn list_task_executions(
799        &self,
800        group_id: &str,
801        pipeline_id: &str,
802        pipeline_run_uuid: &str,
803    ) -> Result<models::RespTaskExecutionList, Error<task_executions_api::ListTaskExecutionsError>>
804    {
805        task_executions_api::list_task_executions(
806            &self.config,
807            group_id,
808            pipeline_id,
809            pipeline_run_uuid,
810        )
811        .await
812    }
813
814    pub async fn update_task_execution_status(
815        &self,
816        x_workflow_executor_token: &str,
817        task_execution_uuid: &str,
818        status: models::EnumRunStatus,
819        req_patch_task_execution: Option<models::ReqPatchTaskExecution>,
820    ) -> Result<models::RespString, Error<task_executions_api::UpdateTaskExecutionStatusError>>
821    {
822        task_executions_api::update_task_execution_status(
823            &self.config,
824            x_workflow_executor_token,
825            task_execution_uuid,
826            status,
827            req_patch_task_execution,
828        )
829        .await
830    }
831}
832
833#[derive(Clone)]
834pub struct TasksClient {
835    config: Arc<configuration::Configuration>,
836}
837
838impl TasksClient {
839    pub async fn create_task(
840        &self,
841        group_id: &str,
842        pipeline_id: &str,
843        req_task: models::ReqTask,
844    ) -> Result<models::RespResourceUrl, Error<tasks_api::CreateTaskError>> {
845        tasks_api::create_task(&self.config, group_id, pipeline_id, req_task).await
846    }
847
848    pub async fn delete_task(
849        &self,
850        group_id: &str,
851        pipeline_id: &str,
852        task_id: &str,
853    ) -> Result<models::RespString, Error<tasks_api::DeleteTaskError>> {
854        tasks_api::delete_task(&self.config, group_id, pipeline_id, task_id).await
855    }
856
857    pub async fn get_task(
858        &self,
859        group_id: &str,
860        pipeline_id: &str,
861        task_id: &str,
862    ) -> Result<models::RespTask, Error<tasks_api::GetTaskError>> {
863        tasks_api::get_task(&self.config, group_id, pipeline_id, task_id).await
864    }
865
866    pub async fn list_tasks(
867        &self,
868        group_id: &str,
869        pipeline_id: &str,
870    ) -> Result<models::RespTaskList, Error<tasks_api::ListTasksError>> {
871        tasks_api::list_tasks(&self.config, group_id, pipeline_id).await
872    }
873
874    pub async fn patch_task(
875        &self,
876        group_id: &str,
877        pipeline_id: &str,
878        task_id: &str,
879        task: models::Task,
880    ) -> Result<models::RespTask, Error<tasks_api::PatchTaskError>> {
881        tasks_api::patch_task(&self.config, group_id, pipeline_id, task_id, task).await
882    }
883}
884
885#[derive(Clone)]
886pub struct UsersClient {
887    config: Arc<configuration::Configuration>,
888}
889
890impl UsersClient {
891    pub async fn add_group_user(
892        &self,
893        group_id: &str,
894        req_group_user: models::ReqGroupUser,
895    ) -> Result<models::RespResourceUrl, Error<users_api::AddGroupUserError>> {
896        users_api::add_group_user(&self.config, group_id, req_group_user).await
897    }
898
899    pub async fn get_group_user(
900        &self,
901        group_id: &str,
902        username: &str,
903    ) -> Result<models::RespGroupUser, Error<users_api::GetGroupUserError>> {
904        users_api::get_group_user(&self.config, group_id, username).await
905    }
906
907    pub async fn list_group_users(
908        &self,
909        group_id: &str,
910    ) -> Result<models::RespGroupUserList, Error<users_api::ListGroupUsersError>> {
911        users_api::list_group_users(&self.config, group_id).await
912    }
913
914    pub async fn remove_group_user(
915        &self,
916        group_id: &str,
917        username: &str,
918    ) -> Result<models::RespGroupUser, Error<users_api::RemoveGroupUserError>> {
919        users_api::remove_group_user(&self.config, group_id, username).await
920    }
921
922    pub async fn update_group_user(
923        &self,
924        group_id: &str,
925        username: &str,
926        req_update_group_user: models::ReqUpdateGroupUser,
927    ) -> Result<models::RespGroupUser, Error<users_api::UpdateGroupUserError>> {
928        users_api::update_group_user(&self.config, group_id, username, req_update_group_user).await
929    }
930}