diff options
Diffstat (limited to 'src/rhrdtime')
-rw-r--r-- | src/rhrdtime/rhrdtime.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/rhrdtime/rhrdtime.go b/src/rhrdtime/rhrdtime.go new file mode 100644 index 0000000..4bdf680 --- /dev/null +++ b/src/rhrdtime/rhrdtime.go @@ -0,0 +1,121 @@ +// +// rhrdtime +// +// The Radio Helsinki Rivendell Time Websocket Server +// +// +// Copyright (C) 2015 Christian Pointner <equinox@helsinki.at> +// +// This file is part of rhrdtime. +// +// rhrdtime is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// rhrdtime is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with rhrdtime. If not, see <http://www.gnu.org/licenses/>. +// + +package main + +import ( + "encoding/json" + "flag" + "fmt" + "net/http" + _ "net/http/pprof" + "time" + + "github.com/gorilla/websocket" +) + +var ( + loc *time.Location +) + +func init() { + var err error + if loc, err = time.LoadLocation("Europe/Vienna"); err != nil { + fmt.Println("Error while loading loaction Europe/Vienna:", err) + } +} + +func getTZOffset(t time.Time) int { + t = t.In(loc) + _, offset := t.Zone() + return offset +} + +type ntpMessage struct { + T1 int64 `json:"t1"` + T2 int64 `json:"t2"` + T3 int64 `json:"t3"` + T4 int64 `json:"t4"` + TZOffset int `json:"tz_offset"` +} + +func handleNTPClient(w http.ResponseWriter, r *http.Request) { + ws, err := websocket.Upgrade(w, r, nil, 1024, 1024) + if _, ok := err.(websocket.HandshakeError); ok { + http.Error(w, "Not a websocket handshake", 400) + return + } else if err != nil { + fmt.Println(err) + return + } + fmt.Println("Client", ws.RemoteAddr(), "connected") + + for { + msgtype, msg, err := ws.ReadMessage() + if err != nil { + fmt.Println("Client", ws.RemoteAddr(), "disconnected:", err) + return + } + now_t2 := time.Now() + if msgtype == websocket.TextMessage { + + var n ntpMessage + if err := json.Unmarshal(msg, &n); err != nil { + fmt.Println("Ignoring malformed (", err, ") NTP message from:", ws.RemoteAddr()) + continue + } + + n.T2 = (now_t2.Unix() * 1000) + int64(now_t2.Nanosecond()/1000000) + n.TZOffset = getTZOffset(now_t2) + + now_t3 := time.Now() + n.T3 = (now_t3.Unix() * 1000) + int64(now_t3.Nanosecond()/1000000) + + ntp_json, err := json.Marshal(n) + if err != nil { + fmt.Println("Error while encoding to json:", err) + continue + } + if err := ws.WriteMessage(websocket.TextMessage, ntp_json); err != nil { + fmt.Println("Client", ws.RemoteAddr(), "write error:", err) + return + } + } + } +} + +func main() { + addr_s := flag.String("addr", ":3000", "addr:port to listen on, default: ':3000'") + help := flag.Bool("help", false, "show usage") + + flag.Parse() + if *help { + flag.Usage() + return + } + + http.HandleFunc("/ntp", handleNTPClient) + + http.ListenAndServe(*addr_s, nil) +} |