1use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11use crate::{
12 manifest::{CapabilityDeclarations, ProviderRole},
13 BindIdentity, Principal, RouteTarget,
14};
15
16pub const MODULE_CONTROL_OP_HEALTH_CHECK: &str = "health.check";
17pub const MODULE_TO_SUBC_OP_CATALOG_UPDATE: &str = "catalog.update";
18
19#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
20#[serde(rename_all = "snake_case")]
21pub enum HealthStatus {
22 Ok,
23 Degraded,
24 Failing,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct HealthReport {
29 pub status: HealthStatus,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub detail: Option<String>,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub metrics: Option<Value>,
34}
35
36impl HealthReport {
37 pub fn ok() -> Self {
38 Self {
39 status: HealthStatus::Ok,
40 detail: None,
41 metrics: None,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
48#[serde(tag = "op")]
49#[allow(clippy::large_enum_variant)]
52pub enum ModuleControlRequest {
53 #[serde(rename = "route.bind")]
54 RouteBind {
55 route_channel: u16,
56 epoch: u32,
57 target: RouteTarget,
58 identity: BindIdentity,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
73 principal: Option<Principal>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
82 consumer_capabilities: Option<Vec<String>>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 admission_facts: Option<Value>,
86 },
87 #[serde(rename = "health.check")]
88 HealthCheck {},
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
93#[serde(tag = "op")]
94pub enum ModuleControlResponse {
95 #[serde(rename = "route.bind")]
97 RouteBindAck {},
98 #[serde(rename = "health.check")]
99 HealthCheck {
100 status: HealthStatus,
101 #[serde(default, skip_serializing_if = "Option::is_none")]
102 detail: Option<String>,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
104 metrics: Option<Value>,
105 },
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
114#[serde(tag = "op")]
115pub enum ModuleControlRequestFromModule {
116 #[serde(rename = "catalog.update")]
117 CatalogUpdate {
118 provides: Vec<ProviderRole>,
119 #[serde(default, skip_serializing_if = "Option::is_none")]
123 capabilities: Option<CapabilityDeclarations>,
124 },
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
129#[serde(tag = "op")]
130pub enum ModuleControlResponseToModule {
131 #[serde(rename = "catalog.update")]
132 CatalogUpdate {},
133}
134
135impl From<HealthReport> for ModuleControlResponse {
136 fn from(report: HealthReport) -> Self {
137 Self::HealthCheck {
138 status: report.status,
139 detail: report.detail,
140 metrics: report.metrics,
141 }
142 }
143}
144
145impl ModuleControlResponse {
146 pub fn health_report(&self) -> Option<HealthReport> {
147 match self {
148 Self::HealthCheck {
149 status,
150 detail,
151 metrics,
152 } => Some(HealthReport {
153 status: *status,
154 detail: detail.clone(),
155 metrics: metrics.clone(),
156 }),
157 Self::RouteBindAck {} => None,
158 }
159 }
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
164#[serde(tag = "op")]
165pub enum ModuleControlPush {
166 #[serde(rename = "route.status")]
167 RouteStatus {
168 route_channel: u16,
169 route_epoch: u32,
170 status: String,
171 },
172}