Skip to main content

fakecloud_swf/
shared.rs

1//! Primitives shared across the Amazon SWF handlers: ARN synthesis, run-id
2//! minting, timestamps, and the type/token key derivation. Kept in one place so
3//! the register / describe / poll paths cannot diverge on wire format.
4
5/// Current time as awsJson1_0 epoch-seconds (a floating-point number). SWF's
6/// `Timestamp` shape carries no `@timestampFormat`, so awsJson1_0's default
7/// epoch-seconds applies (SWF returns e.g. `1420070400.123`).
8pub fn now_epoch() -> f64 {
9    chrono::Utc::now().timestamp_millis() as f64 / 1000.0
10}
11
12/// A fresh, AWS-shaped SWF run id: a base64url-ish opaque token AWS returns from
13/// `StartWorkflowExecution`. We mint a stable random 43-ish char id; the exact
14/// alphabet is opaque to clients, they only echo it back.
15pub fn new_run_id() -> String {
16    // Two v4 UUIDs (simple, no dashes) give a 64-hex opaque token, matching the
17    // opaque-string contract SWF run ids satisfy.
18    format!(
19        "{}{}",
20        uuid::Uuid::new_v4().simple(),
21        uuid::Uuid::new_v4().simple()
22    )
23}
24
25/// A fresh opaque task token (decision or activity). Clients treat it as opaque.
26pub fn new_task_token() -> String {
27    format!(
28        "AAAAK{}{}",
29        uuid::Uuid::new_v4().simple(),
30        uuid::Uuid::new_v4().simple()
31    )
32}
33
34/// Amazon SWF domain ARN, `arn:aws:swf:{region}:{account}:/domain/{name}`.
35pub fn domain_arn(region: &str, account: &str, name: &str) -> String {
36    format!("arn:aws:swf:{region}:{account}:/domain/{name}")
37}
38
39/// Internal storage key for an activity or workflow type: `name` + a unit
40/// separator + `version`. The separator can never appear in a Smithy `Name` or
41/// `Version` value, so the key round-trips unambiguously.
42pub fn type_key(name: &str, version: &str) -> String {
43    format!("{name}\u{1}{version}")
44}
45
46/// Split a [`type_key`] back into `(name, version)`.
47pub fn split_type_key(key: &str) -> Option<(&str, &str)> {
48    key.split_once('\u{1}')
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn type_key_round_trips() {
57        let k = type_key("send-email", "1.0");
58        assert_eq!(split_type_key(&k), Some(("send-email", "1.0")));
59    }
60
61    #[test]
62    fn domain_arn_shape() {
63        assert_eq!(
64            domain_arn("us-east-1", "000000000000", "orders"),
65            "arn:aws:swf:us-east-1:000000000000:/domain/orders"
66        );
67    }
68
69    #[test]
70    fn run_ids_are_unique_and_shaped() {
71        let a = new_run_id();
72        let b = new_run_id();
73        assert_ne!(a, b);
74        assert_eq!(a.len(), 64);
75        assert!(a.chars().all(|c| c.is_ascii_hexdigit()));
76    }
77}