1use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11use crate::{BindIdentity, Principal, RouteTarget};
12
13pub const MODULE_CONTROL_OP_HEALTH_CHECK: &str = "health.check";
14
15#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
16#[serde(rename_all = "snake_case")]
17pub enum HealthStatus {
18 Ok,
19 Degraded,
20 Failing,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub struct HealthReport {
25 pub status: HealthStatus,
26 #[serde(default, skip_serializing_if = "Option::is_none")]
27 pub detail: Option<String>,
28 #[serde(default, skip_serializing_if = "Option::is_none")]
29 pub metrics: Option<Value>,
30}
31
32impl HealthReport {
33 pub fn ok() -> Self {
34 Self {
35 status: HealthStatus::Ok,
36 detail: None,
37 metrics: None,
38 }
39 }
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44#[serde(tag = "op")]
45pub enum ModuleControlRequest {
46 #[serde(rename = "route.bind")]
47 RouteBind {
48 route_channel: u16,
49 target: RouteTarget,
50 identity: BindIdentity,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
52 principal: Option<Principal>,
53 },
54 #[serde(rename = "health.check")]
55 HealthCheck {},
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
60#[serde(tag = "op")]
61pub enum ModuleControlResponse {
62 #[serde(rename = "route.bind")]
64 RouteBindAck {},
65 #[serde(rename = "health.check")]
66 HealthCheck {
67 status: HealthStatus,
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 detail: Option<String>,
70 #[serde(default, skip_serializing_if = "Option::is_none")]
71 metrics: Option<Value>,
72 },
73}
74
75impl From<HealthReport> for ModuleControlResponse {
76 fn from(report: HealthReport) -> Self {
77 Self::HealthCheck {
78 status: report.status,
79 detail: report.detail,
80 metrics: report.metrics,
81 }
82 }
83}
84
85impl ModuleControlResponse {
86 pub fn health_report(&self) -> Option<HealthReport> {
87 match self {
88 Self::HealthCheck {
89 status,
90 detail,
91 metrics,
92 } => Some(HealthReport {
93 status: *status,
94 detail: detail.clone(),
95 metrics: metrics.clone(),
96 }),
97 Self::RouteBindAck {} => None,
98 }
99 }
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
104#[serde(tag = "op")]
105pub enum ModuleControlPush {
106 #[serde(rename = "route.status")]
107 RouteStatus { route_channel: u16, status: String },
108}