mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-01 16:48:19 +00:00
add radio preset view
move refresh for materialized views into helper and call at boot
This commit is contained in:
+16
-6
@@ -108,6 +108,9 @@ func main() {
|
||||
|
||||
store := db.New(pool)
|
||||
|
||||
// refresh meterialized views on boot or restart to stay fresh
|
||||
refreshMaterializedViews(ctx, store)
|
||||
|
||||
// ── Seed config data ─────────────────────────────────────────────────────
|
||||
if err := config.Seed(ctx, cfg, store); err != nil {
|
||||
log.Fatalf("failed to seed config: %v", err)
|
||||
@@ -194,12 +197,7 @@ func main() {
|
||||
if err := store.DeleteOldPackets(ctx, time.Now().Add(-packetRetention)); err != nil {
|
||||
log.Printf("cleanup: delete old packets failed: %v", err)
|
||||
}
|
||||
if err := store.RefreshHourlyStats(ctx); err != nil {
|
||||
log.Printf("cleanup: refresh materialized view for hourly stats failed: %v", err)
|
||||
}
|
||||
if err := store.RefreshTopNodes(ctx); err != nil {
|
||||
log.Printf("cleanup: refresh materialized view for top nodes failed: %v", err)
|
||||
}
|
||||
refreshMaterializedViews(ctx, store)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
@@ -254,3 +252,15 @@ func mustEnv(key string) string {
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func refreshMaterializedViews(ctx context.Context, store *db.Store) {
|
||||
if err := store.RefreshHourlyStats(ctx); err != nil {
|
||||
log.Printf("refresh: materialized view for hourly stats failed: %v", err)
|
||||
}
|
||||
if err := store.RefreshTopNodes(ctx); err != nil {
|
||||
log.Printf("refresh: materialized view for top nodes failed: %v", err)
|
||||
}
|
||||
if err := store.RefreshRadioPresets(ctx); err != nil {
|
||||
log.Printf("refresh: materialized view for radio presets failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,3 +340,34 @@ CREATE UNIQUE INDEX idx_mv_top_nodes
|
||||
|
||||
CREATE UNIQUE INDEX idx_mv_hourly_iata_stats
|
||||
ON mv_hourly_iata_stats(iata, hour);
|
||||
|
||||
CREATE MATERIALIZED VIEW mv_radio_presets AS
|
||||
SELECT
|
||||
concat(o.radio_freq_mhz, ',', o.radio_bw_khz, ',', o.radio_sf) AS preset,
|
||||
(SELECT po.iata FROM packet_observations po WHERE po.observer_id = o.id ORDER BY po.heard_at DESC LIMIT 1) AS iata,
|
||||
'observer' AS source_type,
|
||||
COUNT(*) AS count
|
||||
FROM observers o
|
||||
WHERE o.radio_freq_mhz IS NOT NULL
|
||||
AND o.radio_sf IS NOT NULL
|
||||
AND o.radio_bw_khz IS NOT NULL
|
||||
GROUP BY concat(o.radio_freq_mhz, ',', o.radio_bw_khz, ',', o.radio_sf),
|
||||
(SELECT po.iata FROM packet_observations po WHERE po.observer_id = o.id ORDER BY po.heard_at DESC LIMIT 1)
|
||||
HAVING (SELECT po.iata FROM packet_observations po WHERE po.observer_id = o.id ORDER BY po.heard_at DESC LIMIT 1) IS NOT NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
concat(n.radio_freq_mhz, ',', n.radio_bw_khz, ',', n.radio_sf) AS preset,
|
||||
ni.iata,
|
||||
'node' AS source_type,
|
||||
COUNT(*) AS count
|
||||
FROM nodes n
|
||||
JOIN node_iatas ni ON ni.node_id = n.id
|
||||
WHERE n.radio_freq_mhz IS NOT NULL
|
||||
AND n.radio_sf IS NOT NULL
|
||||
AND n.radio_bw_khz IS NOT NULL
|
||||
GROUP BY concat(n.radio_freq_mhz, ',', n.radio_bw_khz, ',', n.radio_sf), ni.iata;
|
||||
|
||||
CREATE UNIQUE INDEX idx_mv_radio_presets
|
||||
ON mv_radio_presets(preset, iata, source_type);
|
||||
|
||||
@@ -636,3 +636,6 @@ REFRESH MATERIALIZED VIEW CONCURRENTLY mv_hourly_iata_stats;
|
||||
|
||||
-- name: RefreshTopNodes :exec
|
||||
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_top_nodes_by_iata;
|
||||
|
||||
-- name: RefreshRadioPresets :exec
|
||||
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_radio_presets;
|
||||
|
||||
@@ -759,6 +759,12 @@ func (s *Store) RefreshTopNodes(ctx context.Context) error {
|
||||
return s.q.RefreshTopNodes(ctx)
|
||||
}
|
||||
|
||||
// RefreshRadioPresets refreshes the mv_radio_presets materialized view.
|
||||
// Called by the cleanup goroutine to keep top node rankings current.
|
||||
func (s *Store) RefreshRadioPresets(ctx context.Context) error {
|
||||
return s.q.RefreshRadioPresets(ctx)
|
||||
}
|
||||
|
||||
// GetObserverTelemetry returns telemetry points for an observer within the given time range.
|
||||
// since and until define the window; pass zero times to use defaults (last 24h).
|
||||
// TODO: implement server-side bucketing by interval when needed.
|
||||
|
||||
Reference in New Issue
Block a user