2020-07-16 22:47:01 +00:00
|
|
|
package service
|
2020-07-16 03:26:31 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
2020-07-16 22:47:01 +00:00
|
|
|
var port = 22495
|
|
|
|
|
|
|
|
|
|
// Listen listens for location requests from clients and return my current coordinates from the db located at dbPath
|
|
|
|
|
// my last known location is always the tail end of the file
|
|
|
|
|
func Listen(dbPath string) {
|
|
|
|
|
http.HandleFunc("/current_location", listenHandler(dbPath))
|
|
|
|
|
log.Printf("Listening: 0.0.0.0:%d", port)
|
|
|
|
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 03:26:31 +00:00
|
|
|
type Location struct {
|
|
|
|
|
Lat float64 `json:"lat"`
|
|
|
|
|
Lon float64 `json:"lon"`
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 22:47:01 +00:00
|
|
|
func listenHandler(dbPath string) (handler func(http.ResponseWriter, *http.Request)) {
|
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
location := currentLocation(dbPath)
|
|
|
|
|
byteArray, err := json.MarshalIndent(location, "", " ")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("error providing current location: %v", err)
|
|
|
|
|
}
|
2020-07-16 03:26:31 +00:00
|
|
|
|
2020-07-16 22:47:01 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
fmt.Fprintf(w, string(byteArray))
|
|
|
|
|
}
|
2020-07-16 03:26:31 +00:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 22:47:01 +00:00
|
|
|
func currentLocation(dbPath string) (location Location) {
|
|
|
|
|
var err error
|
2020-07-16 03:26:31 +00:00
|
|
|
fileHandle, err := os.Open(dbPath)
|
|
|
|
|
if err != nil {
|
2020-07-16 22:47:01 +00:00
|
|
|
log.Fatalf("unable to open db file: %v", err)
|
2020-07-16 03:26:31 +00:00
|
|
|
}
|
|
|
|
|
defer fileHandle.Close()
|
|
|
|
|
|
|
|
|
|
line := ""
|
|
|
|
|
stat, _ := fileHandle.Stat()
|
|
|
|
|
fs := stat.Size()
|
|
|
|
|
var cursor int64 = fs - 1 // start before the newline
|
|
|
|
|
for {
|
|
|
|
|
cursor--
|
|
|
|
|
|
|
|
|
|
char := make([]byte, 1)
|
|
|
|
|
fileHandle.ReadAt(char, cursor)
|
|
|
|
|
|
|
|
|
|
if cursor != -1 && (char[0] == '\n') { // stop if we find a line
|
2020-08-10 01:28:22 +00:00
|
|
|
parseNmeaSentence(line, &location)
|
|
|
|
|
|
|
|
|
|
// break when a 'good' location has been found. This will usually be myst last known location.
|
|
|
|
|
// when the router is reporting 0 coordinates, it doesn't have a signal
|
|
|
|
|
if location.Lat != 0 || location.Lon != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
2020-07-16 03:26:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line = fmt.Sprintf("%s%s", string(char), line) // there is more efficient way
|
|
|
|
|
|
|
|
|
|
if cursor == -fs { // stop if we are at the begining
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-10 01:28:22 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseNmeaSentence(sentence string, location *Location) {
|
|
|
|
|
fields := strings.Split(sentence, ",")
|
2020-07-16 03:26:31 +00:00
|
|
|
|
|
|
|
|
if f, err := strconv.ParseFloat(fields[0], 64); err == nil {
|
|
|
|
|
location.Lat = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f, err := strconv.ParseFloat(fields[1], 64); err == nil {
|
|
|
|
|
location.Lon = f
|
|
|
|
|
}
|
|
|
|
|
}
|