storage

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 2, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

ADS-B / aircraft log writer — drains KindAircraftReport events off the shared bus and writes one row per decoded Mode-S frame to the SQLite aircraft_log table. Mirrors vessellog.go / aprslog.go / dsclog.go.

APRS log writer — drains KindAPRSPacket events off the shared bus and writes one row per decoded packet to the SQLite aprs_log table. Mirrors pagerlog.go and locationlog.go in structure.

Bookmark storage — operator-managed conventional channel bookmarks. Persisted to SQLite alongside the call log and location log so they survive a daemon restart and back up with the rest of the daemon state.

The store is decoupled from the SDR pool and the scanner — a bookmark is plain metadata (frequency + display name + mode + notes); the spectrum panel uses it to render click-to-tune markers, the conventional scanner uses it as an alternative to the YAML channel list. Mutations are bus-published so subscribed surfaces (web SPA, TUI) can re-render without polling.

DSC log writer — drains KindDSCMessage events off the shared bus and writes one row per decoded sequence to the SQLite dsc_log table. Mirrors aprslog.go / vessellog.go / pagerlog.go.

M17 link-setup log writer — drains KindM17LinkSetup events off the shared bus and writes one row per reassembled Link Setup Frame to the SQLite m17_log table. Mirrors dsclog.go / aprslog.go.

MDC1200 log writer — drains KindMDC1200Message events off the shared bus and writes one row per decoded signaling burst to the SQLite mdc1200_log table. Mirrors dsclog.go / aprslog.go.

PagerLog persists POCSAG (and eventually FLEX) pager messages to the SQLite pager_log table by subscribing to events.KindPagerMessage on the shared bus. The decoder pipeline publishes one event per fully-reassembled page; this consumer writes a row and the web panel queries the recent rows via /api/v1/pager/messages.

Package storage persists GopherTrunk's runtime data to disk.

The default backend is SQLite via the pure-Go `modernc.org/sqlite` driver — CGO_ENABLED=0 stays true across the daemon and the daemon cross-compiles to linux/arm64 without toolchain gymnastics.

Layout:

sqlite.go     Open + schema migrations. One-shot at startup.
calllog.go    CallLog: subscribes to events.KindCallStart /
              KindCallEnd from the trunking engine, writes rows
              keyed by (device serial, started_at).
retention.go  Background sweeper that deletes DB rows + the WAV /
              raw files written by internal/voice older than a
              configurable cutoff.

The API's /api/v1/calls/history endpoint reads through the `History` query helpers exposed here. There is no gRPC call-log service today (history is REST only).

AIS / vessel log writer — drains KindAISMessage events off the shared bus and writes one row per decoded message to the SQLite vessel_log table. Mirrors aprslog.go and pagerlog.go in structure.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AISMessage added in v0.2.6

type AISMessage struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	MMSI       uint32    `json:"mmsi"`
	Type       string    `json:"type"`
	Body       string    `json:"body"`

	// Position fields — populated when the message carries lat/lon.
	Latitude         float64 `json:"latitude,omitempty"`
	Longitude        float64 `json:"longitude,omitempty"`
	SpeedOverGround  float64 `json:"sog,omitempty"`
	CourseOverGround float64 `json:"cog,omitempty"`
	Heading          int     `json:"heading,omitempty"`
	HasPosition      bool    `json:"has_position"`

	// Static-data fields — populated for types 5 and 24.
	VesselName  string `json:"vessel_name,omitempty"`
	Callsign    string `json:"callsign,omitempty"`
	Destination string `json:"destination,omitempty"`
	ShipType    int    `json:"ship_type,omitempty"`
	IMO         uint32 `json:"imo,omitempty"`

	// RawHex is the wire-bit payload as hex for round-tripping into
	// offline decoders / debugging unrecognised message types.
	RawHex string `json:"raw_hex"`
	FCSOK  bool   `json:"fcs_ok"`
}

AISMessage is one persisted decoded AIS message. Position-bearing types (1/2/3/4/18/19/27) carry Latitude / Longitude + COG / SOG + Heading; static-data types (5/24) carry VesselName / Callsign / Destination etc. Everything else stays empty so the column shape is stable across types.

type APRSLog added in v0.2.4

type APRSLog struct {
	// contains filtered or unexported fields
}

APRSLog drains KindAPRSPacket events until ctx cancels or the bus closes.

func NewAPRSLog added in v0.2.4

func NewAPRSLog(db *DB, bus *events.Bus, logger *slog.Logger) (*APRSLog, error)

NewAPRSLog wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*APRSLog) Close added in v0.2.4

func (a *APRSLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*APRSLog) Recent added in v0.2.4

func (a *APRSLog) Recent(limit int) ([]APRSPacket, error)

Recent returns the most recent packets, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*APRSLog) Run added in v0.2.4

func (a *APRSLog) Run(ctx context.Context) error

Run drains KindAPRSPacket events until ctx cancels or the bus closes.

type APRSPacket added in v0.2.4

type APRSPacket struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	Src        string    `json:"src"`
	Dst        string    `json:"dst"`
	Path       string    `json:"path"`
	Type       string    `json:"type"`
	Body       string    `json:"body"`
	Latitude   float64   `json:"latitude,omitempty"`
	Longitude  float64   `json:"longitude,omitempty"`
	RawInfo    string    `json:"raw_info"`
	FCSOK      bool      `json:"fcs_ok"`
}

APRSPacket is one persisted decoded APRS packet. Mirrors the aprs.Packet shape with the AX.25 envelope flattened to a callsign-string triple (src, dst, path) and the sub-payload summarised into a single "body" field for compact rendering. Latitude / Longitude are populated only for position-bearing types and stay 0 otherwise.

type AircraftLog added in v0.2.6

type AircraftLog struct {
	// contains filtered or unexported fields
}

AircraftLog drains KindAircraftReport events until ctx cancels or the bus closes.

func NewAircraftLog added in v0.2.6

func NewAircraftLog(db *DB, bus *events.Bus, logger *slog.Logger) (*AircraftLog, error)

NewAircraftLog wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*AircraftLog) Close added in v0.2.6

func (a *AircraftLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*AircraftLog) CurrentAircraft added in v0.3.0

func (a *AircraftLog) CurrentAircraft(maxAge time.Duration) ([]AircraftReport, error)

CurrentAircraft returns the latest known state of each aircraft seen within maxAge, one row per ICAO. Because aircraft_log stores one message type per row (identification, position, and velocity arrive as separate Mode-S messages), this coalesces the most recent non-empty value of each field group — callsign, position, altitude, velocity — into a single live-state record. ReceivedAt is the aircraft's last-seen time. Rows are newest-last-seen first.

maxAge ≤ 0 defaults to 5 minutes. This powers the "currently visible aircraft" panel, distinct from the raw message log Recent returns.

func (*AircraftLog) Recent added in v0.2.6

func (a *AircraftLog) Recent(limit int) ([]AircraftReport, error)

Recent returns the most recent reports, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000. ADS-B is the highest-rate decoder (aircraft transmit ~2 msg/s), so operators commonly want a tighter window — set limit lower if rendering full panels live.

func (*AircraftLog) Run added in v0.2.6

func (a *AircraftLog) Run(ctx context.Context) error

Run drains KindAircraftReport events until ctx cancels or the bus closes.

type AircraftReport added in v0.2.6

type AircraftReport struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`

	// 24-bit ICAO aircraft address — rendered as a 6-char hex
	// string in the JSON ("4840D6") for readability while staying
	// integer in the SQL column for index efficiency.
	ICAO     uint32 `json:"icao"`
	ICAOHex  string `json:"icao_hex"`
	Kind     string `json:"kind"` // "ident" | "airborne-pos" | "velocity" | ...
	Body     string `json:"body"` // kind-specific summary
	CRCValid bool   `json:"crc_valid"`

	// Identification fields (KindIdentification).
	Callsign string `json:"callsign,omitempty"`
	Category int    `json:"category,omitempty"`

	// Position fields (KindAirbornePosition / KindSurfacePosition).
	// Surfaces the globally-decoded lat/lon when the per-ICAO
	// CPR pairing succeeded; HasPosition distinguishes that from
	// "raw CPR fields preserved but no global decode".
	Latitude    float64 `json:"latitude,omitempty"`
	Longitude   float64 `json:"longitude,omitempty"`
	Altitude    int     `json:"altitude_ft,omitempty"`
	HasPosition bool    `json:"has_position"`
	HasAltitude bool    `json:"has_altitude"`

	// Velocity fields (KindAirborneVelocity).
	GroundSpeedKn   int     `json:"ground_speed_kn,omitempty"`
	TrackDeg        float64 `json:"track_deg,omitempty"`
	VerticalRateFPM int     `json:"vertical_rate_fpm,omitempty"`

	// Raw 112-bit (or 56-bit) frame hex. Round-trips into raw_hex
	// for debugging frames the parser doesn't fully decode.
	RawHex string `json:"raw_hex"`
}

AircraftReport is one persisted decoded Mode-S frame. Different message kinds populate different columns: identification frames fill Callsign + Category, airborne-position fills lat/lon + altitude, velocity fills GroundSpeedKn + TrackDeg + VerticalRateFPM, etc. Everything else stays empty so the column shape is stable across kinds.

type Bookmark added in v0.2.3

type Bookmark struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	FreqHz    uint32    `json:"freq_hz"`
	Mode      string    `json:"mode"` // "FM", "NFM", "AM", "USB", "LSB", "CW", "DMR", ...
	CTCSSHz   float64   `json:"ctcss_hz,omitempty"`
	DCSCode   uint16    `json:"dcs_code,omitempty"`
	Notes     string    `json:"notes,omitempty"`
	Group     string    `json:"group,omitempty"` // operator-defined category
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Bookmark is one row in the bookmarks table.

type BookmarkStore added in v0.2.3

type BookmarkStore struct {
	// contains filtered or unexported fields
}

BookmarkStore is the CRUD layer over the bookmarks table.

func NewBookmarkStore added in v0.2.3

func NewBookmarkStore(db *DB, bus *events.Bus) (*BookmarkStore, error)

NewBookmarkStore returns a store backed by the given DB. The bus is optional — when nil, no mutation events are published (useful for tests). When non-nil, every Create / Update / Delete publishes a bookmark.{created,updated,deleted} event so UI surfaces refresh without polling.

func (*BookmarkStore) Create added in v0.2.3

func (s *BookmarkStore) Create(ctx context.Context, b Bookmark) (Bookmark, error)

Create inserts a bookmark and returns it with ID + timestamps populated. Name is required; mode defaults to "FM" when empty.

func (*BookmarkStore) Delete added in v0.2.3

func (s *BookmarkStore) Delete(ctx context.Context, id int64) error

Delete removes the bookmark by id. Returns sql.ErrNoRows when the id is unknown.

func (*BookmarkStore) Get added in v0.2.3

func (s *BookmarkStore) Get(ctx context.Context, id int64) (Bookmark, error)

Get returns the bookmark with the given id, or sql.ErrNoRows when it's missing.

func (*BookmarkStore) List added in v0.2.3

func (s *BookmarkStore) List(ctx context.Context) ([]Bookmark, error)

List returns all bookmarks sorted by group then name. Empty result is not an error.

func (*BookmarkStore) Update added in v0.2.3

func (s *BookmarkStore) Update(ctx context.Context, b Bookmark) (Bookmark, error)

Update modifies the bookmark identified by b.ID. Only the editable fields (name, freq, mode, ctcss, dcs, notes, group) are written; created_at is preserved, updated_at refreshed. Returns the new row.

type CallLog

type CallLog struct {
	// contains filtered or unexported fields
}

CallLog persists trunking calls to the SQLite call_log table by subscribing to events.KindCallStart and events.KindCallEnd on the shared events bus.

Rows are keyed by (device_serial, started_at). On CallStart we INSERT with a NULL ended_at; on CallEnd we UPDATE the matching row with the ended_at, duration, and end-reason. The unique index in the schema keeps duplicate-start events idempotent.

func NewCallLog

func NewCallLog(db *DB, bus *events.Bus, logger *slog.Logger) (*CallLog, error)

NewCallLog wires the call log to the bus. It subscribes immediately so callers can publish events before Run is called.

func (*CallLog) Close

func (c *CallLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*CallLog) Run

func (c *CallLog) Run(ctx context.Context) error

Run drains call.start / call.end events until ctx cancels.

type CallRow

type CallRow struct {
	ID             int64     `json:"id"`
	System         string    `json:"system"`
	Protocol       string    `json:"protocol"`
	GroupID        uint32    `json:"group_id"`
	SourceID       uint32    `json:"source_id"`
	FrequencyHz    uint32    `json:"frequency_hz"`
	Encrypted      bool      `json:"encrypted"`
	AlgorithmID    uint8     `json:"algorithm_id"`
	KeyID          uint16    `json:"key_id"`
	Emergency      bool      `json:"emergency"`
	DataCall       bool      `json:"data_call"`
	DeviceSerial   string    `json:"device_serial"`
	StartedAt      time.Time `json:"started_at"`
	EndedAt        time.Time `json:"ended_at,omitempty"` // zero if call still active
	DurationMs     int64     `json:"duration_ms,omitempty"`
	EndReason      string    `json:"end_reason,omitempty"`
	TalkgroupAlpha string    `json:"talkgroup_alpha,omitempty"`
}

CallRow is one row from the call_log table.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB is a thin wrapper over *sql.DB that lets the call-log + retention helpers share a typed handle. The schema is migrated on Open.

func Open

func Open(path string) (*DB, error)

Open creates (or opens) a SQLite database at path and applies the embedded schema migrations. The path's parent directory is created if missing.

`:memory:` and the standard "file:..." DSN forms are passed through to the driver — useful for tests.

func (*DB) Close

func (d *DB) Close() error

Close releases the connection.

func (*DB) History

func (d *DB) History(ctx context.Context, f HistoryFilter) ([]CallRow, error)

History queries the call_log with the supplied filter, newest-first.

func (*DB) SQL

func (d *DB) SQL() *sql.DB

SQL returns the underlying *sql.DB. Exposed so tests and future integrations (an /api/v1/calls/history handler, etc.) can run their own queries without adding a method here for every shape.

type DSCLog added in v0.2.6

type DSCLog struct {
	// contains filtered or unexported fields
}

DSCLog drains KindDSCMessage events until ctx cancels or the bus closes.

func NewDSCLog added in v0.2.6

func NewDSCLog(db *DB, bus *events.Bus, logger *slog.Logger) (*DSCLog, error)

NewDSCLog wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*DSCLog) Close added in v0.2.6

func (d *DSCLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*DSCLog) Recent added in v0.2.6

func (d *DSCLog) Recent(limit int) ([]DSCMessage, error)

Recent returns the most recent messages, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*DSCLog) Run added in v0.2.6

func (d *DSCLog) Run(ctx context.Context) error

Run drains KindDSCMessage events until ctx cancels or the bus closes.

type DSCMessage added in v0.2.6

type DSCMessage struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	Format     string    `json:"format"`   // "distress" | "all-ships" | "individual" | "group" | ...
	Category   string    `json:"category"` // "distress" | "urgency" | "safety" | "routine"
	SelfMMSI   uint64    `json:"self_mmsi"`
	TargetMMSI uint64    `json:"target_mmsi,omitempty"`
	Nature     string    `json:"nature,omitempty"`   // distress nature ("fire", "sinking", ...)
	TimeUTC    string    `json:"time_utc,omitempty"` // HH:MM, distress only

	// Position fields — populated only on distress alerts that
	// included a position field with a non-sentinel value.
	Latitude    float64 `json:"latitude,omitempty"`
	Longitude   float64 `json:"longitude,omitempty"`
	HasPosition bool    `json:"has_position"`

	Body   string `json:"body"`    // type-specific summary
	RawHex string `json:"raw_hex"` // hex-encoded 7-bit symbol stream
}

DSCMessage is one persisted decoded DSC sequence.

type HistoryFilter

type HistoryFilter struct {
	System    string
	GroupID   uint32 // 0 = no filter (filters call_log.group_id)
	SourceID  uint32 // 0 = no filter (filters call_log.source_id — RID)
	Since     time.Time
	Until     time.Time
	Limit     int
	OnlyEnded bool
}

HistoryFilter narrows a History query.

type LocationLog added in v0.1.9

type LocationLog struct {
	// contains filtered or unexported fields
}

LocationLog persists geographic fixes to the SQLite location_log table by subscribing to events.KindLocation on the shared bus.

func NewLocationLog added in v0.1.9

func NewLocationLog(db *DB, bus *events.Bus, logger *slog.Logger) (*LocationLog, error)

NewLocationLog wires the location log to the bus. It subscribes immediately so callers can publish before Run starts.

func (*LocationLog) Close added in v0.1.9

func (l *LocationLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*LocationLog) Recent added in v0.1.9

func (l *LocationLog) Recent(limit int) ([]LocationRow, error)

Recent returns the most recent fixes, newest first, capped at limit.

func (*LocationLog) Run added in v0.1.9

func (l *LocationLog) Run(ctx context.Context) error

Run drains KindLocation events until ctx cancels or the bus closes.

type LocationRow added in v0.1.9

type LocationRow struct {
	ID         int64     `json:"id"`
	System     string    `json:"system"`
	Protocol   string    `json:"protocol"`
	RadioID    uint32    `json:"radio_id"`
	Talkgroup  uint32    `json:"talkgroup"`
	Latitude   float64   `json:"latitude"`
	Longitude  float64   `json:"longitude"`
	SpeedKnots float64   `json:"speed_knots"`
	HeadingDeg float64   `json:"heading_deg"`
	ReportedAt time.Time `json:"reported_at"`
}

LocationRow is one persisted fix, returned by Recent.

type M17LinkSetup added in v0.2.9

type M17LinkSetup struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	Src        string    `json:"src"`
	Dst        string    `json:"dst"`
	Mode       string    `json:"mode"` // "voice" | "data" | "voice+data" | "packet"
	CAN        uint8     `json:"can"`  // channel-access number
	Meta       string    `json:"meta"` // hex-encoded META block
	CRCOK      bool      `json:"crc_ok"`
	Body       string    `json:"body"` // display summary
}

M17LinkSetup is one persisted M17 link-setup frame.

type M17Log added in v0.2.9

type M17Log struct {
	// contains filtered or unexported fields
}

M17Log drains KindM17LinkSetup events until ctx cancels or the bus closes.

func NewM17Log added in v0.2.9

func NewM17Log(db *DB, bus *events.Bus, logger *slog.Logger) (*M17Log, error)

NewM17Log wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*M17Log) Close added in v0.2.9

func (m *M17Log) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*M17Log) Recent added in v0.2.9

func (m *M17Log) Recent(limit int) ([]M17LinkSetup, error)

Recent returns the most recent link-setup frames, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*M17Log) Run added in v0.2.9

func (m *M17Log) Run(ctx context.Context) error

Run drains KindM17LinkSetup events until ctx cancels or the bus closes.

type MDC1200Log added in v0.2.7

type MDC1200Log struct {
	// contains filtered or unexported fields
}

MDC1200Log drains KindMDC1200Message events until ctx cancels or the bus closes.

func NewMDC1200Log added in v0.2.7

func NewMDC1200Log(db *DB, bus *events.Bus, logger *slog.Logger) (*MDC1200Log, error)

NewMDC1200Log wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*MDC1200Log) Close added in v0.2.7

func (m *MDC1200Log) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*MDC1200Log) Recent added in v0.2.7

func (m *MDC1200Log) Recent(limit int) ([]MDC1200Message, error)

Recent returns the most recent bursts, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*MDC1200Log) Run added in v0.2.7

func (m *MDC1200Log) Run(ctx context.Context) error

Run drains KindMDC1200Message events until ctx cancels or the bus closes.

type MDC1200Message added in v0.2.7

type MDC1200Message struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	Op         uint8     `json:"op"`
	Arg        uint8     `json:"arg"`
	UnitID     uint16    `json:"unit_id"`
	Operation  string    `json:"operation"` // "PTT ID" | "Emergency" | ... ("" if unknown)
	Body       string    `json:"body"`
	RawHex     string    `json:"raw_hex"`
	CRCOK      bool      `json:"crc_ok"`
}

MDC1200Message is one persisted decoded MDC1200 burst.

type PagerLog added in v0.2.3

type PagerLog struct {
	// contains filtered or unexported fields
}

PagerLog drains KindPagerMessage off the bus and writes one row per page. Mirrors LocationLog's Run/Close lifecycle.

func NewPagerLog added in v0.2.3

func NewPagerLog(db *DB, bus *events.Bus, logger *slog.Logger) (*PagerLog, error)

NewPagerLog wires the log to the bus. The bus subscription happens at construction time so the decoder can publish before Run begins without losing events.

func (*PagerLog) Close added in v0.2.3

func (p *PagerLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*PagerLog) Recent added in v0.2.3

func (p *PagerLog) Recent(limit int) ([]PagerMessage, error)

Recent returns the most recent pages, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*PagerLog) Run added in v0.2.3

func (p *PagerLog) Run(ctx context.Context) error

Run drains KindPagerMessage events until ctx cancels or the bus closes.

type PagerMessage added in v0.2.3

type PagerMessage struct {
	ID         int64     `json:"id"`
	ReceivedAt time.Time `json:"received_at"`
	Protocol   string    `json:"protocol"` // "pocsag" | "flex"
	RIC        uint32    `json:"ric"`
	Func       uint8     `json:"func"` // 0..3 = A..D
	Encoding   string    `json:"encoding"`
	Body       string    `json:"body"`
	Corrected  int       `json:"corrected"`
}

PagerMessage is one persisted page. Mirrors the pocsag.Page shape but with the "encoding" enum widened to a string for storage + JSON convenience.

type Retention

type Retention struct {
	// contains filtered or unexported fields
}

Retention deletes old data on a schedule:

  1. call_log rows with started_at older than CallRowMaxAge.
  2. decoder log-table rows (pager_log, aprs_log, vessel_log, dsc_log, aircraft_log, mdc1200_log, m17_log, location_log) with received_at older than LogRowMaxAge.
  3. WAV / raw files under FilesRoot whose modification time is older than FilesMaxAge.

File deletion is opt-in by setting FilesRoot; an empty value skips the filesystem sweep. The sweeper is idempotent and safe to run concurrently with the log writers (SQLite serialises).

func NewRetention

func NewRetention(opts RetentionOptions) (*Retention, error)

func (*Retention) Run

func (r *Retention) Run(ctx context.Context) error

Run sweeps once at startup and then every Interval until ctx cancels.

func (*Retention) SweepOnce

func (r *Retention) SweepOnce(ctx context.Context)

SweepOnce runs the configured deletions. Errors are logged and swallowed so a transient FS or DB problem doesn't kill the loop.

type RetentionOptions

type RetentionOptions struct {
	DB *DB
	// FilesRoot is the directory the voice recorder writes WAV / raw
	// files under. Empty disables the filesystem sweep.
	FilesRoot string
	// CallRowMaxAge: call_log rows with started_at older than this are
	// deleted. Zero (the default) disables call-row deletion.
	CallRowMaxAge time.Duration
	// LogRowMaxAge: decoder log-table rows (pager_log, aprs_log,
	// vessel_log, dsc_log, aircraft_log, mdc1200_log, m17_log,
	// location_log) with received_at older than this are deleted. Zero
	// (the default) disables decoder-log deletion.
	LogRowMaxAge time.Duration
	// FilesMaxAge: files older than this (mtime) are deleted. Zero
	// disables file deletion.
	FilesMaxAge time.Duration
	// Interval between sweeps. Default 1 h.
	Interval time.Duration
	Log      *slog.Logger
}

RetentionOptions configure a Retention sweeper.

type VesselLog added in v0.2.6

type VesselLog struct {
	// contains filtered or unexported fields
}

VesselLog drains KindAISMessage events until ctx cancels or the bus closes.

func NewVesselLog added in v0.2.6

func NewVesselLog(db *DB, bus *events.Bus, logger *slog.Logger) (*VesselLog, error)

NewVesselLog wires the log to the bus. Subscription happens at construction so events published before Run() begins aren't lost.

func (*VesselLog) Close added in v0.2.6

func (v *VesselLog) Close() error

Close releases the bus subscription and waits for Run to drain.

func (*VesselLog) Recent added in v0.2.6

func (v *VesselLog) Recent(limit int) ([]AISMessage, error)

Recent returns the most recent messages, newest first, capped at limit. limit ≤ 0 picks 200; limit > 5000 caps at 5000.

func (*VesselLog) Run added in v0.2.6

func (v *VesselLog) Run(ctx context.Context) error

Run drains KindAISMessage events until ctx cancels or the bus closes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL