# Контракт: IPC (D-Bus) > Backbone связей: реестр D-Bus-сервисов, их интерфейсов и соглашений. > Формализует карту связей из [architecture.md](../architecture.md) §5 в конкретные > контракты. К нему цепляются data-model, plugin-sdk и все домены. Статус: **v2 (на ревью).** v2 — после ретро-ревью (10 находок). Связано с: [architecture.md](../architecture.md) (§4–5) · [data-model.md](data-model.md) · [plugin-sdk.md](plugin-sdk.md) · [security-privacy.md](security-privacy.md) Область: **control plane** (D-Bus). Аудио/видео/графика — НЕ здесь (PipeWire/Wayland, см. architecture §4). --- ## 1. Шина и топология - **Одна системная шина устройства** (Штурман — single-purpose appliance, системная шина *и есть* его шина) со строгой D-Bus-политикой. - Ядро-сервисы общаются на ней напрямую. - **Песочные апы/плагины напрямую шину НЕ видят** — каждому выдаётся **фильтрующий D-Bus-прокси** (паттерн `xdg-dbus-proxy`), настроенный App-Host'ом из capabilities манифеста (см. §5). Это реализация портал-модели из решения №5. > 🟡 *Мелкий выбор на подтверждение:* системная шина устройства (рекомендую, > проще) vs выделенный экземпляр `dbus-daemon` только для Штурмана (чище изоляция > от хост-сервисов, но лишний компонент). Прокси-фильтрация даёт изоляцию в обоих > случаях. ## 2. Соглашения | Аспект | Правило | |--------|---------| | Well-known имя | `ru.shturman.` (напр. `ru.shturman.VehicleData`) | | Путь объекта | `/ru/shturman/` | | Интерфейс | `ru.shturman.N` — `N` = мажорная версия (напр. `…VehicleData1`) | | Версионирование | аддитивно внутри версии; ломающее → **добавляется** `…2` рядом со старым `…1`; оба сосуществуют в окне поддержки (старые плагины работают без правок; EOL мажора синхронизируется с `shturman_api` в манифесте) | | Ошибки | `ru.shturman.Error.`: `PermissionDenied`, `NotAvailable` (PID не поддержан машиной — постоянно), `Stale`/`Timeout` (транзиентно: таймаут/устарело), `ReadOnly`, `InvalidArgument`, `Unsupported` | | Действие | **метод** | | Изменение состояния | **сигнал** | | Текущее состояние | **property** (+ стандартный `PropertiesChanged`) | | Асинхронность | всё async (zbus + tokio); долгие операции не блокируют | | Стандартные интерфейсы | `org.freedesktop.DBus.{Properties,Introspectable,Peer}` | | Идентичность вызывающего | по **аутентифицированному соединению** (`sender` → PID/cgroup → манифест, привязка App-Host'ом), НЕ по аргументу метода; подменить нельзя | | Жизненный цикл клиент-состояния | серверное состояние клиента (подписки, регистрации тайлов/интентов) **снимается автоматически** при исчезновении владельца имени (`NameOwnerChanged`) — крэш/рестарт не оставляет мусора | > Полные сигнатуры (XML-интроспекция) фиксируются при реализации; здесь — реестр и ключевые члены. --- ## 3. Реестр сервисов — ядро (привилегированные) ### `ru.shturman.VehicleData` — данные машины (**READ-ONLY**) - **Методы (только чтение):** `ListSignals() → [(name, availability)]`, `GetSignal(name) → (value, unit, ts, quality)`, `Subscribe(names, desired_max_hz)`/`Unsubscribe(names)`, `GetDtcs() → [(code, status, desc)]`. - **Авторизация по имени сигнала — в самом сервисе:** прокси (§5) не видит payload, поэтому `vehicle_read:[…]` enforce-ит **VehicleData по идентичности вызывающего** (`sender` → манифест), отвергая незаявленные имена `PermissionDenied`. Сигналы **адресные**: `SignalChanged(name, value, ts, quality)` шлётся только подписчику и только по `Subscribe ∩ манифест`; `DtcsChanged([...])`. - **Частота:** `desired_max_hz` — верхняя граница, которую готов принять подписчик, и вход в **агрегатный** опрос: фактический опрос PID = `max()` запрошенных, ограничен потолком шины (~10–20 Гц) и источником. Доставка индивидуально не троттлится — слабый клиент (приборка) прореживает сам. Имя `desired_` подчёркивает: не гарантия «моей частоты». - **Подписки привязаны к владельцу соединения** — снимаются автоматически при крэше/рестарте; агрегатный опрос пересчитывается, опрос PID останавливается без живых подписчиков (бережёт скудный ELM327). - **Таймаут/staleness:** `GetSignal` имеет таймаут → `Stale`/`Timeout` (или stale-flag в `quality`), не виснет на медленном ELM327-PID. `NotAvailable` = PID не поддержан машиной (постоянно); `Stale` = транзиентно (двигатель заглушен/таймаут). - **Properties (горячие):** `Speed`, `Rpm`, `CoolantTemp`, `ModuleVoltage` (питание ЭБУ ≈ бортсеть, не клеммы АКБ), `Online`. - ⛔ **Методов записи нет** — ни `SetSignal`, ни actuator-команд, ни clear-DTC. Архитектурная гарантия read-only (принцип #2). Типы — [data-model.md](data-model.md). ### `ru.shturman.Power` — питание и жизненный цикл - **Методы:** `GetPowerState() → state`, `RequestSleep()` (внутр.). - **Сигналы:** `AccChanged(on)`, `ShutdownImminent(seconds)`, `Sleep()`, `Wake()`. - **Properties:** `IgnitionState`, `Uptime`, `PowerSource`. ### `ru.shturman.Settings` — конфигурация и состояние - **Методы:** `Get(key) → value`, `Set(key, value)`, `List(prefix) → [key]`, `Reset(key)`. - **Сигналы:** `Changed(key, value)`. - **Namespace изолирует сам сервис Settings** по идентичности вызывающего (`sender` → app-id): Get/Set/List/Reset вне своего namespace → `PermissionDenied` (прокси этого не делает — не инспектирует строку `key`). Свой namespace — read/write по умолчанию (ambient, без отдельной capability). ### `ru.shturman.PermBroker` — политика разрешений (привратник) - **Идентичность — только из соединения** (`sender` → манифест), **никогда из аргумента** (иначе спуфинг/проверка за чужой ап). - **Методы:** `CheckCapability(cap) → bool` (sender-scoped — ап спрашивает про СЕБЯ; кросс-ап форма доступна только привилегированным core по D-Bus-политике), `RequestRuntimeGrant(cap) → granted` (рантайм-промпт; целевой ап = `sender`). - **Сигналы:** `GrantChanged(cap, granted)` — адресно владельцу гранта (чужие не получают). - Статическая фильтрация — прокси + sandbox (§5, владеет App-Host); broker — политика и рантайм-согласия. ### `ru.shturman.AppHost` — запуск/супервизия апов и плагинов - **Методы:** `ListApps() → [(id, status)]`, `StartApp(id)`, `StopApp(id)`, `GetStatus(id) → status`. - **Сигналы:** `AppStarted(id)`, `AppStopped(id)`, `AppCrashed(id, reason)`. - (Установка/дистрибуция плагинов — домен F, не здесь.) ### `ru.shturman.Connectivity` — сеть (обёртка NM/MM) - **Методы:** `GetStatus() → status`, `ListNetworks() → [...]`, `Connect(id)`, `Disconnect()`. - **Сигналы:** `ConnectivityChanged(online)`, `NetworkChanged(...)`. - **Properties:** `Online` (bool — «сервис ещё не поднят» ≠ «offline»), `Type` (wifi/modem), `SignalStrength`. ### `ru.shturman.Location` — GPS/положение (владелец — домен K) - **Properties:** `Latitude`, `Longitude`, `Heading`, `Speed` (GPS-скорость), `FixQuality`, `ts`. - **Сигналы:** `LocationChanged(...)`, `FixChanged(quality)`. - Источник — NMEA/gpsd (hardware §4); гейтится capability `location`. **GPS-скорость берётся ОТСЮДА** (не из VehicleData/E — E это CAN/OBD, появляется в v2). До домена K — мок-стаб (dev fake-GPS). --- ## 4. Реестр сервисов — апы (на SDK) ### `ru.shturman.Assistant` - **Методы:** `SendText(query) → reply`, `StartListening()`, `StopListening()`, `RegisterIntents(handler_path)` — привязывает handler к фразам **из манифеста** `assistant_intents` (фразы НЕ передаются в рантайме, иначе обходится install-ревью). - **Сигналы:** `StateChanged(idle|listening|thinking|speaking)`, `TranscriptUpdated(text)`, `ReplyUpdated(text)`. - Контекст машины подмешивается ассистентом из `VehicleData` (см. architecture §5). ### `ru.shturman.Shell` — UX-host (слот-модель, решение №6) - **Методы:** `RegisterTile(decl)`, `RegisterScreen(decl) → slot_token` (для поверхности клиент предъявляет slot-token в Wayland slot-протоколе `ru.shturman.shell_slot`, не передаёт `wl_surface` по D-Bus — см. c-shell §4), `RequestForeground(slot)`, `ShowOverlay(decl)`. - **Сигналы:** `ForegroundChanged(app)`, `NavigatedTo(screen)`, `DistractionModeChanged(level)`. - Декларативный вклад = данные (рендерит shell); богатый = Wayland-поверхность. ### `ru.shturman.Media` / `…Nav` / `…Phone` - Свои интерфейсы (play/pause/route; navigateTo/cancel; dial/answer/hangup). **Детали — в спеках доменов** H/I/G; здесь — только факт регистрации на шине. --- ## 5. Брокеринг доступа песочных апов (портал-паттерн) 1. Манифест плагина декларирует capabilities (`vehicle_read:[speed]`, `network`, `assistant_intents`…). 2. App-Host поднимает плагин в bubblewrap и даёт ему **фильтрующий D-Bus-прокси**, сконфигурированный под эти capabilities. 3. Прокси даёт **грубую** изоляцию — сервис/интерфейс/метод/сигнал (payload/аргументы НЕ инспектирует). Пример: `vehicle_read:[speed]` → `VehicleData` (read) **достижим**, а `Power`, чужие апы и write-методы — **нет**. **Тонкую** авторизацию по конкретному имени сигнала / ключу настроек делает сам сервис по идентичности `sender` (см. VehicleData, Settings). 4. Рантайм-согласия (сеть «сейчас») — через `PermBroker.RequestRuntimeGrant`. Итог: плагин физически не может дотянуться до того, чего нет в манифесте. Детали модели — [security-privacy.md](security-privacy.md). --- ## 6. Точки расширения через IPC - **Интенты ассистента:** плагин реализует `ru.shturman.IntentHandler1.HandleIntent(intent_id, slots) → result` и регистрируется через `Assistant.RegisterIntents`. Латентно-критичные интенты (громче, домой) ассистент обрабатывает локально без LLM. - **Вклад в UI:** плагин зовёт `Shell.RegisterTile/RegisterScreen` (декларативно или поверхностью). Полные контракты SDK (манифест, биндинги, точки расширения) — [plugin-sdk.md](plugin-sdk.md). --- ## Открытые вопросы (найдено на self-review → роутинг в нужные доки) Не теряем; решается в указанных документах. - ✅ **Гейтинг data-plane, не только D-Bus.** → решено в [security-privacy.md](security-privacy.md) §4 (PipeWire/Wayland гейтятся capability'ями через bubblewrap-сокеты). API-часть — в plugin-sdk. - ✅ **Экспорт объектов из песочницы.** → решено в [security-privacy.md](security-privacy.md) §4 (плагин OWN под префиксом `ru.shturman.plugin..*`). - ✅ **Приватное хранилище апа.** → решено в [security-privacy.md](security-privacy.md) §4 (`storage` → mount `/data/apps//`). - ✅ **Коллизия интентов.** → решено в [plugin-sdk.md](plugin-sdk.md) §5 (слоистая политика разрешения); тонкости LLM-роутинга — домен D. - 🟡 **Целостность манифеста.** Модель доверия — [security-privacy.md](security-privacy.md) §6; подпись/стор — задел домена F. - ◻️ **Быстрый канал для приборки.** → [architecture.md](../architecture.md) §4 + домен E (**открыто**). --- ## Журнал решений (ipc) | Решение | Выбор | Дата | |---------|-------|------| | Топология шины | системная шина устройства + фильтрующий прокси на ап (🟡 на подтверждение) | 2026-06-16 | | Изоляция доступа апов | портал-паттерн: per-app dbus-proxy из манифеста | 2026-06-16 | | Соглашения имён/версий | `ru.shturman.*`, версия в имени интерфейса; мажоры сосуществуют в окне поддержки (аддитивно) | 2026-06-16 | | Enforcement | грубо — прокси (сервис/метод); тонко (per-signal/per-key) — сам сервис по `sender` | 2026-06-16 | | Идентичность | только из аутентиф. соединения, не из аргумента; клиент-состояние снимается по `NameOwnerChanged` | 2026-06-16 | | Location/GPS | отдельный сервис `ru.shturman.Location` (домен K); GPS-скорость не через E | 2026-06-16 |