From 5ffdc1dda8763e3e8d74800b9abbc85e5f3f4fcf Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 19 Dec 2021 14:58:39 +0100 Subject: [PATCH 1/6] added go-notify dependency added minimal notification interface --- README.md | 3 +++ go.mod | 2 ++ go.sum | 4 ++++ internal/ui/notification.go | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 internal/ui/notification.go diff --git a/README.md b/README.md index d53f9e8..5c842c6 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ yay -S fan2go-git Download the latest release from GitHub: ```shell +# Install dependencies +sudo pacman -S libnotify + curl -L -o fan2go https://github.com/markusressel/fan2go/releases/latest/download/fan2go-linux-amd64 chmod +x fan2go sudo cp ./fan2go /usr/bin/fan2go diff --git a/go.mod b/go.mod index ba19d59..98fb216 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,11 @@ require ( github.com/guptarohit/asciigraph v0.5.2 github.com/looplab/tarjan v0.1.0 github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 // indirect github.com/md14454/gosensors v0.0.0-20180726083412-bded752ab001 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/mitchellh/go-homedir v1.1.0 + github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093 github.com/oklog/run v1.1.0 github.com/prometheus/client_golang v1.11.0 github.com/pterm/pterm v0.12.33 diff --git a/go.sum b/go.sum index 9b19ccf..0dec5bc 100644 --- a/go.sum +++ b/go.sum @@ -258,6 +258,8 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 h1:GMB3MVJnxysGrSvjWGsgK8L3XGI3F4etQQq37Py6W5A= +github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5/go.mod h1:PwzwfeB5syFHXORC3MtPylVcjIoTDT/9cvkKpEndGVI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= @@ -291,6 +293,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093 h1:OvySnanP8CQIKS+MTq9AXBwEXzm0YaKeu331bWql3ug= +github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093/go.mod h1:AthsKyBZ9hqwU7DBWFiOxYObyF8nVyYVubXv/pQNC5E= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= diff --git a/internal/ui/notification.go b/internal/ui/notification.go new file mode 100644 index 0000000..c054c70 --- /dev/null +++ b/internal/ui/notification.go @@ -0,0 +1,36 @@ +package ui + +import ( + "github.com/mqu/go-notify" +) + +// For a list of possible icons, see: https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html +const ( + IconDialogError = "dialog-error" + IconDialogInfo = "dialog-information" + IconDialogWarn = "dialog-warning" +) + +func init() { + notify.Init("fan2go") +} + +func NotifyInfo(title, text string) { + NotifySend(title, text, IconDialogInfo) +} + +func NotifyWarn(title, text string) { + NotifySend(title, text, IconDialogWarn) +} + +func NotifyError(title, text string) { + NotifySend(title, text, IconDialogError) +} + +func NotifySend(title, text, icon string) { + hello := notify.NotificationNew(title, text, icon) + err := hello.Show() + if err != nil { + Error("Error sending notification: %v", err) + } +} From aa70b82b7fd34d93e276d121a84a4ee042b0ca2c Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Thu, 12 May 2022 02:38:31 +0200 Subject: [PATCH 2/6] added custom implementation for sending notifications via notify-send --- internal/ui/notification.go | 50 +++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/internal/ui/notification.go b/internal/ui/notification.go index c054c70..3b6ba36 100644 --- a/internal/ui/notification.go +++ b/internal/ui/notification.go @@ -1,7 +1,9 @@ package ui import ( - "github.com/mqu/go-notify" + "os" + "os/exec" + "strings" ) // For a list of possible icons, see: https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html @@ -11,10 +13,6 @@ const ( IconDialogWarn = "dialog-warning" ) -func init() { - notify.Init("fan2go") -} - func NotifyInfo(title, text string) { NotifySend(title, text, IconDialogInfo) } @@ -28,8 +26,46 @@ func NotifyError(title, text string) { } func NotifySend(title, text, icon string) { - hello := notify.NotificationNew(title, text, icon) - err := hello.Show() + display, exists := os.LookupEnv("DISPLAY") + if !exists { + Warning("Cannot send notification, missing env variable 'DISPLAY'!") + return + } + + cmd := exec.Command("who") + output, err := cmd.Output() + if err != nil { + Warning("Cannot send notification, unable to find user of display session: %v", err) + return + } + lines := strings.Split(string(output), "\n") + var user string + for _, line := range lines { + if strings.Contains(line, display) { + user = strings.TrimSpace(strings.Fields(line)[0]) + break + } + } + + if len(user) <= 0 { + Warning("Cannot send notification, unable to detect user of current display session") + return + } + + cmd = exec.Command("id", "-u", user) + output, err = cmd.Output() + userIdString := strings.TrimSpace(string(output)) + if len(userIdString) <= 0 { + Warning("Cannot send notification, unable to detect user id") + return + } + + cmd = exec.Command("sudo", "-u", user, + "DISPLAY="+display, + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/"+userIdString+"/bus", + "notify-send", "-i", icon, title, text, + ) + err = cmd.Run() if err != nil { Error("Error sending notification: %v", err) } From 865ffd7a2cf7812aca20bee0c2715ffec0c76038 Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 15 May 2022 11:28:03 +0200 Subject: [PATCH 3/6] notifications: added app name, added urgency level --- cmd/root.go | 4 +++- internal/ui/logging.go | 2 ++ internal/ui/notification.go | 18 +++++++++++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index de2b82b..e2c2e5b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -38,7 +38,9 @@ on your computer based on temperature sensors.`, configuration.LoadConfig() err := configuration.Validate(configPath) if err != nil { - ui.Fatal(err.Error()) + ui.Error(err.Error()) + ui.NotifyError("Validation Error", err.Error()) + return } internal.RunDaemon() diff --git a/internal/ui/logging.go b/internal/ui/logging.go index a65bd96..44eceb8 100644 --- a/internal/ui/logging.go +++ b/internal/ui/logging.go @@ -1,6 +1,7 @@ package ui import ( + "fmt" "github.com/pterm/pterm" ) @@ -37,5 +38,6 @@ func Error(format string, a ...interface{}) { } func Fatal(format string, a ...interface{}) { + NotifyError("fan2go: Fatal", fmt.Sprintf(format, a...)) pterm.Fatal.Printfln(format, a...) } diff --git a/internal/ui/notification.go b/internal/ui/notification.go index 3b6ba36..d0206c6 100644 --- a/internal/ui/notification.go +++ b/internal/ui/notification.go @@ -11,21 +11,25 @@ const ( IconDialogError = "dialog-error" IconDialogInfo = "dialog-information" IconDialogWarn = "dialog-warning" + + UrgencyLow = "low" + UrgencyNormal = "normal" + UrgencyCritical = "critical" ) func NotifyInfo(title, text string) { - NotifySend(title, text, IconDialogInfo) + NotifySend(UrgencyLow, title, text, IconDialogInfo) } func NotifyWarn(title, text string) { - NotifySend(title, text, IconDialogWarn) + NotifySend(UrgencyNormal, title, text, IconDialogWarn) } func NotifyError(title, text string) { - NotifySend(title, text, IconDialogError) + NotifySend(UrgencyCritical, title, text, IconDialogError) } -func NotifySend(title, text, icon string) { +func NotifySend(urgency, title, text, icon string) { display, exists := os.LookupEnv("DISPLAY") if !exists { Warning("Cannot send notification, missing env variable 'DISPLAY'!") @@ -63,7 +67,11 @@ func NotifySend(title, text, icon string) { cmd = exec.Command("sudo", "-u", user, "DISPLAY="+display, "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/"+userIdString+"/bus", - "notify-send", "-i", icon, title, text, + "notify-send", + "-a", "fan2go", + "-u", urgency, + "-i", icon, + title, text, ) err = cmd.Run() if err != nil { From 2030105ef860f8bad9f91e8d16751269c9b49bed Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 15 May 2022 12:00:47 +0200 Subject: [PATCH 4/6] notify in more places --- cmd/root.go | 3 +-- internal/backend.go | 7 ++++--- internal/configuration/config.go | 2 +- internal/controller/controller.go | 2 +- internal/persistence/persistence.go | 2 +- internal/ui/logging.go | 12 +++++++++++- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index e2c2e5b..825da64 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -38,8 +38,7 @@ on your computer based on temperature sensors.`, configuration.LoadConfig() err := configuration.Validate(configPath) if err != nil { - ui.Error(err.Error()) - ui.NotifyError("Validation Error", err.Error()) + ui.ErrorAndNotify("Validation Error", err.Error()) return } diff --git a/internal/backend.go b/internal/backend.go index beb08c6..d17c1b3 100644 --- a/internal/backend.go +++ b/internal/backend.go @@ -64,7 +64,7 @@ func RunDaemon() { go func() { if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - ui.Error("Cannot start prometheus metrics endpoint (%s)", err.Error()) + ui.ErrorAndNotify("Statistics Error", "Cannot start prometheus metrics endpoint (%s)", err.Error()) } }() @@ -112,14 +112,15 @@ func RunDaemon() { fanController := c g.Add(func() error { err := fanController.Run(ctx) - ui.Info("Fan controller for fan %s stopped.", fan.GetId()) + ui.Info("Fan Controller Error", "Fan controller for fan %s stopped.", fan.GetId()) if err != nil { + ui.NotifyError(fmt.Sprintf("Fan Controller: %s", fan.GetId()), err.Error()) panic(err) } return err }, func(err error) { if err != nil { - ui.Warning("Something went wrong: %v", err) + ui.WarningAndNotify(fmt.Sprintf("Fan Controller: %s", fan.GetId()), "Something went wrong: %v", err) } }) } diff --git a/internal/configuration/config.go b/internal/configuration/config.go index 62b12fc..7bce3c6 100644 --- a/internal/configuration/config.go +++ b/internal/configuration/config.go @@ -42,7 +42,7 @@ func InitConfig(cfgFile string) { // Find home directory. home, err := homedir.Dir() if err != nil { - ui.Error("Couldn't detect home directory: %v", err) + ui.ErrorAndNotify("Path Error", "Couldn't detect home directory: %v", err) os.Exit(1) } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 39b4309..3b3224d 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -146,7 +146,7 @@ func (f *fanController) Run(ctx context.Context) error { case <-tick: err = f.UpdateFanSpeed() if err != nil { - ui.Error("Error in FanController for fan %s: %v", fan.GetId(), err) + ui.ErrorAndNotify("Fan Control Error", "Fan %s: %v", fan.GetId(), err) f.restorePwmEnabled() return nil } diff --git a/internal/persistence/persistence.go b/internal/persistence/persistence.go index 70274b9..ddb291b 100644 --- a/internal/persistence/persistence.go +++ b/internal/persistence/persistence.go @@ -34,7 +34,7 @@ func NewPersistence(dbPath string) Persistence { func (p persistence) openPersistence() *bolt.DB { db, err := bolt.Open(p.dbPath, 0600, &bolt.Options{Timeout: 1 * time.Minute}) if err != nil { - ui.Error("Could not open database file: %v", err) + ui.ErrorAndNotify("Persistence Error", "Could not open database file: %v", err) os.Exit(1) } return db diff --git a/internal/ui/logging.go b/internal/ui/logging.go index 44eceb8..a7e3562 100644 --- a/internal/ui/logging.go +++ b/internal/ui/logging.go @@ -33,11 +33,21 @@ func Warning(format string, a ...interface{}) { pterm.Warning.Printfln(format, a...) } +func WarningAndNotify(title string, format string, a ...interface{}) { + Error(format, a...) + NotifyError(title, fmt.Sprintf(format, a...)) +} + func Error(format string, a ...interface{}) { pterm.Error.Printfln(format, a...) } +func ErrorAndNotify(title string, format string, a ...interface{}) { + Error(format, a...) + NotifyError(title, fmt.Sprintf(format, a...)) +} + func Fatal(format string, a ...interface{}) { - NotifyError("fan2go: Fatal", fmt.Sprintf(format, a...)) + NotifyError("Fatal Error", fmt.Sprintf(format, a...)) pterm.Fatal.Printfln(format, a...) } From 033134b9e3e83de5100f073f16d66db5d9514e56 Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 15 May 2022 12:01:59 +0200 Subject: [PATCH 5/6] more specific message --- cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 825da64..eb5a69d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -38,7 +38,7 @@ on your computer based on temperature sensors.`, configuration.LoadConfig() err := configuration.Validate(configPath) if err != nil { - ui.ErrorAndNotify("Validation Error", err.Error()) + ui.ErrorAndNotify("Config Validation Error", err.Error()) return } From c034f0386119bfe73e5dbe94961ec9ac88db0dfd Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 15 May 2022 12:07:12 +0200 Subject: [PATCH 6/6] fiy typo --- internal/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backend.go b/internal/backend.go index d17c1b3..29667fc 100644 --- a/internal/backend.go +++ b/internal/backend.go @@ -112,7 +112,7 @@ func RunDaemon() { fanController := c g.Add(func() error { err := fanController.Run(ctx) - ui.Info("Fan Controller Error", "Fan controller for fan %s stopped.", fan.GetId()) + ui.Info("Fan controller for fan %s stopped.", fan.GetId()) if err != nil { ui.NotifyError(fmt.Sprintf("Fan Controller: %s", fan.GetId()), err.Error()) panic(err)