diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..fb4bc70 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/actions/generate-icons/action.yml b/.github/actions/generate-icons/action.yml new file mode 100644 index 0000000..cbc40a9 --- /dev/null +++ b/.github/actions/generate-icons/action.yml @@ -0,0 +1,27 @@ +name: "Generate icons" +description: "Generate icons and push it as an artifact" + +inputs: + upload_artifact: + description: 'Upload artifact' + default: 'true' + +runs: + using: composite + steps: + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Compiled icons + shell: bash + run: | + GOPATH=$(go env GOPATH) + export GOPATH + go get github.com/cratonica/2goarray + go install github.com/cratonica/2goarray + ./generate-icons.sh + - uses: actions/upload-artifact@v4 + if: ${{ inputs.upload_artifact == 'true' }} + with: + name: icons + path: icons/*.go \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fd3c2a1..22d1721 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,20 +2,32 @@ name: Release on: push: branches: - - main + - feat-support-windows permissions: contents: read jobs: + generate-icons: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/generate-icons + windows-build: runs-on: windows-latest + needs: [ generate-icons ] steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.22' - - run: go build -o ipingtray.exe + - uses: actions/download-artifact@v4 + with: + name: icons + path: icons + + - run: go build -ldflags -H=windowsgui -o ipingtray.exe - name: Set up NSIS run: choco install nsis @@ -33,11 +45,16 @@ jobs: macos-build: runs-on: macos-13 + needs: [ generate-icons ] steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.22' + - uses: actions/download-artifact@v4 + with: + name: icons + path: icons - run: go build -o ipingtray - run: go install github.com/machinebox/appify@latest diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index b76ec69..b4939dc 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -21,10 +21,15 @@ jobs: with: fetch-depth: 0 + - uses: ./.github/actions/generate-icons + with: + upload_artifact: false + - name: Super-linter uses: super-linter/super-linter@v6.5.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VALIDATE_GO_MODULES: false # @see https://github.com/cratonica/2goarray/issues/14 commitlint: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 5657f6e..2068911 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -vendor \ No newline at end of file +vendor +icons/*.go \ No newline at end of file diff --git a/README.md b/README.md index bfbdc37..2de3edd 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ this option cannot be configured at this time) ## Start app automatically on boot -###  MacOS +###  macOS You can follow the article from Apple which explain how to start the app automatically at boot: -https://support.apple.com/guide/mac-help/open-items-automatically-when-you-log-in-mh15189 + ### Thresholds @@ -41,6 +41,24 @@ https://support.apple.com/guide/mac-help/open-items-automatically-when-you-log-i ![./docs/screenshot.png](/docs/screenshot.png) +## Development + +### Generate icons + +If you wish to update the icons, you need to run the `generate-icons.sh` which gonna generate +golang []bytes array representing the icon. + +To generate icons, you also need to install [`2goarray`](https://github.com/cratonica/2goarray) + +```bash +go get github.com/cratonica/2goarray +go install github.com/cratonica/2goarray +``` + +> ⚠️ We use .ico file because it's the only supported format on windows, according to +> [@ZGGSONG](https://github.com/getlantern/systray/issues/154#issuecomment-1207607136) + + ## Contribution Feel free to contribute ! diff --git a/generate-icons.sh b/generate-icons.sh new file mode 100755 index 0000000..4f4e64d --- /dev/null +++ b/generate-icons.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -x + +for icon in icons/*.ico; do + icon_name=$(basename "${icon%.*}") + capitalized_name=$(echo "${icon_name:0:1}" | tr '[:lower:]' '[:upper:]')${icon_name:1} + "${GOPATH}/bin/2goarray" "${capitalized_name}" icons <"${icon}" >"icons/${icon_name}.go" +done diff --git a/icons/green.ico b/icons/green.ico new file mode 100644 index 0000000..7d32f7f Binary files /dev/null and b/icons/green.ico differ diff --git a/icons/orange.ico b/icons/orange.ico new file mode 100644 index 0000000..b0f3d2e Binary files /dev/null and b/icons/orange.ico differ diff --git a/icons/red.ico b/icons/red.ico new file mode 100644 index 0000000..2b6ff1d Binary files /dev/null and b/icons/red.ico differ diff --git a/icons/white.ico b/icons/white.ico new file mode 100644 index 0000000..4338da7 Binary files /dev/null and b/icons/white.ico differ diff --git a/main.go b/main.go index 34de3a1..2b91af2 100644 --- a/main.go +++ b/main.go @@ -3,13 +3,14 @@ package main import ( "fmt" "log" + "runtime" "strings" "fyne.io/systray" probing "github.com/prometheus-community/pro-bing" -) -var pinger *probing.Pinger + "ipingtray/icons" +) func main() { systray.Run(onReady, onExit) @@ -17,6 +18,7 @@ func main() { func onReady() { systray.SetTitle("Initializing...") + systray.SetIcon(icons.White) mLatencyLabel := systray.AddMenuItem("Latency", "Current Latency") mLatencyLabel.Disable() @@ -24,47 +26,40 @@ func onReady() { systray.AddSeparator() mQuit := systray.AddMenuItem("Quit", "Quit the app") - var err error - pinger, err = probing.NewPinger("8.8.8.8") - if err != nil { - panic(err) - } - pinger.SetLogger(nil) - // Update tray title pinger.OnRecv = func(pkt *probing.Packet) { latency := pkt.Rtt.Milliseconds() + icon := icons.Red switch { case latency < 50: - systray.SetTitle(fmt.Sprintf("🟢 %d ms", latency)) + icon = icons.Green case latency < 75: - systray.SetTitle(fmt.Sprintf("🟠 %d ms", latency)) - default: - systray.SetTitle(fmt.Sprintf("🔴 %d ms", latency)) + icon = icons.Orange } + updateTray(fmt.Sprintf("%d ms", latency), icon) mLatencyLabel.SetTitle(fmt.Sprintf("%s: %d ms", pinger.IPAddr().String(), latency)) } pinger.OnSendError = func(_ *probing.Packet, err error) { - systray.SetTitle("🔴 Network unavailable") + updateTray("Network Unavailable", icons.Red) if strings.Contains(err.Error(), "sendto") { parts := strings.Split(err.Error(), ": ") if len(parts) >= 2 { - mLatencyLabel.SetTitle(fmt.Sprintf("8.8.8.8: %s", parts[len(parts)-1])) + mLatencyLabel.SetTitle(fmt.Sprintf("%s: %s", pinger.Addr(), parts[len(parts)-1])) return } } - mLatencyLabel.SetTitle(fmt.Sprintf("8.8.8.8: %s", err.Error())) + mLatencyLabel.SetTitle(fmt.Sprintf("%s: %s", pinger.Addr(), err.Error())) } // Running the ping go func() { if err := pinger.Run(); err != nil { - log.Println("Pinger has crashed") + log.Printf("pinger has crashed: %v\n", err) systray.Quit() } }() @@ -76,6 +71,15 @@ func onReady() { }() } +func updateTray(title string, icon []byte) { + systray.SetTitle(title) + systray.SetIcon(icon) + + if runtime.GOOS == "windows" { + systray.SetTooltip(title) + } +} + func onExit() { pinger.Stop() } diff --git a/ping.go b/ping.go new file mode 100644 index 0000000..13a963f --- /dev/null +++ b/ping.go @@ -0,0 +1,23 @@ +package main + +import ( + "runtime" + + probing "github.com/prometheus-community/pro-bing" +) + +var pinger *probing.Pinger + +func init() { + var err error + pinger, err = probing.NewPinger("8.8.8.8") + if err != nil { + panic(err) + } + + pinger.SetLogger(nil) + + if runtime.GOOS == "windows" { + pinger.SetPrivileged(true) + } +}