131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"brainbaking.com/restictray/restic"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
"os"
|
|
"time"
|
|
|
|
"fyne.io/systray"
|
|
"fyne.io/systray/example/icon"
|
|
)
|
|
|
|
// I'm ignoring go threading issues here; assume no clicks happen at the same time.
|
|
var wrapper *restic.Wrapper
|
|
|
|
func main() {
|
|
// init and setup logging
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
|
wrapper = &restic.Wrapper{}
|
|
|
|
// bootstrap systray (this is a blocking call, second func is onExit)
|
|
systray.Run(onSystrayReady, func() {})
|
|
}
|
|
|
|
func addMenuLatestSnapshot() {
|
|
snapshot := wrapper.LastSnapshot()
|
|
systray.AddMenuItem("Latest: "+snapshot.Id+" @ "+snapshot.ShortTime(), "Latest Restic snapshot")
|
|
}
|
|
|
|
func addMenuNextTime(cnf *restic.Config) {
|
|
nextTime := wrapper.LastSnapshot().Time.Add(time.Duration(cnf.BackupTimeInHours) * time.Hour)
|
|
msg := "Next @ " + nextTime.Format(restic.ShortTimeFormat)
|
|
if time.Now().After(nextTime) {
|
|
msg = "⚠️ Overdue - " + msg
|
|
}
|
|
|
|
systray.AddMenuItem(msg, "Future Restic snapshot")
|
|
}
|
|
|
|
func addMenuQuit() {
|
|
systray.AddSeparator()
|
|
addMenuWithQuitAction("Quit", "Quit Restictray")
|
|
}
|
|
|
|
func addMenuError(err error) {
|
|
addMenuWithQuitAction("❗ "+err.Error(), "Restictray Error")
|
|
}
|
|
|
|
func handleError(err error) {
|
|
log.Err(err).Msg("")
|
|
systray.ResetMenu()
|
|
addMenuError(err)
|
|
addMenuQuit()
|
|
}
|
|
|
|
func addMenuWithQuitAction(title string, tooltip string) {
|
|
mQuit := systray.AddMenuItem(title, tooltip)
|
|
go func() {
|
|
<-mQuit.ClickedCh
|
|
log.Info().Msg("Requesting quit")
|
|
systray.Quit()
|
|
}()
|
|
}
|
|
|
|
func onSystrayReady() {
|
|
systray.SetTemplateIcon(icon.Data, icon.Data)
|
|
systray.SetTooltip("Restictray")
|
|
systray.AddMenuItem("... Initializing", "Initializing, please wait.")
|
|
addMenuQuit()
|
|
|
|
cnf, err := restic.ReadConfig()
|
|
if err != nil {
|
|
handleError(err)
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
err := wrapper.UpdateLatestSnapshots(cnf)
|
|
if err != nil {
|
|
handleError(err)
|
|
return
|
|
}
|
|
|
|
resetAndBuildMainMenu(cnf)
|
|
}()
|
|
}
|
|
|
|
// See https://github.com/fyne-io/systray/tree/master/example for more examples
|
|
func resetAndBuildMainMenu(cnf *restic.Config) {
|
|
systray.ResetMenu()
|
|
addMenuLatestSnapshot()
|
|
addMenuNextTime(cnf)
|
|
systray.AddSeparator()
|
|
mnuBackupNow := systray.AddMenuItem("Backup now", "Backup now")
|
|
mnuBrowse := systray.AddMenuItem("Browse backups in Finder...", "Mount and browse backups")
|
|
addMenuQuit()
|
|
|
|
for {
|
|
select {
|
|
case <-mnuBackupNow.ClickedCh:
|
|
onClickedMenuBackupNow(mnuBackupNow, cnf)
|
|
case <-mnuBrowse.ClickedCh:
|
|
onClickedMenuBrowse(mnuBrowse, cnf)
|
|
}
|
|
}
|
|
}
|
|
|
|
func onClickedMenuBrowse(browse *systray.MenuItem, cnf *restic.Config) {
|
|
err := wrapper.MountBackups(cnf)
|
|
if err != nil {
|
|
handleError(err)
|
|
}
|
|
}
|
|
|
|
func onClickedMenuBackupNow(mnu *systray.MenuItem, cnf *restic.Config) {
|
|
mnu.SetTitle("🔄 Backup in progress...")
|
|
mnu.Disable()
|
|
// TODO after a backup, reinitialize latest snapshot + latest/next menus
|
|
// TODO not by calling resetAndBuild again: this is from the for{}?
|
|
// TODO how does this interop with a future goroutine that auto-backups?
|
|
// TODO need for separate "backupInProgress" bool?
|
|
err := wrapper.Backup(cnf)
|
|
mnu.SetTitle("Backup now")
|
|
mnu.Enable()
|
|
|
|
if err != nil {
|
|
handleError(err)
|
|
}
|
|
}
|