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.
 
 
 
 

277 lines
5.1 KiB

package main
import (
"git.aiterp.net/lucifer/new-server/models"
"log"
"strconv"
"strings"
"time"
)
type Param struct {
Index int
Key string
Value string
Operator string
}
func (p *Param) String() *string {
if p == nil {
return nil
}
return &p.Value
}
func (p *Param) TimeOfDay() *models.TimeOfDay {
if p == nil {
return nil
}
tod, err := models.ParseTimeOfDay(p.Value)
if err != nil {
return nil
}
return &tod
}
func (p *Param) TimeOfDayOr(fallback models.TimeOfDay) models.TimeOfDay {
tod := p.TimeOfDay()
if tod == nil {
return fallback
}
return *tod
}
func (p *Param) StringOr(fallback string) string {
if p == nil {
return fallback
}
return p.Value
}
func (p *Param) Int() *int {
if p == nil {
return nil
}
n, err := strconv.Atoi(p.Value)
if err != nil {
return nil
}
return &n
}
func (p *Param) IntOr(other int) int {
val := p.Int()
if val == nil {
return other
}
return *val
}
func (p *Param) Float() *float64 {
if p == nil {
return nil
}
n, err := strconv.ParseFloat(p.Value, 64)
if err != nil {
return nil
}
return &n
}
func (p *Param) Bool() *bool {
if p == nil {
return nil
}
v := strings.ToLower(p.Value)
if v == "yes" || v == "true" || v == "on" {
r := true
return &r
} else if v == "no" || v == "false" || v == "off" {
r := false
return &r
}
return nil
}
type Params []Param
func (p Params) Get(key interface{}) *Param {
switch key := key.(type) {
case string:
for _, p := range p {
if p.Key == key {
return &p
}
}
case int:
for _, p := range p {
if p.Index == key {
return &p
}
}
default:
log.Panicf("Incorrect key type %T", key)
}
return nil
}
func (p Params) Subset(prefix string) Params {
if len(p) == 0 {
return Params{}
}
if len(prefix) > 0 && !strings.HasSuffix(prefix, ".") {
prefix += "."
}
res := make(Params, 0, len(p))
for _, param := range p {
if param.Index == -1 && strings.HasPrefix(param.Key, prefix) {
res = append(res, Param{Index: -1, Key: param.Key[len(prefix):], Value: param.Value, Operator: param.Operator})
}
}
return res
}
func (p Params) StringMap() map[string]string {
res := make(map[string]string)
for _, param := range p {
if param.Index == -1 {
res[param.Key] = param.Value
}
}
return res
}
func (p Params) StringPtrMap() map[string]*string {
res := make(map[string]*string)
for _, param := range p {
if param.Index == -1 {
if param.Value == "NULL" {
res[param.Key] = nil
} else {
res[param.Key] = &param.Value
}
}
}
return res
}
func (p Params) Strings(minIndex int) []string {
res := make([]string, 0, len(p))
for _, param := range p {
if param.Index >= minIndex {
res = append(res, param.Value)
}
}
return res
}
func (p Params) EventConditions() map[string]models.EventCondition {
ecMap := make(map[string]models.EventCondition, len(p))
for _, param := range p {
element, ok := ecMap[param.Key]
if !ok {
element = models.EventCondition{}
}
switch param.Operator {
case "<":
element.LT = param.Value
case "<=":
element.LTE = param.Value
case ">=":
element.GTE = param.Value
case ">":
element.GT = param.Value
default:
element.EQ = param.Value
}
ecMap[param.Key] = element
}
return ecMap
}
func (p Params) DeviceState(prefix string) models.NewDeviceState {
return models.NewDeviceState{
Power: p.Get(prefix + "power").Bool(),
Color: p.Get(prefix + "color").String(),
Intensity: p.Get(prefix + "intensity").Float(),
Temperature: p.Get(prefix + "temperature").Int(),
}
}
func (p Params) SceneAssignment(prefix string) *models.DeviceSceneAssignment {
if p.Get(prefix+"scene") == nil {
return nil
}
return &models.DeviceSceneAssignment{
SceneID: p.Get(prefix+"scene").IntOr(-1),
Group: p.Get(prefix+"scene.group").StringOr(time.Now().Format(time.RFC3339)),
DurationMS: int64(p.Get(prefix+"scene.duration").IntOr(0)),
}
}
type Command struct {
Name string
Params Params
}
func parseCommand(args []string) Command {
if len(args) == 0 {
return Command{Name: "help"}
}
cmd := Command{
Name: args[0],
Params: make(Params, 0, len(args)-1),
}
nextIndex := 0
for _, arg := range args[1:] {
kvle := strings.SplitN(arg, "<=", 2)
kvge := strings.SplitN(arg, ">=", 2)
kvl := strings.SplitN(arg, "<", 2)
kvg := strings.SplitN(arg, ">", 2)
kve := strings.SplitN(arg, "=", 2)
if len(kvle) == 2 {
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvle[0], Value: kvle[1], Operator: "<="})
} else if len(kvge) == 2 {
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvge[0], Value: kvge[1], Operator: ">="})
} else if len(kvl) == 2 {
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvl[0], Value: kvl[1], Operator: "<"})
} else if len(kvg) == 2 {
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvg[0], Value: kvg[1], Operator: ">"})
} else if len(kve) == 2 {
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kve[0], Value: kve[1], Operator: "="})
} else {
cmd.Params = append(cmd.Params, Param{Index: nextIndex, Value: arg})
nextIndex += 1
}
}
return cmd
}