Added received time and APRS API
Some checks failed
Test and build / Test and lint (push) Failing after 35s
Test and build / Build collector (push) Failing after 34s
Test and build / Build receiver (push) Failing after 35s

This commit is contained in:
2026-03-05 16:11:24 +01:00
parent 13afa08e8a
commit 7a8d7b0275
3 changed files with 86 additions and 72 deletions

View File

@@ -2,7 +2,6 @@ package hamview
import ( import (
"context" "context"
"database/sql"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"strings" "strings"
@@ -173,22 +172,22 @@ func (c *Collector) processRadio(ctx context.Context, received *Radio) {
} }
} }
func (c *Collector) processAPRSPacket(ctx context.Context, received *Packet) { func (c *Collector) processAPRSPacket(ctx context.Context, packet *Packet) {
radio, err := c.getRadioByID(ctx, received.RadioID) radio, err := c.getRadioByID(ctx, packet.RadioID)
if err != nil { if err != nil {
Logger.Warnf("collector: process %s packet: can't find radio %q: %v", received.Protocol, received.RadioID, err) Logger.Warnf("collector: process %s packet: can't find radio %q: %v", packet.Protocol, packet.RadioID, err)
return return
} }
decoded, err := aprs.Parse(string(received.Raw)) decoded, err := aprs.Parse(string(packet.Raw))
if err != nil { if err != nil {
Logger.Warnf("collector: invalid %s packet: %v", received.Protocol, err) Logger.Warnf("collector: invalid %s packet: %v", packet.Protocol, err)
return return
} }
Logger.Tracef("collector: process %s packet (%d bytes)", Logger.Tracef("collector: process %s packet (%d bytes)",
received.Protocol, packet.Protocol,
len(received.Raw)) len(packet.Raw))
engine := schema.Query(ctx) engine := schema.Query(ctx)
station := new(schema.APRSStation) station := new(schema.APRSStation)
@@ -198,10 +197,10 @@ func (c *Collector) processAPRSPacket(ctx context.Context, received *Packet) {
return return
} else if has { } else if has {
cols := []string{"last_heard_at"} cols := []string{"last_heard_at"}
station.LastHeardAt = received.Time station.LastHeardAt = packet.Time
if decoded.Latitude != 0 { if decoded.Latitude != 0 {
station.LastLatitude = sql.NullFloat64{Float64: decoded.Latitude, Valid: true} station.LastLatitude = &decoded.Latitude
station.LastLongitude = sql.NullFloat64{Float64: decoded.Longitude, Valid: true} station.LastLongitude = &decoded.Longitude
cols = append(cols, "last_latitude", "last_longitude") cols = append(cols, "last_latitude", "last_longitude")
} }
if _, err = engine.ID(station.ID).Cols(cols...).Update(station); err != nil { if _, err = engine.ID(station.ID).Cols(cols...).Update(station); err != nil {
@@ -212,18 +211,12 @@ func (c *Collector) processAPRSPacket(ctx context.Context, received *Packet) {
station = &schema.APRSStation{ station = &schema.APRSStation{
Call: strings.ToUpper(decoded.Source.String()), Call: strings.ToUpper(decoded.Source.String()),
Symbol: decoded.Symbol, Symbol: decoded.Symbol,
FirstHeardAt: received.Time, FirstHeardAt: packet.Time,
LastHeardAt: received.Time, LastHeardAt: packet.Time,
} }
if decoded.Latitude != 0 { if decoded.Latitude != 0 {
station.LastLatitude = sql.NullFloat64{ station.LastLatitude = &decoded.Latitude
Float64: decoded.Latitude, station.LastLongitude = &decoded.Longitude
Valid: decoded.Latitude != 0,
}
station.LastLongitude = sql.NullFloat64{
Float64: decoded.Longitude,
Valid: decoded.Longitude != 0,
}
} }
if station.ID, err = engine.Insert(station); err != nil { if station.ID, err = engine.Insert(station); err != nil {
Logger.Warnf("collector: can't insert APRS station: %v", err) Logger.Warnf("collector: can't insert APRS station: %v", err)
@@ -231,7 +224,7 @@ func (c *Collector) processAPRSPacket(ctx context.Context, received *Packet) {
} }
} }
packet := &schema.APRSPacket{ save := &schema.APRSPacket{
RadioID: radio.ID, RadioID: radio.ID,
StationID: station.ID, StationID: station.ID,
Source: station.Call, Source: station.Call,
@@ -239,20 +232,15 @@ func (c *Collector) processAPRSPacket(ctx context.Context, received *Packet) {
Path: decoded.Path.String(), Path: decoded.Path.String(),
Comment: decoded.Comment, Comment: decoded.Comment,
Symbol: string(decoded.Symbol[:]), Symbol: string(decoded.Symbol[:]),
Raw: string(received.Raw), Raw: string(packet.Raw),
ReceivedAt: packet.Time,
} }
if decoded.Latitude != 0 { if decoded.Latitude != 0 {
packet.Latitude = sql.NullFloat64{ save.Latitude = &decoded.Latitude
Float64: decoded.Latitude, save.Longitude = &decoded.Longitude
Valid: decoded.Latitude != 0,
}
packet.Longitude = sql.NullFloat64{
Float64: decoded.Longitude,
Valid: decoded.Longitude != 0,
}
} }
if _, err = engine.Insert(packet); err != nil { if _, err = engine.Insert(save); err != nil {
Logger.Warnf("collector: can't insert APRS packet: %v", err) Logger.Warnf("collector: can't insert APRS packet: %v", err)
} }
} }
@@ -287,8 +275,7 @@ func (c *Collector) processMeshCorePacket(ctx context.Context, packet *Packet) {
} }
} }
var ( save := &schema.MeshCorePacket{
save = &schema.MeshCorePacket{
RadioID: radio.ID, RadioID: radio.ID,
SNR: packet.SNR, SNR: packet.SNR,
RSSI: packet.RSSI, RSSI: packet.RSSI,
@@ -302,7 +289,6 @@ func (c *Collector) processMeshCorePacket(ctx context.Context, packet *Packet) {
Raw: packet.Raw, Raw: packet.Raw,
ReceivedAt: packet.Time, ReceivedAt: packet.Time,
} }
)
if _, err = schema.Query(ctx).Insert(save); err != nil { if _, err = schema.Query(ctx).Insert(save); err != nil {
Logger.Warnf("collector: error storing packet: %v", err) Logger.Warnf("collector: error storing packet: %v", err)
return return

View File

@@ -2,7 +2,6 @@ package schema
import ( import (
"context" "context"
"database/sql"
"os" "os"
"strings" "strings"
"time" "time"
@@ -21,8 +20,8 @@ type APRSStation struct {
Symbol string `xorm:"varchar(2)" json:"symbol"` Symbol string `xorm:"varchar(2)" json:"symbol"`
FirstHeardAt time.Time `xorm:"timestamp not null"` FirstHeardAt time.Time `xorm:"timestamp not null"`
LastHeardAt time.Time `xorm:"timestamp not null"` LastHeardAt time.Time `xorm:"timestamp not null"`
LastLatitude sql.NullFloat64 LastLatitude *float64 `xorm:"numeric(10,8)" json:"latitude,omitempty"`
LastLongitude sql.NullFloat64 LastLongitude *float64 `xorm:"numeric(11,8)" json:"longitude,omitempty"`
} }
func GetAPRSStation(ctx context.Context, call string) (*APRSStation, error) { func GetAPRSStation(ctx context.Context, call string) (*APRSStation, error) {
@@ -48,18 +47,18 @@ func (station APRSStation) GetPackets(ctx context.Context) ([]*APRSPacket, error
type APRSPacket struct { type APRSPacket struct {
ID int64 `xorm:"pk autoincr" json:"id"` ID int64 `xorm:"pk autoincr" json:"id"`
RadioID int64 `xorm:"index" json:"radio_id"` RadioID int64 `xorm:"index" json:"radio_id"`
Radio Radio `json:"radio"` Radio *Radio `xorm:"-" json:"radio"`
StationID int64 `json:"-"` StationID int64 `json:"-"`
Station *APRSStation `xorm:"-" json:"station"`
Source string `xorm:"varchar(10) not null" json:"src"` Source string `xorm:"varchar(10) not null" json:"src"`
Destination string `xorm:"varchar(10) not null" json:"dst"` Destination string `xorm:"varchar(10) not null" json:"dst"`
Path string `xorm:"varchar(88) not null default ''" json:"path"` Path string `xorm:"varchar(88) not null default ''" json:"path"`
Comment string `xorm:"varchar(250)" json:"comment"` Comment string `xorm:"varchar(250)" json:"comment"`
Latitude sql.NullFloat64 `json:"latitude,omitempty"` Latitude *float64 `xorm:"numeric(10,8)" json:"latitude,omitempty"`
Longitude sql.NullFloat64 `json:"longitude,omitempty"` Longitude *float64 `xorm:"numeric(11,8)" json:"longitude,omitempty"`
Symbol string `xorm:"varchar(2)" json:"symbol"` Symbol string `xorm:"varchar(2)" json:"symbol"`
Raw string `json:"raw"` Raw string `json:"raw"`
ReceivedAt time.Time `json:"received_at"` ReceivedAt time.Time `json:"received_at"`
//Station *APRSStation `xorm:"-" json:"station"`
} }
func GetAPRSPackets(ctx context.Context, limit int) ([]*APRSPacket, error) { func GetAPRSPackets(ctx context.Context, limit int) ([]*APRSPacket, error) {

View File

@@ -3,6 +3,7 @@ package schema
import ( import (
"context" "context"
"database/sql" "database/sql"
"fmt"
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -89,7 +90,11 @@ func Open(driver, config string) error {
names.LintGonicMapper[name] = true names.LintGonicMapper[name] = true
} }
xormEngine.SetMapper(names.GonicMapper{}) xormEngine.SetMapper(names.GonicMapper{})
xormEngine.SetLogger(xormLogger{})
logger := &xormLogger{}
//logger.SetLevel(log.LOG_DEBUG)
xormEngine.SetLogger(logger)
xormEngine.ShowSQL(true)
for _, model := range registeredModels { for _, model := range registeredModels {
Logger.Debugf("schema: sync schema %T", model) Logger.Debugf("schema: sync schema %T", model)
@@ -136,10 +141,32 @@ func NULLTime(t time.Time) *time.Time {
return &t return &t
} }
type xormLogger struct{} type xormLogger struct {
showSQL bool
}
func (l xormLogger) BeforeSQL(ctx log.LogContext) {
var sessionPart string
v := ctx.Ctx.Value(log.SessionIDKey)
if key, ok := v.(string); ok {
sessionPart = fmt.Sprintf(" [%s]", key)
}
Logger.Debugf("[SQL (before)]%s %s %v", sessionPart, ctx.SQL, ctx.Args)
}
func (l xormLogger) AfterSQL(ctx log.LogContext) {
var sessionPart string
v := ctx.Ctx.Value(log.SessionIDKey)
if key, ok := v.(string); ok {
sessionPart = fmt.Sprintf(" [%s]", key)
}
if ctx.ExecuteTime > 0 {
Logger.Infof("[SQL (after)]%s %s %v - %v", sessionPart, ctx.SQL, ctx.Args, ctx.ExecuteTime)
} else {
Logger.Infof("[SQL (after)]%s %s %v", sessionPart, ctx.SQL, ctx.Args)
}
} // only invoked when IsShowSQL is true
func (l xormLogger) BeforeSQL(context log.LogContext) {} // only invoked when IsShowSQL is true
func (l xormLogger) AfterSQL(context log.LogContext) {} // only invoked when IsShowSQL is true
func (l xormLogger) Debug(args ...any) { Logger.Debug(append([]any{"engine: "}, args...)...) } func (l xormLogger) Debug(args ...any) { Logger.Debug(append([]any{"engine: "}, args...)...) }
func (l xormLogger) Debugf(format string, args ...any) { Logger.Debugf("engine: "+format, args...) } func (l xormLogger) Debugf(format string, args ...any) { Logger.Debugf("engine: "+format, args...) }
func (l xormLogger) Error(args ...any) { Logger.Error(append([]any{"engine: "}, args...)...) } func (l xormLogger) Error(args ...any) { Logger.Error(append([]any{"engine: "}, args...)...) }
@@ -181,12 +208,14 @@ func (l xormLogger) SetLevel(level log.LogLevel) {
} }
} }
func (l xormLogger) ShowSQL(show ...bool) { func (l *xormLogger) ShowSQL(show ...bool) {
_ = show if len(show) > 0 {
l.showSQL = show[0]
}
} }
func (l xormLogger) IsShowSQL() bool { func (l xormLogger) IsShowSQL() bool {
return false return l.showSQL
} }
var _ log.ContextLogger = (*xormLogger)(nil) var _ log.ContextLogger = (*xormLogger)(nil)