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] = ¶m.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 }