websocket backend + frontend patching.

This commit is contained in:
2023-08-30 22:56:58 +02:00
parent e8b77ae69c
commit 64bb737569
17 changed files with 664 additions and 361 deletions
+55 -1
View File
@@ -8,10 +8,12 @@ import (
"git.aiterp.net/lucifer3/server/services/script"
"git.aiterp.net/lucifer3/server/services/uistate"
"github.com/google/uuid"
"github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"log"
"net"
"net/http"
"sync"
)
@@ -24,6 +26,11 @@ var zeroUUID = uuid.UUID{
func New(addr string) (lucifer3.Service, error) {
svc := &service{}
upgrader := websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
e := echo.New()
e.HideBanner = true
@@ -38,6 +45,28 @@ func New(addr string) (lucifer3.Service, error) {
return c.JSON(200, data)
})
e.GET("/subscribe", func(c echo.Context) error {
ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
if err != nil {
return err
}
sub := make(chan uistate.Patch, 64)
svc.addSub(sub)
defer svc.removeSub(sub)
defer ws.Close()
for patch := range sub {
err := ws.WriteJSON(patch)
if err != nil {
break
}
}
return nil
})
e.POST("/command", func(c echo.Context) error {
var input commandInput
err := c.Bind(&input)
@@ -115,6 +144,7 @@ type service struct {
mu sync.Mutex
data uistate.Data
bus *lucifer3.EventBus
subs []chan uistate.Patch
}
func (s *service) Active() bool {
@@ -130,12 +160,36 @@ func (s *service) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
case uistate.Patch:
s.mu.Lock()
s.data = s.data.WithPatch(event)
subs := s.subs
s.mu.Unlock()
// TODO: Broadcast websockets
for _, sub := range subs {
select {
case sub <- event:
default:
}
}
}
}
func (s *service) addSub(ch chan uistate.Patch) {
s.mu.Lock()
s.subs = append(s.subs, ch)
s.mu.Unlock()
}
func (s *service) removeSub(ch chan uistate.Patch) {
s.mu.Lock()
s.subs = append([]chan uistate.Patch{}, s.subs...)
for i, sub := range s.subs {
if sub == ch {
s.subs = append(s.subs[:i], s.subs[i+1:]...)
break
}
}
s.mu.Unlock()
}
type commandInput struct {
Assign *assignInput `json:"assign,omitempty"`
AddAlias *commands.AddAlias `json:"addAlias,omitempty"`
+2 -2
View File
@@ -155,7 +155,7 @@ func (b *Bridge) RefreshAll() ([]lucifer3.Event, error) {
}
}
if res.Type == "device" {
if res.Type == "device" && !strings.HasPrefix(res.Metadata.Archetype, "bridge") {
hwState, hwEvent := res.GenerateEvent(b.host, resources)
if hwState.SupportFlags == 0 {
continue
@@ -219,7 +219,7 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
for _, resource := range resources {
if resource.Owner != nil && resource.Owner.Kind == "device" {
if parent, ok := mapCopy[resource.Owner.ID]; ok {
if parent, ok := mapCopy[resource.Owner.ID]; ok && !strings.HasPrefix(parent.Metadata.Archetype, "bridge") {
hwState, _ := parent.GenerateEvent(b.host, mapCopy)
eventList = append(eventList, hwState)
+11 -9
View File
@@ -29,6 +29,7 @@ func (d *Data) WithPatch(patches ...Patch) Data {
gentools.ApplyUpdatePtr(&pd.DesiredState, patch.Device.DesiredState)
gentools.ApplyUpdatePtr(&pd.Assignment, patch.Device.Assignment)
gentools.ApplyUpdatePtr(&pd.ActiveColorRGB, patch.Device.ActiveColorRGB)
gentools.ApplyUpdatePtr(&pd.DesiredColorRGB, patch.Device.DesiredColorRGB)
if patch.Device.AddAlias != nil {
pd.Aliases = append(pd.Aliases[:0:0], pd.Aliases...)
@@ -125,15 +126,16 @@ func (d *Data) ensureAssignment(id uuid.UUID) Assignment {
}
type Device struct {
ID string `json:"id"`
Name string `json:"name"`
HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
HWState *events.HardwareState `json:"hwState"`
ActiveColorRGB *color.RGB `json:"activeColorRgb"`
DesiredState *device.State `json:"desiredState"`
Aliases []string `json:"aliases"`
Assignment *uuid.UUID `json:"assignment"`
Sensors DeviceSensors `json:"sensors"`
ID string `json:"id"`
Name string `json:"name"`
HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
HWState *events.HardwareState `json:"hwState"`
DesiredColorRGB *color.RGB `json:"desiredColorRgb"`
ActiveColorRGB *color.RGB `json:"activeColorRgb"`
DesiredState *device.State `json:"desiredState"`
Aliases []string `json:"aliases"`
Assignment *uuid.UUID `json:"assignment"`
Sensors DeviceSensors `json:"sensors"`
}
type DeviceSensors struct {
+4
View File
@@ -38,6 +38,9 @@ func (e Patch) EventDescription() string {
case e.Device.ActiveColorRGB != nil:
col := color.Color{RGB: e.Device.ActiveColorRGB}
return fmt.Sprintf("uistate.Patch(device=%s, activeColorRgb=%s)", e.Device.ID, col.String())
case e.Device.DesiredColorRGB != nil:
col := color.Color{RGB: e.Device.DesiredColorRGB}
return fmt.Sprintf("uistate.Patch(device=%s, desiredColorRgb=%s)", e.Device.ID, col.String())
default:
return fmt.Sprintf("uistate.Patch(device=%s, ...other)", e.Device.ID)
}
@@ -61,6 +64,7 @@ type DevicePatch struct {
RemoveAlias *string `json:"removeAlias,omitempty"`
Assignment *uuid.UUID `json:"assignment,omitempty"`
ClearAssignment bool `json:"clearAssignment,omitempty"`
DesiredColorRGB *color.RGB `json:"desiredColorRgb,omitempty"`
ActiveColorRGB *color.RGB `json:"activeColorRgb,omitempty"`
ClearActiveColorRGB bool `json:"clearActiveColorRGB,omitempty"`
Sensors *DeviceSensors `json:"sensors,omitempty"`
+28 -6
View File
@@ -5,6 +5,7 @@ import (
"git.aiterp.net/lucifer3/server/commands"
"git.aiterp.net/lucifer3/server/effects"
"git.aiterp.net/lucifer3/server/events"
"git.aiterp.net/lucifer3/server/internal/color"
"git.aiterp.net/lucifer3/server/internal/gentools"
"git.aiterp.net/lucifer3/server/services/script"
"github.com/google/uuid"
@@ -36,11 +37,29 @@ func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command
switch command := command.(type) {
case commands.SetState:
patches = []Patch{{Device: &DevicePatch{ID: command.ID, DesiredState: &command.State}}}
rgb := color.Color{}
if command.State.Color != nil {
rgb, _ = command.State.Color.ToRGB()
}
patches = []Patch{{Device: &DevicePatch{
ID: command.ID,
DesiredState: &command.State,
DesiredColorRGB: rgb.RGB,
}}}
case commands.SetStateBatch:
for id, state := range command {
rgb := color.Color{}
if state.Color != nil {
rgb, _ = state.Color.ToRGB()
}
patches = append(patches, Patch{
Device: &DevicePatch{ID: id, DesiredState: gentools.ShallowCopy(&state)},
Device: &DevicePatch{
ID: id,
DesiredState: gentools.ShallowCopy(&state),
DesiredColorRGB: rgb.RGB,
},
})
}
case script.Update:
@@ -129,10 +148,13 @@ func (s *service) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
}})
case events.AssignmentVariables:
// Always set the assignment
patches = append(patches, Patch{Assignment: &AssignmentPatch{
ID: event.ID,
Variables: event.Map,
}})
if len(event.Map) > 0 {
patches = append(patches, Patch{Assignment: &AssignmentPatch{
ID: event.ID,
Variables: event.Map,
}})
}
}
if len(patches) > 0 {