1use std::fmt;
2use std::sync::Arc;
3use std::time::Duration;
4
5use rivet_envoy_client::config::HttpRequest;
6
7use crate::inspector::InspectorTabEntry;
8
9const DEFAULT_STATE_SAVE_INTERVAL: Duration = Duration::from_secs(1);
10const DEFAULT_CREATE_VARS_TIMEOUT: Duration = Duration::from_secs(5);
11const DEFAULT_CREATE_CONN_STATE_TIMEOUT: Duration = Duration::from_secs(5);
12const DEFAULT_ON_BEFORE_CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
13const DEFAULT_ON_CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
14const DEFAULT_ON_MIGRATE_TIMEOUT: Duration = Duration::from_secs(30);
15const DEFAULT_ACTION_TIMEOUT: Duration = Duration::from_secs(60);
16const DEFAULT_SLEEP_TIMEOUT: Duration = Duration::from_secs(30);
17const DEFAULT_SLEEP_GRACE_PERIOD: Duration = Duration::from_secs(15);
18const DEFAULT_CONNECTION_LIVENESS_TIMEOUT: Duration = Duration::from_millis(2500);
19const DEFAULT_CONNECTION_LIVENESS_INTERVAL: Duration = Duration::from_secs(5);
20const DEFAULT_MAX_QUEUE_SIZE: u32 = 1000;
21const DEFAULT_MAX_QUEUE_MESSAGE_SIZE: u32 = 65_536;
22const DEFAULT_MAX_INCOMING_MESSAGE_SIZE: u32 = 65_536;
23const DEFAULT_MAX_OUTGOING_MESSAGE_SIZE: u32 = 1_048_576;
24
25#[derive(Clone)]
26pub enum CanHibernateWebSocket {
27 Bool(bool),
28 Callback(Arc<dyn Fn(&HttpRequest) -> bool + Send + Sync>),
29}
30
31impl fmt::Debug for CanHibernateWebSocket {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
35 Self::Callback(_) => f.write_str("Callback(..)"),
36 }
37 }
38}
39
40impl Default for CanHibernateWebSocket {
41 fn default() -> Self {
42 Self::Bool(false)
43 }
44}
45
46#[derive(Clone, Debug, Default)]
47pub struct ActorConfigOverrides {
48 pub sleep_grace_period: Option<Duration>,
49}
50
51#[derive(Clone, Debug)]
52pub struct ActionDefinition {
53 pub name: String,
54}
55
56#[derive(Clone, Debug)]
57pub struct ActorConfig {
58 pub name: Option<String>,
59 pub icon: Option<String>,
60 pub has_database: bool,
63 pub remote_sqlite: bool,
64 pub has_state: bool,
67 pub can_hibernate_websocket: CanHibernateWebSocket,
68 pub state_save_interval: Duration,
69 pub create_vars_timeout: Duration,
70 pub create_conn_state_timeout: Duration,
71 pub on_before_connect_timeout: Duration,
72 pub on_connect_timeout: Duration,
73 pub on_migrate_timeout: Duration,
74 pub action_timeout: Duration,
75 pub sleep_timeout: Duration,
76 pub no_sleep: bool,
77 pub sleep_grace_period: Duration,
78 pub sleep_grace_period_overridden: bool,
79 pub connection_liveness_timeout: Duration,
80 pub connection_liveness_interval: Duration,
81 pub max_queue_size: u32,
82 pub max_queue_message_size: u32,
83 pub max_incoming_message_size: u32,
84 pub max_outgoing_message_size: u32,
85 pub preload_max_workflow_bytes: Option<u64>,
86 pub preload_max_connections_bytes: Option<u64>,
87 pub overrides: Option<ActorConfigOverrides>,
88 pub actions: Vec<ActionDefinition>,
89 pub inspector_tabs: Vec<InspectorTabEntry>,
92}
93
94#[derive(Clone, Debug, Default)]
96pub struct ActorConfigInput {
97 pub name: Option<String>,
98 pub icon: Option<String>,
99 pub has_database: Option<bool>,
100 pub remote_sqlite: Option<bool>,
101 pub has_state: Option<bool>,
102 pub can_hibernate_websocket: Option<bool>,
103 pub state_save_interval_ms: Option<u32>,
104 pub create_vars_timeout_ms: Option<u32>,
105 pub create_conn_state_timeout_ms: Option<u32>,
106 pub on_before_connect_timeout_ms: Option<u32>,
107 pub on_connect_timeout_ms: Option<u32>,
108 pub on_migrate_timeout_ms: Option<u32>,
109 pub action_timeout_ms: Option<u32>,
110 pub sleep_timeout_ms: Option<u32>,
111 pub no_sleep: Option<bool>,
112 pub sleep_grace_period_ms: Option<u32>,
113 pub connection_liveness_timeout_ms: Option<u32>,
114 pub connection_liveness_interval_ms: Option<u32>,
115 pub max_queue_size: Option<u32>,
116 pub max_queue_message_size: Option<u32>,
117 pub max_incoming_message_size: Option<u32>,
118 pub max_outgoing_message_size: Option<u32>,
119 pub preload_max_workflow_bytes: Option<f64>,
120 pub preload_max_connections_bytes: Option<f64>,
121 pub actions: Option<Vec<ActionDefinition>>,
122 pub inspector_tabs: Option<Vec<InspectorTabEntry>>,
123}
124
125impl ActorConfig {
126 pub fn from_input(config: ActorConfigInput) -> Self {
127 let mut actor_config = Self {
128 name: config.name,
129 icon: config.icon,
130 has_database: config.has_database.unwrap_or(false),
131 remote_sqlite: config.remote_sqlite.unwrap_or(false),
132 has_state: config.has_state.unwrap_or(false),
133 ..Self::default()
134 };
135 if let Some(can_hibernate_websocket) = config.can_hibernate_websocket {
136 actor_config.can_hibernate_websocket =
137 CanHibernateWebSocket::Bool(can_hibernate_websocket);
138 }
139 if let Some(value) = config.state_save_interval_ms {
140 actor_config.state_save_interval = duration_ms(value);
141 }
142 if let Some(value) = config.create_vars_timeout_ms {
143 actor_config.create_vars_timeout = duration_ms(value);
144 }
145 if let Some(value) = config.create_conn_state_timeout_ms {
146 actor_config.create_conn_state_timeout = duration_ms(value);
147 }
148 if let Some(value) = config.on_before_connect_timeout_ms {
149 actor_config.on_before_connect_timeout = duration_ms(value);
150 }
151 if let Some(value) = config.on_connect_timeout_ms {
152 actor_config.on_connect_timeout = duration_ms(value);
153 }
154 if let Some(value) = config.on_migrate_timeout_ms {
155 actor_config.on_migrate_timeout = duration_ms(value);
156 }
157 if let Some(value) = config.action_timeout_ms {
158 actor_config.action_timeout = duration_ms(value);
159 }
160 if let Some(value) = config.sleep_timeout_ms {
161 actor_config.sleep_timeout = duration_ms(value);
162 }
163 if let Some(value) = config.no_sleep {
164 actor_config.no_sleep = value;
165 }
166 if let Some(value) = config.sleep_grace_period_ms {
167 actor_config.sleep_grace_period = duration_ms(value);
168 actor_config.sleep_grace_period_overridden = true;
169 }
170 if let Some(value) = config.connection_liveness_timeout_ms {
171 actor_config.connection_liveness_timeout = duration_ms(value);
172 }
173 if let Some(value) = config.connection_liveness_interval_ms {
174 actor_config.connection_liveness_interval = duration_ms(value);
175 }
176 if let Some(value) = config.max_queue_size {
177 actor_config.max_queue_size = value;
178 }
179 if let Some(value) = config.max_queue_message_size {
180 actor_config.max_queue_message_size = value;
181 }
182 if let Some(value) = config.max_incoming_message_size {
183 actor_config.max_incoming_message_size = value;
184 }
185 if let Some(value) = config.max_outgoing_message_size {
186 actor_config.max_outgoing_message_size = value;
187 }
188 actor_config.preload_max_workflow_bytes =
189 config.preload_max_workflow_bytes.map(|value| value as u64);
190 actor_config.preload_max_connections_bytes = config
191 .preload_max_connections_bytes
192 .map(|value| value as u64);
193 if let Some(actions) = config.actions {
194 actor_config.actions = actions;
195 }
196 if let Some(tabs) = config.inspector_tabs {
197 actor_config.inspector_tabs = tabs;
198 }
199
200 actor_config
201 }
202
203 pub fn effective_sleep_grace_period(&self) -> Duration {
204 cap_duration(
205 self.sleep_grace_period,
206 self.overrides
207 .as_ref()
208 .and_then(|overrides| overrides.sleep_grace_period),
209 )
210 }
211
212 pub fn validate(&self) -> anyhow::Result<()> {
217 crate::inspector::validate_inspector_tabs(&self.inspector_tabs)?;
218 Ok(())
219 }
220}
221
222impl Default for ActorConfig {
223 fn default() -> Self {
224 Self {
225 name: None,
226 icon: None,
227 has_database: false,
228 remote_sqlite: false,
229 has_state: false,
230 can_hibernate_websocket: CanHibernateWebSocket::default(),
231 state_save_interval: DEFAULT_STATE_SAVE_INTERVAL,
232 create_vars_timeout: DEFAULT_CREATE_VARS_TIMEOUT,
233 create_conn_state_timeout: DEFAULT_CREATE_CONN_STATE_TIMEOUT,
234 on_before_connect_timeout: DEFAULT_ON_BEFORE_CONNECT_TIMEOUT,
235 on_connect_timeout: DEFAULT_ON_CONNECT_TIMEOUT,
236 on_migrate_timeout: DEFAULT_ON_MIGRATE_TIMEOUT,
237 action_timeout: DEFAULT_ACTION_TIMEOUT,
238 sleep_timeout: DEFAULT_SLEEP_TIMEOUT,
239 no_sleep: false,
240 sleep_grace_period: DEFAULT_SLEEP_GRACE_PERIOD,
241 sleep_grace_period_overridden: false,
242 connection_liveness_timeout: DEFAULT_CONNECTION_LIVENESS_TIMEOUT,
243 connection_liveness_interval: DEFAULT_CONNECTION_LIVENESS_INTERVAL,
244 max_queue_size: DEFAULT_MAX_QUEUE_SIZE,
245 max_queue_message_size: DEFAULT_MAX_QUEUE_MESSAGE_SIZE,
246 max_incoming_message_size: DEFAULT_MAX_INCOMING_MESSAGE_SIZE,
247 max_outgoing_message_size: DEFAULT_MAX_OUTGOING_MESSAGE_SIZE,
248 preload_max_workflow_bytes: None,
249 preload_max_connections_bytes: None,
250 overrides: None,
251 actions: Vec::new(),
252 inspector_tabs: Vec::new(),
253 }
254 }
255}
256
257fn cap_duration(duration: Duration, override_duration: Option<Duration>) -> Duration {
258 if let Some(override_duration) = override_duration {
259 duration.min(override_duration)
260 } else {
261 duration
262 }
263}
264
265fn duration_ms(value: u32) -> Duration {
266 Duration::from_millis(u64::from(value))
267}
268
269#[cfg(test)]
271#[path = "../../tests/config.rs"]
272mod tests;