ados_protocol/
cloud_link.rs1use std::path::Path;
12
13use serde::{Deserialize, Serialize};
14
15pub const CLOUD_LINK_SIDECAR: &str = "/run/ados/cloud-link.json";
17
18pub const CLOUD_LINK_SIDECAR_VERSION: u16 = 1;
20
21pub const CLOUD_LINK_STALE_MS: i64 = 20_000;
23
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26pub struct CloudLink {
27 #[serde(default)]
29 pub version: u16,
30 pub generated_at_ms: Option<i64>,
32 #[serde(default)]
34 pub paired: bool,
35 #[serde(default)]
37 pub cloud_url_set: bool,
38 pub broker_connected: Option<bool>,
41 pub last_heartbeat_ok_ms: Option<i64>,
43 pub last_heartbeat_status: Option<u16>,
45 pub last_heartbeat_error: Option<String>,
47}
48
49pub fn read_cloud_link_from(path: &Path, now_ms: i64) -> Option<CloudLink> {
52 let text = std::fs::read_to_string(path).ok()?;
53 let link: CloudLink = serde_json::from_str(&text).ok()?;
54 let generated = link.generated_at_ms?;
55 if generated > now_ms || now_ms - generated > CLOUD_LINK_STALE_MS {
57 return None;
58 }
59 crate::sidecar::check_sidecar_version("cloud-link", link.version, CLOUD_LINK_SIDECAR_VERSION);
60 Some(link)
61}
62
63pub fn read_cloud_link(now_ms: i64) -> Option<CloudLink> {
65 read_cloud_link_from(Path::new(CLOUD_LINK_SIDECAR), now_ms)
66}
67
68pub fn write_cloud_link_to(path: &Path, link: &CloudLink) -> std::io::Result<()> {
70 if let Some(parent) = path.parent() {
71 std::fs::create_dir_all(parent)?;
72 }
73 let body = serde_json::to_vec(link).map_err(std::io::Error::other)?;
74 let tmp = path.with_extension("json.tmp");
75 std::fs::write(&tmp, body)?;
76 std::fs::rename(&tmp, path)
77}
78
79pub fn write_cloud_link(link: &CloudLink) -> std::io::Result<()> {
81 write_cloud_link_to(Path::new(CLOUD_LINK_SIDECAR), link)
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn a_fresh_link_reads_back_and_a_stale_or_future_one_does_not() {
90 let dir = tempfile::tempdir().unwrap();
91 let path = dir.path().join("cloud-link.json");
92 let now = 1_700_000_000_000i64;
93 let link = CloudLink {
94 version: CLOUD_LINK_SIDECAR_VERSION,
95 generated_at_ms: Some(now),
96 paired: true,
97 cloud_url_set: true,
98 broker_connected: Some(true),
99 last_heartbeat_ok_ms: Some(now - 2_000),
100 last_heartbeat_status: Some(200),
101 last_heartbeat_error: None,
102 };
103 write_cloud_link_to(&path, &link).unwrap();
104 assert_eq!(read_cloud_link_from(&path, now + 1_000), Some(link));
105 assert!(read_cloud_link_from(&path, now + CLOUD_LINK_STALE_MS + 1).is_none());
106 assert!(read_cloud_link_from(&path, now - 1).is_none());
107 }
108}