Skip to content

Commit 42b6272

Browse files
committed
init project
0 parents  commit 42b6272

File tree

12 files changed

+384
-0
lines changed

12 files changed

+384
-0
lines changed

.github/workflows/release.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Build & Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout source
14+
uses: actions/checkout@v4
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@v5
18+
with:
19+
go-version: "1.24"
20+
21+
- name: Build binaries
22+
run: make
23+
24+
- name: Create GitHub Release
25+
uses: softprops/action-gh-release@v2
26+
with:
27+
files: |
28+
build/radar-linux
29+
build/radar-mac
30+
build/radar-windows.exe

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Code coverage profiles and other test artifacts
15+
*.out
16+
coverage.*
17+
*.coverprofile
18+
profile.cov
19+
20+
# Dependency directories (remove the comment below to include it)
21+
# vendor/
22+
23+
# Go workspace file
24+
go.work
25+
go.work.sum
26+
27+
# env file
28+
.env
29+
30+
# Editor/IDE
31+
# .idea/
32+
# .vscode/
33+
34+
build/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 ohmydevops
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
OUTPUT_DIR = build
2+
SOURCE = main.go
3+
4+
all: linux windows mac
5+
6+
linux:
7+
GOOS=linux GOARCH=amd64 go build -o $(OUTPUT_DIR)/radar-linux $(SOURCE)
8+
9+
windows:
10+
GOOS=windows GOARCH=amd64 go build -o $(OUTPUT_DIR)/radar-windows.exe $(SOURCE)
11+
12+
mac:
13+
GOOS=darwin GOARCH=amd64 go build -o $(OUTPUT_DIR)/radar-mac $(SOURCE)
14+
15+
clean:
16+
rm -rf $(OUTPUT_DIR)

README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Radar Notif
2+
3+
A desktop notification system that monitors internet connectivity across various Iranian ISPs using ArvanCloud's Radar service.
4+
5+
![windows notif](./screenshots/screen3.jpg)
6+
7+
8+
## Features
9+
10+
- Real-time monitoring of multiple ISPs
11+
- Desktop notifications for internet outages and recoveries
12+
- Cross-platform support (Linux, Windows, macOS)
13+
- Concurrent monitoring of multiple ISPs
14+
- Configurable service monitoring (currently set to Google)
15+
16+
## Prerequisites
17+
18+
- Go 1.16 or higher
19+
- Make (for building)
20+
21+
## Installation
22+
23+
1. Clone the repository:
24+
```bash
25+
git clone https://github.com/yourusername/radar-notif.git
26+
cd radar-notif
27+
```
28+
29+
2. Build for your platform:
30+
31+
For all platforms:
32+
```bash
33+
make all
34+
```
35+
36+
Or build for a specific platform:
37+
```bash
38+
make linux # For Linux
39+
make windows # For Windows
40+
make mac # For macOS
41+
```
42+
43+
The built executables will be available in the `build` directory.
44+
45+
## Usage
46+
47+
Simply run the executable for your platform:
48+
49+
```bash
50+
./build/radar-linux # On Linux
51+
./build/radar-mac # On macOS
52+
./build/radar-windows.exe # On Windows
53+
```
54+
55+
The application will:
56+
- Start monitoring the configured ISPs every minute
57+
- Show desktop notifications when internet connectivity issues are detected
58+
- Display notifications when connectivity is restored
59+
- Print real-time status updates in the terminal
60+
61+
## Monitored ISPs
62+
63+
- Sindad (Multiple locations)
64+
- Bertina
65+
- AbrBaran
66+
- Tehran Network
67+
- HostIran
68+
- ParsOnline
69+
- Afranet
70+
- MCI
71+
- Irancell
72+
73+
## Common Issues
74+
75+
1. Notification not working:
76+
- Make sure you have notification permissions enabled on your system
77+
- Verify that the `icon.png` file is in the same directory as the executable
78+
79+
2. Build errors:
80+
- Ensure you have Go 1.16 or higher installed
81+
- Run `go mod tidy` to resolve any dependency issues
82+
83+
3. Runtime errors:
84+
- Check your internet connection
85+
- Verify that ArvanCloud's Radar service is accessible
86+
87+
For more issues, please check the [Issues](https://github.com/yourusername/radar-notif/issues) page.
88+
89+
## Contributing
90+
91+
Contributions are welcome! Please feel free to submit a Pull Request.
92+
93+
## License
94+
95+
This project is open source and available under the MIT License.
96+
97+
## Acknowledgments
98+
99+
- Thanks to ArvanCloud for providing the Radar API
100+
- Uses [beeep](https://github.com/gen2brain/beeep) for cross-platform notifications
101+
102+
---
103+
104+
![windows notif](./screenshots/screen2.png)

go.mod

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module arvancloud-radar-notif
2+
3+
go 1.24.5
4+
5+
require github.com/gen2brain/beeep v0.11.1
6+
7+
require (
8+
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
9+
github.com/esiqveland/notify v0.13.3 // indirect
10+
github.com/go-ole/go-ole v1.3.0 // indirect
11+
github.com/godbus/dbus/v5 v5.1.0 // indirect
12+
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
13+
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
14+
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
15+
github.com/sergeymakinen/go-ico v1.0.0-beta.0 // indirect
16+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
17+
golang.org/x/sys v0.30.0 // indirect
18+
)

go.sum

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
2+
git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6+
github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
7+
github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
8+
github.com/gen2brain/beeep v0.11.1 h1:EbSIhrQZFDj1K2fzlMpAYlFOzV8YuNe721A58XcCTYI=
9+
github.com/gen2brain/beeep v0.11.1/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
10+
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
11+
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
12+
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
13+
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
14+
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
15+
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
16+
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
17+
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
18+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
19+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
20+
github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
21+
github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
22+
github.com/sergeymakinen/go-ico v1.0.0-beta.0 h1:m5qKH7uPKLdrygMWxbamVn+tl2HfiA3K6MFJw4GfZvQ=
23+
github.com/sergeymakinen/go-ico v1.0.0-beta.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
24+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
25+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
26+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
27+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
28+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
29+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
30+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
31+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
32+
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
33+
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
35+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
36+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
37+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
38+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
39+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

icon.png

2.21 KB
Loading

main.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"net/http/cookiejar"
9+
"time"
10+
11+
"github.com/gen2brain/beeep"
12+
)
13+
14+
const baseURL = "https://radar.arvancloud.ir/api/v1/internet-monitoring?isp="
15+
16+
var (
17+
errorCounts = make(map[string]int)
18+
erroredISPs = make(map[string]bool)
19+
)
20+
21+
var serviceIndicator string = "google"
22+
23+
var isps = []string{
24+
"sindad-buf",
25+
"sindad-thr-fanava",
26+
"sindad-thr",
27+
"bertina-xrx",
28+
"ajk-abrbaran",
29+
"tehran-3",
30+
"tehran-2",
31+
"bertina-thr",
32+
"hostiran",
33+
"parsonline",
34+
"afranet",
35+
"mci",
36+
"irancell",
37+
}
38+
39+
func fetchData(client *http.Client, isp string) (float64, error) {
40+
url := baseURL + isp
41+
42+
req, err := http.NewRequest("GET", url, nil)
43+
if err != nil {
44+
return 0, fmt.Errorf("❌ request creation error: %v", err)
45+
}
46+
47+
resp, err := client.Do(req)
48+
if err != nil {
49+
return 0, fmt.Errorf("❌ request error: %v", err)
50+
}
51+
defer resp.Body.Close()
52+
53+
body, err := io.ReadAll(resp.Body)
54+
if err != nil {
55+
return 0, fmt.Errorf("❌ error reading response: %v", err)
56+
}
57+
58+
var data map[string][]float64
59+
if err := json.Unmarshal(body, &data); err != nil {
60+
return 0, fmt.Errorf("❌ JSON parse error: %v", err)
61+
}
62+
63+
googleValues, ok := data[serviceIndicator]
64+
if !ok || googleValues == nil || len(googleValues) == 0 {
65+
return 0, fmt.Errorf("-")
66+
}
67+
68+
return googleValues[len(googleValues)-1], nil
69+
}
70+
71+
func checkStatus(isp string, value float64) {
72+
fmt.Printf("[%s] => Value: %.2f\n", isp, value)
73+
beeep.AppName = "Arvan Cloud Radar"
74+
if value != 0 {
75+
errorCounts[isp]++
76+
if errorCounts[isp] >= 3 && !erroredISPs[isp] {
77+
err := beeep.Notify("🔴 Internet Outage", fmt.Sprintf("Google unreachable from %s", isp), "./icon.png")
78+
if err != nil {
79+
fmt.Printf("[%s] ❌ Notification error: %v\n", isp, err)
80+
}
81+
erroredISPs[isp] = true
82+
}
83+
} else {
84+
if erroredISPs[isp] {
85+
err := beeep.Notify("🟢 Internet Outage fixed", fmt.Sprintf("Google reachable from %s", isp), "./icon.png")
86+
if err != nil {
87+
fmt.Printf("[%s] ❌ Notification error: %v\n", isp, err)
88+
}
89+
fmt.Printf("[%s] 🟢 Google is reachable again\n", isp)
90+
}
91+
errorCounts[isp] = 0
92+
erroredISPs[isp] = false
93+
}
94+
}
95+
96+
func waitUntilNextMinute() {
97+
now := time.Now()
98+
delay := time.Until(now.Truncate(time.Minute).Add(time.Minute))
99+
time.Sleep(delay)
100+
}
101+
102+
func main() {
103+
fmt.Println("Arvan Cloud Outage Notification started ...")
104+
jar, _ := cookiejar.New(nil)
105+
client := &http.Client{Jar: jar}
106+
107+
waitUntilNextMinute()
108+
for {
109+
fmt.Printf("⏰ %s\n", time.Now().Format("15:04:05"))
110+
for _, isp := range isps {
111+
go func(isp string) {
112+
value, err := fetchData(client, isp)
113+
if err != nil {
114+
fmt.Printf("[%s] %v\n", isp, err)
115+
return
116+
}
117+
checkStatus(isp, value)
118+
}(isp)
119+
}
120+
time.Sleep(1 * time.Minute)
121+
}
122+
}

screenshots/screen.png

61.5 KB
Loading

0 commit comments

Comments
 (0)