summaryrefslogtreecommitdiff
path: root/src/rhrdtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/rhrdtime')
-rw-r--r--src/rhrdtime/rhrdtime.go121
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)
+}