1use serde::{Deserialize, Serialize};
10use time::OffsetDateTime;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum SailboxStatus {
16 Running,
18 Paused,
20 Sleeping,
22 Failed,
24 Terminated,
26 Other(String),
28}
29
30impl SailboxStatus {
31 pub fn as_str(&self) -> &str {
33 match self {
34 SailboxStatus::Running => "running",
35 SailboxStatus::Paused => "paused",
36 SailboxStatus::Sleeping => "sleeping",
37 SailboxStatus::Failed => "failed",
38 SailboxStatus::Terminated => "terminated",
39 SailboxStatus::Other(s) => s,
40 }
41 }
42}
43
44impl From<&str> for SailboxStatus {
45 fn from(s: &str) -> SailboxStatus {
46 match s {
47 "running" => SailboxStatus::Running,
48 "paused" => SailboxStatus::Paused,
49 "sleeping" => SailboxStatus::Sleeping,
50 "failed" => SailboxStatus::Failed,
51 "terminated" => SailboxStatus::Terminated,
52 other => SailboxStatus::Other(other.to_string()),
53 }
54 }
55}
56
57impl std::fmt::Display for SailboxStatus {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 f.write_str(self.as_str())
60 }
61}
62
63impl Serialize for SailboxStatus {
64 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
65 serializer.serialize_str(self.as_str())
66 }
67}
68
69impl<'de> Deserialize<'de> for SailboxStatus {
70 fn deserialize<D: serde::Deserializer<'de>>(
71 deserializer: D,
72 ) -> Result<SailboxStatus, D::Error> {
73 Ok(SailboxStatus::from(
74 String::deserialize(deserializer)?.as_str(),
75 ))
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum SailboxStatusFilter {
84 Running,
86 Paused,
88 Sleeping,
90 Failed,
92 Terminated,
94}
95
96impl SailboxStatusFilter {
97 pub fn as_str(&self) -> &'static str {
99 match self {
100 SailboxStatusFilter::Running => "running",
101 SailboxStatusFilter::Paused => "paused",
102 SailboxStatusFilter::Sleeping => "sleeping",
103 SailboxStatusFilter::Failed => "failed",
104 SailboxStatusFilter::Terminated => "terminated",
105 }
106 }
107
108 pub fn parse(s: &str) -> Option<SailboxStatusFilter> {
110 match s {
111 "running" => Some(SailboxStatusFilter::Running),
112 "paused" => Some(SailboxStatusFilter::Paused),
113 "sleeping" => Some(SailboxStatusFilter::Sleeping),
114 "failed" => Some(SailboxStatusFilter::Failed),
115 "terminated" => Some(SailboxStatusFilter::Terminated),
116 _ => None,
117 }
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
124pub enum Protocol {
125 Tcp,
127 Http,
129 Other(String),
131}
132
133impl Protocol {
134 pub fn as_str(&self) -> &str {
136 match self {
137 Protocol::Tcp => "tcp",
138 Protocol::Http => "http",
139 Protocol::Other(s) => s,
140 }
141 }
142}
143
144impl From<&str> for Protocol {
145 fn from(s: &str) -> Protocol {
146 match s {
147 "tcp" => Protocol::Tcp,
148 "http" => Protocol::Http,
149 other => Protocol::Other(other.to_string()),
150 }
151 }
152}
153
154impl std::fmt::Display for Protocol {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 f.write_str(self.as_str())
157 }
158}
159
160impl Serialize for Protocol {
161 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
162 serializer.serialize_str(self.as_str())
163 }
164}
165
166impl<'de> Deserialize<'de> for Protocol {
167 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Protocol, D::Error> {
168 Ok(Protocol::from(String::deserialize(deserializer)?.as_str()))
169 }
170}
171
172#[derive(Debug, Clone, PartialEq, Eq)]
175pub enum ListenerRouteStatus {
176 Unspecified,
178 Pending,
180 Active,
182 Restoring,
184 Unavailable,
186 Other(String),
188}
189
190impl ListenerRouteStatus {
191 pub fn as_str(&self) -> &str {
193 match self {
194 ListenerRouteStatus::Unspecified => "LISTENER_ROUTE_STATUS_UNSPECIFIED",
195 ListenerRouteStatus::Pending => "LISTENER_ROUTE_STATUS_PENDING",
196 ListenerRouteStatus::Active => "LISTENER_ROUTE_STATUS_ACTIVE",
197 ListenerRouteStatus::Restoring => "LISTENER_ROUTE_STATUS_RESTORING",
198 ListenerRouteStatus::Unavailable => "LISTENER_ROUTE_STATUS_UNAVAILABLE",
199 ListenerRouteStatus::Other(s) => s,
200 }
201 }
202}
203
204impl From<&str> for ListenerRouteStatus {
205 fn from(s: &str) -> ListenerRouteStatus {
206 match s {
207 "LISTENER_ROUTE_STATUS_UNSPECIFIED" => ListenerRouteStatus::Unspecified,
208 "LISTENER_ROUTE_STATUS_PENDING" => ListenerRouteStatus::Pending,
209 "LISTENER_ROUTE_STATUS_ACTIVE" => ListenerRouteStatus::Active,
210 "LISTENER_ROUTE_STATUS_RESTORING" => ListenerRouteStatus::Restoring,
211 "LISTENER_ROUTE_STATUS_UNAVAILABLE" => ListenerRouteStatus::Unavailable,
212 other => ListenerRouteStatus::Other(other.to_string()),
213 }
214 }
215}
216
217impl std::fmt::Display for ListenerRouteStatus {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 f.write_str(self.as_str())
220 }
221}
222
223impl Serialize for ListenerRouteStatus {
224 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
225 serializer.serialize_str(self.as_str())
226 }
227}
228
229impl<'de> Deserialize<'de> for ListenerRouteStatus {
230 fn deserialize<D: serde::Deserializer<'de>>(
231 deserializer: D,
232 ) -> Result<ListenerRouteStatus, D::Error> {
233 Ok(ListenerRouteStatus::from(
234 String::deserialize(deserializer)?.as_str(),
235 ))
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243pub enum IngressProtocol {
244 Tcp,
246 Http,
248}
249
250impl IngressProtocol {
251 pub fn as_str(&self) -> &'static str {
253 match self {
254 IngressProtocol::Tcp => "tcp",
255 IngressProtocol::Http => "http",
256 }
257 }
258
259 pub fn parse(s: &str) -> Option<IngressProtocol> {
262 match s {
263 "tcp" => Some(IngressProtocol::Tcp),
264 "http" => Some(IngressProtocol::Http),
265 _ => None,
266 }
267 }
268}
269
270impl std::fmt::Display for IngressProtocol {
271 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272 f.write_str(self.as_str())
273 }
274}
275
276impl Serialize for IngressProtocol {
277 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
278 serializer.serialize_str(self.as_str())
279 }
280}
281
282#[derive(Debug, Clone, Serialize)]
285pub struct SailboxHandle {
286 pub sailbox_id: String,
288 pub name: String,
290 pub status: SailboxStatus,
292 pub worker_address: String,
294 pub exec_endpoint: String,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct SailboxInfo {
302 pub sailbox_id: String,
304 pub app_id: String,
306 pub app_name: String,
308 pub image_id: String,
310 pub name: String,
312 pub status: SailboxStatus,
314 pub memory_mib: i64,
316 pub vcpu_count: i64,
318 pub state_disk_size_gib: i64,
320 pub cpu_requested_vcpu: i64,
322 pub cpu_used_vcpu: f64,
324 pub memory_requested_bytes: i64,
326 pub memory_used_bytes: i64,
328 pub disk_requested_bytes: i64,
330 pub disk_used_bytes: i64,
332 pub architecture: String,
334 #[serde(default)]
336 pub guest_schema_version: Option<i64>,
337 #[serde(default)]
339 pub error_message: Option<String>,
340 pub checkpoint_generation: i64,
342 #[serde(with = "time::serde::rfc3339::option", default)]
344 pub started_at: Option<OffsetDateTime>,
345 #[serde(with = "time::serde::rfc3339::option", default)]
347 pub last_checkpointed_at: Option<OffsetDateTime>,
348 #[serde(with = "time::serde::rfc3339")]
350 pub created_at: OffsetDateTime,
351 #[serde(with = "time::serde::rfc3339")]
353 pub updated_at: OffsetDateTime,
354}
355
356#[derive(Debug, Clone, Serialize)]
358pub struct SailboxPage {
359 pub items: Vec<SailboxInfo>,
361 pub limit: i64,
363 pub offset: i64,
365 pub total: i64,
367 pub has_more: bool,
369}
370
371#[derive(Debug, Clone, Serialize)]
375pub struct SailboxCheckpoint {
376 pub checkpoint_id: String,
378 pub sailbox_id: String,
380 pub checkpoint_generation: i64,
382 pub status: SailboxStatus,
384}
385
386#[derive(Debug, Clone)]
388pub struct ListQuery {
389 pub app: Option<String>,
391 pub status: Option<SailboxStatusFilter>,
393 pub search: Option<String>,
395 pub max_guest_schema_version: Option<i64>,
397 pub limit: i64,
399 pub offset: i64,
401}
402
403pub const DEFAULT_LIST_LIMIT: i64 = 50;
406
407pub const MAX_SAILBOX_VCPUS: i64 = 4;
411pub const MIN_SAILBOX_MEMORY_MIB: i64 = 1024;
413pub const MAX_SAILBOX_MEMORY_MIB: i64 = 8192;
415pub const MAX_SAILBOX_DISK_GIB: i64 = 32;
417
418impl Default for ListQuery {
419 fn default() -> ListQuery {
420 ListQuery {
421 app: None,
422 status: None,
423 search: None,
424 max_guest_schema_version: None,
425 limit: DEFAULT_LIST_LIMIT,
426 offset: 0,
427 }
428 }
429}
430
431#[derive(Debug, Clone, Serialize)]
433pub struct IngressPort {
434 pub guest_port: u32,
436 pub protocol: IngressProtocol,
438 pub allowlist: Vec<String>,
442}
443
444#[derive(Debug, Clone, Serialize)]
446pub struct VolumeMount {
447 pub volume_id: String,
449 pub mount_path: String,
451}
452
453#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct NfsVolume {
457 pub volume_id: String,
459 pub name: String,
461 pub backend: String,
463 pub status: String,
465 #[serde(with = "time::serde::rfc3339::option", default)]
467 pub created_at: Option<OffsetDateTime>,
468 #[serde(with = "time::serde::rfc3339::option", default)]
470 pub updated_at: Option<OffsetDateTime>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct AddListenerResponse {
478 pub guest_port: u32,
480 pub protocol: Protocol,
482 #[serde(default)]
484 pub public_url: String,
485 #[serde(default)]
487 pub tcp_public_host: String,
488 #[serde(default)]
490 pub tcp_public_port: u32,
491}
492
493#[derive(Debug, Clone)]
496pub struct IssuedUserCert {
497 pub certificate: String,
499 pub key_id: String,
501}
502
503impl AddListenerResponse {
504 pub fn endpoint(&self) -> Option<String> {
507 if !self.public_url.is_empty() {
508 return Some(self.public_url.clone());
509 }
510 if !self.tcp_public_host.is_empty() && self.tcp_public_port != 0 {
511 return Some(format!("{}:{}", self.tcp_public_host, self.tcp_public_port));
512 }
513 None
514 }
515}
516
517#[derive(Debug, Clone)]
521pub struct CreateSailboxRequest {
522 pub app_id: String,
524 pub name: String,
526 pub ingress_ports: Vec<IngressPort>,
528 pub volume_mounts: Vec<VolumeMount>,
530 pub image: crate::image::ImageSpec,
533 pub cpu: Option<i64>,
535 pub memory_mib: Option<i64>,
537 pub state_disk_size_gib: Option<i64>,
539 pub autosleep_timeout_min: Option<i64>,
541}
542
543#[cfg(test)]
544mod tests {
545 use super::*;
546
547 #[test]
548 fn list_query_default_uses_a_valid_nonzero_limit() {
549 let query = ListQuery::default();
552 assert_eq!(query.limit, DEFAULT_LIST_LIMIT);
553 assert!(query.limit > 0);
554 assert_eq!(query.offset, 0);
555 }
556}