Checkpoint
Some checks failed
Test and build / Test and lint (push) Failing after 36s
Test and build / Build collector (push) Failing after 43s
Test and build / Build receiver (push) Failing after 42s

This commit is contained in:
2026-03-05 15:38:18 +01:00
parent 3106b2cf45
commit 13afa08e8a
108 changed files with 19509 additions and 729 deletions

273
server/types.go Normal file
View File

@@ -0,0 +1,273 @@
// Package server provides HTTP API endpoints for HAMView
//
// # API Documentation
//
// This package exposes REST API endpoints for querying amateur radio data.
// All endpoints return JSON responses and use standard HTTP status codes.
//
// # Base URL
//
// All API endpoints are prefixed with `/api/v1`
//
// # Response Format
//
// Success responses return the requested data with HTTP 200 OK status.
// Error responses return JSON with the following structure:
//
// {
// "error": "error message description"
// }
//
// # HTTP Status Codes
//
// - 200 OK: Request successful
// - 400 Bad Request: Invalid query parameters
// - 404 Not Found: Resource not found
// - 500 Internal Server Error: Server error
//
// # Data Types
//
// ## Radio
//
// Represents an amateur radio receiver/station.
//
// JSON Schema:
//
// {
// "id": integer, // Unique identifier
// "name": string, // Station name (unique)
// "is_online": boolean, // Current online status
// "manufacturer": string, // Hardware manufacturer
// "device": string | null, // Device model name
// "firmware_version": string | null, // Firmware version string
// "firmware_date": string | null, // Firmware date (ISO 8601)
// "antenna": string | null, // Antenna description
// "modulation": string, // Modulation type (e.g., "LoRa")
// "protocol": string, // Protocol name (e.g., "meshcore", "aprs")
// "latitude": number | null, // Latitude in decimal degrees
// "longitude": number | null, // Longitude in decimal degrees
// "altitude": number | null, // Altitude in meters
// "frequency": number, // Frequency in Hz
// "bandwidth": number, // Bandwidth in Hz
// "power": number | null, // Transmit power in dBm
// "gain": number | null, // Antenna gain in dBi
// "lora_sf": integer | null, // LoRa spreading factor (7-12)
// "lora_cr": integer | null, // LoRa coding rate (5-8)
// "extra": object | null, // Additional metadata
// "created_at": string, // Creation timestamp (ISO 8601)
// "updated_at": string // Last update timestamp (ISO 8601)
// }
//
// Example:
//
// {
// "id": 1,
// "name": "Station-Alpha",
// "is_online": true,
// "manufacturer": "Heltec",
// "device": "WiFi LoRa 32 V3",
// "firmware_version": "1.0.0",
// "firmware_date": "2026-01-15T00:00:00Z",
// "antenna": "868MHz 3dBi",
// "modulation": "LoRa",
// "protocol": "meshcore",
// "latitude": 52.3667,
// "longitude": 4.8945,
// "altitude": 5.0,
// "frequency": 868.1,
// "bandwidth": 125.0,
// "power": 14.0,
// "gain": 3.0,
// "lora_sf": 7,
// "lora_cr": 5,
// "extra": null,
// "created_at": "2026-01-01T12:00:00Z",
// "updated_at": "2026-03-05T10:30:00Z"
// }
//
// ## MeshCorePacket
//
// Represents a received MeshCore protocol packet.
//
// JSON Schema:
//
// {
// "id": integer, // Unique packet identifier
// "radio_id": integer, // Radio that received this packet
// "radio": Radio | null, // Radio object (when populated)
// "snr": number, // Signal-to-noise ratio in dB
// "rssi": integer, // Received signal strength in dBm
// "version": integer, // Protocol version
// "route_type": integer, // Routing type (0=broadcast, 1=unicast, etc.)
// "payload_type": integer, // Payload type identifier
// "hash": string, // 16-character hex hash
// "path": string, // Base64-encoded routing path
// "payload": string, // Base64-encoded payload data
// "raw": string, // Base64-encoded raw packet
// "parsed": object | null, // Parsed payload (type depends on payload_type)
// "channel_hash": string, // 2-character channel hash (for group messages)
// "received_at": string // Reception timestamp (ISO 8601)
// }
//
// Example:
//
// {
// "id": 12345,
// "radio_id": 1,
// "radio": null,
// "snr": 8.5,
// "rssi": -95,
// "version": 1,
// "route_type": 0,
// "payload_type": 3,
// "hash": "a1b2c3d4e5f67890",
// "path": "AQIDBA==",
// "payload": "SGVsbG8gV29ybGQ=",
// "raw": "AQIDBAUGBwg=",
// "parsed": {"text": "Hello World"},
// "channel_hash": "ab",
// "received_at": "2026-03-05T14:30:00Z"
// }
//
// ## MeshCoreNode
//
// Represents a MeshCore network node.
//
// JSON Schema:
//
// {
// "id": integer, // Unique node identifier
// "packet": MeshCorePacket[], // Associated packets
// "name": string, // Node name/callsign
// "type": integer, // Node type (0=repeater, 1=chat, 2=room, 3=sensor)
// "prefix": string, // 2-character network prefix
// "public_key": string, // Hex-encoded Ed25519 public key (64 chars)
// "first_heard_at": string, // First heard timestamp (ISO 8601)
// "last_heard_at": string, // Last heard timestamp (ISO 8601)
// "last_latitude": number | null, // Last known latitude
// "last_longitude": number | null, // Last known longitude
// "distance": number // Distance in meters (only in proximity queries)
// }
//
// Example:
//
// {
// "id": 42,
// "packet": [],
// "name": "NODE-CHARLIE",
// "type": 0,
// "prefix": "mc",
// "public_key": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
// "first_heard_at": "2026-01-15T08:00:00Z",
// "last_heard_at": "2026-03-05T14:25:00Z",
// "last_latitude": 52.3667,
// "last_longitude": 4.8945,
// "distance": 0
// }
//
// ## MeshCoreGroup
//
// Represents a MeshCore group/channel.
//
// JSON Schema:
//
// {
// "id": integer, // Unique group identifier
// "name": string, // Group name (max 32 chars)
// "secret": string // Group secret/key (32 chars)
// }
//
// Example:
//
// {
// "id": 5,
// "name": "General Chat",
// "secret": "0123456789abcdef0123456789abcdef"
// }
//
// ## MeshCoreStats
//
// Aggregated statistics for the MeshCore network.
//
// JSON Schema:
//
// {
// "messages": integer, // Total message count
// "nodes": integer, // Total node count
// "receivers": integer, // Total receiver count
// "packets": {
// "timestamps": integer[], // Unix timestamps
// "packets": integer[] // Packet counts per timestamp
// }
// }
//
// Example:
//
// {
// "messages": 150234,
// "nodes": 127,
// "receivers": 8,
// "packets": {
// "timestamps": [1709650800, 1709654400, 1709658000],
// "packets": [142, 203, 178]
// }
// }
//
// ## NodesCloseToResponse
//
// Response for nodes proximity query.
//
// JSON Schema:
//
// {
// "node": MeshCoreNode, // The reference node
// "nodes": MeshCoreNode[] // Nearby nodes (with distance field populated)
// }
//
// Example:
//
// {
// "node": {
// "id": 42,
// "name": "NODE-CHARLIE",
// "type": 0,
// "prefix": "mc",
// "public_key": "1234...abcdef",
// "first_heard_at": "2026-01-15T08:00:00Z",
// "last_heard_at": "2026-03-05T14:25:00Z",
// "last_latitude": 52.3667,
// "last_longitude": 4.8945,
// "distance": 0
// },
// "nodes": [
// {
// "id": 43,
// "name": "NODE-DELTA",
// "type": 0,
// "prefix": "mc",
// "public_key": "abcd...5678",
// "first_heard_at": "2026-02-01T10:00:00Z",
// "last_heard_at": "2026-03-05T14:20:00Z",
// "last_latitude": 52.3700,
// "last_longitude": 4.9000,
// "distance": 450.5
// }
// ]
// }
//
// ## ErrorResponse
//
// Standard error response format.
//
// JSON Schema:
//
// {
// "error": string // Human-readable error message
// }
//
// Example:
//
// {
// "error": "invalid hash"
// }
package server