diff --git a/functions.go b/functions.go new file mode 100644 index 0000000..bb5c2d9 --- /dev/null +++ b/functions.go @@ -0,0 +1,34 @@ +package main + +import ( + "math" + + "github.com/umahmood/haversine" +) + +func rad2deg(rad float64) float64 { + return rad * (180 / math.Pi) +} + +func calcDistance(lat_from float64, lon_from float64, lat_to float64, lon_to float64) float64 { + from := haversine.Coord{Lat: lat_from, Lon: lon_from} + to := haversine.Coord{Lat: lat_to, Lon: lon_to} + _, km := haversine.Distance(from, to) + return km +} + +func calcMps(km float64, seconds float64) float64 { + return (km * 1000) / seconds +} + +func calcKnots(mps float64) float64 { + return mps * 1.94384449 +} + +func calcKph(mps float64) float64 { + return mps * 3.6 +} + +func calcMph(mps float64) float64 { + return mps * 2.23694 +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e2dc2e4 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module gitea.ligthert.net/dcsw_server_map/Listener + +go 1.21.6 + +require github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b6f394d --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 h1:UFHFmFfixpmfRBcxuu+LA9l8MdURWVdVNUHxO5n1d2w= +github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26/go.mod h1:IGhd0qMDsUa9acVjsbsT7bu3ktadtGOHI79+idTew/M= diff --git a/http_listener.go b/http_listener.go new file mode 100644 index 0000000..e94e80b --- /dev/null +++ b/http_listener.go @@ -0,0 +1,11 @@ +package main + +import ( + "io" + "net/http" +) + +func (pool *Pool) getRoot(w http.ResponseWriter, r *http.Request) { + //fmt.Printf("got / request\n") + io.WriteString(w, string(pool.jsonst)+"\n") +} \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..56154c3 --- /dev/null +++ b/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "errors" + "net/http" + "os" + "log" +) + +func main() { + + var pool Pool + pool.logger = log.New(os.Stdout, "[DCS] ", log.Ldate | log.Ltime) + + http.HandleFunc("/", pool.getRoot) + + pool.logger.Println("Starting TCP listener.") + go pool.tcplistener() + + pool.logger.Println("Starting HTTP listener.") + err := http.ListenAndServe("0.0.0.0:8888", nil) + if errors.Is(err, http.ErrServerClosed) { + pool.logger.Println("server closed.") + } else if err != nil { + pool.logger.Printf("error starting server: %s\n", err) + os.Exit(1) + } +} \ No newline at end of file diff --git a/tcp_listener.go b/tcp_listener.go new file mode 100644 index 0000000..8ae2a5a --- /dev/null +++ b/tcp_listener.go @@ -0,0 +1,112 @@ +package main + +import ( + "encoding/json" + "net" + "os" +) + +func (pool *Pool) tcplistener() { + // Listen for incoming connections. + l, err := net.Listen("tcp", "0.0.0.0:12345") + if err != nil { + pool.logger.Println("Error listening:", err.Error()) + os.Exit(1) + } + + // Close the listener when the application closes. + defer l.Close() + + for { + // Listen for an incoming connection. + conn, err := l.Accept() + if err != nil { + pool.logger.Println("Error accepting: ", err.Error()) + os.Exit(1) + } + // Handle connections in a new goroutine. + pool.logger.Println("DCS Mission Started") + go pool.handleRequest(conn) + } +} + +// Handles incoming requests. +func (pool *Pool) handleRequest(conn net.Conn) { + + // Close the connection when you're done with it. + defer conn.Close() + + for { + + // Make an MB of buffer to hold incoming data. + buf := make([]byte, 1024*1024) + + // Read the incoming connection into the buffer. + read_len, err := conn.Read(buf) + if err != nil { + if err.Error() == "EOF" { + pool.logger.Println("Socket closed -- DCS Mission over?") + // Reset buffers + pool.latest = "" + pool.oldest = "" + pool.jsonst = "" + } else { + pool.logger.Println("Error reading:", err.Error()) + } + return + } + + // Copy messages around + pool.oldest = pool.latest + pool.latest = string(buf)[:read_len] + + // Make sure we only do things if there is actual data: + if pool.oldest != "" { + + // Parse JSON + var err error + var json_oldest json_units + var json_latest json_units + + err = json.Unmarshal([]byte(pool.oldest), &json_oldest) + if err != nil { + pool.logger.Println("json_oldest error:", err) + pool.logger.Println("pool.oldest", pool.oldest) + pool.logger.Println("json_oldest", json_oldest) + } + + err = json.Unmarshal([]byte(pool.latest), &json_latest) + if err != nil { + pool.logger.Println("json.latest error:", err) + pool.logger.Println("pool.latest", pool.latest) + pool.logger.Println("json_latest", json_latest) + } + + // Compare JSON + var units []Unit + + for _, vvoor := range json_latest.Units { + for _, vna := range json_oldest.Units { + if vna.UnitName == vvoor.UnitName { + SpeedInMps := calcMps(calcDistance(vvoor.Latitude, vvoor.Longitude, vna.Latitude, vna.Longitude), vvoor.AgeInSeconds-vna.AgeInSeconds) + SpeedInKnots := calcKnots(SpeedInMps) + SpeedInKph := calcKph(SpeedInMps) + SpeedInMph := calcMph(SpeedInMps) + units = append(units, Unit{vna.AgeInSeconds, vna.UnitName, vna.GroupName, vna.Name, vna.Latitude, vna.Longitude, vna.AltitudeInFeet, SpeedInKnots, SpeedInKph, SpeedInMps, SpeedInMph, vna.HeadingInRads, rad2deg(vna.HeadingInRads), vna.PitchInRads, rad2deg(vna.PitchInRads), vna.BankInRads, rad2deg(vna.BankInRads), vna.Coalition, vna.Type}) + } + } + } + + if pool.jsonst == "" { + pool.logger.Println("Making JSON available on HTTP.") + } + json_final, _ := json.Marshal(units) + pool.jsonst = string(json_final) + } + + // Send a response back to person contacting us. + //conn.Write([]byte("Message received\n")) + + } + +} \ No newline at end of file diff --git a/types.go b/types.go new file mode 100644 index 0000000..9df4928 --- /dev/null +++ b/types.go @@ -0,0 +1,51 @@ +package main + +import ( + "log" +) + +type Pool struct { + latest string + oldest string + jsonst string // JSON string, trust me + logger *log.Logger +} + +type json_units struct { + Units []struct { + AgeInSeconds float64 `json:"age_in_seconds"` + UnitName string `json:"unit_name"` + GroupName string `json:"group_name"` + Name string `json:"name"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + AltitudeInFeet float64 `json:"altitude_in_feet"` + HeadingInRads float64 `json:"heading_in_rads"` + PitchInRads float64 `json:"pitch_in_rads"` + BankInRads float64 `json:"bank_in_rads"` + Coalition string `json:"coalition"` + Type string `json:"type"` + } `json:"units"` +} + +type Unit struct { + AgeInSeconds float64 + UnitName string + GroupName string + Name string + Latitude float64 + Longitude float64 + AltitudeInFeet float64 + SpeedInKnots float64 + SpeedInKph float64 + SpeedInMps float64 + SpeedInMph float64 + HeadingInRads float64 + Heading float64 + PitchInRads float64 + Pitch float64 + BankInRads float64 + Bank float64 + Coalition string + Type string +} \ No newline at end of file