diff --git a/asset/player.go b/asset/player.go index d91c3d3..42b86da 100644 --- a/asset/player.go +++ b/asset/player.go @@ -1,7 +1,6 @@ package asset import ( - "fmt" "github.com/hajimehoshi/go-mp3" "github.com/hajimehoshi/oto" "io" @@ -31,7 +30,5 @@ func Beep() error { return err } - fmt.Print("\a") - return nil } diff --git a/component/runchart/runchart.go b/component/runchart/runchart.go index 1b9f181..1bdcfcb 100644 --- a/component/runchart/runchart.go +++ b/component/runchart/runchart.go @@ -2,6 +2,7 @@ package runchart import ( "fmt" + "github.com/sqshq/sampler/component/trigger" "github.com/sqshq/sampler/console" "github.com/sqshq/sampler/data" "image" @@ -36,6 +37,7 @@ const ( type RunChart struct { ui.Block + triggers []trigger.Trigger lines []TimeLine grid ChartGrid timescale time.Duration diff --git a/component/trigger/trigger.go b/component/trigger/trigger.go new file mode 100644 index 0000000..4307d88 --- /dev/null +++ b/component/trigger/trigger.go @@ -0,0 +1,99 @@ +package trigger + +import ( + "fmt" + "github.com/sqshq/sampler/asset" + "github.com/sqshq/sampler/config" + "os" + "os/exec" +) + +const ( + TrueIndicator = "1" + BellCharacter = "\a" +) + +type Trigger struct { + title string + condition string + actions Actions + data map[string]Data +} + +type Actions struct { + terminalBell bool + sound bool + visual bool + script *string +} + +type Data struct { + previousValue interface{} + currentValue interface{} +} + +func NewTrigger(config config.TriggerConfig) Trigger { + return Trigger{ + title: config.Title, + condition: config.Condition, + actions: Actions{ + terminalBell: *config.Actions.TerminalBell, + sound: *config.Actions.Sound, + visual: *config.Actions.Visual, + script: config.Actions.Script, + }, + } +} + +func (t Trigger) execute(label string, value interface{}) { + go func() { + if data, ok := t.data[label]; ok { + data.previousValue = data.currentValue + data.currentValue = value + } else { + t.data[label] = Data{previousValue: nil, currentValue: value} + } + t.evaluate(label, t.data[label]) + }() +} + +func (t Trigger) evaluate(label string, data Data) { + + output, err := runScript(t.condition, label, data) + + if err != nil { + println(err) // TODO visual notification + } + + if string(output) != TrueIndicator { + return + } + + if t.actions.terminalBell { + fmt.Print(BellCharacter) + } + + if t.actions.sound { + _ = asset.Beep() + } + + if t.actions.visual { + // TODO visual notification + } + + if t.actions.script != nil { + _, _ = runScript(*t.actions.script, label, data) + } +} + +func runScript(script, label string, data Data) ([]byte, error) { + cmd := exec.Command("sh", "-c", script) + + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, + fmt.Sprintf("prev=%v", data.previousValue), + fmt.Sprintf("cur=%v", data.currentValue), + fmt.Sprintf("label=%v", label)) + + return cmd.Output() +} diff --git a/config.yml b/config.yml index 73c4b60..70b49b7 100644 --- a/config.yml +++ b/config.yml @@ -6,7 +6,6 @@ runcharts: size: w: 53 h: 16 - scale: 3 triggers: - title: PROCESSING STARTED # ${prev} ${cur} ${lavel} echo $(( 3 < 4 && 1 > 2 )) condition: ((${prev} == 0 && ${cur} > 0)) diff --git a/config/component.go b/config/component.go index 6076b85..e6c236a 100644 --- a/config/component.go +++ b/config/component.go @@ -7,10 +7,11 @@ import ( ) type ComponentConfig struct { - Title string `yaml:"title"` - RefreshRateMs *int `yaml:"refresh-rate-ms,omitempty"` - Position Position `yaml:"position"` - Size Size `yaml:"size"` + Title string `yaml:"title"` + RefreshRateMs *int `yaml:"refresh-rate-ms,omitempty"` + Position Position `yaml:"position"` + Size Size `yaml:"size"` + Triggers []TriggerConfig `yaml:"triggers,omitempty"` } type TriggerConfig struct { @@ -28,7 +29,6 @@ type ActionsConfig struct { type GaugeConfig struct { ComponentConfig `yaml:",inline"` - Triggers []TriggerConfig `yaml:"triggers"` Scale *int `yaml:"scale,omitempty"` Color *ui.Color `yaml:"color,omitempty"` Values map[string]string `yaml:"values"` @@ -37,24 +37,21 @@ type GaugeConfig struct { type BarChartConfig struct { ComponentConfig `yaml:",inline"` - Triggers []TriggerConfig `yaml:"triggers"` - Scale *int `yaml:"scale,omitempty"` - Items []data.Item `yaml:"items"` + Scale *int `yaml:"scale,omitempty"` + Items []data.Item `yaml:"items"` } type AsciiBoxConfig struct { ComponentConfig `yaml:",inline"` - Triggers []TriggerConfig `yaml:"triggers"` data.Item `yaml:",inline"` Font *asciibox.AsciiFont `yaml:"font,omitempty"` } type RunChartConfig struct { ComponentConfig `yaml:",inline"` - Triggers []TriggerConfig `yaml:"triggers"` - Legend *LegendConfig `yaml:"legend,omitempty"` - Scale *int `yaml:"scale,omitempty"` - Items []data.Item `yaml:"items"` + Legend *LegendConfig `yaml:"legend,omitempty"` + Scale *int `yaml:"scale,omitempty"` + Items []data.Item `yaml:"items"` } type LegendConfig struct { diff --git a/config/config.go b/config/config.go index 3ad3716..ce64c29 100644 --- a/config/config.go +++ b/config/config.go @@ -24,16 +24,16 @@ type Flags struct { func Load() (Config, Flags) { - //if len(os.Args) < 2 { - // println("Please specify config file location. See www.github.com/sqshq/sampler for the reference") - // os.Exit(0) - //} + if len(os.Args) < 2 { + println("Please specify config file location. See www.github.com/sqshq/sampler for the reference") + os.Exit(0) + } - cfg := readFile("config.yml") + cfg := readFile(os.Args[1]) cfg.validate() cfg.setDefaults() - flg := Flags{ConfigFileName: "config.yml"} + flg := Flags{ConfigFileName: os.Args[1]} return *cfg, flg }