chore: release v0.20.2
This commit is contained in:
+64
-7
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -217,12 +218,12 @@ func (a *App) publishLiveStatus() {
|
||||
return
|
||||
}
|
||||
_, err := a.logDb.ExecContext(a.ctx,
|
||||
"INSERT INTO live_status (operator, station, freq_hz, band, mode, online, last_qso_at, updated_at) "+
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, UTC_TIMESTAMP()) "+
|
||||
"INSERT INTO live_status (operator, station, freq_hz, band, mode, online, version, last_qso_at, updated_at) "+
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, UTC_TIMESTAMP()) "+
|
||||
"ON DUPLICATE KEY UPDATE station=VALUES(station), freq_hz=VALUES(freq_hz), "+
|
||||
"band=VALUES(band), mode=VALUES(mode), online=VALUES(online), "+
|
||||
"band=VALUES(band), mode=VALUES(mode), online=VALUES(online), version=VALUES(version), "+
|
||||
"last_qso_at=VALUES(last_qso_at), updated_at=UTC_TIMESTAMP()",
|
||||
op, station, freqHz, band, mode, online, lastQSOArg)
|
||||
op, station, freqHz, band, mode, online, appVersion, lastQSOArg)
|
||||
if err != nil {
|
||||
applog.Printf("livestatus: INSERT failed: %v", err)
|
||||
return
|
||||
@@ -230,6 +231,60 @@ func (a *App) publishLiveStatus() {
|
||||
applog.Printf("livestatus: published op=%s station=%s %dHz %s %s online=%d", op, station, freqHz, band, mode, online)
|
||||
}
|
||||
|
||||
// LiveStation is one operator's live status for the multi-op "who's on air" widget.
|
||||
type LiveStation struct {
|
||||
Operator string `json:"operator"`
|
||||
Station string `json:"station"`
|
||||
FreqHz int64 `json:"freq_hz"`
|
||||
Band string `json:"band"`
|
||||
Mode string `json:"mode"`
|
||||
Online bool `json:"online"` // logged a QSO in the last 5 min
|
||||
Version string `json:"version"` // that operator's OpsLog version
|
||||
AgeSec int `json:"age_sec"` // seconds since their last heartbeat (stale = OpsLog closed)
|
||||
}
|
||||
|
||||
// GetLiveStations returns every operator's live status from the shared MySQL
|
||||
// logbook (empty on a local SQLite logbook). Rows whose heartbeat is very stale
|
||||
// (OpsLog closed without clearing its row) are dropped. Online stations first.
|
||||
func (a *App) GetLiveStations() []LiveStation {
|
||||
if a.logDb == nil || a.dbBackend != "mysql" {
|
||||
return nil
|
||||
}
|
||||
if err := a.ensureLiveStatusTable(); err != nil {
|
||||
return nil
|
||||
}
|
||||
rows, err := a.logDb.QueryContext(a.ctx,
|
||||
"SELECT operator, COALESCE(station,''), COALESCE(freq_hz,0), COALESCE(band,''), "+
|
||||
"COALESCE(mode,''), COALESCE(online,0), COALESCE(version,''), "+
|
||||
"TIMESTAMPDIFF(SECOND, updated_at, UTC_TIMESTAMP()) "+
|
||||
"FROM live_status ORDER BY online DESC, operator")
|
||||
if err != nil {
|
||||
applog.Printf("livestatus: list failed: %v", err)
|
||||
return nil
|
||||
}
|
||||
defer rows.Close()
|
||||
out := []LiveStation{}
|
||||
for rows.Next() {
|
||||
var s LiveStation
|
||||
var online int
|
||||
var age sql.NullInt64
|
||||
if err := rows.Scan(&s.Operator, &s.Station, &s.FreqHz, &s.Band, &s.Mode, &online, &s.Version, &age); err != nil {
|
||||
continue
|
||||
}
|
||||
// Drop rows from an OpsLog that hasn't heartbeated in a while (closed): the
|
||||
// heartbeat is every 15 s, so > 3 min means it's gone.
|
||||
if age.Valid && age.Int64 > 180 {
|
||||
continue
|
||||
}
|
||||
s.Online = online == 1
|
||||
if age.Valid {
|
||||
s.AgeSec = int(age.Int64)
|
||||
}
|
||||
out = append(out, s)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *App) ensureLiveStatusTable() error {
|
||||
if _, err := a.logDb.ExecContext(a.ctx,
|
||||
"CREATE TABLE IF NOT EXISTS live_status ("+
|
||||
@@ -239,15 +294,17 @@ func (a *App) ensureLiveStatusTable() error {
|
||||
"band VARCHAR(16), "+
|
||||
"mode VARCHAR(16), "+
|
||||
"online TINYINT DEFAULT 0, "+
|
||||
"version VARCHAR(32), "+
|
||||
"last_qso_at DATETIME NULL, "+
|
||||
"updated_at DATETIME)"); err != nil {
|
||||
return err
|
||||
}
|
||||
// Add the online/last_qso_at columns to a table created by an older build.
|
||||
// MySQL has no portable "ADD COLUMN IF NOT EXISTS", so just run the ALTERs and
|
||||
// ignore the duplicate-column error when they already exist.
|
||||
// Add newer columns to a table created by an older build. MySQL has no portable
|
||||
// "ADD COLUMN IF NOT EXISTS", so just run the ALTERs and ignore the duplicate-
|
||||
// column error when they already exist.
|
||||
for _, ddl := range []string{
|
||||
"ALTER TABLE live_status ADD COLUMN online TINYINT DEFAULT 0",
|
||||
"ALTER TABLE live_status ADD COLUMN version VARCHAR(32)",
|
||||
"ALTER TABLE live_status ADD COLUMN last_qso_at DATETIME NULL",
|
||||
} {
|
||||
if _, err := a.logDb.ExecContext(a.ctx, ddl); err != nil && !strings.Contains(strings.ToLower(err.Error()), "duplicate column") {
|
||||
|
||||
Reference in New Issue
Block a user