I have created a Golang WebApp that shows the time. I am new to the Golang programming language so thought this little app would allow me to use golang as a webserver, learn about goroutines and websockets which I am also new to.
I would like to know if my code follows best practices especially regarding goroutines/threading and the use of websockets.
Index.html
<!doctype html> <html class="no-js" lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> </head> <body> <!--[if lt IE 8]> <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> <![endif]--> <h1>Golang Clock WebApp</h1> <h3> <span id="name">Header Text</span> <button id="get-time-manually">Update Time</button> </h3> <hr/> <div id="container"></div> <script type="text/javascript"> $ ( document ).ready(function() { getTime(); $ ( "#get-time-manually" ).click(function() { getTime(); }); var ws; if (window.WebSocket === undefined) { $ ("#container").append("Your browser does not support WebSockets"); return; } else { ws = initWS(); } }); function getTime() { $ .get( "/time", function( data ) { $ ( "#name" ).html( JSON.parse(data) ); }); }; function initWS() { var socket = new WebSocket("ws://localhost:8080/ws"), container = $ ("#container") socket.onmessage = function (e) { $ ( "#name" ).html( JSON.parse(e.data) ); }; return socket; }; </script> </body> </html>
main.go
package main import ( "encoding/json" "fmt" "net/http" "time" "github.com/gorilla/mux" "github.com/gorilla/websocket" ) func newRouter() *mux.Router { router := mux.NewRouter() router.HandleFunc("/time", getTimeHandler).Methods("GET") router.HandleFunc("/ws", getWebSocketHandler) // /assets/ Page staticFileDirectory := http.Dir("./assets/") staticFileHandler := http.StripPrefix("/assets/", http.FileServer(staticFileDirectory)) router.PathPrefix("/assets/").Handler(staticFileHandler).Methods("GET") return router } func main() { router := newRouter() http.ListenAndServe(":8080", router) } func getTimeHandler(w http.ResponseWriter, r *http.Request) { timeBytes, err := json.Marshal(getTimeNow()) // If there is an error, print it to the console, and return a server // error response to the user if err != nil { fmt.Println(fmt.Errorf("Error: %v", err)) w.WriteHeader(http.StatusInternalServerError) return } // If all goes well, write the JSON to the response w.Write(timeBytes) } func getWebSocketHandler(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Origin") != "http://"+r.Host { //"ws://" + location.host + "/ws" http.Error(w, "Origin not allowed", 403) return } conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) if err != nil { http.Error(w, "Could not open websocket connection", http.StatusBadRequest) } go timeRoutine(conn) } func timeRoutine(conn *websocket.Conn) { t := time.NewTicker(time.Second * 3) for { timeString := getTimeNow() if err := conn.WriteJSON(timeString); err != nil { fmt.Println(err) } <-t.C } } func getTimeNow() string { timeNow := time.Now() formattedTime := timeNow.Format("Mon Jan 02 15:04:05 MST 2006") return formattedTime }
The full repo can be found here