use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
pub const SNAPSHOTS_PATH: &str = "/internal/v1/moulin/snapshots";
pub const SANDBOXES_PATH: &str = "/internal/v1/moulin/sandboxes";
pub const SANDBOX_PATH: &str = "/internal/v1/moulin/sandboxes/{sandbox}";
pub const BINDINGS_PATH: &str = "/internal/v1/moulin/runtime-bindings";
pub const BINDING_PATH: &str = "/internal/v1/moulin/runtime-bindings/{bindingId}";
pub const BINDING_BY_RUNTIME_PATH: &str = "/internal/v1/moulin/runtime-bindings:by-runtime";
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SnapshotView {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SnapshotPage {
pub items: Vec<SnapshotView>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CreateSandboxRequest {
pub snapshot: String,
#[serde(default)]
pub env: Option<BTreeMap<String, String>>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SandboxView {
pub sandbox: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub snapshot: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runtime_identity_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub binding_id: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SandboxPage {
pub items: Vec<SandboxView>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct BindRuntimeRequest {
pub runtime_identity_id: String,
pub sandbox: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeSandboxBinding {
pub id: String,
pub tenant_id: String,
pub project_id: String,
pub runtime_identity_id: String,
pub sandbox: String,
pub created_at_ms: u64,
pub updated_at_ms: u64,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BindingPage {
pub items: Vec<RuntimeSandboxBinding>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TenantProjectScope {
pub tenant_id: String,
pub project_id: String,
}
impl TenantProjectScope {
pub fn new(
tenant_id: impl Into<String>,
project_id: impl Into<String>,
) -> Result<Self, String> {
let tenant_id = tenant_id.into();
let project_id = project_id.into();
if tenant_id.trim().is_empty() || tenant_id.len() > 128 {
return Err("tenant_id must contain 1..=128 bytes".into());
}
if project_id.trim().is_empty() || project_id.len() > 128 {
return Err("project_id must contain 1..=128 bytes".into());
}
Ok(Self {
tenant_id,
project_id,
})
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LookupBindingQuery {
pub runtime_identity_id: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_sandbox_requires_snapshot() {
let request: CreateSandboxRequest =
serde_json::from_str(r#"{"snapshot":"python"}"#).unwrap();
assert_eq!(request.snapshot, "python");
assert!(request.env.is_none());
}
}