matemat/uncanny/server.go
2021-01-31 16:56:33 +01:00

120 lines
3.7 KiB
Go

package uncanny
import (
"log"
"fmt"
"net/http"
"path"
"strconv"
)
const (
// highest slot number (range: 0..maxSlot)
maxSlot = 4
)
type Server struct {
*http.ServeMux
can *Can
}
func NewServer(can *Can) *Server {
ret := &Server{
ServeMux: http.NewServeMux(),
can: can,
}
ret.registerHandlers()
return ret
}
func (s *Server) registerHandlers() {
s.HandleFunc("/", http.NotFound)
s.HandleFunc("/dispense/", func(rw http.ResponseWriter, r *http.Request) {
if matched, _ := path.Match("/dispense/[0-9]?[0-9]*", r.URL.Path); matched {
slot, err := strconv.ParseUint(path.Base(r.URL.Path), 10, 32)
if err != nil {
log.Printf("Error decoding slot number: %v", err)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else if slot < 0 || slot > maxSlot {
log.Printf("Invalid slot number: %u", slot)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else {
err = s.can.Dispense(int(slot))
if err != nil {
log.Printf("Error sending dispense command: %v", err)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintf(rw, "%u error", slot)
} else {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusOK)
fmt.Fprintf(rw, "%u dispense", slot)
}
}
} else {
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
})
s.HandleFunc("/stop", func(rw http.ResponseWriter, r *http.Request) {
err := s.can.Cancel()
if err != nil {
log.Printf("Error sending stop command: %v", err)
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintf(rw, "error")
} else {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusOK)
fmt.Fprintf(rw, "stopped")
}
})
s.HandleFunc("/level/", func(rw http.ResponseWriter, r *http.Request) {
if matched, _ := path.Match("/level/[0-9]?[0-9]*", r.URL.Path); matched {
slot, err := strconv.ParseUint(path.Base(r.URL.Path), 10, 32)
if err != nil {
log.Printf("Error decoding slot number: %v", err)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else if slot < 0 || slot > maxSlot {
log.Printf("Invalid slot number: %u", slot)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusOK)
if s.can.IsEmpty(int(slot)) {
fmt.Fprintf(rw, "%u empty", slot)
} else {
fmt.Fprintf(rw, "%u full", slot)
}
}
} else {
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
})
s.HandleFunc("/active/", func(rw http.ResponseWriter, r *http.Request) {
if matched, _ := path.Match("/active/[0-9]?[0-9]*", r.URL.Path); matched {
slot, err := strconv.ParseUint(path.Base(r.URL.Path), 10, 32)
if err != nil {
log.Printf("Error decoding slot number: %v", err)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else if slot < 0 || slot > maxSlot {
log.Printf("Invalid slot number: %u", slot)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
} else {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusOK)
if s.can.IsDispensing(int(slot)) {
fmt.Fprintf(rw, "%u dispensing", slot)
} else {
fmt.Fprintf(rw, "%u off", slot)
}
}
} else {
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}
})
}
func (s *Server) ListenAndServe(addr string) error {
return http.ListenAndServe(addr, s)
}