mtsatellite/cmd/mtwebmapper/players.go

98 lines
1.8 KiB
Go

package main
import (
"bufio"
"bytes"
"encoding/json"
"html/template"
"log"
"net/http"
"os"
"sync"
"time"
)
const sleepInterval = time.Second * 5
var geoJSONTmpl = template.Must(template.New("geojson").Parse(
`{ "type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [{{.X}}, {{.Z}}]
},
"properties": {
"name": "{{.Name | html }}"
}
}`))
type player struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
Name string `json:"name"`
}
type players struct {
fifo string
wsf *websocketForwarder
pls []*player
mu sync.RWMutex
}
func newPlayers(fifo string, wsf *websocketForwarder) *players {
return &players{fifo: fifo, wsf: wsf, pls: []*player{}}
}
func (p *player) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
if err := geoJSONTmpl.Execute(&buf, p); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (ps *players) readFromFIFO() ([]*player, error) {
file, err := os.Open(ps.fifo)
if err != nil {
return nil, err
}
defer file.Close()
reader := bufio.NewReader(file)
decoder := json.NewDecoder(reader)
var pls []*player
if err = decoder.Decode(&pls); err != nil {
return nil, err
}
return pls, nil
}
func (ps *players) run() {
for {
pls, err := ps.readFromFIFO()
if err != nil {
time.Sleep(sleepInterval)
continue
}
ps.mu.Lock()
ps.pls = pls
ps.mu.Unlock()
if ps.wsf != nil {
// TODO: Throttle this!
ps.wsf.BroadcastPlayers(pls)
}
}
}
func (ps *players) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set("Content-Type", "application/json")
var pls []*player
ps.mu.RLock()
pls = ps.pls
ps.mu.RUnlock()
encoder := json.NewEncoder(rw)
if err := encoder.Encode(pls); err != nil {
log.Printf("error: sending JSON failed: %s\n", err)
}
}