mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-01 16:48:19 +00:00
feat: add lastheard TS for node IATAs
This commit is contained in:
@@ -318,14 +318,18 @@ WHERE id = $1 AND supports_multibyte_traces = FALSE;
|
||||
-- name: GetNodeByPubkey :one
|
||||
SELECT *,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id,
|
||||
(SELECT json_agg(json_build_object('iata', ni.iata, 'lastHeard', extract(epoch from ni.last_heard) * 1000)::bigint ORDER BY ni.last_heard DESC)
|
||||
FROM node_iatas ni WHERE ni.node_id = n.id) AS iatas
|
||||
FROM nodes n
|
||||
WHERE n.public_key = $1;
|
||||
|
||||
-- name: GetNodeByID :one
|
||||
SELECT *,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id,
|
||||
(SELECT json_agg(json_build_object('iata', ni.iata, 'lastHeard', extract(epoch from ni.last_heard) * 1000)::bigint ORDER BY ni.last_heard DESC)
|
||||
FROM node_iatas ni WHERE ni.node_id = n.id) AS iatas
|
||||
FROM nodes n
|
||||
WHERE n.id = $1;
|
||||
|
||||
@@ -333,7 +337,7 @@ WHERE n.id = $1;
|
||||
-- name: ListNodes :many
|
||||
SELECT n.id, n.public_key, n.node_type, n.name, n.latitude, n.longitude, n.last_seen,
|
||||
n.radio_freq_mhz, n.radio_sf, n.radio_bw_khz,
|
||||
array_remove(array_agg(DISTINCT ni.iata ORDER BY ni.iata), NULL)::text[] AS iatas,
|
||||
json_agg(json_build_object('iata', ni.iata, 'lastHeard', (extract(epoch from ni.last_heard) * 1000)::bigint) ORDER BY ni.last_heard DESC) FILTER (WHERE ni.iata IS NOT NULL) AS iatas,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
FROM nodes n
|
||||
|
||||
+12
-4
@@ -208,7 +208,9 @@ func (q *Queries) GetIATA(ctx context.Context, iata string) (IataCode, error) {
|
||||
const getNodeByID = `-- name: GetNodeByID :one
|
||||
SELECT id, public_key, node_type, name, latitude, longitude, location_source, last_advert_at, supports_multibyte_paths, supports_multibyte_traces, min_firmware_version, first_seen, last_seen, radio_freq_mhz, radio_sf, radio_bw_khz, metadata,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id,
|
||||
(SELECT json_agg(json_build_object('iata', ni.iata, 'lastHeard', extract(epoch from ni.last_heard) * 1000)::bigint ORDER BY ni.last_heard DESC)
|
||||
FROM node_iatas ni WHERE ni.node_id = n.id) AS iatas
|
||||
FROM nodes n
|
||||
WHERE n.id = $1
|
||||
`
|
||||
@@ -233,6 +235,7 @@ type GetNodeByIDRow struct {
|
||||
Metadata []byte `json:"metadata"`
|
||||
IsObserver bool `json:"is_observer"`
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
Iatas []byte `json:"iatas"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNodeByID(ctx context.Context, id uuid.UUID) (GetNodeByIDRow, error) {
|
||||
@@ -258,6 +261,7 @@ func (q *Queries) GetNodeByID(ctx context.Context, id uuid.UUID) (GetNodeByIDRow
|
||||
&i.Metadata,
|
||||
&i.IsObserver,
|
||||
&i.ObserverID,
|
||||
&i.Iatas,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -265,7 +269,9 @@ func (q *Queries) GetNodeByID(ctx context.Context, id uuid.UUID) (GetNodeByIDRow
|
||||
const getNodeByPubkey = `-- name: GetNodeByPubkey :one
|
||||
SELECT id, public_key, node_type, name, latitude, longitude, location_source, last_advert_at, supports_multibyte_paths, supports_multibyte_traces, min_firmware_version, first_seen, last_seen, radio_freq_mhz, radio_sf, radio_bw_khz, metadata,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id,
|
||||
(SELECT json_agg(json_build_object('iata', ni.iata, 'lastHeard', extract(epoch from ni.last_heard) * 1000)::bigint ORDER BY ni.last_heard DESC)
|
||||
FROM node_iatas ni WHERE ni.node_id = n.id) AS iatas
|
||||
FROM nodes n
|
||||
WHERE n.public_key = $1
|
||||
`
|
||||
@@ -290,6 +296,7 @@ type GetNodeByPubkeyRow struct {
|
||||
Metadata []byte `json:"metadata"`
|
||||
IsObserver bool `json:"is_observer"`
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
Iatas []byte `json:"iatas"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNodeByPubkey(ctx context.Context, publicKey []byte) (GetNodeByPubkeyRow, error) {
|
||||
@@ -315,6 +322,7 @@ func (q *Queries) GetNodeByPubkey(ctx context.Context, publicKey []byte) (GetNod
|
||||
&i.Metadata,
|
||||
&i.IsObserver,
|
||||
&i.ObserverID,
|
||||
&i.Iatas,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -1355,7 +1363,7 @@ func (q *Queries) ListNodeObservations(ctx context.Context, arg ListNodeObservat
|
||||
const listNodes = `-- name: ListNodes :many
|
||||
SELECT n.id, n.public_key, n.node_type, n.name, n.latitude, n.longitude, n.last_seen,
|
||||
n.radio_freq_mhz, n.radio_sf, n.radio_bw_khz,
|
||||
array_remove(array_agg(DISTINCT ni.iata ORDER BY ni.iata), NULL)::text[] AS iatas,
|
||||
json_agg(json_build_object('iata', ni.iata, 'lastHeard', (extract(epoch from ni.last_heard) * 1000)::bigint) ORDER BY ni.last_heard DESC) FILTER (WHERE ni.iata IS NOT NULL) AS iatas,
|
||||
EXISTS (SELECT 1 FROM observers o WHERE o.public_key = n.public_key) AS is_observer,
|
||||
(SELECT o.id FROM observers o WHERE o.public_key = n.public_key LIMIT 1) AS observer_id
|
||||
FROM nodes n
|
||||
@@ -1395,7 +1403,7 @@ type ListNodesRow struct {
|
||||
RadioFreqMhz *float32 `json:"radio_freq_mhz"`
|
||||
RadioSf *int16 `json:"radio_sf"`
|
||||
RadioBwKhz *float32 `json:"radio_bw_khz"`
|
||||
Iatas []string `json:"iatas"`
|
||||
Iatas []byte `json:"iatas"`
|
||||
IsObserver bool `json:"is_observer"`
|
||||
ObserverID uuid.UUID `json:"observer_id"`
|
||||
}
|
||||
|
||||
+13
-6
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -849,10 +850,15 @@ func (s *Store) ListNodes(ctx context.Context, nodeType int16, iata string, supp
|
||||
Name: v.Name,
|
||||
Latitude: v.Latitude,
|
||||
Longitude: v.Longitude,
|
||||
IATAs: v.Iatas,
|
||||
IsObserver: v.IsObserver,
|
||||
ObvserverID: nullableUUID(v.ObserverID),
|
||||
}
|
||||
if len(v.Iatas) > 0 {
|
||||
if err := json.Unmarshal(v.Iatas, &node.IATAs); err != nil {
|
||||
log.Printf("store: failed to unmarshal node iatas: %v", err)
|
||||
node.IATAs = []api.NodeIATA{}
|
||||
}
|
||||
}
|
||||
if v.RadioFreqMhz != nil && v.RadioSf != nil && v.RadioBwKhz != nil {
|
||||
s := fmt.Sprintf("%.1f,%g,%d", *v.RadioFreqMhz, *v.RadioBwKhz, *v.RadioSf)
|
||||
node.Radio = &s
|
||||
@@ -878,10 +884,6 @@ func (s *Store) GetNode(ctx context.Context, nodeID uuid.UUID) (*api.Node, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iatas, err := s.q.GetNodeIATAs(ctx, nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node := &api.Node{
|
||||
NodeSummary: api.NodeSummary{
|
||||
ID: row.ID,
|
||||
@@ -891,7 +893,6 @@ func (s *Store) GetNode(ctx context.Context, nodeID uuid.UUID) (*api.Node, error
|
||||
Name: row.Name,
|
||||
Latitude: row.Latitude,
|
||||
Longitude: row.Longitude,
|
||||
IATAs: iatas,
|
||||
IsObserver: row.IsObserver,
|
||||
ObvserverID: nullableUUID(row.ObserverID),
|
||||
},
|
||||
@@ -903,6 +904,12 @@ func (s *Store) GetNode(ctx context.Context, nodeID uuid.UUID) (*api.Node, error
|
||||
LastSeen: row.LastSeen.Time.UnixMilli(),
|
||||
Metadata: row.Metadata,
|
||||
}
|
||||
if len(row.Iatas) > 0 {
|
||||
if err := json.Unmarshal(row.Iatas, &node.IATAs); err != nil {
|
||||
log.Printf("store: failed to unmarshal node iatas: %v", err)
|
||||
node.IATAs = []api.NodeIATA{}
|
||||
}
|
||||
}
|
||||
if row.RadioFreqMhz != nil && row.RadioSf != nil && row.RadioBwKhz != nil {
|
||||
s := fmt.Sprintf("%.1f,%g,%d", *row.RadioFreqMhz, *row.RadioBwKhz, *row.RadioSf)
|
||||
node.Radio = &s
|
||||
|
||||
@@ -180,6 +180,12 @@ type ObserverTelemetry struct {
|
||||
Points []ObserverTelemetryPoint `json:"points"`
|
||||
}
|
||||
|
||||
// NodeIATA represents a single IATA code and the last time the node was heard there.
|
||||
type NodeIATA struct {
|
||||
IATA string `json:"iata"`
|
||||
LastHeard int64 `json:"lastHeard"` // epoch ms
|
||||
}
|
||||
|
||||
// NodeSummary is the minimal node representation used in list responses.
|
||||
type NodeSummary struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
@@ -192,7 +198,7 @@ type NodeSummary struct {
|
||||
Latitude *float64 `json:"lat,omitempty"`
|
||||
Longitude *float64 `json:"lng,omitempty"`
|
||||
Radio *string `json:"radio,omitempty"`
|
||||
IATAs []string `json:"iatas"`
|
||||
IATAs []NodeIATA `json:"iatas"`
|
||||
}
|
||||
|
||||
// Node is the full node representation including firmware capability flags,
|
||||
|
||||
Reference in New Issue
Block a user