package app import ( "fmt" "io" "log" "net/http" "net/url" "os" "time" "git.buddy.wtf/buddy/open-hardware-monitor-client/lib/client" "git.buddy.wtf/buddy/open-hardware-monitor-client/lib/metrics" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/urfave/cli/v2" ) // App context type App struct { cli *cli.App Client *client.Client Out io.Writer } // FlagHost flag for host var FlagHost = &cli.StringFlag{ Name: "host", EnvVars: []string{"OHWM_HOST"}, Value: "127.0.0.1", Usage: "open hardware monitor host [OSHW_HOST]", } // FlagPort flag for host var FlagPort = &cli.IntFlag{ Name: "port", EnvVars: []string{"OHWM_PORT"}, Value: 8085, Usage: "open hardware port [OSHW_PORT]", } // FlagScheme flag for host var FlagScheme = &cli.StringFlag{ Name: "scheme", EnvVars: []string{"OHWM_SCHEME"}, Value: "http", Usage: "open hardware monitor scheme (http/https)", } // FlagPath flag for path url var FlagPath = &cli.StringFlag{ Name: "path", EnvVars: []string{"OHWM_PATH"}, Value: "/data.json", Usage: "open hardware monitor path (ie /data.json)", } // FlagInterface flag for host var FlagInterface = &cli.StringFlag{ Name: "http", EnvVars: []string{"OHWM_HTTP"}, Value: ":9200", Usage: "interface to serve http requests", } // New returns instance of an app func New() *App { cliapp := cli.NewApp() app := &App{ Out: os.Stdout, cli: cliapp, } app.cli.Name = "ohwm-client" app.cli.Description = "Open Hardware Manager Client" app.cli.UsageText = "ohwm-client [flags] [flags]" app.cli.HideVersion = true app.cli.Flags = []cli.Flag{ FlagHost, FlagPort, FlagScheme, FlagPath, } app.cli.Commands = []*cli.Command{ &cli.Command{ Name: "print", Usage: "pretty prints api result", Action: app.ActionPrint, }, &cli.Command{ Name: "export", Usage: "runs http exporter for prometheus", Action: app.ActionMetrics, Flags: []cli.Flag{ FlagInterface, }, }, } app.cli.Before = app.Before return app } // Run runs cli action func (a *App) Run(args []string) error { return a.cli.Run(args) } // Before sets up app func (a *App) Before(ctx *cli.Context) error { host := fmt.Sprintf("%s:%d", ctx.String("host"), ctx.Int("port")) a.Client = &client.Client{ Timeout: time.Second, URL: url.URL{ Scheme: ctx.String("scheme"), Host: host, Path: ctx.String("path"), }, } return nil } // ActionPrint prints api result func (a *App) ActionPrint(_ *cli.Context) error { node, err := a.Client.Fetch() if err != nil { return err } fmt.Fprint(a.Out, node.Stringify()) return nil } // ActionMetrics serves http func (a *App) ActionMetrics(ctx *cli.Context) error { addr := ctx.String("http") http.HandleFunc("/metrics", a.HandleMetrics) log.Println("listen on: " + addr) return http.ListenAndServe(addr, nil) } // HandleMetrics handler func (a *App) HandleMetrics(resp http.ResponseWriter, req *http.Request) { root, err := a.Client.Fetch() if err != nil { http.Error(resp, err.Error(), http.StatusInternalServerError) return } vals, err := root.Values() if err != nil { http.Error(resp, err.Error(), http.StatusInternalServerError) return } collection := metrics.FromVals(vals) registry := prometheus.NewRegistry() if err := registry.Register(collection); err != nil { http.Error(resp, err.Error(), http.StatusInternalServerError) return } handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{ Registry: registry, }) handler.ServeHTTP(resp, req) registry.Unregister(collection) }