diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml new file mode 100644 index 0000000..2b58092 --- /dev/null +++ b/.github/workflows/pipeline.yml @@ -0,0 +1,70 @@ +name: CI/CD + +on: + push: + branches: + - main # Trigger on pushes to the main branch + pull_request: + branches: + - main # Trigger on pull requests targeting the main branch + workflow_dispatch: # Allow manual triggers + +jobs: + build-and-test: + name: Build and Test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable # Use the stable toolchain + profile: minimal # Install only essential components + override: true + + - name: Cache Cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Cache Cargo build + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-build- + + - name: Build the project + run: cargo build --workspace --all-targets + + - name: Run tests + run: cargo test --workspace --all-targets + + release: + name: Publish to crates.io + needs: build-and-test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' # Only run on the main branch + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Publish to crates.io + run: cargo publish --workspace --allow-dirty + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d3d2bda --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/target/debug/${workspaceRootFolderName}.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "preLaunchTask": "cargo build" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c57f378..a223826 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,16 +60,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "sdk-rust" -version = "0.1.0" -dependencies = [ - "serde", - "serde_derive", - "serde_json", - "serde_yaml", -] - [[package]] name = "serde" version = "1.0.217" @@ -115,6 +105,25 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "serverless-workflow-builders" +version = "1.0.0-alpha6" +dependencies = [ + "serde_json", + "serde_yaml", + "serverless_workflow_core", +] + +[[package]] +name = "serverless_workflow_core" +version = "1.0.0-alpha6" +dependencies = [ + "serde", + "serde_derive", + "serde_json", + "serde_yaml", +] + [[package]] name = "syn" version = "2.0.96" diff --git a/Cargo.toml b/Cargo.toml index bc7fbfe..0242af9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] members = [ - "core" + "core", + "builders" ] \ No newline at end of file diff --git a/builders/Cargo.toml b/builders/Cargo.toml new file mode 100644 index 0000000..700085f --- /dev/null +++ b/builders/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "serverless-workflow-builders" +version = "1.0.0-alpha6" +edition = "2021" +authors = ["The Serverless Workflow Authors "] +description = "Contains services used to build ServerlessWorkflow workflow definitions programatically" +homepage = "https://serverlessworkflow.io" +repository = "https://github.com/serverlessworkflow/sdk-rust" +documentation = "https://github.com/serverlessworkflow/sdk-rust" +license = "Apache-2.0" +keywords = ["serverless-workflow", "serverless", "workflow", "dsl", "sdk", "builders", "services"] +categories = ["dsl", "sdk", "builders", "services"] + +[dependencies] +serverless_workflow_core = { path = "../core" } +serde_json = "1.0" +serde_yaml = "0.9" \ No newline at end of file diff --git a/builders/src/lib.rs b/builders/src/lib.rs new file mode 100644 index 0000000..f955bfd --- /dev/null +++ b/builders/src/lib.rs @@ -0,0 +1,495 @@ +pub mod services; + +#[cfg(test)] +mod unit_tests { + + use serverless_workflow_core::models::any::*; + use serverless_workflow_core::models::duration::*; + use serverless_workflow_core::models::error::OneOfErrorDefinitionOrReference; + use crate::services::workflow::WorkflowBuilder; + use serverless_workflow_core::models::task::*; + use serverless_workflow_core::models::timeout::*; + use std::collections::HashMap; + use serde_json::json; + + #[test] + fn build_workflow_should_work() { + //arrange + let dsl_version = "1.0.0"; + let namespace = "namespace"; + let name = "fake-name"; + let version = "1.0.0"; + let title = "fake-title"; + let summary = "fake-summary"; + let tags: HashMap = vec![ + ("key1".to_string(), "value1".to_string()), + ("key2".to_string(), "value2".to_string())] + .into_iter() + .collect(); + let mut timeout_duration = Duration::default(); + timeout_duration.minutes = Some(69); + let basic_name = "fake-basic"; + let username = "fake-username"; + let password = "fake-password"; + let call_task_name = "call-task"; + let call_function_name = "fake-function"; + let call_task_with: HashMap = vec![ + ("key1".to_string(), AnyValue::String("value1".to_string())), + ("key2".to_string(), AnyValue::String("value2".to_string()))] + .into_iter() + .collect(); + let do_task_name = "do-task"; + let emit_task_name = "emit-task"; + let emit_event_attributes: HashMap = vec![ + ("key1".to_string(), AnyValue::String("value1".to_string())), + ("key2".to_string(), AnyValue::String("value2".to_string()))] + .into_iter() + .collect(); + let for_task_name = "for-task"; + let for_each = "item"; + let for_each_in = "items"; + let for_each_at = "index"; + let fork_task_name = "fork-task"; + let listen_task_name = "listen-task"; + let raise_task_name = "raise-task-name"; + let raise_error_type = "error-type"; + let raise_error_status = AnyValue::Int16(400); + let raise_error_title = "error-title"; + let raise_error_detail = "error-detail"; + let raise_error_instance = "error-instance"; + let run_container_task_name = "run-container-task-name"; + let container_image = "container-image-name"; + let container_command = "container-command"; + let container_ports: HashMap = vec![ + (8080, 8081), + (8082, 8083)] + .into_iter() + .collect(); + let container_volumes: HashMap = vec![ + ("volume-1".to_string(), "/some/fake/path".to_string())] + .into_iter() + .collect(); + let container_environment: HashMap = vec![ + ("env1-name".to_string(), "env1-value".to_string()), + ("env2-name".to_string(), "env2-value".to_string())] + .into_iter() + .collect(); + let run_script_task_name = "run-script-task-name"; + let script_code = "script-code"; + let run_shell_task_name = "run-shell-task-name"; + let shell_command_name = "run-shell-command"; + let run_workflow_task_name = "run-workflow-task-name"; + let workflow_namespace = "workflow-namespace"; + let workflow_name = "workflow-name"; + let workflow_version = "workflow-version"; + let workflow_input = AnyValue::Json(json!({"hello": "world"})); + let set_task_name = "set-task-name"; + let set_task_variables : HashMap = vec![ + ("var1-name".to_string(), AnyValue::String("var1-value".to_string())), + ("var2-name".to_string(), AnyValue::UInt64(69))] + .into_iter() + .collect(); + let switch_task_name = "switch-task-name"; + let switch_case_name = "switch-case-name"; + let switch_case_when = "true"; + let switch_case_then = "continue"; + let try_task_name = "try-task-name"; + let catch_when = "catch-when"; + let catch_errors_attributes: HashMap = vec![ + ("var1-name".to_string(), AnyValue::String("var1-value".to_string())), + ("var2-name".to_string(), AnyValue::UInt64(69))] + .into_iter() + .collect(); + let retry_except_when = "retry-except-when"; + let wait_task_name = "wait-task"; + let wait_duration = OneOfDurationOrIso8601Expression::Duration(Duration::from_days(3)); + + //act + let workflow = WorkflowBuilder::new() + .use_dsl(dsl_version) + .with_namespace(namespace) + .with_name(name) + .with_version(version) + .with_title(title) + .with_summary(summary) + .with_tags(tags.clone()) + .with_timeout(|t| { t.after(timeout_duration.clone()); }) + .use_authentication(basic_name, |a| { + a.basic() + .with_username(username) + .with_password(password);}) + .do_(call_task_name, |task| { + task.call(call_function_name) + .with_arguments(call_task_with.clone()); + }) + .do_(do_task_name, |task| { + task.do_() + .do_("fake-wait-task", |st| { + st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25))); + }); + }) + .do_(emit_task_name, |task| { + task.emit(|e|{ + e.with_attributes(emit_event_attributes.clone()); + }); + }) + .do_(for_task_name, |task| { + task.for_() + .each(for_each) + .in_(for_each_in) + .at(for_each_at) + .do_("fake-wait-task", |st| { + st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25))); + }); + }) + .do_(fork_task_name, |task| { + task.fork() + .branch(|b| { + b.do_("fake-wait-task", |st| { + st.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(25))); + }); + }); + }) + .do_(listen_task_name, |task| { + task.listen() + .to(|e|{ + e.one() + .with("key", AnyValue::String("value".to_string())); + }); + }) + .do_(raise_task_name, |task| { + task.raise() + .error() + .with_type(raise_error_type) + .with_status(raise_error_status) + .with_title(raise_error_title) + .with_detail(raise_error_detail) + .with_instance(raise_error_instance); + }) + .do_(run_container_task_name, |task|{ + task.run() + .container() + .with_image(container_image) + .with_command(container_command) + .with_ports(container_ports.clone()) + .with_volumes(container_volumes.clone()) + .with_environment_variables(container_environment.clone()); + }) + .do_(run_script_task_name, |task|{ + task.run() + .script() + .with_code(script_code); + }) + .do_(run_shell_task_name, |task|{ + task.run() + .shell() + .with_command(shell_command_name); + }) + .do_(run_workflow_task_name, |task|{ + task.run() + .workflow() + .with_namespace(workflow_namespace) + .with_name(workflow_name) + .with_version(workflow_version) + .with_input(workflow_input.clone()); + }) + .do_(set_task_name, |task|{ + task.set() + .variables(set_task_variables.clone()); + }) + .do_(switch_task_name, |task|{ + task.switch() + .case(switch_case_name, |case|{ + case.when(switch_case_when) + .then(switch_case_then); + }); + + }) + .do_(try_task_name, |task|{ + task.try_() + .do_(|tasks|{ + tasks + .do_("fake-wait-task", |subtask|{ + subtask.wait(OneOfDurationOrIso8601Expression::Duration(Duration::from_seconds(5))); + }); + }) + .catch(|catch| { + catch + .errors(|errors|{ + errors + .with_attributes(catch_errors_attributes.clone()); + }) + .when(catch_when) + .retry(|retry|{ + retry + .except_when(retry_except_when) + .delay(Duration::from_seconds(1)) + .backoff(|backoff|{ + backoff + .linear() + .with_increment(Duration::from_milliseconds(500)); + }) + .jitter(|jitter|{ + jitter + .from(Duration::from_seconds(1)) + .to(Duration::from_seconds(3)); + }); + }); + }); + }) + .do_(wait_task_name, |task| { + task.wait(wait_duration.clone()); + }) + .build(); + + //assert + assert_eq!(workflow.document.dsl, dsl_version); + assert_eq!(workflow.document.namespace, namespace); + assert_eq!(workflow.document.name, name); + assert_eq!(workflow.document.version, version); + assert_eq!(workflow.document.title, Some(title.to_string())); + assert_eq!(workflow.document.summary, Some(summary.to_string())); + assert_eq!(workflow.document.tags, Some(tags)); + assert_eq!(workflow.timeout + .as_ref() + .and_then(|t| match t { + OneOfTimeoutDefinitionOrReference::Timeout(definition) => match &definition.after { + OneOfDurationOrIso8601Expression::Duration(duration) => Some(duration), + OneOfDurationOrIso8601Expression::Iso8601Expression(_) => None, + }, + OneOfTimeoutDefinitionOrReference::Reference(_) => None}), + Some(&timeout_duration)); + assert!( + workflow.use_.as_ref() + .and_then(|component_collection| component_collection.authentications.as_ref()) + .and_then(|authentications| authentications.get(basic_name)) + .map(|auth_policy| auth_policy.basic.is_some()) + .unwrap_or(false), + "Expected authentications to contain an entry with the name '{}' and a non-null `basic` property.", + basic_name); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&call_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Call(call_task) = task { + call_task.call == call_function_name && call_task.with == Some(call_task_with.clone()) + } else { + false + } + })), + "Expected a task with key '{}' and a CallTaskDefinition with 'call'={} and 'with'={:?}", + call_task_name, + call_function_name, + call_task_with); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&do_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Do(_do_task) = task { + true + } else { + false + } + })), + "Expected a do task with key '{}'", + do_task_name); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&emit_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Emit(emit_task) = task { + emit_task.emit.event.with == emit_event_attributes.clone() + } else { + false + } + })), + "Expected a task with key '{}' and a EmitTaskDefinition with 'emit.event.with' matching supplied attributes", + emit_task_name); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&for_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::For(for_task) = task { + for_task.for_.each == for_each && for_task.for_.in_ == for_each_in && for_task.for_.at == Some(for_each_at.to_string()) + } else { + false + } + })), + "Expected a task with key '{}' and a ForTaskDefinition with 'for.each'={}, 'for.in'={}' and 'for.at'={}'", + for_task_name, + for_each, + for_each_in, + for_each_at); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&fork_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Fork(_fork_task) = task { + true + } else { + false + } + })), + "Expected a fork task with key '{}'", + fork_task_name,); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&listen_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Listen(_listen_task) = task { + true + } else { + false + } + })), + "Expected a listen task with key '{}'", + listen_task_name); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&raise_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Raise(raise_task) = task { + if let OneOfErrorDefinitionOrReference::Error(error) = &raise_task.raise.error { + error.type_ == raise_error_type + && error.title == raise_error_title + && error.detail == Some(raise_error_detail.to_string()) + && error.instance == Some(raise_error_instance.to_string()) + } else { + false + } + } else { + false + } + })), + "Expected a task with key '{}' and a RaiseTaskDefinition with 'raise.error.type'={}, 'raise.error.title'={}, 'raise.error.detail'={} and 'raise.error.instance'={}", + raise_task_name, + raise_error_type, + raise_error_title, + raise_error_detail, + raise_error_instance); + assert!( + workflow + .do_ + .entries + .iter() + .any(|entry| entry.get(&run_container_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Run(run_task) = task { + if let Some(container) = &run_task.run.container { + container.image == container_image + && container.command == Some(container_command.to_string()) + && container.ports == Some(container_ports.clone()) + && container.volumes == Some(container_volumes.clone()) + && container.environment == Some(container_environment.clone()) + } else { + false + } + } else { + false + } + })), + "Expected a task with key '{}' and a RunTaskDefinition with 'container.image'={}, 'container.command'={}, 'container.ports'={:?}, 'container.volumes'={:?}, and 'container.environment'={:?}", + run_container_task_name, + container_image, + container_command, + container_ports, + container_volumes, + container_environment); + assert!( + workflow + .do_ + .entries + .iter() + .any(|entry| entry.get(&run_workflow_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Run(run_task) = task { + if let Some(subflow) = &run_task.run.workflow{ + subflow.namespace == workflow_namespace.to_string() + && subflow.name == workflow_name.to_string() + && subflow.version == workflow_version.to_string() + && subflow.input == Some(workflow_input.clone()) + } + else{ + false + } + } else { + false + } + })), + "Expected a task with key '{}' and a RunTaskDefinition with 'workflow.namespace'={}, 'workflow.name'={}, 'workflow.version'={}, and 'workflow.input'={:?}", + run_container_task_name, + workflow_namespace, + workflow_name, + workflow_version, + workflow_input); + assert!( + workflow + .do_ + .entries + .iter() + .any(|entry| entry.get(&set_task_name.to_string()).map_or(false, |task|{ + if let TaskDefinition::Set(set_task) = task { + set_task.set == set_task_variables.clone() + } + else{ + false + } + })), + "Expected a task with key '{}' and a SetTaskDefinition with specified variables", + set_task_name); + assert!( + workflow + .do_ + .entries + .iter() + .any(|entry| entry.get(&switch_task_name.to_string()).map_or(false, |task|{ + if let TaskDefinition::Switch(switch_task) = task{ + switch_task + .switch + .entries + .iter() + .any(|case| case.contains_key(switch_case_name)) + } + else{ + false + } + })), + "Expected a task with key '{}' and a SwitchTaskDefinition with a case named '{}'", + set_task_name, + switch_case_name); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&try_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Try(try_task) = task { + try_task.catch.when == Some(catch_when.to_string()) + } else { + false + } + })), + "Expected a task with key '{}' and a TryTaskDefinition with 'catch.when'={}", + try_task_name, + catch_when); + assert!( + workflow.do_ + .entries + .iter() + .any(|entry| entry.get(&wait_task_name.to_string()).map_or(false, |task| { + if let TaskDefinition::Wait(wait_task) = task { + wait_task.duration == wait_duration + } else { + false + } + })), + "Expected a task with key '{}' and a WaitTaskDefinition with 'duration'={}", + wait_task_name, + wait_duration); + } + +} \ No newline at end of file diff --git a/builders/src/services/authentication.rs b/builders/src/services/authentication.rs new file mode 100644 index 0000000..e018050 --- /dev/null +++ b/builders/src/services/authentication.rs @@ -0,0 +1,529 @@ +use serverless_workflow_core::models::authentication::*; + +/// Represents a service used to build AuthenticationPolicyDefinitions +pub struct AuthenticationPolicyDefinitionBuilder{ + reference: Option, + builder: Option +} +impl AuthenticationPolicyDefinitionBuilder { + + /// Initializes a new AuthenticationPolicyDefinition + pub fn new() -> Self{ + Self { + reference: None, + builder: None + } + } + + /// Sets the name of the top-level authentication policy to use + pub fn use_(mut self, reference: &str){ + self.reference = Some(reference.to_string()); + } + + /// Configures the policy to use 'Basic' authentication + pub fn basic(&mut self) -> &mut BasicAuthenticationSchemeDefinitionBuilder{ + let builder = BasicAuthenticationSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::Basic(builder)); + if let Some(AuthenticationSchemeBuilder::Basic(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Basic"); + } + } + + /// Configures the policy to use 'Bearer' authentication + pub fn bearer(&mut self) -> &mut BearerAuthenticationSchemeDefinitionBuilder{ + let builder = BearerAuthenticationSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::Bearer(builder)); + if let Some(AuthenticationSchemeBuilder::Bearer(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Bearer"); + } + } + + /// Configures the policy to use 'Certificate' authentication + pub fn certificate(&mut self) -> &mut CertificateAuthenticationSchemeDefinitionBuilder{ + let builder = CertificateAuthenticationSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::Certificate(builder)); + if let Some(AuthenticationSchemeBuilder::Certificate(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Certificate"); + } + } + + /// Configures the policy to use 'Digest' authentication + pub fn digest(&mut self) -> &mut DigestAuthenticationSchemeDefinitionBuilder{ + let builder = DigestAuthenticationSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::Digest(builder)); + if let Some(AuthenticationSchemeBuilder::Digest(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Digest"); + } + } + + /// Configures the policy to use 'OAUTH2' authentication + pub fn oauth2(&mut self) -> &mut OAuth2AuthenticationSchemeDefinitionBuilder{ + let builder = OAuth2AuthenticationSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::OAUTH2(builder)); + if let Some(AuthenticationSchemeBuilder::OAUTH2(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to OAUTH2"); + } + } + + /// Configures the policy to use 'OpenIdConnect' authentication + pub fn oidc(&mut self) -> &mut OpenIDConnectSchemeDefinitionBuilder{ + let builder = OpenIDConnectSchemeDefinitionBuilder::new(); + self.builder = Some(AuthenticationSchemeBuilder::OIDC(builder)); + if let Some(AuthenticationSchemeBuilder::OIDC(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to OpenIdConnect"); + } + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + if self.reference.is_some(){ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.use_ = self.reference; + authentication + } + else{ + if let Some(builder) = self.builder { + match builder { + AuthenticationSchemeBuilder::Basic(builder) => builder.build(), + AuthenticationSchemeBuilder::Bearer(builder) => builder.build(), + AuthenticationSchemeBuilder::Certificate(builder) => builder.build(), + AuthenticationSchemeBuilder::Digest(builder) => builder.build(), + AuthenticationSchemeBuilder::OAUTH2(builder) => builder.build(), + AuthenticationSchemeBuilder::OIDC(builder) => builder.build() + } + } + else { + panic!("The authentication policy must be configured"); + } + } + } + +} + +/// Enumerates all supported authentication scheme builders +pub enum AuthenticationSchemeBuilder{ + Basic(BasicAuthenticationSchemeDefinitionBuilder), + Bearer(BearerAuthenticationSchemeDefinitionBuilder), + Certificate(CertificateAuthenticationSchemeDefinitionBuilder), + Digest(DigestAuthenticationSchemeDefinitionBuilder), + OAUTH2(OAuth2AuthenticationSchemeDefinitionBuilder), + OIDC(OpenIDConnectSchemeDefinitionBuilder) +} + +/// Represents the service used to build BasicAuthenticationSchemeDefinitions +pub struct BasicAuthenticationSchemeDefinitionBuilder{ + scheme: BasicAuthenticationSchemeDefinition +} +impl BasicAuthenticationSchemeDefinitionBuilder{ + + /// Initializes a new BasicAuthenticationSchemeDefinitionBuilder + pub fn new() -> Self{ + Self { scheme: BasicAuthenticationSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Sets the username to use + pub fn with_username(&mut self, username: &str) -> &mut Self{ + self.scheme.username = Some(username.to_string()); + self + } + + /// Sets the password to use + pub fn with_password(&mut self, password: &str) -> &mut Self{ + self.scheme.password = Some(password.to_string()); + self + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.basic = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build BearerAuthenticationSchemeDefinitions +pub struct BearerAuthenticationSchemeDefinitionBuilder{ + scheme: BearerAuthenticationSchemeDefinition +} +impl BearerAuthenticationSchemeDefinitionBuilder{ + + /// Initializes a new BearerAuthenticationSchemeDefinitionBuilder + pub fn new() -> Self{ + Self { scheme: BearerAuthenticationSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(&mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Sets the bearer token to use + pub fn with_token(&mut self, token: &str) -> &mut Self{ + self.scheme.token = Some(token.to_string()); + self + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.bearer = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build CertificateAuthenticationSchemeDefinitions +pub struct CertificateAuthenticationSchemeDefinitionBuilder{ + scheme: CertificateAuthenticationSchemeDefinition +} +impl CertificateAuthenticationSchemeDefinitionBuilder{ + + /// Initializes a new CertificateAuthenticationSchemeDefinitionBuilder + pub fn new() -> Self{ + Self { scheme: CertificateAuthenticationSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.certificate = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build DigestAuthenticationSchemeDefinitions +pub struct DigestAuthenticationSchemeDefinitionBuilder{ + scheme: DigestAuthenticationSchemeDefinition +} +impl DigestAuthenticationSchemeDefinitionBuilder{ + + /// Initializes a new DigestAuthenticationSchemeDefinitionBuilder + pub fn new() -> Self{ + Self { scheme: DigestAuthenticationSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Sets the username to use + pub fn with_username(&mut self, username: &str) -> &mut Self{ + self.scheme.username = Some(username.to_string()); + self + } + + /// Sets the password to use + pub fn with_password(&mut self, password: &str) -> &mut Self{ + self.scheme.password = Some(password.to_string()); + self + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.digest = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build OAuth2AuthenticationSchemeDefinitions +pub struct OAuth2AuthenticationSchemeDefinitionBuilder{ + scheme: OAuth2AuthenticationSchemeDefinition +} +impl OAuth2AuthenticationSchemeDefinitionBuilder{ + + /// Initializes a new OAuth2AuthenticationSchemeDefinitions + pub fn new() -> Self{ + Self { scheme: OAuth2AuthenticationSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Sets the OAUTH2 endpoints to use + pub fn with_endpoints(&mut self, endpoints: OAuth2AuthenticationEndpointsDefinition) -> &mut Self{ + self.scheme.endpoints = Some(endpoints); + self + } + + /// Sets the uri of the OAUTH2 authority to use + pub fn with_authority(&mut self, uri: &str) -> &mut Self{ + self.scheme.authority = Some(uri.to_string()); + self + } + + /// Sets the grant type to use + pub fn with_grant_type(&mut self, grant: &str) -> &mut Self{ + self.scheme.grant = Some(grant.to_string()); + self + } + + /// Sets the definition of the client to use + pub fn with_client(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut OAuth2AuthenticationClientDefinitionBuilder) { + let mut builder = OAuth2AuthenticationClientDefinitionBuilder::new(); + setup(&mut builder); + let client = builder.build(); + self.scheme.client = Some(client); + self + } + + /// Sets the configuration of the request to use + pub fn with_request(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut OAuth2AuthenticationRequestDefinitionBuilder) { + let mut builder = OAuth2AuthenticationRequestDefinitionBuilder::new(); + setup(&mut builder); + let request = builder.build(); + self.scheme.request = Some(request); + self + } + + /// Sets supported issuers for issued tokens + pub fn with_issuers(&mut self, issuers: Vec) -> &mut Self{ + self.scheme.issuers = Some(issuers); + self + } + + /// Sets the scopes to request the token for + pub fn with_scopes(&mut self, scopes: Vec) -> &mut Self{ + self.scheme.scopes = Some(scopes); + self + } + + /// Sets the audiences to request the token for + pub fn with_audiences(&mut self, audiences: Vec) -> &mut Self{ + self.scheme.audiences = Some(audiences); + self + } + + /// Sets the username to use + pub fn with_username(&mut self, username: &str) -> &mut Self{ + self.scheme.username = Some(username.to_string()); + self + } + + /// Sets the password to use + pub fn with_password(&mut self, password: &str) -> &mut Self{ + self.scheme.password = Some(password.to_string()); + self + } + + /// Sets the security token that represents the identity of the party on behalf of whom the request is being made. Used only if grant + pub fn with_subject(&mut self, subject: OAuth2TokenDefinition) -> &mut Self{ + self.scheme.subject = Some(subject); + self + } + + /// Sets the security token that represents the identity of the acting party. Typically, this will be the party that is authorized to use the requested security token and act on behalf of the subject + pub fn with_actor(&mut self, actor: OAuth2TokenDefinition) -> &mut Self{ + self.scheme.actor = Some(actor); + self + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.oauth2 = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build OpenIDConnectSchemeDefinition +pub struct OpenIDConnectSchemeDefinitionBuilder{ + scheme: OpenIDConnectSchemeDefinition +} +impl OpenIDConnectSchemeDefinitionBuilder{ + + /// Initializes a new OpenIDConnectSchemeDefinitionBuilder + pub fn new() -> Self{ + Self { scheme: OpenIDConnectSchemeDefinition::default() } + } + + /// Configures the authentication scheme to load from the specified secret + pub fn use_secret(mut self, secret: &str){ + self.scheme.use_ = Some(secret.to_string()); + } + + /// Sets the uri of the OAUTH2 authority to use + pub fn with_authority(&mut self, uri: &str) -> &mut Self{ + self.scheme.authority = Some(uri.to_string()); + self + } + + /// Sets the grant type to use + pub fn with_grant_type(&mut self, grant: &str) -> &mut Self{ + self.scheme.grant = Some(grant.to_string()); + self + } + + /// Sets the definition of the client to use + pub fn with_client(mut self, setup: F) -> Self + where F: FnOnce(&mut OAuth2AuthenticationClientDefinitionBuilder) { + let mut builder = OAuth2AuthenticationClientDefinitionBuilder::new(); + setup(&mut builder); + let client = builder.build(); + self.scheme.client = Some(client); + self + } + + /// Sets the configuration of the request to use + pub fn with_request(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut OAuth2AuthenticationRequestDefinitionBuilder) { + let mut builder = OAuth2AuthenticationRequestDefinitionBuilder::new(); + setup(&mut builder); + let request = builder.build(); + self.scheme.request = Some(request); + self + } + + /// Sets supported issuers for issued tokens + pub fn with_issuers(&mut self, issuers: Vec) -> &mut Self{ + self.scheme.issuers = Some(issuers); + self + } + + /// Sets the scopes to request the token for + pub fn with_scopes(&mut self, scopes: Vec) -> &mut Self{ + self.scheme.scopes = Some(scopes); + self + } + + /// Sets the audiences to request the token for + pub fn with_audiences(&mut self, audiences: Vec) -> &mut Self{ + self.scheme.audiences = Some(audiences); + self + } + + /// Sets the username to use + pub fn with_username(&mut self, username: &str) -> &mut Self{ + self.scheme.username = Some(username.to_string()); + self + } + + /// Sets the password to use + pub fn with_password(&mut self, password: &str) -> &mut Self{ + self.scheme.password = Some(password.to_string()); + self + } + + /// Sets the security token that represents the identity of the party on behalf of whom the request is being made. Used only if grant + pub fn with_subject(&mut self, subject: OAuth2TokenDefinition) -> &mut Self{ + self.scheme.subject = Some(subject); + self + } + + /// Sets the security token that represents the identity of the acting party. Typically, this will be the party that is authorized to use the requested security token and act on behalf of the subject + pub fn with_actor(&mut self, actor: OAuth2TokenDefinition) -> &mut Self{ + self.scheme.actor = Some(actor); + self + } + + /// Builds the configured AuthenticationPolicyDefinition + pub fn build(self) -> AuthenticationPolicyDefinition{ + let mut authentication = AuthenticationPolicyDefinition::default(); + authentication.oidc = Some(self.scheme); + authentication + } + +} + +/// Represents the service used to build OAuth2AuthenticationClientDefinitions +pub struct OAuth2AuthenticationClientDefinitionBuilder{ + client: OAuth2AuthenticationClientDefinition +} +impl OAuth2AuthenticationClientDefinitionBuilder { + + /// Initializes a new OAuth2AuthenticationClientDefinitionBuilder + pub fn new() -> Self{ + Self { client: OAuth2AuthenticationClientDefinition::default() } + } + + /// Sets the OAUTH2 client's id + pub fn with_id(&mut self, id: &str) -> &mut Self{ + self.client.id = Some(id.to_string()); + self + } + + /// Sets the OAUTH2 client's secret + pub fn with_secret(&mut self, secret: &str) -> &mut Self{ + self.client.secret = Some(secret.to_string()); + self + } + + /// Sets the OAUTH2 client's assertion + pub fn with_assertion(&mut self, assertion: &str) -> &mut Self{ + self.client.assertion = Some(assertion.to_string()); + self + } + + /// Sets the OAUTH2 client's authentication method + pub fn with_authentication_method(&mut self, method: &str) -> &mut Self{ + self.client.authentication = Some(method.to_string()); + self + } + + /// Builds the configured OAuth2AuthenticationClientDefinition + pub fn build(self) -> OAuth2AuthenticationClientDefinition{ + self.client + } + +} + +/// Represents the service used to build OAuth2AuthenticationRequestDefinitions +pub struct OAuth2AuthenticationRequestDefinitionBuilder{ + request : OAuth2AuthenticationRequestDefinition +} +impl OAuth2AuthenticationRequestDefinitionBuilder { + + /// Initializes a new OAuth2AuthenticationRequestDefinitionBuilder + pub fn new() -> Self{ + Self { request: OAuth2AuthenticationRequestDefinition::default() } + } + + /// Configures the OAuth2AuthenticationRequestDefinition to build to use the specified encoding + pub fn with_encoding(&mut self, encoding: &str) -> &mut Self{ + self.request.encoding = encoding.to_string(); + self + } + + /// Builds the configured OAuth2AuthenticationRequestDefinition + pub fn build(self) -> OAuth2AuthenticationRequestDefinition{ + self.request + } + +} \ No newline at end of file diff --git a/builders/src/services/mod.rs b/builders/src/services/mod.rs new file mode 100644 index 0000000..f36e3bd --- /dev/null +++ b/builders/src/services/mod.rs @@ -0,0 +1,4 @@ +pub mod authentication; +pub mod task; +pub mod timeout; +pub mod workflow; \ No newline at end of file diff --git a/builders/src/services/task.rs b/builders/src/services/task.rs new file mode 100644 index 0000000..24f6003 --- /dev/null +++ b/builders/src/services/task.rs @@ -0,0 +1,1661 @@ +use crate::services::authentication::*; +use serverless_workflow_core::models::any::*; +use serverless_workflow_core::models::duration::*; +use serverless_workflow_core::models::error::*; +use serverless_workflow_core::models::event::*; +use serverless_workflow_core::models::map::*; +use serverless_workflow_core::models::resource::*; +use serverless_workflow_core::models::retry::*; +use serverless_workflow_core::models::task::*; +use std::collections::HashMap; + +/// Represents the service used to build TaskDefinitions +pub struct GenericTaskDefinitionBuilder{ + builder: Option +} +impl GenericTaskDefinitionBuilder{ + + /// Initializes a new GenericTaskDefinitionBuilder + pub fn new() -> Self{ + Self{ + builder: None + } + } + + /// Configures the task to call the specified function + pub fn call(&mut self, function: &str) -> &mut CalltaskDefinitionBuilder{ + let builder = CalltaskDefinitionBuilder::new(function); + self.builder = Some(TaskDefinitionBuilder::Call(builder)); + if let Some(TaskDefinitionBuilder::Call(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Call"); + } + } + + /// Configures the task to perform subtasks sequentially + pub fn do_(&mut self) -> &mut DoTaskDefinitionBuilder{ + let builder = DoTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Do(builder)); + if let Some(TaskDefinitionBuilder::Do(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Do"); + } + } + + /// Configures the task to perform subtasks sequentially + pub fn emit(&mut self, setup: F) -> &mut EmitTaskDefinitionBuilder + where F: FnOnce(&mut EventDefinitionBuilder){ + let mut event_builder: EventDefinitionBuilder = EventDefinitionBuilder::new(); + setup(&mut event_builder); + let event = event_builder.build(); + let builder = EmitTaskDefinitionBuilder::new(event); + self.builder = Some(TaskDefinitionBuilder::Emit(builder)); + if let Some(TaskDefinitionBuilder::Emit(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Emit"); + } + } + + /// Configures the task to iterate over a collection and perform a task for each of the items it contains + pub fn for_(&mut self) -> &mut ForTaskDefinitionBuilder{ + let builder = ForTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::For(builder)); + if let Some(TaskDefinitionBuilder::For(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to For"); + } + } + + /// Configures the task to execute branches concurrently + pub fn fork(&mut self) -> &mut ForkTaskDefinitionBuilder{ + let builder = ForkTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Fork(builder)); + if let Some(TaskDefinitionBuilder::Fork(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Fork"); + } + } + + /// Configures the task to listen for events + pub fn listen(&mut self) -> &mut ListenTaskDefinitionBuilder{ + let builder = ListenTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Listen(builder)); + if let Some(TaskDefinitionBuilder::Listen(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Listen"); + } + } + + /// Configures the task to raise the specified error + pub fn raise(&mut self) -> &mut RaiseTaskDefinitionBuilder{ + let builder = RaiseTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Raise(builder)); + if let Some(TaskDefinitionBuilder::Raise(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Raise"); + } + } + + /// Configures the task to run a process + pub fn run(&mut self) -> &mut RunTaskDefinitionBuilder{ + let builder = RunTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Run(builder)); + if let Some(TaskDefinitionBuilder::Run(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Run"); + } + } + + /// Configures the task to set variables + pub fn set(&mut self) -> &mut SetTaskDefinitionBuilder{ + let builder = SetTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Set(builder)); + if let Some(TaskDefinitionBuilder::Set(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Set"); + } + } + + /// Configures the task to branch the flow based on defined conditions + pub fn switch(&mut self) -> &mut SwitchTaskDefinitionBuilder{ + let builder = SwitchTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Switch(builder)); + if let Some(TaskDefinitionBuilder::Switch(ref mut builder)) = self.builder{ + builder + } + else{ + unreachable!("Builder should always be set to Switch"); + } + } + + /// Configures the task to try executing a specific task, and handle potential errors + pub fn try_(&mut self) -> &mut TryTaskDefinitionBuilder{ + let builder = TryTaskDefinitionBuilder::new(); + self.builder = Some(TaskDefinitionBuilder::Try(builder)); + if let Some(TaskDefinitionBuilder::Try(ref mut builder)) = self.builder{ + builder + } + else{ + unreachable!("Builder should always be set to Try"); + } + } + + /// Configures the task to wait a defined amount of time + pub fn wait(&mut self, duration: OneOfDurationOrIso8601Expression) -> &mut WaitTaskDefinitionBuilder{ + let builder = WaitTaskDefinitionBuilder::new(duration); + self.builder = Some(TaskDefinitionBuilder::Wait(builder)); + if let Some(TaskDefinitionBuilder::Wait(ref mut builder)) = self.builder{ + builder + } + else { + unreachable!("Builder should always be set to Wait"); + } + } + + /// Builds the configured task + pub fn build(self) -> TaskDefinition{ + if let Some(builder) = self.builder { + match builder { + TaskDefinitionBuilder::Call(builder) => builder.build(), + TaskDefinitionBuilder::Do(builder) => builder.build(), + TaskDefinitionBuilder::Emit(builder) => builder.build(), + TaskDefinitionBuilder::For(builder) => builder.build(), + TaskDefinitionBuilder::Fork(builder) => builder.build(), + TaskDefinitionBuilder::Listen(builder) => builder.build(), + TaskDefinitionBuilder::Raise(builder) => builder.build(), + TaskDefinitionBuilder::Run(builder) => builder.build(), + TaskDefinitionBuilder::Set(builder) => builder.build(), + TaskDefinitionBuilder::Switch(builder) => builder.build(), + TaskDefinitionBuilder::Try(builder) => builder.build(), + TaskDefinitionBuilder::Wait(builder) => builder.build() + } + } + else { + panic!("The task must be configured"); + } + } + +} + +/// Enumerates all supported task definition builders +pub enum TaskDefinitionBuilder{ + Call(CalltaskDefinitionBuilder), + Do(DoTaskDefinitionBuilder), + Emit(EmitTaskDefinitionBuilder), + For(ForTaskDefinitionBuilder), + Fork(ForkTaskDefinitionBuilder), + Listen(ListenTaskDefinitionBuilder), + Raise(RaiseTaskDefinitionBuilder), + Run(RunTaskDefinitionBuilder), + Set(SetTaskDefinitionBuilder), + Switch(SwitchTaskDefinitionBuilder), + Try(TryTaskDefinitionBuilder), + Wait(WaitTaskDefinitionBuilder) +} + +/// Represents the service used to build CallTaskDefinitions +pub struct CalltaskDefinitionBuilder{ + task: CallTaskDefinition +} +impl CalltaskDefinitionBuilder { + + /// Initializes a new CallTaskDefinitionBuilder + pub fn new(function: &str) -> Self{ + Self { task: CallTaskDefinition::new(function, None, None) } + } + + /// Adds a new argument to call the function with + pub fn with(&mut self, name: &str, value: AnyValue) -> &mut Self{ + if self.task.with.is_none(){ + self.task.with = Some(HashMap::new()); + } + if let Some(with) = &mut self.task.with { + with.insert(name.to_string(), value); + } + self + } + + /// Sets the arguments to call the function with + pub fn with_arguments(&mut self, arguments: HashMap) -> &mut Self{ + self.task.with = Some(arguments); + self + } + + /// Builds the configures CallTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Call(self.task) + } + +} + +/// Represents the service used to build DoTaskDefinitions +pub struct DoTaskDefinitionBuilder{ + task: DoTaskDefinition +} +impl DoTaskDefinitionBuilder { + + /// Initializes a new DoTaskDefinitionBuilder + pub fn new() -> Self{ + Self { task: DoTaskDefinition::default() } + } + + /// Adds a new task with the specified name to the task + pub fn do_(&mut self, name: &str, setup: F) -> &mut Self + where F: FnOnce(&mut GenericTaskDefinitionBuilder){ + let mut builder = GenericTaskDefinitionBuilder::new(); + setup(&mut builder); + let task = builder.build(); + self.task.do_.add(name.to_string(), task); + self + } + + /// Builds the configures DoTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Do(self.task) + } + +} + +/// Represents the service used to build EmitTaskDefinitions +pub struct EmitTaskDefinitionBuilder{ + task: EmitTaskDefinition +} +impl EmitTaskDefinitionBuilder { + + /// Initializes a new EmitTaskDefinitionBuilder + pub fn new(event: EventDefinition) -> Self{ + Self { task: EmitTaskDefinition::new(EventEmissionDefinition::new(event)) } + } + + /// Builds the configures DoTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Emit(self.task) + } + +} + +/// Represents the service used to build ForTaskDefinitions +pub struct ForTaskDefinitionBuilder{ + task: ForTaskDefinition +} +impl ForTaskDefinitionBuilder{ + + /// Initializes a new ForTaskDefinitionBuilder + pub fn new() -> Self{ + Self { task:ForTaskDefinition::default() } + } + + /// Sets the name of the variable to store the iteration item to + pub fn each(&mut self, variable_name: &str) -> &mut Self{ + self.task.for_.each = variable_name.to_string(); + self + } + + /// Sets the runtime expression used to resolve the collection to iterate + pub fn in_(&mut self, expression: &str) -> &mut Self{ + self.task.for_.in_ = expression.to_string(); + self + } + + /// Sets the name of the variable to store the iteration index to + pub fn at(&mut self, variable_name: &str) -> &mut Self{ + self.task.for_.at = Some(variable_name.to_string()); + self + } + + /// Configures the task to execute the specified tasks for each item in the specified collection + pub fn do_(&mut self, name: &str, setup: F) -> &mut Self + where F: FnOnce(&mut GenericTaskDefinitionBuilder){ + let mut builder = GenericTaskDefinitionBuilder::new(); + setup(&mut builder); + let task = builder.build(); + self.task.do_.add(name.to_string(), task); + self + } + + /// Builds the configured ForTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::For(self.task) + } + +} + +/// Represents the service used to build ForkTaskDefinitions +pub struct ForkTaskDefinitionBuilder{ + task: ForkTaskDefinition +} +impl ForkTaskDefinitionBuilder{ + + /// Initializes a new ForkTaskDefinitions + pub fn new() -> Self{ + Self { task:ForkTaskDefinition::default() } + } + + /// Configures the tasks to perform concurrently + pub fn branch(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut TaskDefinitionMapBuilder){ + let mut builder = TaskDefinitionMapBuilder::new(); + setup(&mut builder); + let branches = builder.build(); + self.task.fork.branches = branches; + self + } + + /// Builds the configured ForkTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Fork(self.task) + } + +} + +/// Represents the service used to build ListenTaskDefinitions +pub struct ListenTaskDefinitionBuilder{ + task: ListenTaskDefinition +} +impl ListenTaskDefinitionBuilder{ + + /// Initializes a new ListenTaskDefinitionBuilder + pub fn new() -> Self{ + Self { task:ListenTaskDefinition::default() } + } + + /// Configures the task to listen to the specified event(s) + pub fn to(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut EventConsumptionStrategyDefinitionBuilder){ + let mut builder = EventConsumptionStrategyDefinitionBuilder::new(); + setup(&mut builder); + let consumption_strategy = builder.build(); + self.task.listen.to = consumption_strategy; + self + } + + /// Builds the configured ListenTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Listen(self.task) + } + +} + +/// Represents the service used to build RaiseTaskDefinitions +pub struct RaiseTaskDefinitionBuilder{ + builder: Option, + reference: Option +} +impl RaiseTaskDefinitionBuilder{ + + /// Initializes a new RaiseTaskDefinitionBuilder + pub fn new() -> Self{ + Self { builder: None, reference: None } + } + + /// Sets the error to raise + pub fn error(&mut self) -> &mut ErrorDefinitionBuilder{ + let builder = ErrorDefinitionBuilder::new(); + self.builder = Some(builder); + if let Some(ref mut error_builder) = self.builder{ + error_builder + } + else { + unreachable!("Builder should always be set to Error"); + } + } + + /// Sets a reference to the error to raise + pub fn referenced_error(&mut self, reference: &str){ + self.reference = Some(reference.to_string()); + } + + /// Builds the configured RaiseTaskDefinition + pub fn build(self) -> TaskDefinition{ + let mut task = RaiseTaskDefinition::default(); + if let Some(builder) = self.builder { + let error = builder.build(); + task.raise = RaiseErrorDefinition::new(OneOfErrorDefinitionOrReference::Error(error)); + } + else if let Some(reference) = self.reference{ + task.raise = RaiseErrorDefinition::new(OneOfErrorDefinitionOrReference::Reference(reference)); + } + else{ + panic!("The error to raise must be configured"); + } + TaskDefinition::Raise(task) + } + +} + +/// Represents the service used to build RunTaskDefinitions +pub struct RunTaskDefinitionBuilder{ + builder : Option +} +impl RunTaskDefinitionBuilder{ + + /// Initializes a new RunTaskDefinitionBuilder + pub fn new() -> Self{ + Self{ builder: None } + } + + /// Configures the task to run the specified container + pub fn container(&mut self) -> &mut ContainerProcessDefinitionBuilder{ + self.builder = Some(ProcessDefinitionBuilder::Container(ContainerProcessDefinitionBuilder::new())); + if let Some(ProcessDefinitionBuilder::Container(ref mut container_builder)) = self.builder { + container_builder + } + else { + unreachable!("Builder should always be set to Container"); + } + } + + /// Configures the task to run the specified script + pub fn script(&mut self) -> &mut ScriptProcessDefinitionBuilder{ + self.builder = Some(ProcessDefinitionBuilder::Script(ScriptProcessDefinitionBuilder::new())); + if let Some(ProcessDefinitionBuilder::Script(ref mut script_builder)) = self.builder { + script_builder + } + else { + unreachable!("Builder should always be set to Script"); + } + } + + /// Configures the task to run the specified shell command + pub fn shell(&mut self) -> &mut ShellProcessDefinitionBuilder{ + self.builder = Some(ProcessDefinitionBuilder::Shell(ShellProcessDefinitionBuilder::new())); + if let Some(ProcessDefinitionBuilder::Shell(ref mut shell_builder)) = self.builder { + shell_builder + } + else { + unreachable!("Builder should always be set to Shell"); + } + } + + /// Configures the task to run the specified workflow + pub fn workflow(&mut self) -> &mut WorkflowProcessDefinitionBuilder{ + self.builder = Some(ProcessDefinitionBuilder::Workflow(WorkflowProcessDefinitionBuilder::new())); + if let Some(ProcessDefinitionBuilder::Workflow(ref mut workflow_builder)) = self.builder { + workflow_builder + } + else { + unreachable!("Builder should always be set to Workflow"); + } + } + + /// Builds the configured RunTaskDefinition + pub fn build(self) -> TaskDefinition{ + if let Some(builder) = self.builder { + let process = match builder { + ProcessDefinitionBuilder::Container(builder) => builder.build(), + ProcessDefinitionBuilder::Script(builder) => builder.build(), + ProcessDefinitionBuilder::Shell(builder) => builder.build(), + ProcessDefinitionBuilder::Workflow(builder) => builder.build() + }; + TaskDefinition::Run(process) + } + else{ + panic!("The process to run must be configured"); + } + } + +} + +/// Represents the service used to build SetTaskDefinitions +pub struct SetTaskDefinitionBuilder{ + task: SetTaskDefinition +} +impl SetTaskDefinitionBuilder{ + + /// Initializes a new SetTaskDefinition + pub fn new() -> Self{ + Self { task: SetTaskDefinition::new() } + } + + /// Sets the specified variable + pub fn variable(&mut self, name: &str, value: AnyValue) -> &mut Self{ + self.task.set.insert(name.to_string(), value); + self + } + + /// Configures the task to set the specified variables + pub fn variables(&mut self, variables: HashMap) -> &mut Self{ + self.task.set = variables; + self + } + + /// Builds a new SetTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Set(self.task) + } + +} + +/// Represents the service used to build SwitchTaskDefinitions +pub struct SwitchTaskDefinitionBuilder{ + task: SwitchTaskDefinition +} +impl SwitchTaskDefinitionBuilder{ + + /// Initializes a new SwitchTaskDefinition + pub fn new() -> Self{ + Self { task: SwitchTaskDefinition::new() } + } + + /// Adds a new casev + pub fn case(&mut self, name: &str, setup: F) -> &mut Self + where F: FnOnce(&mut SwitchCaseDefinitionBuilder){ + let mut builder = SwitchCaseDefinitionBuilder::new(); + setup(&mut builder); + let case = builder.build(); + self.task.switch.add(name.to_string(), case); + self + } + + /// Builds a new SwitchTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Switch(self.task) + } + +} + +/// Represents the service used to build TryTaskDefinitions +pub struct TryTaskDefinitionBuilder{ + task: TryTaskDefinition +} +impl TryTaskDefinitionBuilder{ + + /// Initializes a new TryTaskDefinition + pub fn new() -> Self{ + Self { task: TryTaskDefinition::default() } + } + + /// Configures the task to try executing the specified tasks + pub fn do_(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut TaskDefinitionMapBuilder){ + let mut builder = TaskDefinitionMapBuilder::new(); + setup(&mut builder); + self.task.try_ = builder.build(); + self + } + + /// Configures the task to catch defined errors + pub fn catch(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut ErrorCatcherDefinitionBuilder){ + let mut builder = ErrorCatcherDefinitionBuilder::new(); + setup(&mut builder); + self.task.catch = builder.build(); + self + } + + /// Builds a new TryTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Try(self.task) + } + +} + +/// Represents the service used to build WaitTaskDefinitions +pub struct WaitTaskDefinitionBuilder{ + task: WaitTaskDefinition +} +impl WaitTaskDefinitionBuilder { + + /// Initializes a new WaitTaskDefinitionBuilder + pub fn new(duration: OneOfDurationOrIso8601Expression) -> Self{ + Self { task: WaitTaskDefinition::new(duration) } + } + + /// Builds the configures DoTaskDefinition + pub fn build(self) -> TaskDefinition{ + TaskDefinition::Wait(self.task) + } + +} + +/// Represents the service used to build EventDefinitions +pub struct EventDefinitionBuilder{ + event: EventDefinition +} +impl EventDefinitionBuilder{ + + /// Initializes a new EventDefinitionBuilder + pub fn new() -> Self{ + Self { event: EventDefinition::default() } + } + + /// Adds a new attribute to the event + pub fn with(&mut self, name: &str, value: AnyValue) -> &mut Self{ + self.event.with.insert(name.to_string(), value); + self + } + + /// Sets the event's attributes + pub fn with_attributes(&mut self, attributes: HashMap) -> &mut Self{ + self.event.with = attributes; + self + } + + /// Builds the configured EventDefinition + pub fn build(self) -> EventDefinition{ + self.event + } + +} + +/// Represents the service used to build TaskDefinitionMaps +pub struct TaskDefinitionMapBuilder{ + map: Map +} +impl TaskDefinitionMapBuilder{ + + /// Initializes a new TaskDefinitionMapBuilder + pub fn new() -> Self{ + Self { map: Map::new() } + } + + /// Adds a new task with the specified name to the task + pub fn do_(&mut self, name: &str, setup: F) -> &mut Self + where F: FnOnce(&mut GenericTaskDefinitionBuilder){ + let mut builder = GenericTaskDefinitionBuilder::new(); + setup(&mut builder); + let task = builder.build(); + self.map.add(name.to_string(), task); + self + } + + /// Builds the configured TaskDefinitionMap + pub fn build(self) -> Map{ + self.map + } + +} + +/// Represents the service used to build EventConsumptionStrategyDefinition +pub struct EventConsumptionStrategyDefinitionBuilder{ + all: Option, + any: Option, + one: Option, + until_condition: Option, + until_events: Option +} +impl EventConsumptionStrategyDefinitionBuilder{ + + /// Initializes a new EventConsumptionStrategyDefinitionBuilder + pub fn new() -> Self{ + Self { all: None, any: None, one: None, until_condition: None, until_events: None } + } + + /// Configures the task to listen for all of the defined events + pub fn all(&mut self) -> &mut EventFilterDefinitionCollectionBuilder { + let builder = EventFilterDefinitionCollectionBuilder::new(); + self.all = Some(builder); + if let Some(ref mut all_builder) = self.all{ + all_builder + } + else { + unreachable!("Builder should always be set to All"); + } + } + + /// Configures the task to listen for any of the defined events + pub fn any(&mut self) -> &mut EventFilterDefinitionCollectionBuilder { + let builder = EventFilterDefinitionCollectionBuilder::new(); + self.any = Some(builder); + if let Some(ref mut any_builder) = self.any{ + any_builder + } + else { + unreachable!("Builder should always be set to Any"); + } + } + + /// Configures the task to listen for one single event + pub fn one(&mut self) -> &mut EventFilterDefinitionBuilder { + let builder = EventFilterDefinitionBuilder::new(); + self.one = Some(builder); + if let Some(ref mut one_builder) = self.one{ + one_builder + } + else { + unreachable!("Builder should always be set to One"); + } + } + + /// Configures the task to listen to any events until the specified events are consumed + pub fn until(&mut self, setup: F) + where F: FnOnce(&mut EventConsumptionStrategyDefinitionBuilder){ + let mut builder = EventConsumptionStrategyDefinitionBuilder::new(); + setup(&mut builder); + self.until_events = Some(builder.build()); + } + + /// Configures the task to listen to any events until the specified condition matches + pub fn until_condition_matches(&mut self, expression: &str){ + self.until_condition = Some(expression.to_string()); + } + + /// Builds the configured EventConsumptionStrategyDefinition + pub fn build(self) -> EventConsumptionStrategyDefinition{ + let mut strategy = EventConsumptionStrategyDefinition::default(); + if let Some(all_builder) = self.all { + strategy.all = Some(all_builder.build()); + } + else if let Some(any_builder) = self.any { + strategy.any = Some(any_builder.build()); + if let Some(expression) = self.until_condition{ + strategy.until = Some(Box::new(OneOfEventConsumptionStrategyDefinitionOrExpression::Expression(expression.to_string()))); + } + else if let Some(until_events) = self.until_events{ + strategy.until = Some(Box::new(OneOfEventConsumptionStrategyDefinitionOrExpression::Strategy(until_events))); + } + } + else if let Some(one_builder) = self.one { + strategy.one = Some(one_builder.build()); + } + else{ + panic!("No strategy defined!"); + } + strategy + } + +} + +/// Represents the service used to build EventFilterDefinitionCollections +pub struct EventFilterDefinitionCollectionBuilder{ + events: Vec +} +impl EventFilterDefinitionCollectionBuilder{ + + /// Initializes a new EventFilterDefinitionCollectionBuilder + pub fn new() -> Self{ + Self { events: Vec::new() } + } + + /// Adds the specified event filter to the collection + pub fn event(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut EventFilterDefinitionBuilder){ + let mut builder = EventFilterDefinitionBuilder::new(); + setup(&mut builder); + let filter = builder.build(); + self.events.push(filter); + self + } + + /// Builds the configured EventFilterDefinitionCollection + pub fn build(self) -> Vec{ + self.events + } + +} + +/// Represents the service used to build EventFilterDefinitions +pub struct EventFilterDefinitionBuilder{ + filter: EventFilterDefinition +} +impl EventFilterDefinitionBuilder{ + + /// Initializes a new EventFilterDefinition + pub fn new() -> Self{ + Self { filter: EventFilterDefinition::default() } + } + + /// Adds a new attribute to filter events by + pub fn with(&mut self, name: &str, value: AnyValue) -> &mut Self{ + if self.filter.with.is_none(){ + self.filter.with = Some(HashMap::new()); + } + if let Some(with) = &mut self.filter.with { + with.insert(name.to_string(), value); + } + self + } + + /// Sets a name/value mapping of the attributes to filter events by + pub fn with_attributes(&mut self, attributes: HashMap) -> &mut Self{ + self.filter.with = Some(attributes); + self + } + + /// Builds the configured EventFilterDefinition + pub fn build(self) -> EventFilterDefinition{ + self.filter + } + +} + +/// Represents the service used to build ErrorDefinition +pub struct ErrorDefinitionBuilder{ + error: ErrorDefinition +} +impl ErrorDefinitionBuilder{ + + /// Initializes a new ErrorDefinitionBuilder + pub fn new() -> Self{ + Self { error: ErrorDefinition::default() } + } + + /// Sets the error's type + pub fn with_type(&mut self, type_: &str) -> &mut Self{ + self.error.type_ = type_.to_string(); + self + } + + /// Sets the error's status + pub fn with_status(&mut self, status: AnyValue) -> &mut Self{ + self.error.status = status; + self + } + + /// Sets the error's title + pub fn with_title(&mut self, title: &str) -> &mut Self{ + self.error.title = title.to_string(); + self + } + + /// Sets the error's detail + pub fn with_detail(&mut self, detail: &str) -> &mut Self{ + self.error.detail = Some(detail.to_string()); + self + } + + /// Sets a reference to the component the error concerns + pub fn with_instance(&mut self, instance: &str) -> &mut Self{ + self.error.instance = Some(instance.to_string()); + self + } + + /// Builds the configured ErrorDefinition + pub fn build(self) -> ErrorDefinition{ + self.error + } + +} + +/// Enumerates all supported process definition builders +pub enum ProcessDefinitionBuilder{ + Container(ContainerProcessDefinitionBuilder), + Script(ScriptProcessDefinitionBuilder), + Shell(ShellProcessDefinitionBuilder), + Workflow(WorkflowProcessDefinitionBuilder) +} + +///Represents the service used to build ContainerProcessDefinitions +pub struct ContainerProcessDefinitionBuilder{ + process: ContainerProcessDefinition +} +impl ContainerProcessDefinitionBuilder{ + + /// Initializes a new ContainerProcessDefinitionBuilder + pub fn new() -> Self{ + Self { process: ContainerProcessDefinition::default() } + } + + /// Configures the name of the container to spawn + pub fn with_name(&mut self, name: &str) -> &mut Self{ + self.process.name = Some(name.to_string()); + self + } + + /// Configures the container to use the specified image + pub fn with_image(&mut self, image: &str) -> &mut Self{ + self.process.image = image.to_string(); + self + } + + /// Configures the command, if any, to execute on the container + pub fn with_command(&mut self, command: &str) -> &mut Self{ + self.process.command = Some(command.to_string()); + self + } + + /// Adds the specified container port mapping + pub fn with_port(&mut self, host_port: u16, container_port: u16) -> &mut Self{ + if self.process.ports.is_none(){ + self.process.ports = Some(HashMap::new()); + } + if let Some(ports) = &mut self.process.ports { + ports.insert(host_port, container_port); + } + self + } + + /// Sets the container's port mapping + pub fn with_ports(&mut self, ports: HashMap) -> &mut Self{ + self.process.ports = Some(ports); + self + } + + /// Adds the specified volume to the container + pub fn with_volume(&mut self, key: &str, value: &str) -> &mut Self{ + if self.process.volumes.is_none(){ + self.process.volumes = Some(HashMap::new()); + } + if let Some(volumes) = &mut self.process.volumes { + volumes.insert(key.to_string(), value.to_string()); + } + self + } + + /// Sets the container's volumes + pub fn with_volumes(&mut self, volumes: HashMap) -> &mut Self{ + self.process.volumes = Some(volumes); + self + } + + /// Adds the specified environment variable to the container + pub fn with_environment(&mut self, name: &str, value: &str) -> &mut Self{ + if self.process.environment.is_none(){ + self.process.environment = Some(HashMap::new()); + } + if let Some(environment) = &mut self.process.environment { + environment.insert(name.to_string(), value.to_string()); + } + self + } + + /// Sets the container's environment variables + pub fn with_environment_variables(&mut self, environment: HashMap) -> &mut Self{ + self.process.environment = Some(environment); + self + } + + /// Builds the configured RunTaskDefinition + pub fn build(self) -> RunTaskDefinition{ + let mut run_task = RunTaskDefinition::default(); + run_task.run.container = Some(self.process); + run_task + } + +} + +///Represents the service used to build ScriptProcessDefinitions +pub struct ScriptProcessDefinitionBuilder{ + process: ScriptProcessDefinition +} +impl ScriptProcessDefinitionBuilder{ + + /// Initializes a new ScriptProcessDefinitionBuilder + pub fn new() -> Self{ + Self { process: ScriptProcessDefinition::default() } + } + + /// Sets the language of the script to run + pub fn with_language(&mut self, language: &str) -> &mut Self{ + self.process.language = language.to_string(); + self + } + + /// Sets the code of the script to run + pub fn with_code(&mut self, code: &str) -> &mut Self{ + self.process.code = Some(code.to_string()); + self + } + + /// Sets the source of the script to run + pub fn with_source(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut ExternalResourceDefinitionBuilder){ + let mut builder = ExternalResourceDefinitionBuilder::new(); + setup(&mut builder); + let resource = builder.build(); + self.process.source = Some(resource); + self + } + + /// Adds a new argument to execute the script with + pub fn with_argument(&mut self, key: &str, value: &str) -> &mut Self{ + if self.process.arguments.is_none(){ + self.process.arguments = Some(HashMap::new()); + } + if let Some(arguments) = &mut self.process.arguments { + arguments.insert(key.to_string(), value.to_string()); + } + self + } + + /// Sets the arguments of the script to execute + pub fn with_arguments(&mut self, arguments: HashMap) -> &mut Self{ + self.process.arguments = Some(arguments); + self + } + + /// Adds the specified environment variable to the process + pub fn with_environment(&mut self, name: &str, value: &str) -> &mut Self{ + if self.process.environment.is_none(){ + self.process.environment = Some(HashMap::new()); + } + if let Some(environment) = &mut self.process.environment { + environment.insert(name.to_string(), value.to_string()); + } + self + } + + /// Sets the process's environment variables + pub fn with_environment_variables(&mut self, environment: HashMap) -> &mut Self{ + self.process.environment = Some(environment); + self + } + + /// Builds the configured RunTaskDefinition + pub fn build(self) -> RunTaskDefinition{ + let mut run_task = RunTaskDefinition::default(); + run_task.run.script = Some(self.process); + run_task + } + +} + +///Represents the service used to build ShellProcessDefinitions +pub struct ShellProcessDefinitionBuilder{ + process: ShellProcessDefinition +} +impl ShellProcessDefinitionBuilder{ + + /// Initializes a new ShellProcessDefinitions + pub fn new() -> Self{ + Self { process: ShellProcessDefinition::default() } + } + + /// Configures the task to execute the specified shell command + pub fn with_command(&mut self, command: &str) -> &mut Self{ + self.process.command = command.to_string(); + self + } + + /// Adds a new argument to execute the shell command with + pub fn with_argument(&mut self, argument: &str) -> &mut Self{ + if self.process.arguments.is_none(){ + self.process.arguments = Some(Vec::new()); + } + if let Some(arguments) = &mut self.process.arguments { + arguments.push(argument.to_string()); + } + self + } + + /// Sets the arguments of the shell command to execute + pub fn with_arguments(&mut self, arguments: Vec) -> &mut Self{ + self.process.arguments = Some(arguments); + self + } + + /// Adds the specified environment variable to the process + pub fn with_environment(&mut self, name: &str, value: &str) -> &mut Self{ + if self.process.environment.is_none(){ + self.process.environment = Some(HashMap::new()); + } + if let Some(environment) = &mut self.process.environment { + environment.insert(name.to_string(), value.to_string()); + } + self + } + + /// Sets the process's environment variables + pub fn with_environment_variables(&mut self, environment: HashMap) -> &mut Self{ + self.process.environment = Some(environment); + self + } + + /// Builds the configured RunTaskDefinition + pub fn build(self) -> RunTaskDefinition{ + let mut run_task = RunTaskDefinition::default(); + run_task.run.shell = Some(self.process); + run_task + } + +} + +///Represents the service used to build WorkflowProcessDefinitions +pub struct WorkflowProcessDefinitionBuilder{ + process: WorkflowProcessDefinition +} +impl WorkflowProcessDefinitionBuilder{ + + /// Initializes a new WorkflowProcessDefinitions + pub fn new() -> Self{ + Self { process: WorkflowProcessDefinition::default() } + } + + /// Configures the task to run the workflow with the specified namespace + pub fn with_namespace(&mut self, namespace: &str) -> &mut Self{ + self.process.namespace = namespace.to_string(); + self + } + + /// Configures the task to run the workflow with the specified name + pub fn with_name(&mut self, name: &str) -> &mut Self{ + self.process.name = name.to_string(); + self + } + + /// Configures the task to run the workflow with the specified version + pub fn with_version(&mut self, version: &str) -> &mut Self{ + self.process.version = version.to_string(); + self + } + + /// Sets the input of the workflow to run + pub fn with_input(&mut self, input: AnyValue) -> &mut Self{ + self.process.input = Some(input); + self + } + + /// Builds the configured RunTaskDefinition + pub fn build(self) -> RunTaskDefinition{ + let mut run_task = RunTaskDefinition::default(); + run_task.run.workflow = Some(self.process); + run_task + } + +} + +/// Represents the service used to build ExternalResourceDefinitions +pub struct ExternalResourceDefinitionBuilder{ + resource: ExternalResourceDefinition +} +impl ExternalResourceDefinitionBuilder{ + + /// Initializes a new ExternalResourceDefinitionBuilder + pub fn new() -> Self{ + Self { resource:ExternalResourceDefinition::default() } + } + + /// Configures the name of the referenced external resource + pub fn with_name(&mut self, name: &str) -> &mut Self{ + self.resource.name = Some(name.to_string()); + self + } + + /// Configures the endpoint at which to get the defined resource + pub fn with_endpoint(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut EndpointDefinitionBuilder){ + let mut builder = EndpointDefinitionBuilder::new(); + setup(&mut builder); + let endpoint = builder.build(); + self.resource.endpoint = OneOfEndpointDefinitionOrUri::Endpoint(endpoint); + self + } + + /// Configures the endpoint at which to get the defined resource + pub fn with_endpoint_uri(&mut self, uri: &str) -> &mut Self{ + self.resource.endpoint = OneOfEndpointDefinitionOrUri::Uri(uri.to_string()); + self + } + + /// Builds the configured ExternalResourceDefinition + pub fn build(self) -> ExternalResourceDefinition{ + self.resource + } + +} + +/// Represents the service used to build EndpointDefinitions +pub struct EndpointDefinitionBuilder{ + endpoint: EndpointDefinition +} +impl EndpointDefinitionBuilder{ + + /// Initializes a new EndpointDefinitionBuilder + pub fn new() -> Self{ + Self { endpoint: EndpointDefinition::default() } + } + + /// Sets the endpoint's + pub fn with_uri(&mut self, uri: &str) -> &mut Self{ + self.endpoint.uri = uri.to_string(); + self + } + + /// Configures the authentication policy used to access the configured endpoint + pub fn with_authentication(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut AuthenticationPolicyDefinitionBuilder){ + let mut builder = AuthenticationPolicyDefinitionBuilder::new(); + setup(&mut builder); + let authentication = builder.build(); + self.endpoint.authentication = Some(authentication); + self + } + + /// Builds the configured EndpointDefinition + pub fn build(self) -> EndpointDefinition{ + self.endpoint + } + +} + +/// Represents the service used to build SwitchCaseDefinitions +pub struct SwitchCaseDefinitionBuilder{ + case: SwitchCaseDefinition +} +impl SwitchCaseDefinitionBuilder{ + + /// Initializes a new SwitchCaseDefinitionBuilder + pub fn new() -> Self{ + Self { case: SwitchCaseDefinition::default() } + } + + /// Sets a runtime expression that defines whether or not the case applies + pub fn when(&mut self, expression: &str) -> &mut Self{ + self.case.when = Some(expression.to_string()); + self + } + + /// Sets the flow directive to execute when the case is matched + pub fn then(&mut self, directive: &str) -> &mut Self{ + self.case.then = Some(directive.to_string()); + self + } + + /// Builds the configured SwitchCaseDefinition + pub fn build(self) -> SwitchCaseDefinition{ + self.case + } + +} + +/// Represents the service used to build ErrorCatcherDefinitions +pub struct ErrorCatcherDefinitionBuilder{ + catch: ErrorCatcherDefinition +} +impl ErrorCatcherDefinitionBuilder{ + + /// Initializes a new ErrorCatcherDefinitionBuilder + pub fn new() -> Self{ + Self { catch: ErrorCatcherDefinition::default() } + } + + /// Catches errors matching the specified filter + pub fn errors(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut ErrroFilterDefinitionBuilder){ + let mut builder = ErrroFilterDefinitionBuilder::new(); + setup(&mut builder); + self.catch.errors = Some(builder.build()); + self + } + + /// Sets the name of the variable that contains caught errors + pub fn as_(&mut self, variable: &str) -> &mut Self{ + self.catch.as_ = Some(variable.to_string()); + self + } + + /// Sets the runtime expression used to determine whether to catch the filtered error + pub fn when(&mut self, expression: &str) -> &mut Self{ + self.catch.when = Some(expression.to_string()); + self + } + + /// Sets the runtime expression used to determine whether not to catch the filtered error + pub fn except_when(&mut self, expression: &str) -> &mut Self{ + self.catch.except_when = Some(expression.to_string()); + self + } + + /// Sets the reference to the retry policy to use + pub fn retry(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut RetryPolicyDefinitionBuilder){ + let mut builder = RetryPolicyDefinitionBuilder::new(); + setup(&mut builder); + self.catch.retry = Some(OneOfRetryPolicyDefinitionOrReference::Retry(builder.build())); + self + } + + /// Sets the reference to the retry policy to use + pub fn retry_using(&mut self, reference: &str) -> &mut Self{ + self.catch.retry = Some(OneOfRetryPolicyDefinitionOrReference::Reference(reference.to_string())); + self + } + + /// Configures the tasks to execute the specified task after catching or after retry exhaustion + pub fn do_(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut TaskDefinitionMapBuilder){ + let mut builder = TaskDefinitionMapBuilder::new(); + setup(&mut builder); + self.catch.do_ = Some(builder.build()); + self + } + + /// Builds the configured ErrorCatcherDefinition + pub fn build(self) -> ErrorCatcherDefinition{ + self.catch + } + +} + +/// Represents the service used to build ErrroFilterDefinitions +pub struct ErrroFilterDefinitionBuilder{ + filter: ErrorFilterDefinition +} +impl ErrroFilterDefinitionBuilder{ + + /// Initializes a new ErrroFilterDefinitionBuilder + pub fn new() -> Self{ + Self { filter: ErrorFilterDefinition::default() } + } + + /// Adds a new attribute filter + pub fn with(&mut self, name: &str, value: AnyValue) -> &mut Self{ + if self.filter.with.is_none(){ + self.filter.with = Some(HashMap::new()); + } + if let Some(with) = &mut self.filter.with { + with.insert(name.to_string(), value); + } + self + } + + /// Sets a name/value mapping of the attributes to filter errors by + pub fn with_attributes(&mut self, attributes: HashMap) -> &mut Self{ + self.filter.with = Some(attributes); + self + } + + /// Builds the configured ErrorFilterDefinition + pub fn build(self) -> ErrorFilterDefinition{ + self.filter + } + +} + +/// Represents the service used to build RetryPolicyDefinitions +pub struct RetryPolicyDefinitionBuilder{ + retry: RetryPolicyDefinition +} +impl RetryPolicyDefinitionBuilder{ + + /// Initializes a new RetryPolicyDefinitionBuilder + pub fn new() -> Self{ + Self { retry: RetryPolicyDefinition::default() } + } + + /// Sets the runtime expression used to determine whether to retry the filtered error + pub fn when(&mut self, expression: &str) -> &mut Self{ + self.retry.when = Some(expression.to_string()); + self + } + + /// Sets the runtime expression used to determine whether not to retry the filtered error + pub fn except_when(&mut self, expression: &str) -> &mut Self{ + self.retry.except_when = Some(expression.to_string()); + self + } + + /// Sets the limits of the retry policy to build + pub fn limit(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut RetryPolicyLimitDefinitionBuilder){ + let mut builder = RetryPolicyLimitDefinitionBuilder::new(); + setup(&mut builder); + self.retry.limit = Some(builder.build()); + self + } + + /// Sets the delay duration between retry attempts + pub fn delay(&mut self, duration: Duration) -> &mut Self{ + self.retry.delay = Some(duration); + self + } + + /// Sets the backoff strategy of the retry policy to build + pub fn backoff(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut GenericBackoffStrategyDefinitionBuilder){ + let mut builder = GenericBackoffStrategyDefinitionBuilder::new(); + setup(&mut builder); + self.retry.backoff = Some(builder.build()); + self + } + + /// Sets the jitter to apply to the retry policy to build + pub fn jitter(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut JitterDefinitionBuilder){ + let mut builder = JitterDefinitionBuilder::new(); + setup(&mut builder); + self.retry.jitter = Some(builder.build()); + self + } + + /// Builds the configured RetryPolicyDefinition + pub fn build(self) -> RetryPolicyDefinition{ + self.retry + } + +} + +/// Represents the service used to build RetryPolicyLimitDefinitions +pub struct RetryPolicyLimitDefinitionBuilder{ + limit: RetryPolicyLimitDefinition +} +impl RetryPolicyLimitDefinitionBuilder{ + + /// Initializes a new RetryPolicyLimitDefinitionBuilder + pub fn new() -> Self{ + Self { limit: RetryPolicyLimitDefinition::default() } + } + + /// Configures retry attempts limits + pub fn attempt(&mut self, setup: F) -> &mut Self + where F: FnOnce(&mut RetryAttemptLimitDefinitionBuilder){ + let mut builder = RetryAttemptLimitDefinitionBuilder::new(); + setup(&mut builder); + self.limit.attempt = Some(builder.build()); + self + } + + /// Configures the maximum duration during which retrying is allowed + pub fn duration(&mut self, duration: Duration) -> &mut Self{ + self.limit.duration = Some(duration); + self + } + + /// Builds the configured RetryPolicyLimitDefinition + pub fn build(self) -> RetryPolicyLimitDefinition{ + self.limit + } + +} + +/// Represents the service used to build RetryAttemptLimitDefinitions +pub struct RetryAttemptLimitDefinitionBuilder{ + attempt: RetryAttemptLimitDefinition +} +impl RetryAttemptLimitDefinitionBuilder{ + + /// Initializes a new RetryAttemptLimitDefinitionBuilder + pub fn new() -> Self{ + Self { attempt: RetryAttemptLimitDefinition::default() } + } + + /// Sets the maximum attempts count + pub fn count(&mut self, count: u16) -> &mut Self{ + self.attempt.count = Some(count); + self + } + + /// Sets the maximum duration per attempt + pub fn duration(&mut self, duration: Duration) -> &mut Self{ + self.attempt.duration = Some(duration); + self + } + + /// Builds the configured RetryAttemptLimitDefinition + pub fn build(self) -> RetryAttemptLimitDefinition{ + self.attempt + } + +} + +/// Represents the service used to build BackoffStrategyDefinitions +pub struct GenericBackoffStrategyDefinitionBuilder{ + builder: Option +} +impl GenericBackoffStrategyDefinitionBuilder{ + + /// Initializes a new BackoffStrategyDefinitionBuilder + pub fn new() -> Self{ + Self { builder: None } + } + + /// Configures a constant backoff strategy + pub fn constant(&mut self) -> &mut ConstantBackoffDefinitionBuilder{ + let builder = ConstantBackoffDefinitionBuilder::new(); + self.builder = Some(BackoffStrategyDefinitionBuilder::Constant(builder)); + if let Some(BackoffStrategyDefinitionBuilder::Constant(ref mut builder)) = self.builder{ + builder + } + else{ + unreachable!("Builder should always be set to Constant"); + } + } + + /// Configures an exponential backoff strategy + pub fn exponential(&mut self) -> &mut ExponentialBackoffDefinitionBuilder{ + let builder = ExponentialBackoffDefinitionBuilder::new(); + self.builder = Some(BackoffStrategyDefinitionBuilder::Exponential(builder)); + if let Some(BackoffStrategyDefinitionBuilder::Exponential(ref mut builder)) = self.builder{ + builder + } + else{ + unreachable!("Builder should always be set to Exponential"); + } + } + + /// Configures a linear backoff strategy + pub fn linear(&mut self) -> &mut LinearBackoffDefinitionBuilder{ + let builder = LinearBackoffDefinitionBuilder::new(); + self.builder = Some(BackoffStrategyDefinitionBuilder::Linear(builder)); + if let Some(BackoffStrategyDefinitionBuilder::Linear(ref mut builder)) = self.builder{ + builder + } + else{ + unreachable!("Builder should always be set to Linear"); + } + } + + /// Builds the configured BackoffStrategyDefinitions + pub fn build(self) -> BackoffStrategyDefinition{ + if let Some(builder) = self.builder{ + match builder{ + BackoffStrategyDefinitionBuilder::Constant(builder) => builder.build(), + BackoffStrategyDefinitionBuilder::Exponential(builder) => builder.build(), + BackoffStrategyDefinitionBuilder::Linear(builder) => builder.build(), + } + } + else{ + unreachable!("The backoff strategy must be configured") + } + } + +} + +/// Enumerates all supported BackoffStrategyDefinition builders +pub enum BackoffStrategyDefinitionBuilder{ + Constant(ConstantBackoffDefinitionBuilder), + Exponential(ExponentialBackoffDefinitionBuilder), + Linear(LinearBackoffDefinitionBuilder) +} + +/// Represents the service used to build ConstantBackoffDefinitions +pub struct ConstantBackoffDefinitionBuilder; +impl ConstantBackoffDefinitionBuilder{ + + /// Initializes a new ConstantBackoffDefinitionBuilder + pub fn new() -> Self{ + Self{} + } + + /// Builds the configures ConstantBackoffDefinition + pub fn build(self) -> BackoffStrategyDefinition{ + let mut strategy = BackoffStrategyDefinition::new(); + strategy.constant = Some(ConstantBackoffDefinition::new()); + strategy + } + +} + +/// Represents the service used to build ExponentialBackoffDefinitionBuilder +pub struct ExponentialBackoffDefinitionBuilder; +impl ExponentialBackoffDefinitionBuilder{ + + /// Initializes a new ExponentialBackoffDefinitionBuilder + pub fn new() -> Self{ + Self{} + } + + /// Builds the configures ExponentialBackoffDefinition + pub fn build(self) -> BackoffStrategyDefinition{ + let mut strategy = BackoffStrategyDefinition::new(); + strategy.exponential = Some(ExponentialBackoffDefinition::new()); + strategy + } + +} + +/// Represents the service used to build LinearBackoffDefinition +pub struct LinearBackoffDefinitionBuilder{ + increment: Option +} +impl LinearBackoffDefinitionBuilder{ + + /// Initializes a new LinearBackoffDefinitionBuilder + pub fn new() -> Self{ + Self{ increment: None } + } + + /// Sets the linear incrementation to the delay between retry attempts + pub fn with_increment(&mut self, increment: Duration) -> &mut Self{ + self.increment = Some(increment); + self + } + + /// Builds the configures LinearBackoffDefinition + pub fn build(self) -> BackoffStrategyDefinition{ + let mut strategy = BackoffStrategyDefinition::new(); + let mut linear = LinearBackoffDefinition::new(); + linear.increment = self.increment; + strategy.linear = Some(linear); + strategy + } + +} + +/// Represents the service used to build JitterDefinitions +pub struct JitterDefinitionBuilder{ + jitter: JitterDefinition +} +impl JitterDefinitionBuilder{ + + /// Initializes a new JitterDefinitionBuilder + pub fn new() -> Self{ + Self { jitter: JitterDefinition::default() } + } + + /// Sets the jitter range's minimum duration + pub fn from(&mut self, duration: Duration) -> &mut Self{ + self.jitter.from = duration; + self + } + + /// Sets the jitter range's maximum duration + pub fn to(&mut self, duration: Duration) -> &mut Self{ + self.jitter.to = duration; + self + } + + /// Builds the configured JitterDefinition + pub fn build(self) -> JitterDefinition{ + self.jitter + } + +} \ No newline at end of file diff --git a/builders/src/services/timeout.rs b/builders/src/services/timeout.rs new file mode 100644 index 0000000..4c71a05 --- /dev/null +++ b/builders/src/services/timeout.rs @@ -0,0 +1,34 @@ +use serverless_workflow_core::models::duration::*; +use serverless_workflow_core::models::timeout::*; + +/// Represents a service used to build TimeoutDefinitions +pub struct TimeoutDefinitionBuilder { + timeout: TimeoutDefinition +} +impl TimeoutDefinitionBuilder { + + /// Initializes a new TimeoutDefinitionBuilder + pub fn new() -> Self { + Self { + timeout: TimeoutDefinition::default() + } + } + + /// Sets the duration after which to timeout + pub fn after(&mut self, duration: Duration) -> &mut Self{ + self.timeout.after = OneOfDurationOrIso8601Expression::Duration(duration); + self + } + + /// Sets the ISO 8601 expression of the duration after which to timeout + pub fn after_expression(&mut self, duration: String) -> &mut Self{ + self.timeout.after = OneOfDurationOrIso8601Expression::Iso8601Expression(duration); + self + } + + /// Builds the configured TimeoutDefinition + pub fn build(self) -> TimeoutDefinition { + self.timeout + } + +} \ No newline at end of file diff --git a/builders/src/services/workflow.rs b/builders/src/services/workflow.rs new file mode 100644 index 0000000..a72fe80 --- /dev/null +++ b/builders/src/services/workflow.rs @@ -0,0 +1,125 @@ +use crate::services::authentication::*; +use crate::services::task::*; +use crate::services::timeout::*; +use serverless_workflow_core::models::timeout::*; +use serverless_workflow_core::models::workflow::*; +use std::collections::HashMap; + +/// Represents the service used to build workflows +pub struct WorkflowBuilder{ + workflow: WorkflowDefinition +} +impl WorkflowBuilder{ + + /// Initializes a new WorkflowBuilder + pub fn new() -> Self{ + Self { + workflow: WorkflowDefinition::default() + } + } + + /// Sets the semantic version of the Serverless Workflow DSL used to define the workflow + pub fn use_dsl(mut self, version: &str) -> Self { + self.workflow.document.dsl = version.to_string(); + self + } + + /// Sets the workflow's namespace + pub fn with_namespace(mut self, namespace: &str) -> Self{ + self.workflow.document.namespace = namespace.to_string(); + self + } + + /// Sets the workflow's name + pub fn with_name(mut self, name: &str) -> Self{ + self.workflow.document.name = name.to_string(); + self + } + + /// Sets the workflow's version + pub fn with_version(mut self, version: &str) -> Self{ + self.workflow.document.version = version.to_string(); + self + } + + /// Sets the workflow's title + pub fn with_title(mut self, title: &str) -> Self{ + self.workflow.document.title = Some(title.to_string()); + self + } + + /// Sets the workflow's summary + pub fn with_summary(mut self, summary: &str) -> Self{ + self.workflow.document.summary = Some(summary.to_string()); + self + } + + /// Adds a new tag to the workflow + pub fn with_tag(mut self, name: &str, value: &str) -> Self{ + if self.workflow.document.tags.is_none(){ + self.workflow.document.tags = Some(HashMap::new()); + } + if let Some(tags) = &mut self.workflow.document.tags { + tags.insert(name.to_string(), value.to_string()); + } + self + } + + /// Sets the tags of the workflow + pub fn with_tags(mut self, tags: HashMap) -> Self{ + self.workflow.document.tags = Some(tags); + self + } + + /// Sets the workflow's timeout + pub fn with_timeout_reference(mut self, reference: &str) -> Self{ + self.workflow.timeout = Some(OneOfTimeoutDefinitionOrReference::Reference(reference.to_string())); + self + } + + /// Sets the workflow's timeout + pub fn with_timeout(mut self, setup: F) -> Self + where F: FnOnce(&mut TimeoutDefinitionBuilder){ + let mut builder = TimeoutDefinitionBuilder::new(); + setup(&mut builder); + let timeout = builder.build(); + self.workflow.timeout = Some(OneOfTimeoutDefinitionOrReference::Timeout(timeout)); + self + } + + /// Uses the specified authentication policy + pub fn use_authentication(mut self, name: &str, setup: F) -> Self + where F: FnOnce(&mut AuthenticationPolicyDefinitionBuilder){ + let mut builder = AuthenticationPolicyDefinitionBuilder::new(); + setup(&mut builder); + let authentication = builder.build(); + if self.workflow.use_.is_none(){ + self.workflow.use_ = Some(ComponentDefinitionCollection::default()); + } + if let Some(resources) = &mut self.workflow.use_ { + if resources.authentications.is_none(){ + resources.authentications = Some(HashMap::new()); + } + if let Some(authentications) = &mut resources.authentications{ + authentications.insert(name.to_string(), authentication); + } + }; + self + } + + /// Adds a new task with the specified name to the builder + pub fn do_(mut self, name: &str, setup: F) -> Self + where F: FnOnce(&mut GenericTaskDefinitionBuilder){ + let mut builder = GenericTaskDefinitionBuilder::new(); + setup(&mut builder); + let task = builder.build(); + self.workflow.do_.add(name.to_string(), task); + self + } + + /// Builds the configure WorkflowDefinition + pub fn build(self) -> WorkflowDefinition{ + self.workflow + } + +} \ No newline at end of file diff --git a/core/Cargo.toml b/core/Cargo.toml index 737be97..83ba02c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,7 +1,15 @@ [package] -name = "sdk-rust" -version = "0.1.0" +name = "serverless_workflow_core" +version = "1.0.0-alpha6" edition = "2021" +authors = ["The Serverless Workflow Authors "] +description = "Contains Serverless Workflow DSL models" +homepage = "https://serverlessworkflow.io" +repository = "https://github.com/serverlessworkflow/sdk-rust" +documentation = "https://github.com/serverlessworkflow/sdk-rust" +license = "Apache-2.0" +keywords = ["serverless-workflow", "serverless", "workflow", "dsl", "sdk", "models", "core"] +categories = ["dsl", "sdk", "models", "core"] [dependencies] serde = "1.0" diff --git a/core/src/lib.rs b/core/src/lib.rs index 5dc9f73..749c030 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -19,7 +19,7 @@ mod unit_tests { let mut workflow = WorkflowDefinition::new(document); workflow.do_ = Map::new(); workflow.do_.add("callTask".to_string(), TaskDefinition::Call(CallTaskDefinition::new("http", None, Some(true)))); - workflow.do_.add("doTask".to_string(), TaskDefinition::Do(DoTaskDefinition::new(Map::from(vec![("set".to_string(), TaskDefinition::Wait(WaitTaskDefinition::new(Duration::default())))])))); + workflow.do_.add("doTask".to_string(), TaskDefinition::Do(DoTaskDefinition::new(Map::from(vec![("set".to_string(), TaskDefinition::Wait(WaitTaskDefinition::new(OneOfDurationOrIso8601Expression::Duration(Duration::default()))))])))); let json_serialization_result = serde_json::to_string_pretty(&workflow); let yaml_serialization_result = serde_yaml::to_string(&workflow); assert!(json_serialization_result.is_ok(), "JSON Serialization failed: {:?}", json_serialization_result.err()); diff --git a/core/src/models/any.rs b/core/src/models/any.rs index 8cbbd5b..2a974d4 100644 --- a/core/src/models/any.rs +++ b/core/src/models/any.rs @@ -6,12 +6,22 @@ use serde_yaml::Value as YamlValue; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum AnyValue { - /// Variant holding a string String(String), - /// Variant holding a JSON value - JsonValue(JsonValue), - /// Variant holding a YAML value - YamlValue(YamlValue) + Bool(bool), + Int8(i8), + Int16(i16), + Int32(i32), + Int64(i64), + UInt8(u8), + UInt16(u16), + UInt32(u32), + UInt64(u64), + Float32(f32), + Float64(f64), + Vec(Vec), + HashMap(std::collections::HashMap), + Json(JsonValue), + Yaml(YamlValue) } impl Default for AnyValue { fn default() -> Self { diff --git a/core/src/models/catalog.rs b/core/src/models/catalog.rs index 445c6df..a3f5b61 100644 --- a/core/src/models/catalog.rs +++ b/core/src/models/catalog.rs @@ -10,6 +10,6 @@ pub struct CatalogDefinition{ /// Gets/sets the endpoint that defines the root URL at which the catalog is located #[serde(rename = "endpoint")] - pub endpoint: OneOfEndpointDefinitionUri + pub endpoint: OneOfEndpointDefinitionOrUri } \ No newline at end of file diff --git a/core/src/models/duration.rs b/core/src/models/duration.rs index 1dca61d..7710821 100644 --- a/core/src/models/duration.rs +++ b/core/src/models/duration.rs @@ -1,4 +1,5 @@ use serde_derive::{Deserialize, Serialize}; +use std::fmt; /// Represents a duration #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] @@ -27,6 +28,61 @@ pub struct Duration{ } impl Duration{ + /// Initializes a new Duration from the specified amount of days + pub fn from_days(days: u64) -> Self{ + Self { + days: Some(days), + hours: None, + minutes: None, + seconds: None, + milliseconds: None + } + } + + /// Initializes a new Duration from the specified amount of hours + pub fn from_hours(hours: u64) -> Self{ + Self { + days: None, + hours: Some(hours), + minutes: None, + seconds: None, + milliseconds: None + } + } + + /// Initializes a new Duration from the specified amount of minutes + pub fn from_minutes(minutes: u64) -> Self{ + Self { + days: None, + hours: None, + minutes: Some(minutes), + seconds: None, + milliseconds: None + } + } + + /// Initializes a new Duration from the specified amount of seconds + pub fn from_seconds(seconds: u64) -> Self{ + Self { + days: None, + hours: None, + minutes: None, + seconds: Some(seconds), + milliseconds: None + } + } + + /// Initializes a new Duration from the specified amount of milliseconds + pub fn from_milliseconds(milliseconds: u64) -> Self{ + Self { + days: None, + hours: None, + minutes: None, + seconds: None, + milliseconds: Some(milliseconds) + } + } + /// Gets the the duration's total amount of days pub fn total_days(&self) -> f64{ self.total_hours() / 24.0 @@ -58,6 +114,27 @@ impl Duration{ } } +impl fmt::Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut parts = Vec::new(); + if let Some(days) = self.days { + parts.push(format!("{} days", days)); + } + if let Some(hours) = self.hours { + parts.push(format!("{} hours", hours)); + } + if let Some(minutes) = self.minutes { + parts.push(format!("{} minutes", minutes)); + } + if let Some(seconds) = self.seconds { + parts.push(format!("{} seconds", seconds)); + } + if let Some(milliseconds) = self.milliseconds { + parts.push(format!("{} milliseconds", milliseconds)); + } + write!(f, "{}", parts.join(" ")) + } +} /// Represents a value that can be either a Duration or an ISO 8601 duration expression #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -73,4 +150,12 @@ impl Default for OneOfDurationOrIso8601Expression { // Choose a default variant OneOfDurationOrIso8601Expression::Duration(Duration::default()) } +} +impl fmt::Display for OneOfDurationOrIso8601Expression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + OneOfDurationOrIso8601Expression::Duration(duration) => write!(f, "{}", duration), + OneOfDurationOrIso8601Expression::Iso8601Expression(expr) => write!(f, "{}", expr), + } + } } \ No newline at end of file diff --git a/core/src/models/event.rs b/core/src/models/event.rs index f2f3a81..fac9c82 100644 --- a/core/src/models/event.rs +++ b/core/src/models/event.rs @@ -16,7 +16,11 @@ pub struct EventConsumptionStrategyDefinition{ /// Gets/sets the single event to consume #[serde(rename = "one", skip_serializing_if = "Option::is_none")] - pub one: Option + pub one: Option, + + /// Gets/sets the consumption strategy, if any, that defines the events that must be consumed to stop listening + #[serde(rename = "until", skip_serializing_if = "Option::is_none")] + pub until: Option> } @@ -71,4 +75,17 @@ impl EventDefinition { with } } +} + +/// Represents a value that can be either a EventConsumptionStrategyDefinition or a runtime expression +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum OneOfEventConsumptionStrategyDefinitionOrExpression{ + Strategy(EventConsumptionStrategyDefinition), + Expression(String) +} +impl Default for OneOfEventConsumptionStrategyDefinitionOrExpression{ + fn default() -> Self { + OneOfEventConsumptionStrategyDefinitionOrExpression::Expression(String::default()) + } } \ No newline at end of file diff --git a/core/src/models/resource.rs b/core/src/models/resource.rs index f9f8e63..b442bd9 100644 --- a/core/src/models/resource.rs +++ b/core/src/models/resource.rs @@ -7,7 +7,11 @@ pub struct ExternalResourceDefinition{ /// Gets/sets the external resource's name, if any #[serde(rename = "name", skip_serializing_if = "Option::is_none")] - pub name: Option + pub name: Option, + + /// Gets/sets the endpoint at which to get the defined resource + #[serde(rename = "endpoint")] + pub endpoint: OneOfEndpointDefinitionOrUri } @@ -28,15 +32,15 @@ pub struct EndpointDefinition{ /// Represents a value that can be either an EndpointDefinition or an Uri #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(untagged)] -pub enum OneOfEndpointDefinitionUri{ +pub enum OneOfEndpointDefinitionOrUri{ /// Variant holding an EndpointDefinition - EndpointDefinition(EndpointDefinition), + Endpoint(EndpointDefinition), /// Variant holding a URL Uri(String), } -impl Default for OneOfEndpointDefinitionUri { +impl Default for OneOfEndpointDefinitionOrUri { fn default() -> Self { // Choose a default variant. For example, default to an empty Uri. - OneOfEndpointDefinitionUri::Uri(String::new()) + OneOfEndpointDefinitionOrUri::Uri(String::new()) } } \ No newline at end of file diff --git a/core/src/models/retry.rs b/core/src/models/retry.rs index ec8fd2c..fdbf52d 100644 --- a/core/src/models/retry.rs +++ b/core/src/models/retry.rs @@ -15,7 +15,7 @@ pub struct RetryPolicyDefinition{ /// Gets/sets the limits, if any, of the retry policy #[serde(rename = "limit", skip_serializing_if = "Option::is_none")] - pub limitlimit: Option, + pub limit: Option, /// Gets/sets the delay duration between retry attempts #[serde(rename = "delay", skip_serializing_if = "Option::is_none")] @@ -27,7 +27,7 @@ pub struct RetryPolicyDefinition{ /// Gets/sets the parameters, if any, that control the randomness or variability of the delay between retry attempts #[serde(rename = "jitter", skip_serializing_if = "Option::is_none")] - pub jitterjitter: Option + pub jitter: Option } @@ -51,7 +51,7 @@ pub struct RetryAttemptLimitDefinition{ /// Gets/sets the maximum attempts count #[serde(rename = "count", skip_serializing_if = "Option::is_none")] - pub count: Option, + pub count: Option, /// Gets/sets the duration limit, if any, for all retry attempts #[serde(rename = "duration", skip_serializing_if = "Option::is_none")] @@ -75,18 +75,46 @@ pub struct BackoffStrategyDefinition{ #[serde(rename = "linear", skip_serializing_if = "Option::is_none")] pub linear: Option +} +impl BackoffStrategyDefinition{ + + /// Initializes a new BackoffStrategyDefinition + pub fn new() -> Self{ + Self{ + constant: None, + exponential: None, + linear: None + } + } + } /// Represents the definition of a constant backoff #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub struct ConstantBackoffDefinition{ +} +impl ConstantBackoffDefinition{ + + /// Initializes a new ConstantBackoffDefinition + pub fn new() -> Self{ + Self{} + } + } /// Represents the definition of an exponential backoff #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub struct ExponentialBackoffDefinition{ +} +impl ExponentialBackoffDefinition{ + + /// Initializes a new ExponentialBackoffDefinition + pub fn new() -> Self{ + Self{} + } + } /// Represents the definition of a linear backoff @@ -97,6 +125,14 @@ pub struct LinearBackoffDefinition{ #[serde(rename = "increment", skip_serializing_if = "Option::is_none")] pub increment: Option +} +impl LinearBackoffDefinition{ + + /// Initializes a new LinearBackoffDefinition + pub fn new() -> Self{ + Self{ increment: None } + } + } /// Represents the definition of the parameters that control the randomness or variability of a delay, typically between retry attempts diff --git a/core/src/models/task.rs b/core/src/models/task.rs index 97537c4..553a9ee 100644 --- a/core/src/models/task.rs +++ b/core/src/models/task.rs @@ -318,13 +318,13 @@ pub struct ListenerDefinition{ /// Gets/sets the listener's target #[serde(rename = "to")] - pub to_: EventConsumptionStrategyDefinition + pub to: EventConsumptionStrategyDefinition } impl ListenerDefinition { - pub fn new(to_: EventConsumptionStrategyDefinition) -> Self{ + pub fn new(to: EventConsumptionStrategyDefinition) -> Self{ Self{ - to_ + to } } } @@ -359,6 +359,14 @@ pub struct RaiseErrorDefinition{ #[serde(rename = "error")] pub error: OneOfErrorDefinitionOrReference +} +impl RaiseErrorDefinition{ + + /// Initializes a new RaiseErrorDefinition + pub fn new(error: OneOfErrorDefinitionOrReference) -> Self{ + Self { error } + } + } /// Represents the configuration of a task used to run a given process @@ -480,6 +488,10 @@ pub struct ContainerProcessDefinition{ #[serde(rename = "image")] pub image: String, + /// Gets/sets the name of the container to run + #[serde(rename = "name")] + pub name: Option, + /// Gets/sets the command, if any, to execute on the container #[serde(rename = "command", skip_serializing_if = "Option::is_none")] pub command: Option, @@ -498,9 +510,10 @@ pub struct ContainerProcessDefinition{ } impl ContainerProcessDefinition { - pub fn new(image: &str, command: Option, ports: Option>, volumes: Option>, environment: Option>) -> Self{ + pub fn new(image: &str, name: Option, command: Option, ports: Option>, volumes: Option>, environment: Option>) -> Self{ Self { image: image.to_string(), + name, command, ports, volumes, @@ -527,7 +540,7 @@ pub struct ScriptProcessDefinition{ /// Gets/sets a key/value mapping of the arguments, if any, to pass to the script to run #[serde(rename = "arguments", skip_serializing_if = "Option::is_none")] - pub arguments: Option>, + pub arguments: Option>, /// Gets/sets a key/value mapping of the environment variables, if any, to use when running the configured process #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] @@ -537,7 +550,7 @@ pub struct ScriptProcessDefinition{ impl ScriptProcessDefinition { /// Initializes a new script from code - pub fn from_code(language: &str, code: String, arguments: Option>, environment: Option>) -> Self{ + pub fn from_code(language: &str, code: String, arguments: Option>, environment: Option>) -> Self{ Self { language: language.to_string(), code: Some(code), @@ -548,7 +561,7 @@ impl ScriptProcessDefinition { } /// Initializes a new script from an external resource - pub fn from_source(language: &str, source: ExternalResourceDefinition, arguments: Option>, environment: Option>) -> Self{ + pub fn from_source(language: &str, source: ExternalResourceDefinition, arguments: Option>, environment: Option>) -> Self{ Self { language: language.to_string(), code: None, @@ -633,9 +646,9 @@ impl TypedTaskDefinition for SetTaskDefinition { } } impl SetTaskDefinition { - pub fn new(set: HashMap) -> Self{ + pub fn new() -> Self{ Self { - set + set: HashMap::new() } } } @@ -655,9 +668,9 @@ impl TypedTaskDefinition for SwitchTaskDefinition { } } impl SwitchTaskDefinition { - pub fn new(switch: Map) -> Self{ + pub fn new() -> Self{ Self { - switch + switch: Map::new() } } } @@ -749,7 +762,7 @@ pub struct WaitTaskDefinition{ /// Gets/sets the amount of time to wait before resuming workflow #[serde(rename = "duration")] - pub duration: Duration + pub duration: OneOfDurationOrIso8601Expression } impl TypedTaskDefinition for WaitTaskDefinition { @@ -758,7 +771,7 @@ impl TypedTaskDefinition for WaitTaskDefinition { } } impl WaitTaskDefinition { - pub fn new(duration: Duration) -> Self{ + pub fn new(duration: OneOfDurationOrIso8601Expression) -> Self{ Self { duration } diff --git a/core/src/models/workflow.rs b/core/src/models/workflow.rs index 334f7a5..6e5eff2 100644 --- a/core/src/models/workflow.rs +++ b/core/src/models/workflow.rs @@ -1,5 +1,7 @@ use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::models::any::*; +use crate::models::authentication::*; use crate::models::catalog::*; use crate::models::duration::*; use crate::models::error::*; @@ -12,9 +14,6 @@ use crate::models::retry::*; use crate::models::task::*; use crate::models::timeout::*; -use super::any::AnyValue; -use super::authentication::AuthenticationPolicyDefinition; - /// Gets the namespace to use by default for workflow definitions pub const DEFAULT_NAMESPACE: &str = "default"; // Provides the default namespace if not specified during deserialization