Skip to main content

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}