1use std::cell::RefCell;
2use std::time::{Duration, SystemTime, UNIX_EPOCH};
3
4use prost_types::Timestamp;
5use tonic::Request;
6use tonic::metadata::MetadataValue;
7
8use crate::HatchetError;
9
10pub(crate) fn proto_timestamp_now() -> Result<Timestamp, HatchetError> {
11 let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
12
13 Ok(Timestamp {
14 seconds: now.as_secs() as i64,
15 nanos: now.subsec_nanos() as i32,
16 })
17}
18
19pub(crate) fn add_grpc_auth_header<T>(
20 request: &mut Request<T>,
21 token: &str,
22) -> Result<(), HatchetError> {
23 let token_header: MetadataValue<_> = format!("Bearer {}", token).parse().map_err(
24 |e: tonic::metadata::errors::InvalidMetadataValue| {
25 HatchetError::InvalidAuthHeader(e.to_string())
26 },
27 )?;
28 request.metadata_mut().insert("authorization", token_header);
29 Ok(())
30}
31
32pub(crate) fn duration_to_expr(duration: Duration) -> String {
34 const HOUR: u64 = 3600;
35 const MINUTE: u64 = 60;
36
37 let seconds = duration.as_secs();
38
39 if seconds == 0 {
40 return String::from("0s");
41 }
42 if seconds.is_multiple_of(HOUR) {
43 return format!("{}h", seconds / HOUR);
44 }
45 if seconds.is_multiple_of(MINUTE) {
46 return format!("{}m", seconds / MINUTE);
47 }
48 format!("{}s", seconds)
49}
50
51#[derive(Clone, Debug)]
52pub(crate) struct ExecutionContext {
53 pub(crate) workflow_run_id: String,
54 pub(crate) task_run_external_id: String,
55 pub(crate) child_index: i32,
56}
57
58tokio::task_local! {
59 pub(crate) static EXECUTION_CONTEXT: RefCell<ExecutionContext>;
60}
61
62#[derive(Debug, Clone, Copy)]
75pub struct EmptyModel;
76
77impl serde::Serialize for EmptyModel {
78 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79 where
80 S: serde::Serializer,
81 {
82 use serde::ser::SerializeMap;
83 let map = serializer.serialize_map(Some(0))?;
84 map.end()
85 }
86}
87
88impl<'de> serde::Deserialize<'de> for EmptyModel {
89 fn deserialize<D>(deserializer: D) -> Result<EmptyModel, D::Error>
90 where
91 D: serde::Deserializer<'de>,
92 {
93 use std::fmt;
94
95 use serde::de::{self, MapAccess, Visitor};
96
97 struct EmptyModelVisitor;
98
99 impl<'de> Visitor<'de> for EmptyModelVisitor {
100 type Value = EmptyModel;
101
102 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
103 formatter.write_str("an empty object")
104 }
105
106 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
107 where
108 A: MapAccess<'de>,
109 {
110 if map.next_entry::<String, serde_json::Value>()?.is_some() {
111 return Err(de::Error::custom("expected empty object"));
112 }
113 Ok(EmptyModel)
114 }
115 }
116
117 deserializer.deserialize_map(EmptyModelVisitor)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_empty_input_serialization() {
127 let empty_model = EmptyModel;
128 let serialized = serde_json::to_value(empty_model).unwrap();
129 assert_eq!(serialized, serde_json::json!({}));
130 }
131
132 #[test]
133 fn test_empty_input_deserialization() {
134 let json = serde_json::json!({});
135 let empty_model: EmptyModel = serde_json::from_value(json).unwrap();
136 assert_eq!(format!("{:?}", empty_model), "EmptyModel");
137 }
138
139 #[test]
140 fn test_duration_to_expr_hours() {
141 assert_eq!(duration_to_expr(Duration::from_secs(3600)), "1h");
142 assert_eq!(duration_to_expr(Duration::from_secs(7200)), "2h");
143 assert_eq!(duration_to_expr(Duration::from_secs(18000)), "5h");
144 }
145
146 #[test]
147 fn test_duration_to_expr_minutes() {
148 assert_eq!(duration_to_expr(Duration::from_secs(60)), "1m");
149 assert_eq!(duration_to_expr(Duration::from_secs(120)), "2m");
150 assert_eq!(duration_to_expr(Duration::from_secs(300)), "5m");
151 assert_eq!(duration_to_expr(Duration::from_secs(3540)), "59m");
152 }
153
154 #[test]
155 fn test_duration_to_expr_seconds() {
156 assert_eq!(duration_to_expr(Duration::from_secs(1)), "1s");
157 assert_eq!(duration_to_expr(Duration::from_secs(30)), "30s");
158 assert_eq!(duration_to_expr(Duration::from_secs(45)), "45s");
159 assert_eq!(duration_to_expr(Duration::from_secs(59)), "59s");
160 assert_eq!(duration_to_expr(Duration::from_secs(3661)), "3661s");
161 }
162
163 #[test]
164 fn test_duration_to_expr_zero() {
165 assert_eq!(duration_to_expr(Duration::from_secs(0)), "0s");
166 }
167}