diff --git a/client/backend.go b/client/backend.go index 8aceb49..bd3f79a 100644 --- a/client/backend.go +++ b/client/backend.go @@ -1,8 +1,35 @@ package client -import "github.com/sqshq/sampler/storage" +import ( + "github.com/sqshq/sampler/metadata" + "net/http" +) -// TODO -func loadLicense(key string) *storage.License { - return nil +const ( + backendUrl = "http://localhost:8080/api/v1" + registrationPath = "/registration" + reportInstallationPath = "/report/installation" + reportCrashPath = "repost/crash" +) + +type BackendClient struct { + client http.Client +} + +func NewBackendClient() *BackendClient { + return &BackendClient{ + client: http.Client{}, + } +} + +func (c *BackendClient) ReportInstallation(statistics *metadata.Statistics) { + // TODO +} + +func (c *BackendClient) ReportCrash() { + // TODO +} + +func (c *BackendClient) Register(key string) { + // TODO } diff --git a/component/layout/layout.go b/component/layout/layout.go index 6e5f6b0..bf69b5f 100644 --- a/component/layout/layout.go +++ b/component/layout/layout.go @@ -41,8 +41,9 @@ const ( statusbarHeight = 1 ) -func NewLayout(width, height int, statusline *component.StatusBar, menu *component.Menu, intro *component.Intro) *Layout { +func NewLayout(statusline *component.StatusBar, menu *component.Menu, intro *component.Intro) *Layout { + width, height := ui.TerminalDimensions() block := *ui.NewBlock() block.SetRect(0, 0, width, height) intro.SetRect(0, 0, width, height) diff --git a/component/statusbar.go b/component/statusbar.go index 3cef5b8..3175da6 100644 --- a/component/statusbar.go +++ b/component/statusbar.go @@ -4,7 +4,7 @@ import ( "fmt" ui "github.com/gizak/termui/v3" "github.com/sqshq/sampler/console" - "github.com/sqshq/sampler/storage" + "github.com/sqshq/sampler/metadata" "image" ) @@ -18,7 +18,7 @@ type StatusBar struct { text string } -func NewStatusLine(configFileName string, palette console.Palette, license *storage.License) *StatusBar { +func NewStatusLine(configFileName string, palette console.Palette, license *metadata.License) *StatusBar { block := *ui.NewBlock() block.Border = false diff --git a/config/config.go b/config/config.go index 8f2a71f..2470d75 100644 --- a/config/config.go +++ b/config/config.go @@ -21,20 +21,34 @@ type Config struct { AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"` } -func LoadConfig() (Config, Options) { +func LoadConfig() (*Config, Options) { var opt Options _, err := flags.Parse(&opt) if err != nil { + panic(err) + } + + if opt.Version == true { + println(console.AppVersion) os.Exit(0) } + if opt.ConfigFile == nil && opt.License == nil { + println("Please specify config file using --config flag. Example: sampler --config example.yml") + os.Exit(0) + } + + if opt.License != nil { + return nil, opt + } + cfg := readFile(opt.ConfigFile) cfg.validate() cfg.setDefaults() - return *cfg, opt + return cfg, opt } func Update(settings []ComponentSettings, options Options) { @@ -91,11 +105,11 @@ func (c *Config) findComponent(componentType ComponentType, componentTitle strin "Failed to find component type %v with title %v", componentType, componentTitle)) } -func readFile(location string) *Config { +func readFile(location *string) *Config { - yamlFile, err := ioutil.ReadFile(location) + yamlFile, err := ioutil.ReadFile(*location) if err != nil { - log.Fatalf("Failed to read config file: %s", location) + log.Fatalf("Failed to read config file: %s", *location) } cfg := new(Config) @@ -108,13 +122,12 @@ func readFile(location string) *Config { return cfg } -func saveFile(config *Config, fileName string) { +func saveFile(config *Config, fileName *string) { file, err := yaml.Marshal(config) if err != nil { log.Fatalf("Failed to marshal config file: %v", err) } - - err = ioutil.WriteFile(fileName, file, os.ModePerm) + err = ioutil.WriteFile(*fileName, file, os.ModePerm) if err != nil { log.Fatalf("Failed to save config file: %v", err) } diff --git a/config/options.go b/config/options.go index c315126..d04277d 100644 --- a/config/options.go +++ b/config/options.go @@ -1,7 +1,8 @@ package config type Options struct { - ConfigFile string `short:"c" long:"config" required:"true" description:"path to YAML config file"` - Variables []string `short:"v" long:"variable" required:"false" description:"specify name=value variable to use in script placeholder as $name. This flag takes precedence over the same name variables, specified in config yml" long-description:"one or more variables can be specified as flags, in order to replace repeated patterns in the scripts, which can be replaced with {$variable-name} placeholder" ` - License []string `short:"l" long:"license" required:"false" description:"provide license key. visit www.sampler.dev for details"` + ConfigFile *string `short:"c" long:"config" required:"false" description:"set path to YAML config file"` + License *string `short:"l" long:"license" required:"false" description:"provide license key. visit www.sampler.dev for details"` + Environment []string `short:"e" long:"env" required:"false" description:"specify name=value variable to use in script placeholder as $name. This flag takes precedence over the same name variables, specified in config yml"` + Version bool `short:"v" long:"version" required:"false" description:"print version"` } diff --git a/data/sampler.go b/data/sampler.go index 89d9475..b0b0d48 100644 --- a/data/sampler.go +++ b/data/sampler.go @@ -23,7 +23,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options items, triggers, make(chan *Sample), - mergeVariables(fileVariables, options.Variables), + mergeVariables(fileVariables, options.Environment), } go func() { diff --git a/data/trigger.go b/data/trigger.go index 4f670fa..ebc449f 100644 --- a/data/trigger.go +++ b/data/trigger.go @@ -120,7 +120,7 @@ func (t *Trigger) runScript(script, label string, data Values) ([]byte, error) { cmd := exec.Command("sh", "-c", script) cmd.Env = os.Environ() - for _, variable := range t.options.Variables { + for _, variable := range t.options.Environment { cmd.Env = append(cmd.Env, variable) } diff --git a/main.go b/main.go index 3780e8a..4224d07 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( ui "github.com/gizak/termui/v3" "github.com/sqshq/sampler/asset" + "github.com/sqshq/sampler/client" "github.com/sqshq/sampler/component" "github.com/sqshq/sampler/component/asciibox" "github.com/sqshq/sampler/component/barchart" @@ -15,7 +16,7 @@ import ( "github.com/sqshq/sampler/console" "github.com/sqshq/sampler/data" "github.com/sqshq/sampler/event" - "github.com/sqshq/sampler/storage" + "github.com/sqshq/sampler/metadata" "time" ) @@ -45,54 +46,58 @@ func main() { player := asset.NewAudioPlayer() defer player.Close() + license := metadata.GetLicense() + statistics := metadata.PersistStatistics(cfg) + + if opt.License != nil { + // validate license + // save to storage on success + // exit with info + return + } + palette := console.GetPalette(*cfg.Theme) - width, height := ui.TerminalDimensions() - - license := storage.GetLicense() - _ = storage.UpdateStatistics(cfg, width, height) - - lout := layout.NewLayout(width, height, component.NewStatusLine(opt.ConfigFile, palette, license), component.NewMenu(palette), component.NewIntro(palette)) - starter := &Starter{lout, player, opt, cfg} + lout := layout.NewLayout(component.NewStatusLine(*opt.ConfigFile, palette, license), component.NewMenu(palette), component.NewIntro(palette)) + bc := client.NewBackendClient() if license == nil { lout.RunIntro() - storage.InitLicense() + metadata.InitLicense() + bc.ReportInstallation(statistics) } else if !license.Purchased /* && random */ { // TODO lout.showNagWindow() with timeout and OK button - // TODO verify license - // TODO send stats } - for _, c := range cfg.RunCharts { - cpt := runchart.NewRunChart(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers) - } - - for _, c := range cfg.SparkLines { - cpt := sparkline.NewSparkLine(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) - } - - for _, c := range cfg.BarCharts { - cpt := barchart.NewBarChart(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers) - } - - for _, c := range cfg.Gauges { - cpt := gauge.NewGauge(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Cur, c.Min, c.Max}, c.Triggers) - } - - for _, c := range cfg.AsciiBoxes { - cpt := asciibox.NewAsciiBox(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) - } - - for _, c := range cfg.TextBoxes { - cpt := textbox.NewTextBox(c, palette) - starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) - } + starter := &Starter{lout, player, opt, *cfg} + startComponents(starter, cfg, palette) handler := event.NewHandler(lout, opt) handler.HandleEvents() } + +func startComponents(starter *Starter, cfg *config.Config, palette console.Palette) { + for _, c := range cfg.RunCharts { + cpt := runchart.NewRunChart(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers) + } + for _, c := range cfg.SparkLines { + cpt := sparkline.NewSparkLine(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) + } + for _, c := range cfg.BarCharts { + cpt := barchart.NewBarChart(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers) + } + for _, c := range cfg.Gauges { + cpt := gauge.NewGauge(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Cur, c.Min, c.Max}, c.Triggers) + } + for _, c := range cfg.AsciiBoxes { + cpt := asciibox.NewAsciiBox(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) + } + for _, c := range cfg.TextBoxes { + cpt := textbox.NewTextBox(c, palette) + starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) + } +} diff --git a/storage/license.go b/metadata/license.go similarity index 97% rename from storage/license.go rename to metadata/license.go index 391c1af..06afa98 100644 --- a/storage/license.go +++ b/metadata/license.go @@ -1,4 +1,4 @@ -package storage +package metadata import ( "gopkg.in/yaml.v2" diff --git a/storage/statistics.go b/metadata/statistics.go similarity index 75% rename from storage/statistics.go rename to metadata/statistics.go index 2142805..8a417d4 100644 --- a/storage/statistics.go +++ b/metadata/statistics.go @@ -1,6 +1,7 @@ -package storage +package metadata import ( + ui "github.com/gizak/termui/v3" "github.com/sqshq/sampler/config" "github.com/sqshq/sampler/console" "gopkg.in/yaml.v2" @@ -19,27 +20,34 @@ type Statistics struct { const statisticsFileName = "statistics.yml" -func UpdateStatistics(config config.Config, width int, height int) *Statistics { +func PersistStatistics(config *config.Config) *Statistics { statistics := new(Statistics) + w, h := ui.TerminalDimensions() if fileExists(statisticsFileName) { file := readStorageFile(getPlatformStoragePath(statisticsFileName)) err := yaml.Unmarshal(file, statistics) + if err != nil { log.Fatalf("Failed to read statistics file: %v", err) } - statistics.ComponentsCount = countComponentsPerType(config) - statistics.WindowWidth = width - statistics.WindowWidth = height + + if config != nil { + statistics.ComponentsCount = countComponentsPerType(config) + } + + statistics.WindowWidth = w + statistics.WindowWidth = h statistics.LaunchCount += 1 + } else { statistics = &Statistics{ Version: console.AppVersion, OS: runtime.GOOS, LaunchCount: 1, - WindowWidth: width, - WindowHeight: height, + WindowWidth: w, + WindowHeight: h, ComponentsCount: countComponentsPerType(config), } } @@ -54,13 +62,20 @@ func UpdateStatistics(config config.Config, width int, height int) *Statistics { return statistics } -func countComponentsPerType(config config.Config) map[string]int { +func countComponentsPerType(config *config.Config) map[string]int { + m := make(map[string]int) + + if config == nil { + return m + } + m["runcharts"] = len(config.RunCharts) m["sparkLines"] = len(config.SparkLines) m["barcharts"] = len(config.BarCharts) m["gauges"] = len(config.Gauges) m["asciiboxes"] = len(config.AsciiBoxes) m["textboxes"] = len(config.TextBoxes) + return m } diff --git a/storage/storage.go b/metadata/storage.go similarity index 98% rename from storage/storage.go rename to metadata/storage.go index acbe214..beb62d4 100644 --- a/storage/storage.go +++ b/metadata/storage.go @@ -1,4 +1,4 @@ -package storage +package metadata import ( "io/ioutil"