skyview/cmd/vrs-test/main.go

133 lines
2.9 KiB
Go
Raw Normal View History

Add VRS JSON format support for readsb integration Added comprehensive support for VRS (Virtual Radar Server) JSON format as a simpler alternative to Beast binary protocol, enabling integration with readsb --net-vrs-port output. ## Key Features: - **VRS JSON Parser**: Stream parsing of newline-delimited JSON aircraft data - **VRS Client**: TCP client with automatic reconnection and error recovery - **Mixed Format Support**: Use Beast and VRS sources simultaneously - **Enhanced Aircraft Data**: Added VRS-specific fields (registration, type, operator) - **Position Source Tracking**: Identifies ADS-B, MLAT, TIS-B, and satellite positions ## Implementation: - `internal/vrs/parser.go`: VRS JSON message parsing and validation - `internal/client/vrs.go`: VRS TCP client implementation - Enhanced `MultiSourceClient` to support both Beast and VRS formats - Extended `Aircraft` struct with validity flags and additional metadata - Updated configuration to include `format` field ("beast" or "vrs") ## Testing: - Successfully tested against svovel:33005 VRS JSON stream - Verified aircraft data parsing and position tracking - Confirmed mixed-format operation with existing Beast clients ## Documentation: - Updated README.md with VRS format configuration examples - Enhanced ARCHITECTURE.md with VRS parser documentation - Added data format comparison and configuration guide This enables simpler integration with modern readsb installations while maintaining full backward compatibility with existing Beast deployments. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 11:02:27 +02:00
// Package main implements a simple VRS JSON parser test utility.
//
// This utility connects to a VRS JSON source and displays the parsed
// aircraft data for testing and debugging purposes.
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
"skyview/internal/vrs"
)
func main() {
host := flag.String("host", "svovel", "VRS host to connect to")
port := flag.Int("port", 33005, "VRS port to connect to")
flag.Parse()
fmt.Printf("Connecting to VRS JSON source at %s:%d...\n", *host, *port)
// Connect to VRS source
addr := fmt.Sprintf("%s:%d", *host, *port)
conn, err := net.DialTimeout("tcp", addr, 30*time.Second)
if err != nil {
log.Fatalf("Failed to connect to %s: %v", addr, err)
}
defer conn.Close()
fmt.Printf("Connected to %s\n", addr)
// Create VRS parser
parser := vrs.NewParser(conn, "test")
// Set up channels for messages and errors
msgChan := make(chan *vrs.VRSMessage, 100)
errChan := make(chan error, 10)
// Set up signal handling
ctx, cancel := context.WithCancel(context.Background())
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// Start parsing in background
go parser.ParseStream(msgChan, errChan)
// Statistics tracking
messageCount := 0
aircraftCount := 0
startTime := time.Now()
fmt.Println("Receiving VRS JSON data... (Press Ctrl+C to stop)")
fmt.Println("----------------------------------------")
for {
select {
case <-ctx.Done():
fmt.Println("\nShutting down...")
return
case <-sigChan:
fmt.Println("\nReceived interrupt signal")
cancel()
case err := <-errChan:
log.Printf("Parser error: %v", err)
cancel()
case msg := <-msgChan:
if msg == nil {
cancel()
continue
}
messageCount++
aircraftCount += len(msg.AcList)
fmt.Printf("Message %d: %d aircraft\n", messageCount, len(msg.AcList))
// Display first few aircraft for debugging
for i, ac := range msg.AcList {
if i >= 3 { // Only show first 3 aircraft per message
fmt.Printf(" ... and %d more aircraft\n", len(msg.AcList)-i)
break
}
icao, _ := ac.GetICAO24()
fmt.Printf(" ICAO: %06X", icao)
if ac.Call != "" {
fmt.Printf(" Call: %-8s", ac.Call)
}
if ac.HasPosition() {
fmt.Printf(" Pos: %7.3f°, %8.3f°", ac.Lat, ac.Long)
}
if ac.HasAltitude() {
fmt.Printf(" Alt: %5d ft", ac.GetAltitude())
}
if ac.Spd > 0 {
fmt.Printf(" Spd: %3.0f kt", ac.Spd)
}
if ac.Trak > 0 {
fmt.Printf(" Hdg: %3.0f°", ac.Trak)
}
if ac.Gnd {
fmt.Printf(" [GND]")
}
fmt.Printf(" Src: %s\n", ac.GetPositionSource())
}
// Show statistics every 10 messages
if messageCount%10 == 0 {
elapsed := time.Since(startTime)
fmt.Printf("Stats: %d messages, %d total aircraft, %.1fs elapsed\n",
messageCount, aircraftCount, elapsed.Seconds())
}
fmt.Println("----------------------------------------")
}
}
}