Reworking UI concept...

This commit is contained in:
Marcel Otte 2022-06-07 21:20:16 +02:00
parent f62c670955
commit cfc37e575f
6 changed files with 131 additions and 36 deletions

View File

@ -40,6 +40,7 @@ backups:
settings: settings:
systemMountPoint: /mnt/backups systemMountPoint: /mnt/backups
unixSocketLocation: /var/local/backive/backive.sock unixSocketLocation: /var/local/backive/backive.sock
uiUnixSocketLocation: /var/local/backive/ui.sock
logLocation: /var/log/backive logLocation: /var/log/backive
dbLocation: /var/lib/backive dbLocation: /var/lib/backive

View File

@ -29,6 +29,7 @@ var (
config backive.Configuration config backive.Configuration
database backive.Database database backive.Database
events backive.EventHandler events backive.EventHandler
uihdl backive.UIHandler
) )
func defaultCallback(envMap map[string]string) { func defaultCallback(envMap map[string]string) {
@ -127,17 +128,22 @@ func main() {
if err != nil { if err != nil {
log.Printf("Removal of %s failed.", config.Settings.UnixSocketLocation) log.Printf("Removal of %s failed.", config.Settings.UnixSocketLocation)
} }
err = os.Remove(config.Settings.UIUnixSocketLocation)
if err != nil {
log.Printf("Removal of %s failed.", config.Settings.UIUnixSocketLocation)
}
os.Exit(code) os.Exit(code)
}() }()
// TODO: do proper signal handling!
log.Println("backive starting up...") log.Println("backive starting up...")
// find and load config // find and load config
database.Load() database.Load()
config.Load() config.Load()
setupLogging() setupLogging()
backive.Init(config, database) backive.Init(config, database)
uihdl.Init(config.Settings.UIUnixSocketLocation)
// Start UIHandler to be able to inform users through notifications
go uihdl.Listen()
// init scheduler and check for next needed runs? // init scheduler and check for next needed runs?
// start event loop // start event loop
events.Init(config.Settings.UnixSocketLocation) events.Init(config.Settings.UnixSocketLocation)

View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"time"
"fyne.io/fyne/v2/app" "fyne.io/fyne/v2/app"
"github.com/qwc/backive" "github.com/qwc/backive"
@ -20,7 +22,10 @@ func main() {
app := app.NewWithID("Backive UI") app := app.NewWithID("Backive UI")
backiveui.Init(app, nil, config, database) backiveui.Init(app, nil, config, database)
go func() { go func() {
backiveui.NotificationRun() for {
backiveui.NotificationRun()
time.Sleep(time.Second)
}
}() }()
app.Run() app.Run()

View File

@ -18,11 +18,12 @@ type Configuration struct {
// Settings struct holds the global configuration items // Settings struct holds the global configuration items
type Settings struct { type Settings struct {
SystemMountPoint string `mapstructure:"systemMountPoint"` SystemMountPoint string `mapstructure:"systemMountPoint"`
UserMountPoint string `mapstructure:"userMountPoint"` UserMountPoint string `mapstructure:"userMountPoint"`
UnixSocketLocation string `mapstructure:"unixSocketLocation"` UnixSocketLocation string `mapstructure:"unixSocketLocation"`
LogLocation string `mapstructure:"logLocation"` UIUnixSocketLocation string `mapstructure:"uiUnixSocketLocation"`
DbLocation string `mapstructure:"dbLocation"` LogLocation string `mapstructure:"logLocation"`
DbLocation string `mapstructure:"dbLocation"`
} }
// CreateViper creates a viper instance for usage later // CreateViper creates a viper instance for usage later

View File

@ -1,7 +1,9 @@
package ui package ui
import ( import (
"encoding/json"
"fmt" "fmt"
"net"
"time" "time"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
@ -16,16 +18,52 @@ var (
config backive.Configuration config backive.Configuration
db backive.Database db backive.Database
doNotShowUntil time.Time = time.Unix(0, 0) doNotShowUntil time.Time = time.Unix(0, 0)
c net.Conn
) )
func Init(a fyne.App, w fyne.Window, c backive.Configuration, d backive.Database) { func Init(a fyne.App, w fyne.Window, conf backive.Configuration, d backive.Database) {
app = a app = a
a.SetIcon(theme.FyneLogo()) a.SetIcon(theme.FyneLogo())
makeTray(app) makeTray(app)
config = c config = conf
db = d db = d
go PollConnection()
} }
func PollConnection() {
var err error
for {
if c == nil {
c, err = net.Dial("unix", config.Settings.UIUnixSocketLocation)
} else {
err = fmt.Errorf("Connection already established")
}
if err != nil {
// ignore
err = nil
// sleep a while and then retry
time.Sleep(10 * time.Second)
}
}
}
func NotificationRun() { func NotificationRun() {
if c != nil {
b := make([]byte, 2048)
i, err := c.Read(b)
if err == nil && i > 0 {
var data map[string]string
err = json.Unmarshal(b, &data)
if err == nil {
ShowNotification(data)
}
// else ignore and try to read again
err = nil
}
// we just try again and discard the error
err = nil
}
/*
if doNotShowUntil == time.Unix(0, 0) || time.Now().After(doNotShowUntil) { if doNotShowUntil == time.Unix(0, 0) || time.Now().After(doNotShowUntil) {
ShowNotification() ShowNotification()
if doNotShowUntil != time.Unix(0, 0) { if doNotShowUntil != time.Unix(0, 0) {
@ -34,40 +72,22 @@ func NotificationRun() {
} }
h, _ := time.ParseDuration("15m") h, _ := time.ParseDuration("15m")
time.Sleep(h) time.Sleep(h)
//*/
} }
func ShowNotification() { func ShowNotification(data map[string]string) {
displayStr, err := MakeNotificationString() if ShallShow(data) {
if err == nil {
app.SendNotification( app.SendNotification(
fyne.NewNotification( fyne.NewNotification(
"Backups are overdue...", data["header"],
fmt.Sprintf("Name\t(device)\t[overdue]\n%s", displayStr), data["message"],
), ),
) )
} }
} }
func MakeNotificationString() (string, error) { func ShallShow(data map[string]string) bool {
db.Load() return true
var displayStr string = ""
var runs backive.Runs
runs.Load(db)
fmt.Printf("Notification run\n")
for _, v := range config.Backups {
fmt.Printf("Notification run %s\n", v.Name)
if v.ShouldRun() && v.Frequency > 0 {
fmt.Printf("Notification for %s\n", v.Name)
lastBackup, err := runs.LastRun(v)
if err != nil {
return "", err
}
freq, _ := time.ParseDuration(fmt.Sprintf("%dd", v.Frequency))
days := time.Now().Sub(lastBackup.Add(freq))
displayStr += fmt.Sprintf("%s\t(%s)\t[%f days]\n", v.Name, v.TargetDevice, days.Hours()/24)
}
}
return displayStr, nil
} }
func makeTray(app fyne.App) { func makeTray(app fyne.App) {
@ -75,7 +95,6 @@ func makeTray(app fyne.App) {
menu := fyne.NewMenu( menu := fyne.NewMenu(
"backive", "backive",
fyne.NewMenuItem("Show notifications again", func() { fyne.NewMenuItem("Show notifications again", func() {
ShowNotification()
}), }),
fyne.NewMenuItem("Hide notifications for today", func() { fyne.NewMenuItem("Hide notifications for today", func() {
doNotShowUntil = time.Now().AddDate(0, 0, 1) doNotShowUntil = time.Now().AddDate(0, 0, 1)

63
ui_handler.go Normal file
View File

@ -0,0 +1,63 @@
package backive
import (
"encoding/json"
"fmt"
"log"
"net"
"path"
)
type UIHandler struct {
ls net.Listener
client net.Conn
}
var mockUIAccept = func(uh *UIHandler) (net.Conn, error) {
log.Println("Calling eh.ls.Accept()")
return uh.ls.Accept()
}
func (uh *UIHandler) Init(socketPath string) error {
log.Println("Initializing UIHandler")
var err error
dir, _ := path.Split(socketPath)
CreateDirectoryIfNotExists(dir)
uh.ls, err = net.Listen("unix", socketPath)
if err != nil {
return err
}
return nil
}
func (uh *UIHandler) Listen() {
log.Println("Running UIHandler loop")
func() {
for {
var err error
uh.client, err = uh.ls.Accept()
if err != nil {
log.Printf("Accept failed %e\n", err)
}
}
}()
}
func (uh *UIHandler) DisplayMessage(header string, message string, level int) error {
if uh.client != nil {
var data map[string]interface{}
data["level"] = level
data["header"] = header
data["message"] = message
b, err := json.Marshal(data)
if err != nil {
log.Printf("Problem in sending message to UI: %e", err)
return err
}
uh.client.Write(b)
return nil
} else {
log.Println("No UI client available, msg did not get delivered.")
return fmt.Errorf("No UI client available, msg not delivered.")
}
}