fix(hamlog): stop offering an upload that cannot succeed

HAMLOG.online no longer issues API keys, and its upload API takes
nothing else. An operator without a key cannot obtain one, so the
auto-upload switch, the on-close sweep and the 'Send to' entry were all
arming something that could only fail — silently, once per QSO.

Closed at the source rather than hidden in the UI: the upload returns a
sentinel that says why, the manager stops routing to it and says so once
a session, and the manual path refuses with the same words. The settings
page states it plainly instead of showing a switch that does nothing.

Nothing else goes. Their confirmations arrive as an ADIF FILE and never
needed a key, so that import stays; the sent/received state already in
operators' logs stays readable, filterable and bulk-editable; and the
upload itself is kept whole as uploadHamlogLive, still covered by its
request-shape tests, against the day keys come back.
This commit is contained in:
2026-09-03 22:28:32 +02:00
parent 96b5f2d91f
commit 6cbe29fef1
8 changed files with 69 additions and 29 deletions
+13 -15
View File
@@ -84,9 +84,10 @@ type Deps struct {
type Manager struct {
deps Deps
mu sync.Mutex
cfg ExternalServices
rnd *rand.Rand
mu sync.Mutex
cfg ExternalServices
rnd *rand.Rand
hamlogClosedOnce sync.Once
}
// maxUploadAttempts bounds retries of a transient upload failure.
@@ -230,13 +231,13 @@ func (m *Manager) OnQSOLogged(id int64) {
m.route(ServiceCloudlog, id, c)
}
}
// HAMLOG.online — one API key and nothing else to get wrong.
if h := cfg.Hamlog; h.AutoUpload {
if h.APIKey == "" {
m.logf("extsvc: hamlog auto-upload is ON but no API key is set (QSO %d not sent)", id)
} else {
m.route(ServiceHamlog, id, h)
}
// HAMLOG.online is closed to uploads — see ErrHamlogClosed. Said once per
// session rather than per QSO, because an operator who left the switch on
// deserves to know why nothing leaves, and does not deserve it every minute.
if cfg.Hamlog.AutoUpload {
m.hamlogClosedOnce.Do(func() {
m.logf("extsvc: %v", ErrHamlogClosed)
})
}
// HamQTH — the callbook credentials double as the logbook login.
if h := cfg.HamQTH; h.AutoUpload {
@@ -296,9 +297,7 @@ func (m *Manager) onCloseServices() []Service {
if c := cfg.Cloudlog; c.AutoUpload && c.UploadMode == ModeOnClose && c.URL != "" && c.APIKey != "" && c.StationID != "" {
out = append(out, ServiceCloudlog)
}
if h := cfg.Hamlog; h.AutoUpload && h.UploadMode == ModeOnClose && h.APIKey != "" {
out = append(out, ServiceHamlog)
}
if h := cfg.HamQTH; h.AutoUpload && h.UploadMode == ModeOnClose && h.Username != "" && h.Password != "" {
out = append(out, ServiceHamQTH)
}
@@ -348,8 +347,7 @@ func (m *Manager) FlushOnClose() int {
uploaded += m.flushOneByOne(svc, ids, cfg.HRDLog)
case ServiceCloudlog:
uploaded += m.flushOneByOne(svc, ids, cfg.Cloudlog)
case ServiceHamlog:
uploaded += m.flushOneByOne(svc, ids, cfg.Hamlog)
case ServiceHamQTH:
uploaded += m.flushOneByOne(svc, ids, cfg.HamQTH)
}