// // rhrdtime // // The Radio Helsinki Rivendell Time Websocket Server // // // Copyright (C) 2015 Christian Pointner // // 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 . // 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) }