mirror of
https://codeberg.org/frosty/modbot.git
synced 2024-09-19 03:36:35 -04:00
name change and more modules added. config not started.
This commit is contained in:
parent
1e204a2ab7
commit
886e0c5a97
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
||||||
sysinfo
|
modbot
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
# sysinfo
|
# modbot
|
||||||
|
|
||||||
sysinfo queries your system for various information and allows you to format it however you'd like.
|
modbot is a seriously over-engineered system for querying different information about your system. Often used for a status bar like [dzen](https://github.com/robm/dzen) or [lemonbar](https://github.com/LemonBoy/bar).
|
||||||
|
|
||||||
|
Each part of the output is a module, and modbot is an agregator for these modules. You can query different information about your system like load average, CPU temperature, wireless SSID, and even the output of an arbitrary command or file.
|
||||||
|
|
||||||
|
The modules that are in the output are determined at compile time, within the `config.go` file. Don't worry-this process uses a straightforward syntax that doesn't require any programming knowledge. Though, if you're using this, I assume you're smart enough to know that.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module codeberg.org/frosty/sysinfo
|
module codeberg.org/frosty/modbot
|
||||||
|
|
||||||
go 1.22.4
|
go 1.22.4
|
||||||
|
|
||||||
|
|
171
lib/readers/battery.go
Normal file
171
lib/readers/battery.go
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BatteryStatus int
|
||||||
|
type BatteryTechnology int
|
||||||
|
|
||||||
|
const (
|
||||||
|
StatusUnknown BatteryStatus = iota
|
||||||
|
StatusCharging
|
||||||
|
StatusDischarging
|
||||||
|
StatusNotCharging
|
||||||
|
StatusFull
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TechnologyUnknown BatteryTechnology = iota
|
||||||
|
TechnologyNimh
|
||||||
|
TechnologyLiion
|
||||||
|
TechnologyLipoly
|
||||||
|
TechnologyLife
|
||||||
|
TechnologyNicd
|
||||||
|
TechnologyLimn
|
||||||
|
)
|
||||||
|
|
||||||
|
type BatteryInfo struct {
|
||||||
|
Capacity uint8
|
||||||
|
Status BatteryStatus
|
||||||
|
Technology BatteryTechnology
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs BatteryStatus) String() string {
|
||||||
|
switch bs {
|
||||||
|
case StatusCharging:
|
||||||
|
return "Charging"
|
||||||
|
case StatusDischarging:
|
||||||
|
return "Discharging"
|
||||||
|
case StatusNotCharging:
|
||||||
|
return "Not charging"
|
||||||
|
case StatusFull:
|
||||||
|
return "Full"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bt BatteryTechnology) String() string {
|
||||||
|
switch bt {
|
||||||
|
case TechnologyNimh:
|
||||||
|
return "NiMH"
|
||||||
|
case TechnologyLiion:
|
||||||
|
return "Li-ion"
|
||||||
|
case TechnologyLipoly:
|
||||||
|
return "Li-poly"
|
||||||
|
case TechnologyLife:
|
||||||
|
return "LiFe"
|
||||||
|
case TechnologyNicd:
|
||||||
|
return "NiCd"
|
||||||
|
case TechnologyLimn:
|
||||||
|
return "LiMn"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var batteryStatusMap = map[string]BatteryStatus{
|
||||||
|
"Unknown": StatusUnknown,
|
||||||
|
"Charging": StatusCharging,
|
||||||
|
"Discharging": StatusDischarging,
|
||||||
|
"Not charging": StatusNotCharging,
|
||||||
|
"Full": StatusFull,
|
||||||
|
}
|
||||||
|
|
||||||
|
var batteryTechnologyMap = map[string]BatteryTechnology{
|
||||||
|
"Unknown": TechnologyUnknown,
|
||||||
|
"NiMH": TechnologyNimh,
|
||||||
|
"Li-ion": TechnologyLiion,
|
||||||
|
"Li-poly": TechnologyLipoly,
|
||||||
|
"LiFe": TechnologyLife,
|
||||||
|
"NiCd": TechnologyNicd,
|
||||||
|
"LiMn": TechnologyLimn,
|
||||||
|
}
|
||||||
|
|
||||||
|
func BatteryStatusFromStr(statusStr string) BatteryStatus {
|
||||||
|
if status, exists := batteryStatusMap[statusStr]; exists {
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
return StatusUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func BatteryTechnologyFromStr(technologyStr string) BatteryTechnology {
|
||||||
|
if technology, exists := batteryTechnologyMap[technologyStr]; exists {
|
||||||
|
return technology
|
||||||
|
}
|
||||||
|
return TechnologyUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadBattery(batteryName string) (BatteryInfo, error) {
|
||||||
|
capacityPath := fmt.Sprintf("/sys/class/power_supply/%s/capacity", batteryName)
|
||||||
|
statusPath := fmt.Sprintf("/sys/class/power_supply/%s/status", batteryName)
|
||||||
|
technologyPath := fmt.Sprintf("/sys/class/power_supply/%s/technology", batteryName)
|
||||||
|
|
||||||
|
capacityFile, err := os.Open(capacityPath)
|
||||||
|
if err != nil {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to open %s: %w", capacityPath, err)
|
||||||
|
}
|
||||||
|
defer capacityFile.Close()
|
||||||
|
|
||||||
|
capacityScanner := bufio.NewScanner(capacityFile)
|
||||||
|
if !capacityScanner.Scan() {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to read from %s: %w", capacityPath, capacityScanner.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
statusFile, err := os.Open(statusPath)
|
||||||
|
if err != nil {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to open %s: %w", statusPath, err)
|
||||||
|
}
|
||||||
|
defer statusFile.Close()
|
||||||
|
|
||||||
|
statusScanner := bufio.NewScanner(statusFile)
|
||||||
|
if !statusScanner.Scan() {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to read from %s: %w", statusPath, statusScanner.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
technologyFile, err := os.Open(technologyPath)
|
||||||
|
if err != nil {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to open %s: %w", technologyPath, err)
|
||||||
|
}
|
||||||
|
defer technologyFile.Close()
|
||||||
|
|
||||||
|
technologyScanner := bufio.NewScanner(technologyFile)
|
||||||
|
if !technologyScanner.Scan() {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to read from %s: %w", technologyPath, technologyScanner.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
batteryCapacityStr := capacityScanner.Text()
|
||||||
|
batteryStatus := statusScanner.Text()
|
||||||
|
batteryTechnology := technologyScanner.Text()
|
||||||
|
|
||||||
|
batteryCapacity, err := strconv.ParseUint(batteryCapacityStr, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
return BatteryInfo{}, fmt.Errorf("failed to parse capacity from %s: %w", capacityPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return BatteryInfo{
|
||||||
|
Capacity: uint8(batteryCapacity),
|
||||||
|
Status: BatteryStatusFromStr(batteryStatus),
|
||||||
|
Technology: BatteryTechnologyFromStr(batteryTechnology),
|
||||||
|
}, nil
|
||||||
|
}
|
51
lib/readers/cpu_temperature.go
Normal file
51
lib/readers/cpu_temperature.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CpuTemperatureInfo float32
|
||||||
|
|
||||||
|
func ReadCpuTemperature(hwmonName, tempName string) (CpuTemperatureInfo, error) {
|
||||||
|
tempPath := fmt.Sprintf("/sys/class/hwmon/%s/%s_input", hwmonName, tempName)
|
||||||
|
|
||||||
|
file, err := os.Open(tempPath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to open %s: %w", tempPath, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
if !scanner.Scan() {
|
||||||
|
return 0, fmt.Errorf("failed to read from %s: %w", tempPath, scanner.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
line := scanner.Text()
|
||||||
|
cpuTemperatureMdeg, err := strconv.ParseUint(line, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse cpu temperature from %s: %w", tempPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuTemperature := float32(cpuTemperatureMdeg) / 1000
|
||||||
|
|
||||||
|
return CpuTemperatureInfo(cpuTemperature), nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// sysinfo queries information about your system
|
// modbot is a system information agregator
|
||||||
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
|
17
lib/readers/disk_io.go
Normal file
17
lib/readers/disk_io.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
17
lib/readers/disk_usage.go
Normal file
17
lib/readers/disk_usage.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
58
lib/readers/load.go
Normal file
58
lib/readers/load.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoadInfo struct {
|
||||||
|
OneMinute string
|
||||||
|
FiveMinute string
|
||||||
|
FifteenMinute string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadLoad() (LoadInfo, error) {
|
||||||
|
const loadPath = "/proc/loadavg"
|
||||||
|
|
||||||
|
file, err := os.Open(loadPath)
|
||||||
|
if err != nil {
|
||||||
|
return LoadInfo{}, fmt.Errorf("failed to open %s: %w", loadPath, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
scanner.Scan()
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return LoadInfo{}, fmt.Errorf("failed to read from %s: %w", loadPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
line := scanner.Text()
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) < 3 {
|
||||||
|
return LoadInfo{}, fmt.Errorf("unexpected format in %s: %s", loadPath, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadInfo{
|
||||||
|
OneMinute: fields[0],
|
||||||
|
FiveMinute: fields[1],
|
||||||
|
FifteenMinute: fields[2],
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// sysinfo queries information about your system
|
// modbot is a system information agregator
|
||||||
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// sysinfo queries information about your system
|
// modbot is a system information agregator
|
||||||
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,6 +18,7 @@ package readers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -29,9 +30,11 @@ type OsInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadOs() (OsInfo, error) {
|
func ReadOs() (OsInfo, error) {
|
||||||
file, err := os.Open("/lib/os-release")
|
const osPath = "/lib/os-release"
|
||||||
|
|
||||||
|
file, err := os.Open(osPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return OsInfo{}, err
|
return OsInfo{}, fmt.Errorf("failed to open %s: %w", osPath, err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
@ -41,18 +44,26 @@ func ReadOs() (OsInfo, error) {
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
line = strings.ReplaceAll(line, "\"", "")
|
line = strings.ReplaceAll(line, "\"", "")
|
||||||
columns := strings.Split(line, "=")
|
fields := strings.SplitN(line, "=", 2)
|
||||||
|
|
||||||
|
if len(fields) < 2 {
|
||||||
|
return OsInfo{}, fmt.Errorf("unexpected format in %s: %s", osPath, line)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(line, "NAME="):
|
case strings.HasPrefix(line, "NAME"):
|
||||||
osName = columns[1]
|
osName = fields[1]
|
||||||
case strings.HasPrefix(line, "PRETTY_NAME="):
|
case strings.HasPrefix(line, "PRETTY_NAME"):
|
||||||
osPrettyName = columns[1]
|
osPrettyName = fields[1]
|
||||||
case strings.HasPrefix(line, "VERSION_ID="):
|
case strings.HasPrefix(line, "VERSION_ID"):
|
||||||
osVersion = columns[1]
|
osVersion = fields[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return OsInfo{}, fmt.Errorf("failed to read from %s: %w", osPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
return OsInfo{
|
return OsInfo{
|
||||||
Name: osName,
|
Name: osName,
|
||||||
PrettyName: osPrettyName,
|
PrettyName: osPrettyName,
|
||||||
|
|
94
lib/readers/uptime.go
Normal file
94
lib/readers/uptime.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// modbot is a system information agregator
|
||||||
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecondsInMinute = 60
|
||||||
|
SecondsInHour = 3600
|
||||||
|
SecondsInDay = 86400
|
||||||
|
)
|
||||||
|
|
||||||
|
type UptimeInfo uint64
|
||||||
|
|
||||||
|
func (u UptimeInfo) Days() int {
|
||||||
|
return int(u) / SecondsInDay
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UptimeInfo) Hours() int {
|
||||||
|
return (int(u) % SecondsInDay) / SecondsInHour
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UptimeInfo) Minutes() int {
|
||||||
|
return (int(u) % SecondsInHour) / SecondsInMinute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UptimeInfo) Seconds() int {
|
||||||
|
return int(u) % SecondsInMinute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UptimeInfo) String() string {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
if u.Days() > 0 {
|
||||||
|
builder.WriteString(fmt.Sprintf("%d days, ", u.Days()))
|
||||||
|
}
|
||||||
|
if u.Hours() > 0 {
|
||||||
|
builder.WriteString(fmt.Sprintf("%d hours, ", u.Hours()))
|
||||||
|
}
|
||||||
|
if u.Minutes() > 0 {
|
||||||
|
builder.WriteString(fmt.Sprintf("%d minutes, ", u.Minutes()))
|
||||||
|
}
|
||||||
|
builder.WriteString(fmt.Sprintf("%d seconds", u.Seconds()))
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadUptime() (UptimeInfo, error) {
|
||||||
|
const uptimePath = "/proc/uptime"
|
||||||
|
|
||||||
|
file, err := os.Open(uptimePath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to open %s: %w", uptimePath, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
if !scanner.Scan() {
|
||||||
|
return 0, fmt.Errorf("failed to read from %s: %w", uptimePath, scanner.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
line := scanner.Text()
|
||||||
|
fields := strings.SplitN(line, ".", 2)
|
||||||
|
if len(fields) < 1 {
|
||||||
|
return 0, fmt.Errorf("unexpected format in %s: %s", uptimePath, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
uptime, err := strconv.ParseUint(fields[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse uptime from %s: %w", uptimePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return UptimeInfo(uptime), nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// sysinfo queries information about your system
|
// modbot is a system information agregator
|
||||||
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -19,26 +19,29 @@ package ui
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
kibibyte = 1
|
Kibibyte = 1
|
||||||
mebibyte = 1024 * kibibyte
|
Mebibyte = 1024 * Kibibyte
|
||||||
gibibyte = 1024 * mebibyte
|
Gibibyte = 1024 * Mebibyte
|
||||||
|
Tebibyte = 1024 * Gibibyte
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrettifySize(sizeKibibytes uint64, decimalPlaces uint8) string {
|
func PrettifyKib(sizeKibibytes uint64, decimalPlaces uint8) string {
|
||||||
var size float64
|
var size float64
|
||||||
var unit string
|
var unit string
|
||||||
|
|
||||||
if sizeKibibytes < mebibyte {
|
if sizeKibibytes < Mebibyte {
|
||||||
size = float64(sizeKibibytes)
|
size = float64(sizeKibibytes)
|
||||||
unit = "KiB"
|
unit = "KiB"
|
||||||
} else if sizeKibibytes < gibibyte {
|
} else if sizeKibibytes < Gibibyte {
|
||||||
size = float64(sizeKibibytes) / float64(mebibyte)
|
size = float64(sizeKibibytes) / float64(Mebibyte)
|
||||||
unit = "MiB"
|
unit = "MiB"
|
||||||
} else {
|
} else if sizeKibibytes < Tebibyte {
|
||||||
size = float64(sizeKibibytes) / float64(gibibyte)
|
size = float64(sizeKibibytes) / float64(Gibibyte)
|
||||||
unit = "GiB"
|
unit = "GiB"
|
||||||
|
} else {
|
||||||
|
size = float64(sizeKibibytes) / float64(Tebibyte)
|
||||||
|
unit = "TiB"
|
||||||
}
|
}
|
||||||
|
|
||||||
format := fmt.Sprintf("%%.%df %s", decimalPlaces, unit)
|
return fmt.Sprintf(fmt.Sprintf("%%.%df %s", decimalPlaces, unit), size)
|
||||||
return fmt.Sprintf(format, size)
|
|
||||||
}
|
}
|
||||||
|
|
39
main.go
39
main.go
|
@ -1,4 +1,4 @@
|
||||||
// sysinfo queries information about your system
|
// modbot is a system information agregator
|
||||||
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
// Copyright (C) 2024 frosty <inthishouseofcards@gmail.com>
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -20,13 +20,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"codeberg.org/frosty/sysinfo/lib/readers"
|
"codeberg.org/frosty/modbot/lib/readers"
|
||||||
"codeberg.org/frosty/sysinfo/lib/ui"
|
"codeberg.org/frosty/modbot/lib/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
memoryDecimalPlaces = 2
|
MemoryDecimalPlaces = 2
|
||||||
cpuUsageDecimalPlaces = 2
|
CpuUsageDecimalPlaces = 2
|
||||||
|
CpuTemperatureHwmonName = "hwmon6"
|
||||||
|
CpuTemperatureTempName = "temp1"
|
||||||
|
BatteryName = "BAT1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -40,11 +43,33 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("%v\n", err)
|
log.Fatalf("%v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("RAM: %v / %v\n", ui.PrettifySize(memoryInfo.Used, memoryDecimalPlaces), ui.PrettifySize(memoryInfo.Total, memoryDecimalPlaces))
|
fmt.Printf("RAM: %v / %v\n", ui.PrettifyKib(memoryInfo.Used, MemoryDecimalPlaces), ui.PrettifyKib(memoryInfo.Total, MemoryDecimalPlaces))
|
||||||
|
|
||||||
cpuUsageInfo, err := readers.ReadCpuUsage()
|
cpuUsageInfo, err := readers.ReadCpuUsage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("%v\n", err)
|
log.Fatalf("%v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("CPU: %.*f%%\n", cpuUsageDecimalPlaces, cpuUsageInfo.UsagePercent)
|
cpuTemperatureInfo, err := readers.ReadCpuTemperature(CpuTemperatureHwmonName, CpuTemperatureTempName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("CPU: %.1f°C (%.*f%%)\n", cpuTemperatureInfo, CpuUsageDecimalPlaces, cpuUsageInfo.UsagePercent)
|
||||||
|
|
||||||
|
loadInfo, err := readers.ReadLoad()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Load: %v %v %v\n", loadInfo.OneMinute, loadInfo.FiveMinute, loadInfo.FifteenMinute)
|
||||||
|
|
||||||
|
// batteryInfo, err := readers.ReadBattery(BatteryName)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatalf("%v\n", err)
|
||||||
|
// }
|
||||||
|
// fmt.Printf("Battery: %v%% (%v) w/ %v\n", batteryInfo.Capacity, batteryInfo.Status, batteryInfo.Technology)
|
||||||
|
|
||||||
|
uptimeInfo, err := readers.ReadUptime()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Uptime: %v\n", uptimeInfo)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue