http-boot-server/bootserver/controllers/client/client.go
2024-04-30 18:43:01 +02:00

126 lines
4 KiB
Go

package client
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"git.faercol.me/faercol/http-boot-server/bootserver/config"
"git.faercol.me/faercol/http-boot-server/bootserver/helpers"
"git.faercol.me/faercol/http-boot-server/bootserver/homeassistant"
"git.faercol.me/faercol/http-boot-server/bootserver/services"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)
const SetBootRoute = "/config/boot"
type setBootOptionPayload struct {
ClientID string `json:"client_id"`
OptionID string `json:"option_id"`
}
type BootController struct {
clientService *services.ClientHandlerService
appConf *config.AppConfig
l *logrus.Logger
}
func NewBootController(logger *logrus.Logger, service *services.ClientHandlerService, conf *config.AppConfig) *BootController {
return &BootController{
clientService: service,
l: logger,
appConf: conf,
}
}
func (bc *BootController) setBootOption(w http.ResponseWriter, r *http.Request) (int, []byte, error) {
dat, err := io.ReadAll(r.Body)
if err != nil {
return http.StatusInternalServerError, nil, fmt.Errorf("failed to read body: %w", err)
}
var payload setBootOptionPayload
if err := json.Unmarshal(dat, &payload); err != nil {
return http.StatusBadRequest, nil, fmt.Errorf("failed to parse body: %w", err)
}
clientID, err := uuid.Parse(payload.ClientID)
if err != nil {
return http.StatusBadRequest, []byte("bad client ID"), fmt.Errorf("invalid format for client ID: %w", err)
}
optionID, err := uuid.Parse(payload.OptionID)
if err != nil {
return http.StatusBadRequest, []byte("bad option ID"), fmt.Errorf("invalid format for option ID: %w", err)
}
if err := bc.clientService.SetClientBootOption(clientID, optionID.String()); err != nil {
if errors.Is(err, services.ErrUnknownClient) {
return http.StatusNotFound, []byte("unknown client"), err
}
if errors.Is(err, services.ErrUnknownBootOption) {
return http.StatusNotFound, []byte("unknown boot option"), err
}
return http.StatusInternalServerError, nil, fmt.Errorf("failed to set boot option for client: %w", err)
}
if bc.appConf.HomeAssistantEnabled {
bc.l.Debug("Notifying HomeAssistant of change")
newConf, err := bc.clientService.GetClientConfig(clientID)
if err != nil {
bc.l.Errorf("Failed to get new config to send to HA: %s", err.Error())
} else {
if err := homeassistant.New(bc.appConf).SendBootOption(r.Context(), newConf.Name, newConf.Options[newConf.SelectedOption].Name); err != nil {
bc.l.Errorf("Failed to notify HA: %s", err.Error())
}
}
}
return http.StatusAccepted, nil, nil
}
func (bc *BootController) deleteClient(w http.ResponseWriter, r *http.Request) (int, []byte, error) {
dat, err := io.ReadAll(r.Body)
if err != nil {
return http.StatusInternalServerError, nil, fmt.Errorf("failed to read body: %w", err)
}
var payload setBootOptionPayload
if err := json.Unmarshal(dat, &payload); err != nil {
return http.StatusBadRequest, nil, fmt.Errorf("failed to parse body: %w", err)
}
clientID, err := uuid.Parse(payload.ClientID)
if err != nil {
return http.StatusBadRequest, []byte("bad client ID"), fmt.Errorf("invalid format for client ID: %w", err)
}
if err := bc.clientService.DeleteClient(clientID); err != nil {
return http.StatusInternalServerError, []byte("failed to delete client"), fmt.Errorf("failed to delete client: %w", err)
}
return http.StatusOK, nil, nil
}
func (bc *BootController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var returncode int
var content []byte
var err error
switch r.Method {
case http.MethodPut:
returncode, content, err = bc.setBootOption(w, r)
if err != nil {
bc.l.Errorf("Error setting boot option for client: %s", err.Error())
}
case http.MethodDelete:
returncode, content, err = bc.deleteClient(w, r)
if err != nil {
bc.l.Errorf("Error setting boot option for client: %s", err.Error())
}
default:
helpers.HandleResponse(w, r, http.StatusMethodNotAllowed, nil, bc.l)
return
}
helpers.HandleResponse(w, r, returncode, content, bc.l)
}