Evan's Blog
EvanZhu0721 / 公开仓库

SBMS

镜像已同步

SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.

上游 GitHub
READ-ONLY MIRROR

README、源码与 Release 已保存到本站;源码视图固定到 commit a37d6c4b。

main/ root / docs
a37d6c4b· 固定源码快照
docs/configuration.md4.9 KB
预览
1# Configuration profiles
2
3SBMS stores up to three persistent configuration profiles in
4`%LOCALAPPDATA%\SBMS\config-profiles-v1.json`. The complete profile collection,
5the active profile identifier, every profile revision and every nested
6`AppConfig` are committed as one pretty-printed JSON document. Writes use a
7cross-process mutex, a same-directory temporary file, `sync_all`, and a
8write-through atomic replacement.
9
10The first profile operation imports the existing `config-v2.json` as the
11`default` profile. The legacy file is left unchanged. If the old file is
12malformed, unsupported or semantically invalid, initialization fails without
13creating or replacing the profile store. A missing old file produces the
14normal default configuration.
15
16Profile identifiers contain 1–32 ASCII letters, digits, underscores or
17hyphens. They are compared case-insensitively. A collection contains one to
18three profiles and exactly one active profile. Display IDs inside a profile are
19Windows device identities and may need to be changed after importing onto a
20different computer.
21
22## CLI interface
23
24```text
25sbms config path
26sbms config list
27sbms config show [<profile>]
28sbms config save <profile>
29sbms config import <profile> <file.json> [--replace] [--activate]
30sbms config export <profile> <file.json> [--force]
31sbms config activate <profile>
32sbms config delete <profile>
33sbms config reload
34sbms config set-target <monitor-device-path>
35sbms config clear-target
36sbms config reset
37```
38
39- `path` prints the profile-store path.
40- `list` prints a JSON array containing each profile ID, revision and active
41 state.
42- `show` prints the active profile, or the named profile, as a standalone
43 `AppConfig` JSON document.
44- `save` copies the active configuration into the named profile. It creates a
45 new profile or replaces the named profile.
46- `import` reads a standalone `AppConfig` JSON file, strictly validates its
47 schema, version and semantics, and commits it only after validation succeeds.
48 Existing profiles require `--replace`; `--activate` also makes the imported
49 profile active.
50- `export` writes a standalone `AppConfig` JSON file. Existing destinations are
51 rejected atomically unless `--force` is present. The profile-store path can
52 never be used as an export destination, even with `--force`.
53- `activate` atomically changes the active profile and requests a live reload.
54- `delete` rejects the active profile and unknown profiles.
55- `reload` requests that the running tray reload the already-active profile.
56- `set-target`, `clear-target` and `reset` update only the active profile and
57 request a live reload.
58
59A successful configuration commit is not rolled back when the tray is not
60running. CLI output reports `reload=not-running`; the configuration is loaded
61on the next tray or mapping start.
62
63## JSON exchange format
64
65Import and export use the existing standalone `AppConfig` version 2 format,
66not the internal multi-profile collection:
67
68```json
69{
70 "version": 2,
71 "groups": [
72 {
73 "id": 0,
74 "route": {
75 "kind": "mirror",
76 "target_id": "<monitor-device-path>"
77 }
78 }
79 ],
80 "selected_group_id": 0
81}
82```
83
84Unknown fields, unsupported versions, empty or oversized group collections,
85duplicate group IDs or mirror targets, invalid geometry and invalid selected
86group IDs are rejected before any persistent state changes.
87
88## Hot reload contract
89
90The CLI signals the running tray only after the profile transaction has been
91committed. When no mapping is running, the tray reloads the profile and replaces
92its editable in-memory drafts in one UI-thread operation. Existing telemetry is
93preserved for unchanged group IDs.
94
95When a mapping is running or changing state, reload is deferred until the
96controller reports both `running=false` and `busy=false`. Reload never restarts,
97stops or mutates the active mapping. It changes the configuration used by the
98next mapping start.
99
100Each profile has a monotonically increasing revision. UI saves use a
101profile-ID-and-revision compare-and-swap. A stale UI draft therefore cannot
102overwrite a profile imported or activated by another process; the user must
103reload before saving again.
104
105## Rust interface
106
107The public API is exported from `sbms::config`:
108
109- `ConfigProfileStore::default_store()` locates the collection.
110- `list`, `load_active` and `load_profile` return validated persistent state.
111- `save_profile`, `save_active_as`, `activate`, `delete` and `update_active`
112 perform locked atomic transactions.
113- `save_active_if_revision` is the compare-and-swap save operation for a pinned
114 UI session.
115- `ConfigStore::load_strict` validates standalone import files; `save` writes
116 standalone exports atomically.
117- `sbms::control::signal_config_reload` and `listen_for_config_reload` expose
118 the cross-process live-reload notification.
119
120The profile collection is the runtime source of truth after initialization.
121`config-v2.json` remains only as the preserved migration source.
122