From 1444d3fc2b5c0e76190595724023052aae737265 Mon Sep 17 00:00:00 2001 From: Xevion Date: Sun, 27 Oct 2024 16:50:15 -0500 Subject: [PATCH] feat!: complete rearrangement for multi-module platform-specific modules --- .scripts/Install.ps1 | 31 +++ README.md | 4 +- cmd/windows/main.go | 77 +++++++ configs/hass_tray.service | 27 +++ go.mod | 20 +- go.sum | 8 +- go.work | 3 + go.work.sum | 5 + internal/app.go | 190 ++++++++++++++++++ internal/config.go | 16 ++ internal/go.mod | 26 +++ internal/go.sum | 113 +++++++++++ {resources => internal/resources}/closed.ico | Bin internal/resources/error.ico | Bin 0 -> 7284 bytes {resources => internal/resources}/open.ico | Bin internal/resources/open_fault.ico | Bin 0 -> 340 bytes {resources => internal/resources}/unknown.ico | Bin internal/types.go | 19 ++ internal/utility.go | 14 ++ main.go | 150 -------------- resources/result.ico | Bin 15045 -> 0 bytes 21 files changed, 546 insertions(+), 157 deletions(-) create mode 100644 .scripts/Install.ps1 create mode 100644 cmd/windows/main.go create mode 100644 configs/hass_tray.service create mode 100644 go.work create mode 100644 go.work.sum create mode 100644 internal/app.go create mode 100644 internal/config.go create mode 100644 internal/go.mod create mode 100644 internal/go.sum rename {resources => internal/resources}/closed.ico (100%) create mode 100644 internal/resources/error.ico rename {resources => internal/resources}/open.ico (100%) create mode 100644 internal/resources/open_fault.ico rename {resources => internal/resources}/unknown.ico (100%) create mode 100644 internal/types.go create mode 100644 internal/utility.go delete mode 100644 main.go delete mode 100644 resources/result.ico diff --git a/.scripts/Install.ps1 b/.scripts/Install.ps1 new file mode 100644 index 0000000..6cd694d --- /dev/null +++ b/.scripts/Install.ps1 @@ -0,0 +1,31 @@ +# A build & install script for the project's Windows version. +$ErrorActionPreference = "Stop" +$executableName = "door_tray" + +if (-Not (Test-Path -Path "./go.mod")) { + Write-Error "Please run this script from the project's root directory (go.mod not found)." + exit 1 +} + +# Build +go build -o "bin/$executableName-temp.exe" -ldflags "-s -w" "./cmd/windows/" +if ($LASTEXITCODE -ne 0) { + Write-Error "Build failed with exit code $LASTEXITCODE." + exit 1 +} + +# Compress +upx "bin/$executableName-temp.exe" -o "bin/$executableName.exe" -5 -f +if ($LASTEXITCODE -ne 0) { + Write-Error "Compression failed with exit code $LASTEXITCODE." + exit 1 +} +Remove-Item "bin/$executableName-temp.exe" + +# Setup service +$serviceName = "DoorTray" + +# TODO: Stop old service +# TODO: Install new binary +# TODO: Start & verify service +# TODO: Cleanup, print latest logs \ No newline at end of file diff --git a/README.md b/README.md index 5c2974e..4118c01 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# hass-tray +# door-tray A simple Go application to display basic state details (via a tray icon) from a Home Assistant instance. +- Easy install with a single binary + - Windows (Service), Linux (Systemd) - Ultra simple configuration - YAML configuration file - Environment variables diff --git a/cmd/windows/main.go b/cmd/windows/main.go new file mode 100644 index 0000000..50d46e0 --- /dev/null +++ b/cmd/windows/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "log" + "log/slog" + "time" + + "internal" + + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/debug" +) + +type WrapperService struct { + service internal.Service +} + +func (wrapper *WrapperService) Execute(args []string, requestChannel <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) { + const acceptedCommands = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue + tick := time.Tick(5 * time.Second) + + status <- svc.Status{State: svc.StartPending} + status <- svc.Status{State: svc.Running, Accepts: acceptedCommands} + +loop: + for { + select { + case <-tick: + slog.Debug("Tick Handled...!") + case changeRequest := <-requestChannel: + switch changeRequest.Cmd { + case svc.Interrogate: + slog.Debug("Interrogate Requested", "changeRequest", changeRequest) + status <- changeRequest.CurrentStatus + case svc.Stop, svc.Shutdown: + slog.Warn("Shutdown Requested", "changeRequest", changeRequest) + break loop + case svc.Pause: + wrapper.service.Pause() + slog.Warn("Pause Requested", "changeRequest", changeRequest) + status <- svc.Status{State: svc.Paused, Accepts: acceptedCommands} + case svc.Continue: + slog.Info("Continue Requested", "changeRequest", changeRequest) + status <- svc.Status{State: svc.Running, Accepts: acceptedCommands} + default: + slog.Warn("Unexpected Change Request", "changeRequest", changeRequest) + } + } + } + + slog.Info("Service Stopping") + status <- svc.Status{State: svc.StopPending} + return false, 1 +} + +func runService(name string, isDebug bool) { + service := WrapperService{ + service: internal.NewApp(), + } + + if isDebug { + err := debug.Run(name, &service) + if err != nil { + log.Fatalln("Error running service in debug mode.") + } + } else { + err := svc.Run(name, &service) + if err != nil { + log.Fatalln("Error running service in Service Control mode.") + } + } +} + +func main() { + + runService("DoorTray", true) +} diff --git a/configs/hass_tray.service b/configs/hass_tray.service new file mode 100644 index 0000000..af33905 --- /dev/null +++ b/configs/hass_tray.service @@ -0,0 +1,27 @@ +[Unit] +Description=A description +ConditionPathExists=/home/ubuntu/work/src/door_tray/door_tray +After=network.target + +[Service] +Type=simple +User=door_tray +Group=door_tray +LimitNOFILE=1024 + +Restart=on-failure +RestartSec=10 +startLimitIntervalSec=60 + +WorkingDirectory=/home/ubuntu/work/src/door_tray +ExecStart=/home/ubuntu/work/src/door_tray/door_tray --name=foo + +# make sure log directory exists and owned by syslog +PermissionsStartOnly=true +ExecStartPre=/bin/mkdir -p /var/log/door_tray +ExecStartPre=/bin/chown syslog:adm /var/log/door_tray +ExecStartPre=/bin/chmod 755 /var/log/door_tray +SyslogIdentifier=door_tray + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/go.mod b/go.mod index dee36e7..d1b8428 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,21 @@ -module xevion.dev/hass-tray +module xevion.dev/door-tray go 1.23.1 +require ( + golang.org/x/sys v0.1.0 + internal v1.0.0 +) + +replace internal => ./internal/ + +require ( + github.com/getlantern/systray v1.2.2 // indirect + github.com/joho/godotenv v1.5.1 // indirect + golang.org/x/text v0.19.0 // indirect + saml.dev/gome-assistant v0.2.3 // indirect +) + require ( github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect @@ -9,17 +23,13 @@ require ( github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect - github.com/getlantern/systray v1.2.2 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/gobuffalo/envy v1.10.2 // indirect github.com/gobuffalo/packd v1.0.2 // indirect github.com/gobuffalo/packr v1.30.1 // indirect github.com/golang-module/carbon v1.7.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/joho/godotenv v1.5.1 // indirect github.com/nathan-osman/go-sunrise v1.1.0 // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect - golang.org/x/sys v0.1.0 // indirect - saml.dev/gome-assistant v0.2.3 // indirect ) diff --git a/go.sum b/go.sum index 19c9286..8df370d 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= @@ -40,7 +41,6 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= @@ -61,6 +61,7 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -83,6 +84,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -100,6 +103,8 @@ golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -107,6 +112,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= saml.dev/gome-assistant v0.2.3 h1:WuT0yMuUjyM78eHYjry/mbhMypSZ7GKmc4vr+Y4YOQ4= saml.dev/gome-assistant v0.2.3/go.mod h1:NAj56yKBq4PXmHIdrn9oeTmM5SHaNYoLfSWpzTpKjXY= diff --git a/go.work b/go.work new file mode 100644 index 0000000..e2f8485 --- /dev/null +++ b/go.work @@ -0,0 +1,3 @@ +go 1.23.1 + +use ./internal diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..92c146f --- /dev/null +++ b/go.work.sum @@ -0,0 +1,5 @@ +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= diff --git a/internal/app.go b/internal/app.go new file mode 100644 index 0000000..7702ae7 --- /dev/null +++ b/internal/app.go @@ -0,0 +1,190 @@ +package internal + +import ( + "embed" + "fmt" + "log/slog" + "os" + "os/signal" + "runtime" + "time" + + "github.com/getlantern/systray" + dotenv "github.com/joho/godotenv" + "golang.org/x/text/cases" + "golang.org/x/text/language" + ga "saml.dev/gome-assistant" +) + +var () + +type TrayApp struct { + doorIdentifier string + log *slog.Logger + stateChannel chan string + app *ga.App + service *ga.Service +} + +// Status will return the operational status of the service +func (ta *TrayApp) Status() Status { + return StatusUnknown +} + +func (ta *TrayApp) State() string { + // TODO: Implement this method + return "" +} + +func (ta *TrayApp) Connected() bool { + // TODO: Implement this method + return false +} + +func (ta *TrayApp) Reload() error { + // TODO: Implement this method + return nil +} + +func (ta *TrayApp) Pause() error { + // TODO: Implement this method + return nil +} + +func (ta *TrayApp) Resume() error { + // TODO: Implement this method + return nil +} + +func NewApp() *TrayApp { + // Connect to Home Assistant + app, err := ga.NewApp(ga.NewAppRequest{ + IpAddress: "home.imfucked.lol", // Replace with your Home Assistant IP Address + HAAuthToken: os.Getenv("HA_AUTH_TOKEN"), + HomeZoneEntityId: "zone.home", + Port: "443", + Secure: true, + }) + if err != nil { + slog.Error("Error connecting to Home Assistant", "error", err) + os.Exit(1) + } + + service := app.GetService() + + return &TrayApp{ + app: app, + service: service, + stateChannel: make(chan string), + doorIdentifier: "binary_sensor.bedroom_door_opening", + } +} + +var ( + //go:embed "resources/*.ico" + icons embed.FS +) + +func (ta *TrayApp) HandleState(newState string) { + switch newState { + case "on": + ta.stateChannel <- "open" + case "off": + ta.stateChannel <- "closed" + default: + slog.Error("unknown state encountered", "newState", newState) + ta.stateChannel <- "unknown" + } +} + +func (ta *TrayApp) setupHomeAssistant() { + var err error + + // Get the initial state + state, err := ta.app.GetState().Get(ta.doorIdentifier) + if err != nil { + slog.Error("Unable to get initial state", "error", err) + } else { + slog.Debug("Initial State Received") + ta.HandleState(state.State) + } + + ta.app.RegisterEntityListeners(ga. + NewEntityListener(). + EntityIds(ta.doorIdentifier). + Call(func(service *ga.Service, state ga.State, sensor ga.EntityData) { + slog.Debug("Event Received", "identifier", ta.doorIdentifier, "sensor", sensor) + ta.HandleState(sensor.ToState) + }). + Build()) + + ta.app.Start() + + slog.Warn("Home Assistant thread died") + ta.stateChannel <- "unknown" +} + +func (ta *TrayApp) Start() { + dotenv.Load() + + slog.SetDefault(slog.New(slog.NewJSONHandler( + os.Stdout, + &slog.HandlerOptions{ + Level: slog.LevelDebug, + }, + ))) + // binfo, err := buildinfo. + slog.Info("Startup", "runtime", runtime.Version(), "os", runtime.GOOS, "arch", runtime.GOARCH, "pid", os.Getpid()) + + go ta.setupHomeAssistant() + systray.Run(ta.onReady, func() {}) +} + +func (ta *TrayApp) onReady() { + systray.SetTitle("door-tray") + systray.SetTooltip("Setting up...") + menuQuit := systray.AddMenuItem("Quit", "Stops the application") + menuOpenLogs := systray.AddMenuItem("Open Logs", "Opens the logs in the default editor") + menuOpenLogs.Disable() + + // Load icons + systray.SetIcon(getIcon("unknown")) + + // Handle Ctrl+C interrupt + interruptChannel := make(chan os.Signal, 1) + signal.Notify(interruptChannel, os.Interrupt) + signal.Notify(interruptChannel, os.Kill) + +loop: + for { + select { + case signal := <-interruptChannel: + slog.Info("Received interrupt signal, quitting", "signal", signal) + break loop + case <-menuQuit.ClickedCh: + slog.Info("Quit clicked") + break loop + case <-menuOpenLogs.ClickedCh: + slog.Info("Open Logs clicked") + case newState := <-ta.stateChannel: + timeString := time.Now().Format("3:04 PM") + if newState != "unknown" { + systray.SetTooltip(fmt.Sprintf("%s as of %s", cases.Title(language.AmericanEnglish, cases.NoLower).String(newState), timeString)) + switch newState { + case "open": + systray.SetIcon(getIcon("open_fault")) + case "closed": + systray.SetIcon(getIcon("closed")) + } + } else { + slog.Warn("Unknown state", "state", newState) + systray.SetTooltip(fmt.Sprintf("Unknown as of %s", timeString)) + systray.SetIcon(getIcon("unknown")) + } + } + } + + slog.Info("Cleaning up") + systray.Quit() + ta.app.Cleanup() +} diff --git a/internal/config.go b/internal/config.go new file mode 100644 index 0000000..a207a21 --- /dev/null +++ b/internal/config.go @@ -0,0 +1,16 @@ +package internal + +import ( + "fmt" + "log/slog" + "os" +) + +func getIcon(icon string) []byte { + iconBytes, err := icons.ReadFile(fmt.Sprintf("resources/%s.ico", icon)) + if err != nil { + slog.Error("Unable to load icon", "error", err) + os.Exit(1) + } + return iconBytes +} diff --git a/internal/go.mod b/internal/go.mod new file mode 100644 index 0000000..4630e8c --- /dev/null +++ b/internal/go.mod @@ -0,0 +1,26 @@ +module internal + +go 1.22.0 + +require ( + github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect + github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect + github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect + github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect + github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect + github.com/getlantern/systray v1.2.2 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/gobuffalo/envy v1.10.2 // indirect + github.com/gobuffalo/packd v1.0.2 // indirect + github.com/gobuffalo/packr v1.30.1 // indirect + github.com/golang-module/carbon v1.7.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/nathan-osman/go-sunrise v1.1.0 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/text v0.19.0 // indirect + saml.dev/gome-assistant v0.2.3 // indirect +) diff --git a/internal/go.sum b/internal/go.sum new file mode 100644 index 0000000..bb92348 --- /dev/null +++ b/internal/go.sum @@ -0,0 +1,113 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= +github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE= +github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= +github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= +github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang-module/carbon v1.7.1 h1:EDPV0YjxeS2kE2cRedfGgDikU6l5D79HB/teHuZDLu8= +github.com/golang-module/carbon v1.7.1/go.mod h1:M/TDTYPp3qWtW68u49dLDJOyGmls6L6BXdo/pyvkMaU= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/nathan-osman/go-sunrise v1.1.0 h1:ZqZmtmtzs8Os/DGQYi0YMHpuUqR/iRoJK+wDO0wTCw8= +github.com/nathan-osman/go-sunrise v1.1.0/go.mod h1:RcWqhT+5ShCZDev79GuWLayetpJp78RSjSWxiDowmlM= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +saml.dev/gome-assistant v0.2.3 h1:WuT0yMuUjyM78eHYjry/mbhMypSZ7GKmc4vr+Y4YOQ4= +saml.dev/gome-assistant v0.2.3/go.mod h1:NAj56yKBq4PXmHIdrn9oeTmM5SHaNYoLfSWpzTpKjXY= diff --git a/resources/closed.ico b/internal/resources/closed.ico similarity index 100% rename from resources/closed.ico rename to internal/resources/closed.ico diff --git a/internal/resources/error.ico b/internal/resources/error.ico new file mode 100644 index 0000000000000000000000000000000000000000..5ada5170e30c7d35a67f5ed13946ad2ccd0eec83 GIT binary patch literal 7284 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 literal 0 HcmV?d00001 diff --git a/resources/open.ico b/internal/resources/open.ico similarity index 100% rename from resources/open.ico rename to internal/resources/open.ico diff --git a/internal/resources/open_fault.ico b/internal/resources/open_fault.ico new file mode 100644 index 0000000000000000000000000000000000000000..d7dec933509d484c25bdd348072758b0291e101d GIT binary patch literal 340 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