@@ -5,8 +5,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
55
66use crate :: DateVersion ;
77
8- // ── V1 ── (keep for backward-compat; written by gateways <= 2026 .1.0) ───────
9-
8+ /// Old gateway- written manifest format (v2026 .1.0 and prior), supported for backward compatibility.
9+ ///
1010/// Example V1 JSON structure:
1111///
1212/// ```json
@@ -17,7 +17,7 @@ use crate::DateVersion;
1717/// ```
1818#[ derive( Debug , Default , Deserialize , Serialize ) ]
1919#[ serde( rename_all = "PascalCase" ) ]
20- pub struct UpdateJson {
20+ pub struct UpdateManifestV1 {
2121 #[ serde( skip_serializing_if = "Option::is_none" ) ]
2222 pub gateway : Option < ProductUpdateInfo > ,
2323 #[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -62,25 +62,27 @@ pub struct ProductUpdateInfo {
6262 pub target_version : VersionSpecification ,
6363}
6464
65- // ── V2 ── (new agents init update.json with `{"VersionMajor": "2"}`) ─────────
66-
67- /// Minor version of the V2 manifest format written by this build of the agent.
65+ /// Minor version of the V2 manifest format written by current build of the agent.
6866///
69- /// The minor version tracks feature-set additions within V2 (major version):
70- /// a new updatable product or capability increments this value so the gateway
71- /// can detect what the agent supports and reject requests for unsupported features.
67+ /// The minor version tracks backwards-compatible changes within V2 (major version) manifest.
68+ /// Increment this value when adding new fields to `UpdateManifestV2` or making other non-breaking
69+ /// changes that require gateway and agent to be updated in tandem to take advantage of the new
70+ /// features.
7271pub const UPDATE_MANIFEST_V2_MINOR_VERSION : u32 = 1 ;
7372
74- fn default_schedule_window_start ( ) -> u32 {
73+ pub fn default_schedule_window_start ( ) -> u32 {
7574 7_200
7675}
7776
7877/// Auto-update schedule for the Devolutions Agent, embedded in [`UpdateManifestV2`].
7978///
8079/// Written by the gateway via `POST /jet/update/schedule` and consumed by the agent,
81- /// which validates the values, applies them to the running poll loop, and persists them
82- /// to `agent.json`. Exposed to the gateway via `GET /jet/update/schedule` so that the
83- /// current schedule is always readable without touching `agent.json`.
80+ /// which validates the values, applies them to the running scheduling loop, and persists them
81+ /// to `agent.json`.
82+ ///
83+ /// Additionally, Agent writes the current scheduler recorded in `agent.json`
84+ /// so gateway can retrieve it back via `GET /jet/update/schedule` without needing to introduce
85+ /// knowledge of agent's configuration file format on the gateway side.
8486#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq , Default ) ]
8587#[ serde( rename_all = "PascalCase" ) ]
8688pub struct UpdateSchedule {
@@ -99,7 +101,7 @@ pub struct UpdateSchedule {
99101
100102 /// End of the maintenance window as seconds past midnight, local time, exclusive.
101103 ///
102- /// `None` means no upper bound (only single update check at update_window_start) .
104+ /// `None` means no upper bound.
103105 /// When end < start the window crosses midnight.
104106 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
105107 pub update_window_end : Option < u32 > ,
@@ -109,13 +111,13 @@ pub struct UpdateSchedule {
109111 pub products : Vec < UpdateProductKey > ,
110112}
111113
112- /// Sentinel type that always serializes/deserializes as the number `2`.
114+ /// Marker type that always serializes/deserializes as the number `2`.
113115///
114116/// Embedded as the `VersionMajor` field in [`UpdateManifestV2`] so that the
115117/// untagged [`UpdateManifest`] enum can distinguish V2 from legacy V1 payloads:
116118/// if `VersionMajor` is absent or not `"2"`, `ManifestV2` deserialization fails
117119/// and the `Legacy` variant is tried next. When a V3 format is introduced, a new
118- /// sentinel and `ManifestV3` variant are added in the same way.
120+ /// marker type and `ManifestV3` variant are added in a similar way.
119121#[ derive( Debug , Default , Clone , Copy , PartialEq , Eq ) ]
120122pub struct VersionMajorV2 ;
121123
@@ -145,7 +147,9 @@ impl<'de> Deserialize<'de> for VersionMajorV2 {
145147 }
146148}
147149
148- /// V2 manifest: major-version sentinel, minor feature version, product map, and schedule.
150+ /// Version 2 of the update manifest format, written by agent/gateway >=2026.2.0.
151+ /// Includes product update list and auto-update schedule. Adding a product name should always
152+ /// increase the minor version, to allow the gateway API caller to know supported products list.
149153///
150154/// Example (full V2 file):
151155/// ```json
@@ -163,10 +167,10 @@ impl<'de> Deserialize<'de> for VersionMajorV2 {
163167#[ serde( rename_all = "PascalCase" ) ]
164168pub struct UpdateManifestV2 {
165169 /// Always `2` — the presence and value of this field let the untagged
166- /// [`UpdateManifest`] distinguish V2 from legacy V1 payloads.
170+ /// [`UpdateManifest`] distinguish V2 from legacy V1 payloads and prevent further parsing
171+ /// attempt of V2 structure
167172 pub version_major : VersionMajorV2 ,
168173 /// Feature-set version within V2. Defaults to `0` when the field is absent in the file.
169- #[ serde( default ) ]
170174 pub version_minor : u32 ,
171175 /// Auto-update schedule set by the gateway. Agent persists it to `agent.json`.
172176 #[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -187,8 +191,6 @@ impl Default for UpdateManifestV2 {
187191 }
188192}
189193
190- // ── Unified manifest ─────────────────────────────────────────────────────────
191-
192194/// A parsed update manifest: either a V2 file or a legacy V1 file.
193195///
194196/// New agents initialise `update.json` with `{"VersionMajor": "2", "VersionMinor": 0}`;
@@ -205,7 +207,7 @@ pub enum UpdateManifest {
205207 /// V2 format: contains `"VersionMajor": 2`.
206208 ManifestV2 ( UpdateManifestV2 ) ,
207209 /// Legacy V1 format: no `"VersionMajor"` field.
208- Legacy ( UpdateJson ) ,
210+ Legacy ( UpdateManifestV1 ) ,
209211}
210212
211213fn strip_bom ( data : & [ u8 ] ) -> & [ u8 ] {
0 commit comments