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.
 
 
 
 
 
 

118 lines
2.9 KiB

package script
import (
lucifer3 "git.aiterp.net/lucifer3/server"
"git.aiterp.net/lucifer3/server/commands"
"git.aiterp.net/lucifer3/server/device"
"git.aiterp.net/lucifer3/server/internal/formattools"
"git.aiterp.net/lucifer3/server/internal/gentools"
"sort"
"sync"
)
type service struct {
mu sync.Mutex
resolver device.Resolver
variables *Variables
scripts map[string]*Script
}
func (s *service) Active() bool {
return true
}
func (s *service) HandleEvent(_ *lucifer3.EventBus, _ lucifer3.Event) {}
func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
switch command := command.(type) {
case UpdateScript:
s.mu.Lock()
s.scripts[command.Name] = &Script{
Name: command.Name,
Lines: command.Lines,
}
s.mu.Unlock()
case ExecuteScript:
s.mu.Lock()
script := s.scripts[command.Name]
s.mu.Unlock()
if script == nil {
break
}
variables := s.variables.Get()
devices := s.resolver.Resolve(command.Match)
sort.Slice(devices, func(i, j int) bool {
return devices[i].ID < devices[j].ID
})
s.runScript(bus, script.Lines, command.Match, map[string]bool{}, devices, variables)
}
}
func NewService(resolver device.Resolver, variables *Variables) lucifer3.Service {
return &service{
resolver: resolver,
variables: variables,
scripts: map[string]*Script{},
}
}
func (s *service) runScript(bus *lucifer3.EventBus, lines []Line, match string, matchedDevices map[string]bool, devices []device.Pointer, variables VariableSet) {
for _, line := range lines {
if line.If != nil {
devicesIDs := gentools.Map(devices, func(d device.Pointer) string { return d.ID })
if line.If.Condition.Check(variables, match, devicesIDs) {
s.runScript(bus, line.If.Then, match, matchedDevices, devices, variables)
} else {
s.runScript(bus, line.If.Else, match, matchedDevices, devices, variables)
}
} else if line.Assign != nil {
matcher := s.resolver.CompileMatcher(line.Assign.Match)
matched := make([]string, 0)
for _, dev := range devices {
if matchedDevices[dev.ID] {
continue
}
if dev.Matches(matcher) {
matchedDevices[dev.ID] = true
matched = append(matched, dev.ID)
}
}
if len(matched) > 0 {
bus.RunCommand(commands.Assign{
Match: formattools.CompactMatch(matched),
Effect: line.Assign.Effect.Effect,
})
}
} else {
if line.Set != nil {
switch line.Set.Scope {
case "devices":
bus.RunCommand(SetVariable{
Devices: gentools.Map(devices, func(d device.Pointer) string {
return d.ID
}),
Key: line.Set.Key,
Value: line.Set.Value,
})
case "match":
bus.RunCommand(SetVariable{
Match: gentools.Ptr(match),
Key: line.Set.Key,
Value: line.Set.Value,
})
case "global":
bus.RunCommand(SetVariable{
Key: line.Set.Key,
Value: line.Set.Value,
})
}
}
}
}
}