You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

145 lines
2.8 KiB

package mill
import (
"errors"
lucifer3 "git.aiterp.net/lucifer3/server"
"git.aiterp.net/lucifer3/server/commands"
"git.aiterp.net/lucifer3/server/device"
"git.aiterp.net/lucifer3/server/events"
"sync"
)
func NewService() lucifer3.ActiveService {
return &service{
bridges: make([]Bridge, 0, 8),
}
}
type service struct {
mu sync.Mutex
bridges []Bridge
}
func (s *service) Active() bool {
return true
}
func (s *service) HandleEvent(*lucifer3.EventBus, lucifer3.Event) {
// NOP
}
func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
defer s.mu.Unlock()
s.mu.Lock()
switch cmd := command.(type) {
case commands.PairDevice:
// Only mill
if _, ok := cmd.Matches("mill"); !ok {
return
}
// Run connection if needed
err := s.connect(bus, cmd.ID, &cmd.APIKey, nil)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: cmd.ID,
Error: err.Error(),
})
return
}
// Connection successful
bus.RunEvent(events.DeviceAccepted{
ID: cmd.ID,
APIKey: cmd.APIKey,
})
case commands.ConnectDevice:
// Connect if necessary
err := s.connect(bus, cmd.ID, &cmd.APIKey, nil)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: cmd.ID,
Error: err.Error(),
})
return
}
case commands.SetState:
err := s.connect(bus, cmd.ID, nil, &cmd.State)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: cmd.ID,
Error: err.Error(),
})
return
}
case commands.SetStateBatch:
for id, state := range cmd {
err := s.connect(bus, id, nil, &state)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: id,
Error: err.Error(),
})
return
}
}
}
}
func (s *service) connect(
bus *lucifer3.EventBus,
id string,
apiKey *string,
state *device.State,
) error {
hasState := state != nil
if !hasState {
state = &device.State{}
}
// Check if connection is active
for _, bridge := range s.bridges {
// Don't block with dead bridges
if !bridge.IsStarted() {
continue
}
// Setting a dummy state to the bridge to check if it's online
bridge.SetBus(bus)
if ok := bridge.SetState(id, *state); ok {
return nil
}
}
if apiKey == nil {
return errors.New("not connected to device " + id)
}
// Make a bridge, if not a mill ID, this will return ok false
bridge, ok := MakeBridge(id, *apiKey)
if !ok {
return nil
}
bridge.SetBus(bus)
// Start bridge, and throw error if it failed to start
bridge.Start()
if !bridge.IsStarted() {
return errors.New("failed to connect to " + id)
}
// Add bridge to lists
s.bridges = append(s.bridges, bridge)
// Update state, if needed, after first connection
if hasState {
if ok := bridge.SetState(id, *state); !ok {
return errors.New("unable to set state to " + id + " after connecting")
}
}
return nil
}