diff --git a/lib/client/client.go b/lib/client/client.go index 684c1f2..3f52fe6 100644 --- a/lib/client/client.go +++ b/lib/client/client.go @@ -2,379 +2,12 @@ package client import ( "encoding/json" - "fmt" "io" "net/http" "net/url" - "path" - "strconv" - "strings" "time" - - "github.com/gosimple/slug" -) - -// HardwareType type -// https://github.com/openhardwaremonitor/openhardwaremonitor/blob/e199e0ccc69b4da92495266ebc0faf7daad97608/Hardware/IHardware.cs -type HardwareType int - -const ( - // UnknownHardware type - UnknownHardware HardwareType = iota - // Mainboard type - Mainboard - // SuperIO type - SuperIO - // CPU type - CPU - // RAM type - RAM - // GpuNvidia type - GpuNvidia - // GpuAti type - GpuAti - // TBalancer type - TBalancer - // Heatmaster type - Heatmaster - // HDD type - HDD - // Controller type for TBalancer or Heatmaster - Controller - // Computer type for host - Computer ) -// Hardware value -type Hardware struct { - Type HardwareType - Value string - TypeIndex int - TypeCount int -} - -// Sensor for unit -// https://github.com/openhardwaremonitor/openhardwaremonitor/blob/e199e0ccc69b4da92495266ebc0faf7daad97608/Hardware/ISensor.cs -type Sensor int - -const ( - // UnknownSensor in V - UnknownSensor Sensor = iota - // Voltage in V - Voltage - // Clock in MHz - Clock - // Temperature in °C - Temperature - // Load in % - Load - // Fan in RPM - Fan - // Flow in L/h - Flow - // Control in % - Control - // Level in % - Level - // Factor in 1 - Factor - // Power in W - Power - // Data in GB = 2^30 Bytes - Data - // SmallData in MB = 2^20 Bytes - SmallData -) - -var hardwareToMetric = map[HardwareType]string{ - UnknownHardware: "unknown", - Mainboard: "mainboard", - SuperIO: "superio", - CPU: "cpu", - RAM: "ram", - GpuNvidia: "gpu", - GpuAti: "gpu", - TBalancer: "tbalancer", - Heatmaster: "heatmaster", - HDD: "hdd", - Controller: "controller", - Computer: "host", -} - -var sensorToMetric = map[Sensor]string{ - UnknownSensor: "unknown", - Voltage: "voltage", - Clock: "mhz", - Temperature: "temp", - Load: "load", - Fan: "rpm", - Flow: "flow", - Control: "control", - Level: "level", - Factor: "factor", - Power: "power", - Data: "gb", - SmallData: "mb", -} - -var imageToHardware = map[string]HardwareType{ - "ati.png": GpuAti, - // "bigng.png": Heatmaster, - // "bigng.png": TBalancer, - "bigng.png": Controller, - "chip.png": SuperIO, - "cpu.png": CPU, - "hdd.png": HDD, - "mainboard.png": Mainboard, - "nvidia.png": GpuNvidia, - "ram.png": RAM, - "computer.png": Computer, -} - -var sensorToType = map[string]Sensor{ - "Clocks": Clock, - "Controls": Control, - "Data": Data, - "Factors": Factor, - "Fans": Fan, - "Flows": Flow, - "Levels": Level, - "Load": Load, - "Powers": Power, - "Temperatures": Temperature, - "Voltages": Voltage, -} - -func (s Sensor) String() string { - switch s { - case Clock: - return "Clock" - case Control: - return "Control" - case Data: - return "Data" - case Factor: - return "Factor" - case Fan: - return "Fan" - case Flow: - return "Flow" - case Level: - return "Level" - case Load: - return "Load" - case Power: - return "Power" - case SmallData: - return "SmallData" - case Temperature: - return "Temperature" - case Voltage: - return "Voltage" - } - return "Unknown" -} - -func (h HardwareType) String() string { - switch h { - case UnknownHardware: - return "Unknown" - case Mainboard: - return "Mainboard" - case SuperIO: - return "SuperIO" - case CPU: - return "CPU" - case RAM: - return "RAM" - case GpuNvidia: - return "GpuNvidia" - case GpuAti: - return "GpuAti" - case TBalancer: - return "TBalancer" - case Heatmaster: - return "Heatmaster" - case HDD: - return "HDD" - case Controller: - return "Controller" - case Computer: - return "Computer" - } - return "Unknown" -} - -// Value from ohwm -type Value struct { - Hardware []Hardware - Unit Sensor - Label string - Value string -} - -// Float64 gets value as float64 -func (v *Value) Float64() float64 { - val := strings.Split(v.Value, " ") - if len(val) == 0 { - return 0 - } - ret, err := strconv.ParseFloat(val[0], 64) - if err != nil { - return 0 - } - return ret -} - -// MetricName returns value as a metric name -func (v *Value) MetricName() string { - segments := []string{"ohwm"} - for _, hw := range v.Hardware { - metricname, ok := hardwareToMetric[hw.Type] - if !ok { - metricname = hardwareToMetric[UnknownHardware] - } - segments = append(segments, metricname) - if hw.TypeCount > 1 { - segments = append(segments, fmt.Sprintf("%d", hw.TypeIndex)) - } - } - - sensorname, ok := sensorToMetric[v.Unit] - if !ok { - sensorname = sensorToMetric[UnknownSensor] - } - segments = append(segments, sensorname) - - sluglabel := slug.Make(v.Label) - segments = append(segments, sluglabel) - - ret := strings.Join(segments, "_") - return strings.ReplaceAll(ret, "-", "_") -} - -// IsValue true if node has children -func (n *Node) IsValue() bool { - if n.Children == nil { - return false - } - return len(n.Children) == 0 -} - -// IsRoot returns true if json is a root node -func (n *Node) IsRoot() bool { - return n.ID == 0 -} - -// IsSensor returns true if json node is for a sensor type -func (n *Node) IsSensor() bool { - if n.ImageURL == "" || n.Text == "" { - return false - } - _, ok := sensorToType[n.Text] - return ok -} - -// SensorType returns type of sensor -func (n *Node) SensorType() Sensor { - st, _ := sensorToType[n.Text] - // Figure out if data is in GB (Data) or MB (SmallData) - if st == Data { - if len(n.Children) > 0 { - val := n.Children[0] - if strings.HasSuffix(val.Value, "MB") { - st = SmallData - } - } - } - return st -} - -// IsHardware returns true if json node is for hardware -func (n *Node) IsHardware() bool { - if n.ImageURL == "" || n.Text == "" { - return false - } - _, ok := imageToHardware[path.Base(n.ImageURL)] - return ok -} - -// HardwareType returns HardwareType of node -func (n *Node) HardwareType() HardwareType { - ht, _ := imageToHardware[path.Base(n.ImageURL)] - return ht -} - -// Visitor callback function -type Visitor func(v Value) error - -// Walk from json root -func (n *Node) Walk(fn Visitor) error { - return n.walk(fn, Value{Hardware: []Hardware{}}, 0, 0) -} - -func (n *Node) childDeviceTotals() map[HardwareType]int { - totals := map[HardwareType]int{} - for _, child := range n.Children { - totals[child.HardwareType()]++ - } - return totals -} - -func (n *Node) walk(fn Visitor, ctx Value, hwIndex, hwTotal int) error { - if n.IsValue() { - ctx.Label = n.Text - ctx.Value = n.Value - return fn(ctx) - } - if n.IsSensor() { - ctx.Unit = n.SensorType() - } - if n.IsHardware() { - ctx.Hardware = append(ctx.Hardware, Hardware{ - Type: n.HardwareType(), - Value: n.Text, - TypeIndex: hwIndex, - TypeCount: hwTotal, - }) - } - totals := n.childDeviceTotals() - deviceIndex := map[HardwareType]int{} - for _, child := range n.Children { - deviceType := child.HardwareType() - index := deviceIndex[deviceType] - if err := child.walk(fn, ctx, index, totals[deviceType]); err != nil { - return err - } - deviceIndex[deviceType]++ - } - return nil -} - -// Values from json root -func (n *Node) Values() ([]Value, error) { - ret := []Value{} - err := n.Walk(func(val Value) error { - ret = append(ret, val) - return nil - }) - if err != nil { - return nil, err - } - return ret, nil -} - -// Node from data -type Node struct { - ID int `json:"id"` - ImageURL string - Max string - Min string - Text string - Value string - Children []Node -} - // Client for open hardware monitor type Client struct { Timeout time.Duration @@ -401,29 +34,3 @@ func (c *Client) Decode(r io.Reader) (*Node, error) { } return node, nil } - -// Stringify tree -func (n *Node) Stringify() string { - return n.stringify(0) -} - -func (n *Node) stringify(indent int) string { - prefix := "" - for i := 0; i < indent; i++ { - prefix += " " - } - - ret := prefix + n.Text - if n.Value != "" { - ret += ": " + n.Value - } - if n.Max != "" && n.Min != "" && n.Max != "-" && n.Min != "-" { - ret += fmt.Sprintf(" (%s - %s)", n.Min, n.Max) - } - ret += "\n" - for _, child := range n.Children { - ret += child.stringify(indent + 1) - } - - return ret -} diff --git a/lib/client/hardware.go b/lib/client/hardware.go new file mode 100644 index 0000000..909470c --- /dev/null +++ b/lib/client/hardware.go @@ -0,0 +1,192 @@ +package client + +// HardwareType type +// https://github.com/openhardwaremonitor/openhardwaremonitor/blob/e199e0ccc69b4da92495266ebc0faf7daad97608/Hardware/IHardware.cs +type HardwareType int + +const ( + // UnknownHardware type + UnknownHardware HardwareType = iota + // Mainboard type + Mainboard + // SuperIO type + SuperIO + // CPU type + CPU + // RAM type + RAM + // GpuNvidia type + GpuNvidia + // GpuAti type + GpuAti + // TBalancer type + TBalancer + // Heatmaster type + Heatmaster + // HDD type + HDD + // Controller type for TBalancer or Heatmaster + Controller + // Computer type for host + Computer +) + +// Hardware value +type Hardware struct { + Type HardwareType + Value string + TypeIndex int + TypeCount int +} + +// Sensor for unit +// https://github.com/openhardwaremonitor/openhardwaremonitor/blob/e199e0ccc69b4da92495266ebc0faf7daad97608/Hardware/ISensor.cs +type Sensor int + +const ( + // UnknownSensor in V + UnknownSensor Sensor = iota + // Voltage in V + Voltage + // Clock in MHz + Clock + // Temperature in °C + Temperature + // Load in % + Load + // Fan in RPM + Fan + // Flow in L/h + Flow + // Control in % + Control + // Level in % + Level + // Factor in 1 + Factor + // Power in W + Power + // Data in GB = 2^30 Bytes + Data + // SmallData in MB = 2^20 Bytes + SmallData +) + +var hardwareToMetric = map[HardwareType]string{ + UnknownHardware: "unknown", + Mainboard: "mainboard", + SuperIO: "superio", + CPU: "cpu", + RAM: "ram", + GpuNvidia: "gpu", + GpuAti: "gpu", + TBalancer: "tbalancer", + Heatmaster: "heatmaster", + HDD: "hdd", + Controller: "controller", + Computer: "host", +} + +var sensorToMetric = map[Sensor]string{ + UnknownSensor: "unknown", + Voltage: "voltage", + Clock: "mhz", + Temperature: "temp", + Load: "load", + Fan: "rpm", + Flow: "flow", + Control: "control", + Level: "level", + Factor: "factor", + Power: "power", + Data: "gb", + SmallData: "mb", +} + +var imageToHardware = map[string]HardwareType{ + "ati.png": GpuAti, + // "bigng.png": Heatmaster, + // "bigng.png": TBalancer, + "bigng.png": Controller, + "chip.png": SuperIO, + "cpu.png": CPU, + "hdd.png": HDD, + "mainboard.png": Mainboard, + "nvidia.png": GpuNvidia, + "ram.png": RAM, + "computer.png": Computer, +} + +var sensorToType = map[string]Sensor{ + "Clocks": Clock, + "Controls": Control, + "Data": Data, + "Factors": Factor, + "Fans": Fan, + "Flows": Flow, + "Levels": Level, + "Load": Load, + "Powers": Power, + "Temperatures": Temperature, + "Voltages": Voltage, +} + +func (s Sensor) String() string { + switch s { + case Clock: + return "Clock" + case Control: + return "Control" + case Data: + return "Data" + case Factor: + return "Factor" + case Fan: + return "Fan" + case Flow: + return "Flow" + case Level: + return "Level" + case Load: + return "Load" + case Power: + return "Power" + case SmallData: + return "SmallData" + case Temperature: + return "Temperature" + case Voltage: + return "Voltage" + } + return "Unknown" +} + +func (h HardwareType) String() string { + switch h { + case UnknownHardware: + return "Unknown" + case Mainboard: + return "Mainboard" + case SuperIO: + return "SuperIO" + case CPU: + return "CPU" + case RAM: + return "RAM" + case GpuNvidia: + return "GpuNvidia" + case GpuAti: + return "GpuAti" + case TBalancer: + return "TBalancer" + case Heatmaster: + return "Heatmaster" + case HDD: + return "HDD" + case Controller: + return "Controller" + case Computer: + return "Computer" + } + return "Unknown" +} diff --git a/lib/client/node.go b/lib/client/node.go new file mode 100644 index 0000000..69ec2de --- /dev/null +++ b/lib/client/node.go @@ -0,0 +1,155 @@ +package client + +import ( + "fmt" + "path" + "strings" +) + +// Node from data +type Node struct { + ID int `json:"id"` + ImageURL string + Max string + Min string + Text string + Value string + Children []Node +} + +// Visitor callback function +type Visitor func(v Value) error + +// IsValue true if node has children +func (n *Node) IsValue() bool { + if n.Children == nil { + return false + } + return len(n.Children) == 0 +} + +// IsRoot returns true if json is a root node +func (n *Node) IsRoot() bool { + return n.ID == 0 +} + +// IsSensor returns true if json node is for a sensor type +func (n *Node) IsSensor() bool { + if n.ImageURL == "" || n.Text == "" { + return false + } + _, ok := sensorToType[n.Text] + return ok +} + +// SensorType returns type of sensor +func (n *Node) SensorType() Sensor { + st, _ := sensorToType[n.Text] + // Figure out if data is in GB (Data) or MB (SmallData) + if st == Data { + if len(n.Children) > 0 { + val := n.Children[0] + if strings.HasSuffix(val.Value, "MB") { + st = SmallData + } + } + } + return st +} + +// IsHardware returns true if json node is for hardware +func (n *Node) IsHardware() bool { + if n.ImageURL == "" || n.Text == "" { + return false + } + _, ok := imageToHardware[path.Base(n.ImageURL)] + return ok +} + +// HardwareType returns HardwareType of node +func (n *Node) HardwareType() HardwareType { + ht, _ := imageToHardware[path.Base(n.ImageURL)] + return ht +} + +// Walk from json root +func (n *Node) Walk(fn Visitor) error { + return n.walk(fn, Value{Hardware: []Hardware{}}, 0, 0) +} + +func (n *Node) childDeviceTotals() map[HardwareType]int { + totals := map[HardwareType]int{} + for _, child := range n.Children { + totals[child.HardwareType()]++ + } + return totals +} + +func (n *Node) walk(fn Visitor, ctx Value, hwIndex, hwTotal int) error { + if n.IsValue() { + ctx.Label = n.Text + ctx.Value = n.Value + return fn(ctx) + } + if n.IsSensor() { + ctx.Unit = n.SensorType() + } + if n.IsHardware() { + ctx.Hardware = append(ctx.Hardware, Hardware{ + Type: n.HardwareType(), + Value: n.Text, + TypeIndex: hwIndex, + TypeCount: hwTotal, + }) + } + totals := n.childDeviceTotals() + deviceIndex := map[HardwareType]int{} + for _, child := range n.Children { + deviceType := child.HardwareType() + index := deviceIndex[deviceType] + if err := child.walk(fn, ctx, index, totals[deviceType]); err != nil { + return err + } + deviceIndex[deviceType]++ + } + return nil +} + +// Values from json root +func (n *Node) Values() ([]Value, error) { + ret := []Value{} + err := n.Walk(func(val Value) error { + ret = append(ret, val) + return nil + }) + if err != nil { + return nil, err + } + return ret, nil +} + +// Stringify tree +func (n *Node) Stringify() string { + return n.stringify(0) +} + +func (n *Node) stringify(indent int) string { + prefix := "" + for i := 0; i < indent; i++ { + prefix += " " + } + + ret := prefix + n.Text + if n.Value != "" { + ret += ": " + n.Value + } + if n.Max != "" && n.Min != "" && n.Max != "-" && n.Min != "-" { + ret += fmt.Sprintf(" (%s - %s)", n.Min, n.Max) + } + ret += "\n" + for _, child := range n.Children { + ret += child.stringify(indent + 1) + } + + return ret +} diff --git a/lib/client/value.go b/lib/client/value.go new file mode 100644 index 0000000..b5d9a18 --- /dev/null +++ b/lib/client/value.go @@ -0,0 +1,57 @@ +package client + +import ( + "fmt" + "strconv" + "strings" + + "github.com/gosimple/slug" +) + +// Value from ohwm +type Value struct { + Hardware []Hardware + Unit Sensor + Label string + Value string +} + +// Float64 gets value as float64 +func (v *Value) Float64() float64 { + val := strings.Split(v.Value, " ") + if len(val) == 0 { + return 0 + } + ret, err := strconv.ParseFloat(val[0], 64) + if err != nil { + return 0 + } + return ret +} + +// MetricName returns value as a metric name +func (v *Value) MetricName() string { + segments := []string{"ohwm"} + for _, hw := range v.Hardware { + metricname, ok := hardwareToMetric[hw.Type] + if !ok { + metricname = hardwareToMetric[UnknownHardware] + } + segments = append(segments, metricname) + if hw.TypeCount > 1 { + segments = append(segments, fmt.Sprintf("%d", hw.TypeIndex)) + } + } + + sensorname, ok := sensorToMetric[v.Unit] + if !ok { + sensorname = sensorToMetric[UnknownSensor] + } + segments = append(segments, sensorname) + + sluglabel := slug.Make(v.Label) + segments = append(segments, sluglabel) + + ret := strings.Join(segments, "_") + return strings.ReplaceAll(ret, "-", "_") +}