Files
fancy-n/main.go
T

156 lines
3.4 KiB
Go

package main
import (
"encoding/json"
"io"
"log"
"net"
"net/http"
"os"
"strings"
"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{})
mux := http.NewServeMux()
mux.HandleFunc("/controller", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
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("/controller/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/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)
})
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
}
}
})
var addr string
if env, ok := os.LookupEnv("FANCYN_LISTEN"); ok {
addr = env
} else {
addr = "[::1]:8080"
}
var listener net.Listener
if addr == "inetd" {
if l, err := net.FileListener(os.Stdin); err == nil {
listener = l
} else {
log.Fatal(err)
}
} else if strings.HasPrefix(addr, "unix:") {
if l, err := net.Listen("unix", strings.TrimPrefix(addr, "unix:")); err == nil {
listener = l
} else {
log.Fatal(err)
}
} else {
if l, err := net.Listen("tcp", addr); err == nil {
listener = l
} else {
log.Fatal(err)
}
}
defer listener.Close()
log.Printf("Starting server on %s\n", addr)
log.Println(http.Serve(listener, mux))
}