ignition_core/client/connections.rs
1//! DB/OPC connection capability models (02-03, HLTH-05/06).
2//!
3//! The REAL mechanism is the web UI's Connections-page poll — the
4//! resource-list endpoints (network-captured, 02-RESEARCH §DB / OPC
5//! connection status). The ignition-mcp `/data/api/v1/connections/*`
6//! paths are inventions (404) and appear nowhere here;
7//! `/data/api/v1/overview/connections` (web-UI presentation objects) is
8//! deliberately NOT used for the list either.
9//!
10//! ⚠ LOW-CONFIDENCE SHAPE (02-RESEARCH Open Question 1): the research
11//! gateway had ZERO connections configured — the envelope + mechanism
12//! are verified, but the POPULATED `healthchecks` detail is not.
13//! [`GatewayConnection::healthchecks`] is therefore a RAW passthrough
14//! [`serde_json::Value`], rendered as-is; the live check
15//! (`live_connections` in tests/live_gateway.rs) exists to capture the
16//! populated shape against a gateway that HAS a connection (recorded as
17//! an open question for UAT until then).
18
19use std::collections::BTreeMap;
20
21use serde::{Deserialize, Serialize};
22
23/// GET path of the database-connection resource list (web-UI poll,
24/// network-captured).
25pub(crate) const DATABASE_CONNECTIONS_PATH: &str =
26 "/data/api/v1/resources/list/ignition/database-connection";
27
28/// GET path of the OPC-connection resource list (same family).
29pub(crate) const OPC_CONNECTIONS_PATH: &str = "/data/api/v1/resources/list/ignition/opc-connection";
30
31/// One item of the connection resource lists — name/enabled plus the
32/// `healthchecks` map EXACTLY as the gateway reports it (raw
33/// passthrough; see the module docs for the LOW-confidence flag).
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub struct GatewayConnection {
36 /// Resource name, e.g. `"MyPostgres"`.
37 #[serde(default)]
38 pub name: String,
39 /// Whether the connection resource is enabled.
40 #[serde(default)]
41 pub enabled: bool,
42 /// Healthcheck status map — RAW passthrough (`Value`): the populated
43 /// shape is LOW-confidence until captured against a gateway with a
44 /// configured connection (research Open Question 1). Rendered
45 /// as-is, never interpreted.
46 #[serde(default)]
47 pub healthchecks: serde_json::Value,
48 /// `collection`, `signature`, `config`, … resource keys round-trip.
49 #[serde(flatten)]
50 pub extra: BTreeMap<String, serde_json::Value>,
51}
52
53#[cfg(test)]
54mod tests {
55 use super::GatewayConnection;
56
57 /// A plausible resource-list item parses with the passthrough
58 /// healthchecks map and unknown config keys preserved.
59 #[test]
60 fn gateway_connection_parses_with_passthrough_healthchecks() {
61 let connection: GatewayConnection = serde_json::from_value(serde_json::json!({
62 "name": "MyPostgres",
63 "enabled": true,
64 "healthchecks": {"jdbc": "FAIR"},
65 "collection": "database-connections",
66 "config": {"driver": "postgresql"}
67 }))
68 .expect("plausible resource item must parse");
69 assert_eq!(connection.name, "MyPostgres");
70 assert!(connection.enabled);
71 assert_eq!(
72 connection.healthchecks["jdbc"], "FAIR",
73 "healthchecks ride through UNINTERPRETED"
74 );
75 assert_eq!(
76 connection.extra.get("collection"),
77 Some(&serde_json::json!("database-connections")),
78 "resource keys round-trip"
79 );
80
81 // An item WITHOUT a healthchecks map still parses (the research
82 // gateway's empty list could not confirm its presence).
83 let bare: GatewayConnection = serde_json::from_value(serde_json::json!({
84 "name": "Bare",
85 "enabled": false
86 }))
87 .expect("healthchecks may be absent — default Value::Null");
88 assert_eq!(bare.healthchecks, serde_json::Value::Null);
89 }
90}