Przejdź do treści

Kiosk Helper

Co to jest

Kiosk Helper to jeden proces-nadzorca (C#/.NET 8) na maszynie, który zastępuje całą zbieraninę 4 tasków PowerShell wokół kiosku (OTA, czytnik RFID, tray, relaunch). Helper jest rodzicem procesu kiosku — uruchamia go, nadzoruje, aktualizuje, a operatorowi/serwisowi daje tray + zdalne sterowanie z panelu. Status: wdrożony i sprawdzony na LockerBoxie i DynaBoxie.

Po co (problem, który rozwiązuje)

Wcześniej na maszynie działały 4 zadania harmonogramu:

Task Rola
SmartBoxKioskAgent OTA + heartbeat (SYSTEM, AtStartup)
SmartBoxKioskUI uruchamiacz kiosku (interaktywny, AtLogon)
SmartBoxKioskTray ikonka tray
SmartBoxHidReader hook klawiatury RFID → rfid.txt

IPC szło przez pliki (rfid.txt, update-state.json). Główny ból: kiosk sam się odpalał po zamknięciu — bo DWA relaunchery (task UI + watchdog agenta co 30 s) nie wiedziały o serwisie → nie dało się serwisować maszyny.

Rozwiązanie: jeden właściciel cyklu życia. Helper jest rodzicem kiosku (kiosk = proces-dziecko, NIE odpalany przez task), więc Tryb Serwisowy faktycznie zatrzymuje odpalanie. Jedno zadanie autostartu (SmartBoxKioskHelper, AtLogon, Highest) odpala Helpera.

Architektura

flowchart TB
    Task["Task: SmartBoxKioskHelper (AtLogon, sesja konsoli usera)"] --> Helper
    subgraph Helper["KioskHelper.exe (.NET 8)"]
      Sup[KioskSupervisor<br/>rodzic kiosku]
      Loop[HelperHost<br/>pętla 30 s: heartbeat / metryki / OTA / serwis]
      Api[LocalApiServer<br/>REST + WS 127.0.0.1:8810]
      Rfid[WindowsRfidReader<br/>hook WH_KEYBOARD_LL]
      Tray[Tray + config-gate]
    end
    Helper -->|Process.Start / Kill| Kiosk[smartbox_kiosk.exe]
    Helper -->|HTTP X-Machine-Api-Key| Backend[(Backend SmartBox)]
    Helper -. most plikowy .-> Files["rfid.txt · rfid-bridge.log · update-state.json"]
    Files -. czyta .-> Kiosk
    Kiosk -.->|RFID/OTA dziś przez pliki, docelowo WS| Api

Podział cross-platform (mirror SmartConfa):

  • KioskHelper.Core + KioskHelper.Apinet8.0, cross-platform (config-gate, BackendClient, UpdateService/OTA, KioskSupervisor, lokalne API REST+WS).
  • KioskHelper.Appnet8.0-windows (WinForms tray, hook RFID, autostart task, junction, single-instance mutex).

To rozwiązuje pozorną sprzeczność „WPF/WinForms, ale ma działać na Ubuntu": rdzeń jest przenośny, shell jest per-OS (Windows teraz; Linux później reużyje Core+Api — evdev RFID, systemd autostart, symlink).

Co Helper robi

  • Nadzór kioskuKioskSupervisor: startuje C:\smartbox-kiosk\current\smartbox_kiosk.exe, adoptuje już działający (nie plodzi duplikatu ginącego na mutexie), a w trybie „zamknij kiosk" aktywnie ubija kiosk, który wrócił (Reconcile() co tick).
  • OTAUpdateService: pobranie release'u (GET /releases/{id}/file), weryfikacja SHA-256 inline, stop kiosku, rozpakowanie, podmiana junction current, restart, raport INSTALLED/FAILED.
  • RFIDWindowsRfidReader: globalny hook WH_KEYBOARD_LL na wątku STA z pompą komunikatów; flush UID po Enter / po bezczynności.
  • Lokalne API — REST + WebSocket na 127.0.0.1:8810 (jak SmartConf :8800): /v1/status, /v1/config, /v1/service-mode, /v1/restart, /v1/update/check, WS /v1/events.
  • Heartbeat + metryki do backendu (X-Machine-Api-Key) — w panelu maszyna raportuje się przez Helpera (agent="helper").
  • Tray (jak SmartConf): niebieska ikona „SK" (runtime-rysowana), menu: Pokaż/uruchom kiosk · Serwis: komunikat · Serwis: zamknij kiosk · Restart kiosku · Sprawdź aktualizacje · Konfiguracja… · Zamknij.
  • Config-gate — bez ważnego klucza API + połączenia z backendem kiosk NIE wstaje, a tray co ~2 min rzuca powiadomienie „Brak klucza API" (klik → okno konfiguracji).

Most plikowy (kompatybilność)

Żeby Helper był drop-inem pod istniejący build kiosku (pilot bez zmiany Fluttera), LegacyBridge pisze pliki, które czyta obecny kiosk:

  • rfid.txt — append UID na skan (jak stary hid-reader.ps1).
  • rfid-bridge.logtick liveness co 20 s (kiosk śledzi jego mtime; stale >60 s → „czytnik wymaga restartu"). To Helper musi tickać, bo przejął hook.
  • update-state.json — faza OTA dla splash kiosku.

Most vs WebSocket (do zrobienia)

Docelowo kiosk ma czytać RFID + stan OTA przez WebSocket ws://127.0.0.1:8810/v1/events i most plikowy zniknie. Most jest sprawdzony i działa pod każdą wersją kiosku — czysty WS to porządkowy krok, nie blokuje pilota.

Tryby serwisowe (etap-21)

Rozdzielone na dwa niezależne, sterowane z panelu i z traya (zsync. przez backend):

Tryb Flaga Efekt
Komunikat Machine.maintenanceMode kiosk widoczny + baner „przerwa serwisowa"; kiosk renderuje go z /machines/me
Zamknij kiosk Machine.kioskClosed kiosk zamknięty, zostaje tylko Helper → dostęp do Windows na maszynie
  • Helper: czyta obie flagi z /machines/me co tick. kioskClosed (lokalny tray lub panel) → KioskSupervisor zatrzymuje/utrzymuje kiosk zamknięty. maintenanceMode nie dotyka procesu kiosku (to tylko baner).
  • Endpointy: PATCH /machines/:id/kiosk-closed (admin), POST /machines/me/service-mode {maintenanceMode?, kioskClosed?} (klucz maszyny — tray sync z webem).
  • Otwieranie natychmiastowe (bez 30 s oczekiwania): SetServiceMode(false) czyści też zdalną flagę optymistycznie.

Instalacja

Zawsze instaluj DWUKLIKIEM na konsoli maszyny — nie przez SSH

OpenSSH sshd to usługa w sesji 0, więc proces odpalony przez SSH (i installer, i jego auto-start Helpera) ląduje w sesji 0 = niewidocznej dla konsoli usera → kiosk GUI niewidoczny. Dwuklik na konsoli = od razu właściwa sesja interaktywna.

Wariant A — per-maszyna (zaszyty klucz) — zalecany

  1. W panelu: maszyna → przycisk „Instalator Helpera (ta maszyna)" (niebieski).
  2. Pobiera się mały .cmd z świeżo zrotowanym, zaszytym kluczem API.
  3. Rotacja klucza rozłącza działający kiosk → backend zwróci 409 dla maszyny ONLINE; przy świadomej reinstalacji użyj wymuś (?force=true).
  4. Dwuklik .cmd na maszynie → sam się podnosi (UAC) → bierze generic setup.exe (obok albo pobiera z backendu z nagłówkiem X-Machine-Api-Key) → odpala /VERYSILENT /APIBASE /APIKEY → Helper startuje skonfigurowany.

Wariant B — uniwersalny (bez klucza)

  1. Pobierz/skopiuj SmartBoxKioskHelperSetup.exe na maszynę → dwuklik (SmartScreen → „Uruchom mimo to" — niepodpisany).
  2. Instalator sam: kasuje 4 stare taski, ubija stary kiosk, usuwa stare .ps1 (hid-reader/agent/tray), dodaje wyjątek Defendera na C:\smartbox-kiosk, startuje Helpera. Pojawia się w Programy i funkcje.
  3. Klucz: jeśli istnieje C:\smartbox-kiosk\config.json (stary runtime) — Helper bootstrapuje klucz automatycznie. Jeśli pomijasz klucz — kiosk nie wstaje, a tray nag co ~2 min prosi o uzupełnienie (Konfiguracja… → wpisz klucz).
  4. Zalecany restart maszyny — czysty stan: 1 task SmartBoxKioskHelper → Helper → kiosk.

Layout na dysku (bez zmian względem starego)

C:\smartbox-kiosk\ config.json # config KIOSKU (apiBase, machineApiKey, smartconf, template…) helper.json # OSOBNY config Helpera (nie nadpisuje config.json kiosku) helper.log rfid.txt · rfid-bridge.log · update-state.json # most plikowy versions\<ver>\ # buildy kiosku current -> versions\<ver>\ # junction helper\KioskHelper.exe

Build instalatora (dla wdrażającego)

```powershell cd kiosk-helper\installer .\build-installer.ps1 [-SignCertThumbprint ]

-> publish self-contained single-file -> ISCC -> Output\SmartBoxKioskHelperSetup.exe (~74 MB)

Generic exe trzeba **raz** wgrać na VM do hostowania per-maszyna `.cmd`:bash scp Output\SmartBoxKioskHelperSetup.exe smartbox:/tmp/helper-setup.exe ssh smartbox 'docker exec smartbox-backend-1 mkdir -p /data/releases/helper && \ docker cp /tmp/helper-setup.exe smartbox-backend-1:/data/releases/helper/SmartBoxKioskHelperSetup.exe' ```


Audyt / recenzja (stan na dziś)

Co działa i jest zweryfikowane na żywo

  • Cutover — instalator kasuje 4 stare taski + stare .ps1, instaluje Helpera, wpisuje do Programów i funkcji. Sprawdzone na LockerBox + DynaBox.
  • Nadzór + adopt-running — Helper adoptuje działający kiosk zamiast plodzić duplikat (mutex). Sprawdzone: redeploy nie restartuje kiosku.
  • Tryb serwisowy „zamknij kiosk"Reconcile() aktywnie utrzymuje kiosk zamknięty (re-kill); zweryfikowane: zamknięty zostaje ≥40 s, otwarcie natychmiast. (Wcześniejszy bug: stary Helper zamykał tylko lokalnie → po restarcie Helpera kiosk wracał — naprawione przez persist kioskClosed + Reconcile.)
  • RFID przez most — logowanie kartą działa (Helper hook → rfid.txt → kiosk).
  • rfid-bridge.log heartbeat — koniec fałszywego „czytnik wymaga restartu" po reboocie.
  • Ikona „SK" w trayu; config-gate + nag „Brak klucza API"; status w /v1/status (kioskClosed, maintenanceMode, needsConfig).
  • Zdalny tryb serwisowy z panelu (oba tryby) + „Sprawdź aktualizacje" z komunikatem.
  • Generator per-maszyna (.cmd zaszyty klucz) + uniwersalny + hosting generic exe; trasa /machines/installer/helper-setup.exe bramkowana kluczem maszyny.

Gotchy do zapamiętania

Sesje (SSH/silent install)

Instalacja przez SSH/po cichu ląduje w sesji 0 (niewidoczna). Fix po instalacji: taskkill /F /IM KioskHelper.exe + /IM smartbox_kiosk.exe, potem schtasks /Run /TN SmartBoxKioskHelper → task interaktywny w sesji konsoli (LockerBox=sesja 2, DynaBox=sesja 1). Po reboocie task ONLOGON i tak wstaje w konsoli. Dlatego dla usera: dwuklik na konsoli.

Tray po starcie z logowania

Apki startowane przy logowaniu lądują domyślnie w schowku traya („^"), nie na widocznym pasku — to NIE crash. Można przypiąć na stałe.

Do zrobienia

  • Czysty WebSocket w kiosku — usunąć most plikowy (RFID + update-state + service-mode) → ws://127.0.0.1:8810/v1/events; wypchnąć przez OTA.
  • Rollout IKEA + ewentualne pozostałe maszyny (LockerBox + DynaBox zrobione).
  • Podpis instalatora (cert → koniec SmartScreen) — hook -SignCertThumbprint gotowy.
  • Faza 5 — Ubuntu (Avalonia/headless shell + evdev RFID + systemd autostart + symlink); rdzeń już cross-platform.
  • Self-update Helpera (stage .new + restart shim) — odłożone z v1.

Dostęp serwisowy (SSH) do maszyn pilotażowych

  • LockerBox — alias winsrv (172.31.0.201, user ssh, klucz smartbox_win); hostname TEMREXLOCKERBOX. Zdalny shell = PowerShell.
  • DynaBoxtemrex@172.31.0.197 (hasło) przez PuTTY plink/pscp; hostname Dynabox-SDI. Współistnieje z agentem SmartConf.

Powiązane