From 55edafb33ca2a893814e9b387876db05d25acbdb Mon Sep 17 00:00:00 2001 From: evilsocket Date: Thu, 10 Oct 2024 14:33:52 +0200 Subject: [PATCH] new: implemented named tickers (ref #779) --- modules/events_stream/events_view.go | 2 +- modules/ticker/ticker.go | 129 ++++++++++++++++++++++----- 2 files changed, 107 insertions(+), 24 deletions(-) diff --git a/modules/events_stream/events_view.go b/modules/events_stream/events_view.go index c83e0913..56d0e10d 100644 --- a/modules/events_stream/events_view.go +++ b/modules/events_stream/events_view.go @@ -136,7 +136,7 @@ func (mod *EventsStream) Render(output io.Writer, e session.Event) { mod.viewGatewayEvent(output, e) } else if strings.HasPrefix(e.Tag, "zeroconf.") { mod.viewZeroConfEvent(output, e) - } else if e.Tag != "tick" && e.Tag != "session.started" && e.Tag != "session.stopped" { + } else if !strings.HasPrefix(e.Tag, "tick") && e.Tag != "session.started" && e.Tag != "session.stopped" { fmt.Fprintf(output, "[%s] [%s] %v\n", e.Time.Format(mod.timeFormat), tui.Green(e.Tag), e) } } diff --git a/modules/ticker/ticker.go b/modules/ticker/ticker.go index 3ae8515b..e629d2f0 100644 --- a/modules/ticker/ticker.go +++ b/modules/ticker/ticker.go @@ -1,43 +1,71 @@ package ticker import ( + "errors" + "strconv" "time" "github.com/bettercap/bettercap/v2/session" ) -type Ticker struct { - session.SessionModule +type Params struct { Period time.Duration Commands []string + Running bool +} + +type Ticker struct { + session.SessionModule + + main Params + named map[string]*Params } func NewTicker(s *session.Session) *Ticker { mod := &Ticker{ SessionModule: session.NewSessionModule("ticker", s), + named: make(map[string]*Params), } mod.AddParam(session.NewStringParameter("ticker.commands", "clear; net.show; events.show 20", "", - "List of commands separated by a ;")) + "List of commands for the main ticker separated by a ;")) mod.AddParam(session.NewIntParameter("ticker.period", "1", - "Ticker period in seconds")) + "Main ticker period in seconds")) mod.AddHandler(session.NewModuleHandler("ticker on", "", - "Start the ticker.", + "Start the main ticker.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("ticker off", "", - "Stop the ticker.", + "Stop the maint icker.", func(args []string) error { return mod.Stop() })) + mod.AddHandler(session.NewModuleHandler("ticker.create ", + `(?i)^ticker\.create\s+([^\s]+)\s+(\d+)\s+(.+)$`, + "Create and start a named ticker.", + func(args []string) error { + if period, err := strconv.Atoi(args[1]); err != nil { + return err + } else { + return mod.createNamed(args[0], period, args[2]) + } + })) + + mod.AddHandler(session.NewModuleHandler("ticker.destroy ", + `(?i)^ticker\.destroy\s+([^\s]+)$`, + "Stop a named ticker.", + func(args []string) error { + return mod.destroyNamed(args[0]) + })) + return mod } @@ -66,38 +94,93 @@ func (mod *Ticker) Configure() error { return err } - mod.Commands = session.ParseCommands(commands) - mod.Period = time.Duration(period) * time.Second + mod.main = Params{ + Commands: session.ParseCommands(commands), + Period: time.Duration(period) * time.Second, + Running: true, + } return nil } type TickEvent struct{} +func (mod *Ticker) worker(name string, params *Params) { + isMain := name == "main" + eventName := "tick" + + if isMain { + mod.Info("main ticker running with period %.fs", params.Period.Seconds()) + } else { + eventName = "ticker." + name + mod.Info("ticker '%s' running with period %.fs", name, params.Period.Seconds()) + } + + tick := time.NewTicker(params.Period) + for range tick.C { + if !params.Running { + break + } + + session.I.Events.Add(eventName, TickEvent{}) + for _, cmd := range params.Commands { + if err := mod.Session.Run(cmd); err != nil { + mod.Error("%s", err) + } + } + } + + if isMain { + mod.Info("main ticker stopped") + } else { + mod.Info("ticker '%s' stopped", name) + } +} + func (mod *Ticker) Start() error { if err := mod.Configure(); err != nil { return err } return mod.SetRunning(true, func() { - mod.Info("running with period %.fs", mod.Period.Seconds()) - tick := time.NewTicker(mod.Period) - for range tick.C { - if !mod.Running() { - break - } - - session.I.Events.Add("tick", TickEvent{}) - - for _, cmd := range mod.Commands { - if err := mod.Session.Run(cmd); err != nil { - mod.Error("%s", err) - } - } - } + mod.worker("main", &mod.main) }) } func (mod *Ticker) Stop() error { + mod.main.Running = false + for _, params := range mod.named { + params.Running = false + } + return mod.SetRunning(false, nil) } + +func (mod *Ticker) createNamed(name string, period int, commands string) error { + if _, found := mod.named[name]; found { + return errors.New("ticker '" + name + "' already exists") + } + + params := &Params{ + Commands: session.ParseCommands(commands), + Period: time.Duration(period) * time.Second, + Running: true, + } + + mod.named[name] = params + + go mod.worker(name, params) + + return nil +} + +func (mod *Ticker) destroyNamed(name string) error { + if _, found := mod.named[name]; !found { + return errors.New("ticker '" + name + "' not found") + } + + mod.named[name].Running = false + delete(mod.named, name) + + return nil +}