NetworkMonitor/main.go

185 lines
3.4 KiB
Go

package main
import (
"bytes"
_ "embed"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"text/template"
"time"
)
//go:embed index.html
var tmpl string
var report = template.Must(template.New("").Parse(tmpl))
var write_report chan bool
var interval = time.Second * 2
type Network struct {
Name string
IP string
OnFail string
}
var Networks = []*Network{
{
Name: "DSL",
IP: "220.135.85.67",
OnFail: "nmcli connection up DSL",
},
{
Name: "Asus",
IP: "192.168.50.48",
},
}
func main() {
write_report = make(chan bool, 1)
file, err := os.OpenFile("network.log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm)
if err != nil {
log.Panicln(err)
}
defer file.Close()
log.Println("starting network monitor")
go func() {
perr := false
derr := false
for reducer := 0; ; reducer++ {
now := time.Now().Format("2006-01-02 15:04:05")
// Public
go func(print bool) {
_, err = net.LookupIP("google.com")
if err != nil {
if !perr {
perr = true
log.Println(err)
}
fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "failed", "Public")
fmt.Fprintf(file, "\n")
} else {
perr = false
if print {
fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "ok", "Public")
fmt.Fprintf(file, "\n")
}
}
}(reducer == 0)
// devices
go func(print bool) {
for i := range Networks {
_, err = GetOutboundIP(Networks[i].IP + ":0")
if err != nil {
if !derr {
derr = true
log.Println(err)
}
fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "failed", Networks[i].Name)
fmt.Fprintf(file, "\n")
// fmt.Fprintf(file, "%s\t%s\t%s\n", now, Networks[i].Name, "failed")
} else {
derr = false
if print {
fmt.Fprintf(file, `{"x": "%s", "y": "%s", "name": "%s"},`, now, "ok", Networks[i].Name)
fmt.Fprintf(file, "\n")
}
}
}
}(reducer == 0)
<-time.After(interval)
if reducer >= 9 {
reducer = -1
}
}
}()
go func() {
for {
<-time.After(time.Minute * 10)
WriteReport()
}
}()
go func() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, strings.TrimPrefix(r.URL.Path, "/"))
})
if err := http.ListenAndServe("0.0.0.0:1080", nil); err != nil {
log.Fatalln(err)
}
}()
wait := make(chan os.Signal, 1)
signal.Notify(wait, syscall.SIGINT, syscall.SIGTERM)
<-wait
WriteReport()
}
func WriteReport() {
select {
case write_report <- true:
default:
return
}
defer func() { <-write_report }()
f, err := os.OpenFile("report.html", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Println(err)
return
}
defer f.Close()
data, err := os.ReadFile("network.log")
if err != nil {
log.Println(err)
return
}
content := &bytes.Buffer{}
if err = report.Execute(content, map[string]string{"Data": string(data)}); err != nil {
log.Println(err)
return
}
content.WriteTo(f)
}
// Get preferred outbound ip of this machine
func GetOutboundIP(addr string) (net.IP, error) {
iface, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return nil, err
}
dialer := &net.Dialer{LocalAddr: iface}
conn, err := dialer.Dial("udp", "8.8.8.8:80")
if err != nil {
return nil, err
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP, nil
}