Introduce stable server IDs for subscription state
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
"userInfo": {}
|
||||
},
|
||||
"selection": {
|
||||
"desiredServerId": "Amsterdam",
|
||||
"appliedServerId": "Amsterdam"
|
||||
"desiredServerId": "srv_4d7c5d1bcd60d665",
|
||||
"appliedServerId": "srv_4d7c5d1bcd60d665"
|
||||
},
|
||||
"connection": {
|
||||
"desired": "running",
|
||||
@@ -36,7 +36,15 @@
|
||||
"startedAt": null,
|
||||
"error": null
|
||||
},
|
||||
"servers": []
|
||||
"servers": [
|
||||
{
|
||||
"id": "srv_4d7c5d1bcd60d665",
|
||||
"label": "Amsterdam",
|
||||
"host": "nl.example.net",
|
||||
"port": 443,
|
||||
"protocol": "vless"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -56,7 +64,7 @@ Browser transport state lives beside, not inside, the domain snapshot. It record
|
||||
|
||||
`selection.desiredServerId` records the user's requested server. `selection.appliedServerId` changes only after its sing-box configuration has been applied. Likewise, `connection.desired` records intent while `connection.process` reports the observed runtime. A failed operation can therefore leave desired and applied values different without pretending that the request succeeded.
|
||||
|
||||
Server IDs are currently derived from the existing trimmed subscription tag. Stable IDs across cosmetic renames are deferred to TASK-008.
|
||||
Server IDs are deterministic from normalized protocol, host and port, while provider order and the human-readable `label` are separate. Duplicate labels remain separate servers; reorder and cosmetic rename keep the same ID. Ping results, React keys, persisted selection and apply commands use the ID. If the selected endpoint disappears, Harbor stops the active process, clears selection and requires an explicit new choice instead of silently switching traffic.
|
||||
|
||||
## Subscription import and refresh
|
||||
|
||||
@@ -68,8 +76,8 @@ The existing background refresh remains every 15 minutes. Provider requests time
|
||||
|
||||
## Compatibility and migration
|
||||
|
||||
No path, volume or file is renamed. A legacy `state.json` without `revision`, `appliedTag` or `connectionDesired` is normalized on read: revision starts at `0`, the legacy `selectedTag` is treated as both desired and applied, and connection intent is inferred from the existing config. The next domain write stores the added fields. Existing unknown fields remain untouched.
|
||||
No path, volume or file is renamed. A legacy `state.json` without stable IDs is migrated to schema v4. A unique `selectedTag` is matched to its normalized endpoint and stored as `selectedServerId`/`appliedServerId`; an ambiguous or missing tag explicitly clears selection. The raw provider config remains unchanged in subscription cache and is normalized only in memory, so an older Harbor build can still use its original tags after rollback. Existing unknown fields remain untouched.
|
||||
|
||||
During the v0 compatibility window, the snapshot also exposes `selectedTag`, `singboxRunning`, `servers[].tag`, `gatewayAuto` and the other previous GET fields. Mutation responses retain their previous result fields and add `state`. The canonical `subscription` object never contains the full subscription URL.
|
||||
|
||||
Rollback is code-only: deploy the previous build. The added persisted fields are ignored by the previous implementation, so no data rewrite is needed. Revisions created by the newer build remain harmless integers in `state.json`.
|
||||
Rollback is code-only: deploy the previous build. The v4 state keeps `selectedTag`, `appliedTag` and server aliases for older builds, while subscription cache keeps raw provider tags. The added ID fields are ignored by the previous implementation.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Harbor state recovery
|
||||
|
||||
Harbor keeps the existing data paths and volumes. `state.json` now uses `schemaVersion: 3`; subscription cache, generated sing-box config and HWID keep their existing filenames. Schema v2 introduced locally managed domain routing rules. Schema v3 adds the `enabled` state and migrates the former code-owned `.ru` exception into the first ordinary enabled rule.
|
||||
Harbor keeps the existing data paths and volumes. `state.json` now uses `schemaVersion: 4`; subscription cache, generated sing-box config and HWID keep their existing filenames. Schema v2 introduced locally managed domain routing rules. Schema v3 added rule `enabled` state. Schema v4 adds stable server IDs and migrates an unambiguous legacy `selectedTag` to `selectedServerId`.
|
||||
|
||||
## Atomic writes
|
||||
|
||||
@@ -8,13 +8,13 @@ Persistent files are written to a unique temporary file in the same directory, f
|
||||
|
||||
## Migration
|
||||
|
||||
On startup, a legacy `state.json` without `schemaVersion`, or any v1/v2 state, is normalized and migrated to the current schema. Existing custom rules are preserved, default to `enabled: true`, and follow the new ordinary `.ru` rule. A v3 state may keep, disable, or delete that rule without Harbor recreating it. Before replacement Harbor saves the original beside it:
|
||||
On startup, a legacy `state.json` without `schemaVersion`, or any v1-v3 state, is normalized and migrated to the current schema. Existing custom rules are preserved. Server identity is derived from protocol, host and port; a unique legacy tag keeps selection, while duplicate or missing matches require a new explicit choice. Before replacement Harbor saves the original beside it:
|
||||
|
||||
```text
|
||||
state.json.backup-v0-2026-07-11T12-00-00-000Z
|
||||
```
|
||||
|
||||
The migration preserves existing fields, adds normalized revision, selection and server fields, and does not rename the volume. The backup is the safest rollback source because builds that only understand schema v2 do not know the per-rule `enabled` state.
|
||||
The migration preserves compatibility aliases, adds normalized revision, selection and server fields, and does not rename the volume. Subscription cache keeps the raw provider config so older builds can still use its original outbound tags. The backup remains the safest manual recovery source.
|
||||
|
||||
## Corrupt JSON
|
||||
|
||||
|
||||
Reference in New Issue
Block a user