Skip to main content

module_orchestrator/api/rest/
dto.rs

1use std::collections::HashMap;
2use uuid::Uuid;
3
4use modkit::runtime::InstanceState;
5
6use crate::domain::model::{DeploymentMode, InstanceInfo, ModuleInfo};
7
8/// Deployment mode of a module
9#[derive(Debug, Clone)]
10#[modkit_macros::api_dto(response)]
11pub enum DeploymentModeDto {
12    /// Module is compiled into the host binary
13    CompiledIn,
14    /// Module runs as a separate process
15    OutOfProcess,
16}
17
18/// Response DTO for a single registered module
19#[modkit_macros::api_dto(response)]
20pub struct ModuleDto {
21    /// Module name
22    pub name: String,
23    /// Module version (if reported by a running instance)
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub version: Option<String>,
26    /// Declared capabilities (e.g., "rest", "grpc", "system", "db")
27    pub capabilities: Vec<String>,
28    /// Module dependencies (other module names)
29    pub dependencies: Vec<String>,
30    /// Whether the module is compiled-in or out-of-process
31    pub deployment_mode: DeploymentModeDto,
32    /// Running instances of this module
33    pub instances: Vec<ModuleInstanceDto>,
34    /// Plugins provided by this module (reserved for follow-up implementation)
35    #[serde(skip_serializing_if = "Vec::is_empty")]
36    pub plugins: Vec<PluginDto>,
37}
38
39/// Response DTO for a running module instance
40#[modkit_macros::api_dto(response)]
41pub struct ModuleInstanceDto {
42    /// Unique instance ID
43    pub instance_id: Uuid,
44    /// Module version (if reported during registration)
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub version: Option<String>,
47    /// Current instance state (e.g., "registered", "healthy", "quarantined")
48    pub state: String,
49    /// gRPC services provided by this instance (service name -> endpoint URI)
50    pub grpc_services: HashMap<String, String>,
51}
52
53/// Response DTO for a plugin (reserved for follow-up implementation)
54#[modkit_macros::api_dto(response)]
55pub struct PluginDto {
56    /// Plugin GTS identifier
57    pub gts_id: String,
58    /// Plugin version
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub version: Option<String>,
61}
62
63impl From<&ModuleInfo> for ModuleDto {
64    fn from(module: &ModuleInfo) -> Self {
65        // Derive module-level version from the first instance that reports one
66        let version = module
67            .instances
68            .iter()
69            .find_map(|inst| inst.version.clone());
70
71        Self {
72            name: module.name.clone(),
73            version,
74            capabilities: module.capabilities.clone(),
75            dependencies: module.dependencies.clone(),
76            deployment_mode: match module.deployment_mode {
77                DeploymentMode::CompiledIn => DeploymentModeDto::CompiledIn,
78                DeploymentMode::OutOfProcess => DeploymentModeDto::OutOfProcess,
79            },
80            instances: module
81                .instances
82                .iter()
83                .map(ModuleInstanceDto::from)
84                .collect(),
85            plugins: vec![],
86        }
87    }
88}
89
90impl From<&InstanceInfo> for ModuleInstanceDto {
91    fn from(instance: &InstanceInfo) -> Self {
92        Self {
93            instance_id: instance.instance_id,
94            version: instance.version.clone(),
95            state: match instance.state {
96                InstanceState::Registered => "registered",
97                InstanceState::Ready => "ready",
98                InstanceState::Healthy => "healthy",
99                InstanceState::Quarantined => "quarantined",
100                InstanceState::Draining => "draining",
101            }
102            .to_owned(),
103            grpc_services: instance.grpc_services.clone(),
104        }
105    }
106}