Commit Graph
2 Commits
Author SHA1 Message Date
Tobias GesellchenandClaude Opus 4.7 d5f9d16e42 feat(setup): per-field telnet URLs with envswitch derivation rule
Refactors telnetURLConfigCommands into a telnetURLs value type with
explicit per-field URLs (Marge, Stats, SwUpdate, BmxRegistry) and adds
telnetURLsFromOptions to resolve those four URLs from a base targetURL
plus optional per-field overrides via the migration options map
(marge_url, stats_url, sw_update_url, bmx_url).

Envswitch derivation rule: arg1 = u.Marge verbatim, arg2 = u.SwUpdate
verbatim. The soundcork case (Marge has /marge appended) is handled
without any branching — envswitch arg1 carries the same suffix and the
parallel persistence layer stays consistent with the runtime layer on
the next reboot.

The default path is unchanged for users who only enter a base URL: all
four fields share targetURL with the canonical /updates/soundtouch and
/bmx/registry/v1/services suffixes. MigrateSpeaker plumbs the options
map through so the existing handler's option dictionary works for telnet
without UI changes; the UI can layer per-field input on top later.

Existing telnet migration tests updated to call the new signature.
TestMigrateViaTelnet_SoundcorkMargeSuffixPropagatesToEnvswitch is the
load-bearing regression test for the derivation rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:37:11 +02:00
Tobias GesellchenandClaude Opus 4.7 fb47807f70 feat(telnet): add port-17000 migration method and account pairing
Adds an SSH-free third migration path that drives the SoundTouch device's
diagnostic shell on TCP port 17000, plus a hardened replacement for the
fragile /setMargeAccount HTTP pairing call.

* `pkg/telnet` — new reusable, dependency-free client (sibling of `pkg/ssh`)
  with deadline-driven Dial / Probe / SendCommand / Close. Mock-server tests
  cover happy path, command-not-found, mid-stream close, and the wedged-device
  read-timeout scenario.

* `setup.MigrationMethodTelnet` — runs `sys configuration` for all four URLs
  plus the parallel `envswitch boseurls set` persistence layer that otherwise
  wins on reboot, then verifies with `getpdo CurrentSystemConfiguration`.
  Aborts on the first non-OK response so configuration is never half-written.
  No SSH backup or rw pre-flight (the path is SSH-free by design).

* `setup.PairAccount` — probes :8090/supportedURLs first, time-bounds
  POST /setMargeAccount aggressively (5s connect / 12s total) to avoid the
  hangs reported in #236, and falls back to `envswitch accountid set <id>`
  over telnet when the HTTP endpoint is missing or wedged. Returns a
  PairAccountResult breadcrumb so the UI can show which path actually
  succeeded.

* `setup.Reboot(deviceIP, method)` — gains a RebootMethod selector;
  RebootMethodSSH stays the default (preserving prior behavior),
  RebootMethodTelnet sends `sys reboot` over a fresh telnet session and
  treats the inevitable socket-close as success.

* New endpoints on `/setup`:
  - GET  /account-id-suggestions/{deviceId} — returns the device's current
    margeAccountUUID (from :8090/info) plus known account IDs from the
    datastore, so the UI can offer reuse.
  - POST /pair-account/{deviceId}?account_id=NNNNNNN — invokes PairAccount;
    the existing reboot endpoint reads ?method=ssh|telnet from the query
    string.

* Helpers `IsValidAccountID` (exactly 7 digits) and `GenerateAccountID`
  (crypto/rand, retries on collision against a known-IDs list).

Documentation in docs/analysis/TELNET-MIGRATION-METHOD.md is updated to match
the implementation: bare-URL convention for `soundtouch-service`, no automatic
`sys reboot` (user-initiated via the existing button with a method selector),
and the realised package layout. The /etc/hosts method is intentionally not
exposed in the new flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 12:43:36 +02:00