Skip to main content

fakecloud_sns/
state.rs

1use chrono::{DateTime, Utc};
2use parking_lot::RwLock;
3use std::collections::{BTreeMap, HashMap};
4use std::sync::Arc;
5
6#[derive(Debug, Clone)]
7pub struct SnsTopic {
8    pub topic_arn: String,
9    pub name: String,
10    pub attributes: HashMap<String, String>,
11    pub tags: Vec<(String, String)>,
12    pub is_fifo: bool,
13    pub created_at: DateTime<Utc>,
14}
15
16#[derive(Debug, Clone)]
17pub struct SnsSubscription {
18    pub subscription_arn: String,
19    pub topic_arn: String,
20    pub protocol: String,
21    pub endpoint: String,
22    pub owner: String,
23    pub attributes: HashMap<String, String>,
24    pub confirmed: bool,
25    /// Token used for HTTP/HTTPS subscription confirmation.
26    pub confirmation_token: Option<String>,
27}
28
29/// An SNS message attribute (key-value with a data type).
30#[derive(Debug, Clone)]
31pub struct MessageAttribute {
32    pub data_type: String,
33    pub string_value: Option<String>,
34    pub binary_value: Option<Vec<u8>>,
35}
36
37#[derive(Debug, Clone)]
38pub struct PublishedMessage {
39    pub message_id: String,
40    pub topic_arn: String,
41    pub message: String,
42    pub subject: Option<String>,
43    pub message_attributes: HashMap<String, MessageAttribute>,
44    pub message_group_id: Option<String>,
45    pub message_dedup_id: Option<String>,
46    pub timestamp: DateTime<Utc>,
47}
48
49#[derive(Debug, Clone)]
50pub struct PlatformApplication {
51    pub arn: String,
52    pub name: String,
53    pub platform: String,
54    pub attributes: HashMap<String, String>,
55    pub endpoints: HashMap<String, PlatformEndpoint>,
56}
57
58#[derive(Debug, Clone)]
59pub struct PlatformEndpoint {
60    pub arn: String,
61    pub token: String,
62    pub attributes: HashMap<String, String>,
63    pub enabled: bool,
64    pub messages: Vec<PublishedMessage>,
65}
66
67/// A recorded Lambda invocation from SNS delivery.
68#[derive(Debug, Clone)]
69pub struct LambdaInvocation {
70    pub function_arn: String,
71    pub message: String,
72    pub subject: Option<String>,
73    pub timestamp: DateTime<Utc>,
74}
75
76/// A recorded email delivery from SNS (stub).
77#[derive(Debug, Clone)]
78pub struct SentEmail {
79    pub email_address: String,
80    pub message: String,
81    pub subject: Option<String>,
82    pub topic_arn: String,
83    pub timestamp: DateTime<Utc>,
84}
85
86pub struct SnsState {
87    pub account_id: String,
88    pub region: String,
89    pub endpoint: String,
90    pub topics: BTreeMap<String, SnsTopic>, // arn -> topic (ordered for predictable iteration)
91    pub subscriptions: BTreeMap<String, SnsSubscription>, // sub_arn -> subscription
92    pub published: Vec<PublishedMessage>,
93    pub platform_applications: BTreeMap<String, PlatformApplication>,
94    pub sms_attributes: HashMap<String, String>,
95    pub opted_out_numbers: Vec<String>,
96    pub sms_messages: Vec<(String, String)>, // (phone_number, message)
97    /// Recorded Lambda invocations (stub deliveries).
98    pub lambda_invocations: Vec<LambdaInvocation>,
99    /// Recorded email deliveries (stub — not actually sent).
100    pub sent_emails: Vec<SentEmail>,
101}
102
103impl SnsState {
104    pub fn new(account_id: &str, region: &str, endpoint: &str) -> Self {
105        Self {
106            account_id: account_id.to_string(),
107            region: region.to_string(),
108            endpoint: endpoint.to_string(),
109            topics: BTreeMap::new(),
110            subscriptions: BTreeMap::new(),
111            published: Vec::new(),
112            platform_applications: BTreeMap::new(),
113            sms_attributes: HashMap::new(),
114            opted_out_numbers: Vec::new(),
115            sms_messages: Vec::new(),
116            lambda_invocations: Vec::new(),
117            sent_emails: Vec::new(),
118        }
119    }
120
121    pub fn reset(&mut self) {
122        self.topics.clear();
123        self.subscriptions.clear();
124        self.published.clear();
125        self.platform_applications.clear();
126        self.sms_attributes.clear();
127        self.opted_out_numbers.clear();
128        self.sms_messages.clear();
129        self.lambda_invocations.clear();
130        self.sent_emails.clear();
131    }
132
133    /// Seed default opt-out phone numbers.
134    pub fn seed_default_opted_out(&mut self) {
135        if self.opted_out_numbers.is_empty() {
136            self.opted_out_numbers.push("+15005550099".to_string());
137            self.opted_out_numbers.push("+447428545399".to_string());
138        }
139    }
140}
141
142pub type SharedSnsState = Arc<RwLock<SnsState>>;