From 2705ff6140f9f18f805eaba297339a6f5d62a97c Mon Sep 17 00:00:00 2001 From: "kayos@tcp.direct" Date: Fri, 8 Jul 2022 17:09:49 -0700 Subject: [PATCH] _Nice_ --- common/ui.go | 3 ++ config/config.go | 4 +- interactive/cli.go | 26 ++++++++----- interactive/commands.go | 66 +++++++++++++++++--------------- main.go | 25 ++++++------ {lights => ziggy}/lights.go | 40 ++++++++++--------- {lights => ziggy}/multiplexor.go | 2 +- 7 files changed, 92 insertions(+), 74 deletions(-) create mode 100644 common/ui.go rename {lights => ziggy}/lights.go (95%) rename {lights => ziggy}/multiplexor.go (89%) diff --git a/common/ui.go b/common/ui.go new file mode 100644 index 0000000..68f51e8 --- /dev/null +++ b/common/ui.go @@ -0,0 +1,3 @@ +package common + +var ZiggsPointer = func(to []rune) []rune { return []rune(``) } diff --git a/config/config.go b/config/config.go index fb4ba3b..a9edcdd 100644 --- a/config/config.go +++ b/config/config.go @@ -97,9 +97,9 @@ func setDefaults() { "use_date_filename": true, } Opt["bridges"] = map[string]interface{}{ - "hostname": "192.168.6.100", + "hostname": "192.168.69.100", "username": "", - "proxy": "socks5://127.0.0.1:8060", + "proxy": "", } Opt["http"] = map[string]interface{}{ diff --git a/interactive/cli.go b/interactive/cli.go index 310d32c..af521d5 100644 --- a/interactive/cli.go +++ b/interactive/cli.go @@ -11,8 +11,9 @@ import ( tui "github.com/manifoldco/promptui" "github.com/rs/zerolog" + "git.tcp.direct/kayos/ziggs/common" "git.tcp.direct/kayos/ziggs/config" - "git.tcp.direct/kayos/ziggs/lights" + "git.tcp.direct/kayos/ziggs/ziggy" ) var log *zerolog.Logger @@ -45,10 +46,8 @@ func InteractiveAuth() string { // Interpret is where we will actuall define our commands func executor(cmd string) { cmd = strings.TrimSpace(cmd) - var args []string args = strings.Split(cmd, " ") - switch args[0] { case "quit", "exit": os.Exit(0) @@ -57,7 +56,7 @@ func executor(cmd string) { println("use: use ") return } - if br, ok := lights.Lucifer.Bridges[args[1]]; !ok { + if br, ok := ziggy.Lucifer.Bridges[args[1]]; !ok { println("invalid bridge: " + args[1]) } else { selectedBridge = args[1] @@ -83,12 +82,20 @@ func executor(cmd string) { default: bcmd, ok := bridgeCMD[args[0]] if !ok { - println() return } - br, ok := lights.Lucifer.Bridges[selectedBridge] + br, ok := ziggy.Lucifer.Bridges[selectedBridge] if selectedBridge == "" || !ok { - for _, br := range lights.Lucifer.Bridges { + prompt := tui.Select{ + Label: "Send to all known bridges?", + Items: []string{"yes", "no"}, + Pointer: common.ZiggsPointer, + } + _, ch, _ := prompt.Run() + if ch != "yes" { + return + } + for _, br := range ziggy.Lucifer.Bridges { go bcmd(br, args[1:]) } } else { @@ -98,7 +105,6 @@ func executor(cmd string) { } } } - } func getHelp(target string) { @@ -129,7 +135,7 @@ func getHelp(target string) { */ } -func cmdScan(br *lights.Bridge, args []string) error { +func cmdScan(br *ziggy.Bridge, args []string) error { r, err := br.FindLights() if err != nil { return err @@ -171,7 +177,7 @@ func StartCLI() { log = config.GetLogger() var hist []string - processBridges(lights.Lucifer.Bridges) + processBridges(ziggy.Lucifer.Bridges) /* comphead := 0 compmu := &sync.Mutex{} diff --git a/interactive/commands.go b/interactive/commands.go index 11d6664..942038d 100644 --- a/interactive/commands.go +++ b/interactive/commands.go @@ -9,7 +9,7 @@ import ( cli "git.tcp.direct/Mirrors/go-prompt" "github.com/amimof/huego" - "git.tcp.direct/kayos/ziggs/lights" + "git.tcp.direct/kayos/ziggs/ziggy" ) var errInvalidFormat = errors.New("invalid format") @@ -49,7 +49,7 @@ func ParseHexColorFast(s string) (c color.RGBA, err error) { return } -func cmdLights(br *lights.Bridge, args []string) error { +func cmdLights(br *ziggy.Bridge, args []string) error { if len(br.HueLights) == 0 { return errors.New("no lights found") } @@ -61,7 +61,7 @@ func cmdLights(br *lights.Bridge, args []string) error { return nil } -func cmdSet(bridge *lights.Bridge, args []string) error { +func cmdSet(bridge *ziggy.Bridge, args []string) error { if len(args) < 3 { return errors.New("not enough arguments") } @@ -80,7 +80,8 @@ func cmdSet(bridge *lights.Bridge, args []string) error { var groupmap map[string]huego.Group - var action func() error + type action func() error + var actions []action var currentState *huego.State var argHead = -1 @@ -107,11 +108,11 @@ func cmdSet(bridge *lights.Bridge, args []string) error { } target = &g case "on": - action = target.On + actions = append(actions, target.On) case "off": - action = target.Off + actions = append(actions, target.Off) case "brightness--", "dim": - action = func() error { + actions = append(actions, func() error { if currentState == nil { return fmt.Errorf("no state found") } @@ -120,9 +121,9 @@ func cmdSet(bridge *lights.Bridge, args []string) error { err = fmt.Errorf("couldn't lower brightness: %w", err) } return err - } + }) case "brightness++", "brighten": - action = func() error { + actions = append(actions, func() error { if currentState == nil { return fmt.Errorf("no state found") } @@ -131,7 +132,7 @@ func cmdSet(bridge *lights.Bridge, args []string) error { err = fmt.Errorf("couldn't raise brightness: %w", err) } return err - } + }) case "brightness": if len(args) == argHead-1 { return errors.New("no brightness specified") @@ -141,13 +142,13 @@ func cmdSet(bridge *lights.Bridge, args []string) error { if numErr != nil { return fmt.Errorf("given brightness is not a number: %w", numErr) } - action = func() error { + actions = append(actions, func() error { err := target.Bri(uint8(newBrightness)) if err != nil { err = fmt.Errorf("failed to set brightness: %w", err) } return err - } + }) case "color": if len(args) == argHead-1 { return errors.New("not enough arguments") @@ -157,26 +158,26 @@ func cmdSet(bridge *lights.Bridge, args []string) error { if err != nil { return err } - action = func() error { + actions = append(actions, func() error { colErr := target.Col(newcolor) if colErr != nil { colErr = fmt.Errorf("failed to set color: %w", colErr) } return colErr - } + }) case "alert": - action = func() error { + actions = append(actions, func() error { alErr := target.Alert("select") if alErr != nil { alErr = fmt.Errorf("failed to turn on alert: %w", alErr) } return alErr - } + }) default: return fmt.Errorf("unknown argument: " + args[argHead]) } } - if action == nil { + if actions == nil { return errors.New("no action specified") } if target == nil { @@ -191,21 +192,24 @@ func cmdSet(bridge *lights.Bridge, args []string) error { currentState = tl.State } log.Trace().Msgf("current state: %v", currentState) - err := action() - if err != nil { - return err + for d, act := range actions { + log.Trace().Msgf("running action %d", d) + err := act() + if err != nil { + return err + } + switch { + case tgok: + currentState = tg.State + case tlok: + currentState = tl.State + } + log.Trace().Msgf("new state: %v", currentState) } - switch { - case tgok: - currentState = tg.State - case tlok: - currentState = tl.State - } - log.Trace().Msgf("new state: %v", currentState) return nil } -func getGroupMap(br *lights.Bridge) (map[string]huego.Group, error) { +func getGroupMap(br *ziggy.Bridge) (map[string]huego.Group, error) { var groupmap = make(map[string]huego.Group) gs, err := br.Bridge.GetGroups() if err != nil { @@ -217,7 +221,7 @@ func getGroupMap(br *lights.Bridge) (map[string]huego.Group, error) { return groupmap, nil } -func cmdGroups(br *lights.Bridge, args []string) error { +func cmdGroups(br *ziggy.Bridge, args []string) error { groupmap, err := getGroupMap(br) if err != nil { return err @@ -232,7 +236,7 @@ func cmdGroups(br *lights.Bridge, args []string) error { return nil } -type reactor func(bridge *lights.Bridge, args []string) error +type reactor func(bridge *ziggy.Bridge, args []string) error var bridgeCMD = map[string]reactor{ "scan": cmdScan, @@ -247,7 +251,7 @@ type completeMapper map[cli.Suggest][]cli.Suggest var suggestions completeMapper = make(map[cli.Suggest][]cli.Suggest) -func processBridges(brs map[string]*lights.Bridge) { +func processBridges(brs map[string]*ziggy.Bridge) { for brd, c := range brs { suggestions[cli.Suggest{Text: "use"}] = append( suggestions[cli.Suggest{Text: "use"}], diff --git a/main.go b/main.go index ec64ec5..770c5ab 100644 --- a/main.go +++ b/main.go @@ -10,9 +10,10 @@ import ( "github.com/manifoldco/promptui" "github.com/rs/zerolog" + "git.tcp.direct/kayos/ziggs/common" "git.tcp.direct/kayos/ziggs/config" "git.tcp.direct/kayos/ziggs/interactive" - "git.tcp.direct/kayos/ziggs/lights" + "git.tcp.direct/kayos/ziggs/ziggy" ) var ( @@ -28,23 +29,23 @@ func init() { } } -func TurnAll(Known []*lights.Bridge, mode lights.ToggleMode) { +func TurnAll(Known []*ziggy.Bridge, mode ziggy.ToggleMode) { for _, bridge := range Known { for _, l := range bridge.HueLights { - go func(l *lights.HueLight) { + go func(l *ziggy.HueLight) { l.Log().Debug(). Str("caller", bridge.Host). Str("type", l.ProductName). Bool("on", l.IsOn()).Msg(l.ModelID) ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second)) - lights.Assert(ctx, l, mode) + ziggy.Assert(ctx, l, mode) defer cancel() }(l) } } } -func FindLights(ctx context.Context, c *lights.Bridge) error { +func FindLights(ctx context.Context, c *ziggy.Bridge) error { log.Trace().Msg("looking for lights...") resp, err := c.FindLights() if err != nil { @@ -71,7 +72,7 @@ func FindLights(ctx context.Context, c *lights.Bridge) error { } } -func getNewSensors(known *lights.Bridge) { +func getNewSensors(known *ziggy.Bridge) { go known.FindSensors() Sensors, err := known.GetNewSensors() if err != nil { @@ -98,7 +99,7 @@ func selSensor(Sensors []*huego.Sensor) huego.Sensor { CursorPos: 0, HideHelp: false, HideSelected: false, - Pointer: func(to []rune) []rune { return []rune(``) }, + Pointer: common.ZiggsPointer, } i, s, e := p.Run() if e != nil { @@ -109,9 +110,9 @@ func selSensor(Sensors []*huego.Sensor) huego.Sensor { } func main() { - var Known []*lights.Bridge + var Known []*ziggy.Bridge var err error - Known, err = lights.Setup() + Known, err = ziggy.Setup() if err != nil { log.Fatal().Err(err).Msg("failed to get bridges") @@ -123,13 +124,13 @@ func main() { case "on": log.Debug().Msg("turning all " + arg) - TurnAll(Known, lights.ToggleOn) + TurnAll(Known, ziggy.ToggleOn) case "off": log.Debug().Msg("turning all " + arg) - TurnAll(Known, lights.ToggleOff) + TurnAll(Known, ziggy.ToggleOff) case "rainbow": log.Debug().Msg("turning all " + arg) - TurnAll(Known, lights.ToggleRainbow) + TurnAll(Known, ziggy.ToggleRainbow) case "scan": log.Debug().Msg("executing " + arg) if len(os.Args) < 2 { diff --git a/lights/lights.go b/ziggy/lights.go similarity index 95% rename from lights/lights.go rename to ziggy/lights.go index 0fd427e..647cbee 100644 --- a/lights/lights.go +++ b/ziggy/lights.go @@ -1,4 +1,4 @@ -package lights +package ziggy import ( "context" @@ -21,6 +21,7 @@ import ( "golang.org/x/net/proxy" "inet.af/netaddr" + "git.tcp.direct/kayos/ziggs/common" "git.tcp.direct/kayos/ziggs/config" ) @@ -281,9 +282,7 @@ func promptForUser(cnt *Bridge) bool { Items: []string{"Create new user", "Provide existing username"}, CursorPos: 0, IsVimMode: false, - Pointer: func(x []rune) []rune { - return []rune("") - }, + Pointer: common.ZiggsPointer, } choice, _, _ := confirmPrompt.Run() switch choice { @@ -307,9 +306,7 @@ func promptForUser(cnt *Bridge) bool { }, Mask: 'x', HideEntered: false, - Pointer: func(x []rune) []rune { - return []rune("") - }, + Pointer: common.ZiggsPointer, } var err error var input string @@ -409,15 +406,13 @@ func scanChoicePrompt(interfaces []net.Interface) net.Interface { Items: interfaces, CursorPos: 0, IsVimMode: false, - Pointer: func(x []rune) []rune { - return []rune("") - }, + Pointer: common.ZiggsPointer, } choice, _, _ := confirmPrompt.Run() return interfaces[choice] } -func checkAddrs(addrs []net.Addr, working *int32, resChan chan interface{}) { +func checkAddrs(ctx context.Context, addrs []net.Addr, working *int32, resChan chan interface{}) { var init = &sync.Once{} log.Trace().Msg("checking addresses") for _, a := range addrs { @@ -425,11 +420,18 @@ func checkAddrs(addrs []net.Addr, working *int32, resChan chan interface{}) { ips := network.IterateNetRange(netaddr.MustParseIPPrefix(a.String())) for ipa := range ips { init.Do(func() { resChan <- &huego.Bridge{} }) + ctxLoop: for { - if atomic.LoadInt32(working) > 50 { - time.Sleep(time.Second) + select { + case <-ctx.Done(): + return + default: + if atomic.LoadInt32(working) > 25 { + time.Sleep(100 * time.Millisecond) + continue + } + break ctxLoop } - break } log.Trace().Msgf("checking %s", ipa.String()) atomic.AddInt32(working, 1) @@ -461,8 +463,9 @@ func scanForBridges() ([]*huego.Bridge, error) { } var working int32 resChan := make(chan interface{}, 55) + ctx, cancel := context.WithCancel(context.Background()) log.Trace().Interface("addresses", addrs).Msg("checkAddrs()") - go checkAddrs(addrs, &working, resChan) + go checkAddrs(ctx, addrs, &working, resChan) <-resChan // wait for sync.Once to throw us a nil resultLoop: @@ -473,9 +476,12 @@ resultLoop: if ok && bridge != nil { log.Info().Msgf("found %T: %v", bridge, bridge) hueIPs = append(hueIPs, bridge) + cancel() + atomic.StoreInt32(&working, 0) } default: if atomic.LoadInt32(&working) <= 0 { + cancel() break resultLoop } } @@ -495,9 +501,7 @@ func promptForDiscovery() error { Items: []string{"Yes", "No"}, CursorPos: 0, IsVimMode: false, - Pointer: func(x []rune) []rune { - return []rune("") - }, + Pointer: common.ZiggsPointer, } choice, _, _ := confirmPrompt.Run() if choice != 0 { diff --git a/lights/multiplexor.go b/ziggy/multiplexor.go similarity index 89% rename from lights/multiplexor.go rename to ziggy/multiplexor.go index 4b8c6d4..879fbca 100644 --- a/lights/multiplexor.go +++ b/ziggy/multiplexor.go @@ -1,4 +1,4 @@ -package lights +package ziggy // Multiplex is all of the lights (all of the lights). // I'll see myself out.