feat: prototyping a concurrent location service

This commit is contained in:
js0ny 2025-11-29 23:34:59 +00:00
parent dbf71443c7
commit dac3835078
6 changed files with 104 additions and 0 deletions

3
drone-black-box/go.mod Normal file
View file

@ -0,0 +1,3 @@
module drone-black-box
go 1.25.3

95
drone-black-box/main.go Normal file
View file

@ -0,0 +1,95 @@
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"sync"
)
// Define the DroneEvent struct as JSON
type DroneEvent struct {
DroneID string `json:"drone_id"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Timestamp string `json:"timestamp"`
}
// Shared state type alias
type Server struct {
// This is a shared state between handlers
// It is protected by a mutex to prevent concurrent access
mu sync.RWMutex
history []DroneEvent
}
// Ingest handler
func (s *Server) ingestHandler(w http.ResponseWriter, r *http.Request) {
var event DroneEvent
if err := json.NewDecoder(r.Body).Decode(&event); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Printf("Data ingested: %+v\n", event)
s.mu.Lock()
s.history = append(s.history, event)
s.mu.Unlock()
w.WriteHeader(http.StatusCreated)
}
// Snapshot handler
func (s *Server) snapshotHandler(w http.ResponseWriter, r *http.Request) {
timeParam := r.URL.Query().Get("time")
if timeParam == "" {
http.Error(w, "Missing 'time' query parameter", http.StatusBadRequest)
return
}
s.mu.RLock()
defer s.mu.RUnlock()
latestStates := make(map[string]DroneEvent)
for _, event := range s.history {
if event.Timestamp <= timeParam {
latestStates[event.DroneID] = event
}
}
result := make([]DroneEvent, 0, len(latestStates))
for _, event := range latestStates {
result = append(result, event)
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(result); err != nil {
log.Printf("Error encoding response: %v", err)
}
}
func main() {
// By default, listen on port 3000
port := os.Getenv("BLACKBOX_PORT")
if port == "" {
port = "3000"
}
server := &Server{
history: make([]DroneEvent, 0),
}
mux := http.NewServeMux()
mux.HandleFunc("POST /ingest", server.ingestHandler)
mux.HandleFunc("GET /snapshot", server.snapshotHandler)
fmt.Printf("Black Box Service is running on port %s...\n", port)
if err := http.ListenAndServe(":"+port, mux); err != nil {
log.Fatal(err)
os.Exit(1)
}
}