Skip to main content

app_facade_api/
runtime.rs

1use serde::{Deserialize, Serialize};
2
3pub const STATUS_CONTRACT: &str = "mhome.runtime.status.v1";
4pub const STATUS_LIST_TARGET: &str = "/app/runtime/status/list";
5pub const STATUS_CHANGED_TARGET: &str = "/app/runtime/status/changed";
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "camelCase")]
9pub enum StatusResourceType {
10    NodeInstance,
11    NodeRuntime,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
15#[serde(rename_all = "camelCase")]
16pub struct StatusResource {
17    pub r#type: StatusResourceType,
18    pub id: String,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(rename_all = "camelCase")]
23pub struct StatusPayload {
24    pub contract: String,
25    pub scope_id: String,
26    pub hub_generation: String,
27    pub hub_revision: u64,
28    pub observed_at_ms: i64,
29    pub resource: StatusResource,
30    pub deleted: bool,
31    #[serde(default)]
32    pub snapshot: Option<serde_json::Value>,
33}
34
35/// Optional filters for the Hub-owned runtime status projection. An empty
36/// request lists every Node instance and logical Node runtime in the scope.
37#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
38#[serde(rename_all = "camelCase", deny_unknown_fields)]
39pub struct StatusListRequest {
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub resource_type: Option<StatusResourceType>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub resource_id: Option<String>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
47#[serde(rename_all = "camelCase")]
48pub struct StatusListResponse {
49    pub contract: String,
50    pub scope_id: String,
51    pub hub_generation: String,
52    #[serde(default)]
53    pub resources: Vec<StatusPayload>,
54    pub observed_at_ms: i64,
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn public_runtime_resources_are_only_hub_normalized_node_state() {
63        assert_eq!(
64            serde_json::to_value(StatusResourceType::NodeInstance).unwrap(),
65            "nodeInstance"
66        );
67        assert_eq!(
68            serde_json::to_value(StatusResourceType::NodeRuntime).unwrap(),
69            "nodeRuntime"
70        );
71        assert!(serde_json::from_str::<StatusResourceType>("\"hubConnection\"").is_err());
72        assert!(serde_json::from_str::<StatusResourceType>("\"managedService\"").is_err());
73    }
74
75    #[test]
76    fn empty_status_list_request_has_no_filters() {
77        let request: StatusListRequest = serde_json::from_str("{}").unwrap();
78        assert_eq!(request, StatusListRequest::default());
79        assert_eq!(serde_json::to_string(&request).unwrap(), "{}");
80    }
81}