This commit is contained in:
2026-05-28 11:09:07 +02:00
parent a8b7622667
commit d3c9982c66
8 changed files with 380 additions and 200 deletions
+19 -1
View File
@@ -36,6 +36,9 @@ type ServerConfig struct {
}
// Spot is a single DX spot as parsed from the cluster stream.
// Country/Continent are filled by the caller (app.go) before the spot
// is emitted to the UI, so the table never has empty country cells
// flickering in for a few hundred ms.
type Spot struct {
SourceID int64 `json:"source_id"` // ID of the cluster server this came from
SourceName string `json:"source_name"` // display name (handy in the UI when multiple servers)
@@ -47,6 +50,8 @@ type Spot struct {
Comment string `json:"comment,omitempty"`
Locator string `json:"locator,omitempty"` // spotter grid (optional)
TimeUTC string `json:"time_utc,omitempty"`
Country string `json:"country,omitempty"` // DXCC entity name (cty.dat)
Continent string `json:"continent,omitempty"` // 2-letter continent
ReceivedAt time.Time `json:"received_at"`
Raw string `json:"raw"`
}
@@ -92,6 +97,7 @@ type session struct {
conn net.Conn
stopCh chan struct{}
doneCh chan struct{}
stopped bool // guards against double-stop on the same session
spotsCnt int
}
@@ -162,11 +168,14 @@ func (m *Manager) StopServer(id int64) {
if ok {
delete(m.sessions, id)
}
remaining := len(m.sessions)
m.mu.Unlock()
fmt.Printf("cluster.StopServer id=%d found=%v remaining=%d\n", id, ok, remaining)
if !ok {
return
}
s.stop()
fmt.Printf("cluster.StopServer id=%d stopped successfully\n", id)
m.emitStatus()
}
@@ -230,10 +239,19 @@ func (s *session) send(cmd string) error {
}
func (s *session) stop() {
// Critical: do NOT nil out s.stopCh — the supervisor goroutine reads
// `<-s.stopCh` in its select. Setting the field to nil would make
// `<-nil` block forever, leaving the supervisor stuck on its backoff
// timer and then re-dialing → a "deleted" cluster keeps spotting.
// We just close() the channel and let the goroutine see the broadcast.
s.mu.Lock()
if s.stopped {
s.mu.Unlock()
return
}
s.stopped = true
stop, done := s.stopCh, s.doneCh
conn := s.conn
s.stopCh, s.doneCh, s.conn = nil, nil, nil
s.mu.Unlock()
if conn != nil {
_ = conn.Close()