acts/model/act/
timeout.rs1use crate::{ActError, Result, Step};
2use regex::Regex;
3use serde::{Deserialize, Serialize, de};
4use std::str::FromStr;
5
6#[derive(Debug, Default, Clone, Serialize, Deserialize)]
7pub struct Timeout {
8 #[serde(default)]
9 pub on: String,
10 #[serde(default)]
11 pub steps: Vec<Step>,
12}
13
14#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize, Clone)]
15pub enum TimeoutUnit {
16 #[default]
17 Second,
18 Minute,
19 Hour,
20 Day,
21}
22
23#[derive(Debug, Default, PartialEq, Clone)]
24pub struct TimeoutLimit {
25 pub value: i64,
26 pub unit: TimeoutUnit,
27}
28
29impl FromStr for TimeoutLimit {
30 type Err = ActError;
31 fn from_str(s: &str) -> Result<Self> {
32 let value = TimeoutLimit::parse(s)?;
33 Ok(value)
34 }
35}
36
37impl std::fmt::Display for TimeoutLimit {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 f.write_fmt(format_args!(
40 "{}{}",
41 self.value,
42 match self.unit {
43 TimeoutUnit::Second => "s",
44 TimeoutUnit::Minute => "m",
45 TimeoutUnit::Hour => "h",
46 TimeoutUnit::Day => "d",
47 }
48 ))
49 }
50}
51
52impl<'de> Deserialize<'de> for TimeoutLimit {
53 fn deserialize<D>(deserializer: D) -> std::prelude::v1::Result<Self, D::Error>
54 where
55 D: serde::Deserializer<'de>,
56 {
57 struct TimeoutVisitor;
58 impl de::Visitor<'_> for TimeoutVisitor {
59 type Value = TimeoutLimit;
60 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
61 formatter.write_str("step timeout")
62 }
63
64 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
65 where
66 E: de::Error,
67 {
68 TimeoutLimit::parse(v).map_err(|err| E::custom(err))
69 }
70 }
71 deserializer.deserialize_any(TimeoutVisitor)
72 }
73}
74
75impl Serialize for TimeoutLimit {
76 fn serialize<S>(&self, serializer: S) -> std::prelude::v1::Result<S::Ok, S::Error>
77 where
78 S: serde::Serializer,
79 {
80 serializer.serialize_str(&self.to_string())
81 }
82}
83
84impl TimeoutLimit {
85 pub fn parse(expr: &str) -> Result<Self> {
86 let re = Regex::new(r"^(.*)(s|m|h|d)$").unwrap();
87 let caps = re.captures(expr);
88
89 if let Some(caps) = caps {
90 let value = caps.get(1).map_or("0", |m| m.as_str());
91 let unit = caps.get(2).map_or("s", |m| m.as_str());
92
93 let value = value
94 .parse::<i64>()
95 .map_err(|err| ActError::Model(format!("timeout parse error with '{err}'")))?;
96 let unit = TimeoutUnit::parse(unit)?;
97
98 return Ok(Self { value, unit });
99 }
100
101 Err(ActError::Model(format!(
102 "timeout parse error with '{expr}'"
103 )))
104 }
105
106 pub fn as_secs(&self) -> i64 {
107 match self.unit {
108 TimeoutUnit::Second => self.value,
109 TimeoutUnit::Minute => self.value * 60,
110 TimeoutUnit::Hour => self.value * 60 * 60,
111 TimeoutUnit::Day => self.value * 60 * 60 * 24,
112 }
113 }
114}
115
116impl TimeoutUnit {
117 fn parse(expr: &str) -> Result<Self> {
118 match expr {
119 "s" => Ok(TimeoutUnit::Second),
120 "m" => Ok(TimeoutUnit::Minute),
121 "h" => Ok(TimeoutUnit::Hour),
122 "d" => Ok(TimeoutUnit::Day),
123 _ => Err(ActError::Model(format!(
124 "timeout parse error with '{expr}'"
125 ))),
126 }
127 }
128}
129
130impl Timeout {
131 pub fn new() -> Self {
132 Self::default()
133 }
134 pub fn with_on(mut self, v: &str) -> Self {
135 self.on = v.to_string();
138 self
139 }
140
141 pub fn with_step(mut self, build: fn(Step) -> Step) -> Self {
142 self.steps.push(build(Step::default()));
143
144 self
145 }
146}