package main import ( "encoding/json" "io" "log" "net/http" "os" "sync" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ WriteBufferSize: 4096, ReadBufferSize: 0, CheckOrigin: func(r *http.Request) bool { return true }, } type client struct { nudges chan [2]int quit chan bool } type clientsStore struct { set map[*client]struct{} sync.RWMutex } func main() { var clients clientsStore clients.set = make(map[*client]struct{}) go func() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add("Access-Control-Allow-Headers", "*") w.Header().Add("Access-Control-Allow-Methods", "*") switch r.Method { case "OPTIONS": w.WriteHeader(http.StatusNoContent) return case "POST": var nudge [2]int switch r.Header.Get("Content-Type") { case "application/json": var decoder = json.NewDecoder(r.Body) if err := decoder.Decode(&nudge); err != nil { log.Println(err) w.WriteHeader(http.StatusBadRequest) return } default: w.WriteHeader(http.StatusBadRequest) return } (func(){ clients.RLock() defer clients.RUnlock() for c, _ := range clients.set { select { case c.nudges <- nudge: default: log.Println("Client too slow -> dropping nudge") } } })() w.WriteHeader(http.StatusNoContent) case "GET": w.Header().Add("Content-Type", "text/html") w.WriteHeader(http.StatusOK) file, _ := os.Open("./controller/controller.html") defer file.Close() io.Copy(w, file) default: w.WriteHeader(http.StatusMethodNotAllowed) } }) mux.HandleFunc("/main.css", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/css") w.WriteHeader(http.StatusOK) file, _ := os.Open("./display/main.css") defer file.Close() io.Copy(w, file) }) mux.HandleFunc("/controller.js", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/javascript") w.WriteHeader(http.StatusOK) file, _ := os.Open("./controller/controller.js") defer file.Close() io.Copy(w, file) }) log.Println(http.ListenAndServe(":8080", mux)) }() mux := http.NewServeMux() mux.Handle("/", http.FileServer(http.Dir("./display/"))) mux.HandleFunc("/socket", func(w http.ResponseWriter, r *http.Request) { con, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } defer con.Close() var c client c.nudges = make(chan [2]int) (func() { clients.Lock() defer clients.Unlock() clients.set[&c] = struct{}{} })() defer (func() { clients.Lock() defer clients.Unlock() delete(clients.set, &c) log.Println("Closing client connection") })() con.SetCloseHandler(func(code int, text string) error { close(c.nudges) return nil }) for n := range c.nudges { err := con.WriteJSON(n) if err != nil { log.Println(err) return } } }) log.Println(http.ListenAndServe(":8081", mux)) }