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