diff --git a/http/handlers.go b/http/handlers.go index 88fad91..528ee89 100644 --- a/http/handlers.go +++ b/http/handlers.go @@ -20,20 +20,30 @@ type Handler struct { apps map[string]application.App mux *http.ServeMux - verbose bool + verbose bool + autoconnect bool } func NewHandler(verbose bool) *Handler { handler := &Handler{ - verbose: verbose, - apps: map[string]application.App{}, - mux: http.NewServeMux(), - mu: sync.Mutex{}, + verbose: verbose, + apps: map[string]application.App{}, + mux: http.NewServeMux(), + mu: sync.Mutex{}, + autoconnect: false, } handler.registerHandlers() return handler } +// Autoconnect configures the handler to perform auto-discovery of all the cast devices & groups. +// It's intended to be called just after `NewHandler()`, before the handler is registered in the server. +func (h *Handler) Autoconnect() error { + // Setting the autoconnect property - to allow (in future) periodic refresh of the connections. + h.autoconnect = true + return h.connectAllInternal("", "3") +} + func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.mux.ServeHTTP(w, r) } @@ -45,8 +55,9 @@ func (h *Handler) Serve(addr string) error { func (h *Handler) registerHandlers() { /* - GET /devices + GET /devices?wait=...&iface=... POST /connect?uuid=&addr=&port= + POST /connect-all?wait=...&iface=... POST /disconnect?uuid= POST /disconnect-all POST /status?uuid= @@ -66,6 +77,7 @@ func (h *Handler) registerHandlers() { h.mux.HandleFunc("/devices", h.listDevices) h.mux.HandleFunc("/connect", h.connect) + h.mux.HandleFunc("/connect-all", h.connectAll) h.mux.HandleFunc("/disconnect", h.disconnect) h.mux.HandleFunc("/disconnect-all", h.disconnectAll) h.mux.HandleFunc("/status", h.status) @@ -201,28 +213,80 @@ func (h *Handler) connect(w http.ResponseWriter, r *http.Request) { return } + app, err := h.connectInternal(deviceAddr, devicePortI) + if err != nil { + h.log("unable to start application: %v", err) + httpError(w, fmt.Errorf("unable to start application: %v", err)) + return + } + h.mu.Lock() + h.apps[deviceUUID] = app + h.mu.Unlock() + + w.Header().Add("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(connectResponse{DeviceUUID: deviceUUID}); err != nil { + h.log("error encoding json: %v", err) + httpError(w, fmt.Errorf("unable to json encode devices: %v", err)) + return + } +} + +func (h *Handler) connectInternal(deviceAddr string, devicePort int) (application.App, error) { applicationOptions := []application.ApplicationOption{ application.WithDebug(h.verbose), application.WithCacheDisabled(true), } app := application.NewApplication(applicationOptions...) - if err := app.Start(deviceAddr, devicePortI); err != nil { - h.log("unable to start application: %v", err) - httpError(w, fmt.Errorf("unable to start application: %v", err)) - return + if err := app.Start(deviceAddr, devicePort); err != nil { + return nil, err } + return app, nil +} + +func (h *Handler) connectAll(w http.ResponseWriter, r *http.Request) { + h.log("connecting all devices") + q := r.URL.Query() + + wait := q.Get("wait") + iface := q.Get("interface") + + err := h.connectAllInternal(iface, wait) + if err != nil { + h.log("error connecting: %v", err) + httpError(w, fmt.Errorf("unable to connect to device: %v", err)) + } + + var resp []connectResponse h.mu.Lock() - h.apps[deviceUUID] = app + for deviceUUID, _ := range h.apps { + resp = append(resp, connectResponse{DeviceUUID: deviceUUID}) + } h.mu.Unlock() w.Header().Add("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(connectResponse{DeviceUUID: deviceUUID}); err != nil { + if err := json.NewEncoder(w).Encode(resp); err != nil { h.log("error encoding json: %v", err) httpError(w, fmt.Errorf("unable to json encode devices: %v", err)) return } +} + +func (h *Handler) connectAllInternal(iface string, waitSec string) error { + devices := h.discoverDnsEntries(context.Background(), iface, waitSec) + uuidMap := map[string]application.App{} + for _, device := range devices { + app, err := h.connectInternal(device.Addr, device.Port) + if err != nil { + return err + } + uuidMap[device.UUID] = app + } + h.mu.Lock() + h.apps = uuidMap + h.mu.Unlock() + return nil } func (h *Handler) disconnect(w http.ResponseWriter, r *http.Request) {