Files
shturman/docs/specs/plans/03-stub-services.md
T

7.9 KiB
Raw Blame History

План 3 — стаб-сервисы firstboot / settings / power + интеграция на шине

REQUIRED SUB-SKILL: executing-plans + TDD. Полный код — в src по ходу; здесь дизайн/задачи/acceptance.

Goal: поднять привилегированные стаб-сервисы ядра и доказать «шагающий скелет» на живой шине: Power/Settings владеют именами, round-trip настроек, fake-ACC сигнал. First-boot идемпотентно готовит /data.

Architecture: сервисы — отдельные процессы (architecture §3/§4), зависят от ipc (контракт), не от sdk. Каждый — lib + bin (логика в lib для тестов; main тонкий). Bus-bootstrap (connect) — общий, в ipc::conn. Интеграция — на session-шине (dbus-run-session), тесты #[ignore] (не требуют шины в just test).

Tech: zbus #[interface] (server), tokio, shturman-common (Layout/atomic), dbus (session-bus для тестов).

Решения v0: Settings хранит строковые значения (variant на проводе; типы расширим позже) и сам сеет дефолты на первом старте; firstboot создаёт каталоги + machine-id (/dev/urandom) + маркер, дефолты не сеет (single source формата — Settings; шов §7.2 синхронизировать). dev-mocksdefault-фича power (прод: --no-default-features).


P3.1: ipc::conn::connect (рефактор из sdk)

  • crates/shturman-ipc/src/conn.rs: pub async fn connect() -> zbus::Result<zbus::Connection> — система по умолчанию, SHTURMAN_BUS=session → сессия (перенести тело из sdk::connect).
  • ipc/lib.rs: pub mod conn; pub use conn::connect;. sdk/connect.rspub use shturman_ipc::connect;.
  • Build + just test (без регрессий). commit refactor(ipc): connect() в ipc::conn; sdk ре-экспортит.

P3.2: shturman-firstboot (A06) — lib provision + bin (TDD)

  • crates/core/shturman-firstboot (members). Deps: shturman-common, anyhow.
  • lib.rs: pub fn provision(layout: &Layout) -> std::io::Result<bool> — idempotent: маркер есть → Ok(false); иначе создать /data/{apps,settings,state,log}, сгенерить state/machine-id (32 hex из /dev/urandom, если нет), durable-write маркер последнимOk(true). (Привязка machine-id→/etc/machine-id — отдельный every-boot юнит, План 5. Дефолты настроек — Settings.)
  • main.rs: init_tracing("shturman-firstboot"); provision(&Layout::from_env()); лог; exit.
  • TDD-тесты (tmp-/data через Layout::new): (а) идемпотентность (2-й прогон → false, структура/machine-id стабильны); (б) factory-reset (снести маркер+wipe → пересоздание, новый machine-id); (в) mid-run (каталоги без маркера → довосстановление, маркер появился).
  • Red → impl → green → commit feat(firstboot): идемпотентный provision /data + machine-id (A06).

P3.3: shturman-settings — Settings1 server-стаб (lib + bin)

  • crates/core/shturman-settings (members). Deps: shturman-ipc, shturman-common, zbus, tokio, anyhow; dev-deps: shturman-sdk, tempfile.
  • store.rs (lib): Store{ layout, map: BTreeMap<String,String> }load_or_seed (если settings.json нет → дефолты ui.theme=auto, ui.units=metric, durable-write); get/set/reset/list; persist через common::write_atomic. Unit-тесты: seed при пустом, round-trip set→get, reset к дефолту, list по префиксу, неизвестный ключ.
  • service.rs (lib): SettingsService + #[interface(name="ru.shturman.Settings1")]: get(key)->Result<OwnedValue,ipc::Error> (неизвестный → InvalidArgument); set(key,Value) (только строка в v0, иначе InvalidArgument; persist + emit changed); list(prefix); reset(key) (emit changed); #[zbus(signal)] changed(ctx, key, value).
  • main.rs: connect()object_server().at(settings::PATH, svc)request_name(settings::NAME) → park.
  • Build + unit-тесты store зелёные → commit feat(settings): Settings1 стаб + атомарный стор + seed.

P3.4: shturman-power — Power1 server-стаб + dev-mock (lib + bin)

  • crates/core/shturman-power (members). Deps: shturman-ipc, shturman-common, zbus, tokio, anyhow; dev-deps: shturman-sdk, tempfile. Features: default=["dev-mocks"], dev-mocks=[].
  • service.rs (lib): PowerService{ state, ignition, source, epoch } + #[interface(name="ru.shturman.Power1")]: get_power_state()->String (= running стаб); request_sleep() (no-op); #[zbus(property)] ignition_state/uptime(монотон. common::monotonic_secs)/power_source; #[zbus(signal)] acc_changed/shutdown_imminent/shutdown_aborted/sleep/wake. #[cfg(feature="dev-mocks")] второй интерфейс ru.shturman.dev.PowerMock1 на том же объекте: set_acc(bool) (меняет ignition/state + emit acc_changed), set_ignition(String), trigger_shutdown(u32,String) (emit), abort_shutdown() (emit).
  • main.rs: connect()at(power::PATH, svc)request_name(power::NAME) → park.
  • Unit-тест: дефолты (running/running/vehicle_12v), uptime монотонен. Build → commit feat(power): Power1 стаб + dev-mock fake-ACC (feature).

P3.5: интеграция на session-шине + just test-integration

  • shturman-settings/tests/integration.rs (#[ignore]): in-process server на session-conn + sdk::SettingsClient на втором conn → set("ui.theme","night")get==night; приходит changed; неизвестный ключ → ошибка.
  • shturman-power/tests/integration.rs (#[ignore], --features dev-mocks): PowerClient.power_state()==Running; PowerMock1.set_acc(false) → подписчик получил acc_changed(false); снятие подписки по выходу владельца.
  • justfile: test-integration: dbus-run-session -- cargo test --workspace -- --ignored (+ note: нужен dbus).
  • Прогон под dbus-run-session зелёный (вручную; CI/Lima-E2E — План 5). just ci (unit) не затронут (тесты #[ignore]).
  • commit test(core): интеграция Settings/Power на session-шине (#[ignore]).

Acceptance (Плана 3)

  • cargo build --workspace зелёный (3 сервиса; default-фича power включает dev-mock).
  • just test (unit) зелёный: firstboot (идемпотентность/factory-reset/mid-run), settings-store, power-defaults; common/ipc/sdk не сломаны.
  • just test-integration (под dbus-run-session): Settings round-trip + changed; Power state + fake-ACC acc_changed.
  • prod-build-gate: cargo build -p shturman-power --no-default-featuresPowerMock1 не регистрируется (нет dev-mock-символов).
  • just ci зелёный (fmt/clippy/test/deny). Границы: сервисы зависят от ipc, не от sdk.

Дальше

План 4 — shturman-shell (Slint первый кадр на sdk) + slint::testing + slint GPL-3.0 exception в deny.toml. План 5 — dev-tools (валидатор/scaffolding/fixtures) + systemd-юниты + Lima + сквозной E2E.