mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Adds Manager.telnetPreflight that dials port 17000, captures the banner, and runs `getpdo CurrentSystemConfiguration` to read back the device's live URL configuration. Errors are recorded on TelnetProbeError instead of returned, so the probe is best-effort and never breaks summary construction. This is the data-gathering layer that the four already-declared TelnetReachable / TelnetBanner / TelnetVerifiedConfig / TelnetProbeError fields on MigrationSummary were waiting for. Subsequent iterations wire the preflight into GetMigrationSummary (in parallel with SSH) and use TelnetVerifiedConfig as a SSH-free signal for "already migrated". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
58 lines
1.8 KiB
Go
58 lines
1.8 KiB
Go
package setup
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// telnetPreflight performs a read-only check of the device's port-17000
|
|
// diagnostic shell and populates the Telnet* fields on summary.
|
|
//
|
|
// It exists so the migration UI can decide whether to offer the telnet
|
|
// method, and so a telnet-only (SSH-less) device can still tell us whether
|
|
// it is already pointing at our service. The probe is deliberately scoped
|
|
// to safe, non-mutating commands:
|
|
//
|
|
// 1. TCP dial :17000 (Manager.NewTelnet handles the timeouts).
|
|
// 2. Read whatever banner the shell emits.
|
|
// 3. `getpdo CurrentSystemConfiguration` — a read-only command; if the
|
|
// device answers with "command not found" we record that too so the UI
|
|
// can disable the telnet option with a reason.
|
|
//
|
|
// Errors are recorded on summary.TelnetProbeError rather than returned, so
|
|
// preflight is best-effort and never breaks the rest of GetMigrationSummary.
|
|
func (m *Manager) telnetPreflight(summary *MigrationSummary, deviceIP string) {
|
|
if m.NewTelnet == nil {
|
|
summary.TelnetProbeError = "telnet client not configured"
|
|
return
|
|
}
|
|
|
|
t := m.NewTelnet(deviceIP)
|
|
|
|
if err := t.Dial(); err != nil {
|
|
summary.TelnetProbeError = fmt.Sprintf("dial %s:17000: %v", deviceIP, err)
|
|
return
|
|
}
|
|
|
|
defer func() { _ = t.Close() }()
|
|
|
|
summary.TelnetReachable = true
|
|
|
|
if banner, _ := t.Probe(); banner != "" {
|
|
summary.TelnetBanner = strings.TrimSpace(banner)
|
|
}
|
|
|
|
resp, err := t.SendCommand("getpdo CurrentSystemConfiguration")
|
|
if err != nil {
|
|
summary.TelnetProbeError = fmt.Sprintf("getpdo CurrentSystemConfiguration: %v", err)
|
|
return
|
|
}
|
|
|
|
if isCommandNotFound(resp) {
|
|
summary.TelnetProbeError = "device rejected getpdo CurrentSystemConfiguration (firmware does not expose it)"
|
|
return
|
|
}
|
|
|
|
summary.TelnetVerifiedConfig = strings.TrimRight(resp, "\r\n")
|
|
}
|