DB sync mutex
This commit is contained in:
parent
fde06e7a47
commit
b53e440e0e
10 changed files with 136 additions and 747 deletions
|
|
@ -17,5 +17,5 @@ func main() {
|
||||||
|
|
||||||
check.Path(*confPtr)
|
check.Path(*confPtr)
|
||||||
|
|
||||||
web.Gui(*confPtr, *nodePtr) // Start web GUI
|
web.Gui(*confPtr, *nodePtr) // webgui.go
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
go.mod
22
go.mod
|
|
@ -1,24 +1,24 @@
|
||||||
module github.com/aceberg/WatchYourLAN
|
module github.com/aceberg/WatchYourLAN
|
||||||
|
|
||||||
go 1.20
|
go 1.21.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/containrrr/shoutrrr v0.7.1
|
github.com/containrrr/shoutrrr v0.8.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.1
|
||||||
github.com/spf13/viper v1.16.0
|
github.com/spf13/viper v1.16.0
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.14.0
|
||||||
modernc.org/sqlite v1.25.0
|
modernc.org/sqlite v1.26.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fatih/color v1.13.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
|
@ -27,10 +27,10 @@ require (
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.9.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/text v0.12.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.7.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package db
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"log"
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
// Import sqlite module
|
// Import sqlite module
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
|
|
@ -11,23 +12,33 @@ import (
|
||||||
"github.com/aceberg/WatchYourLAN/internal/models"
|
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mu sync.Mutex
|
||||||
|
|
||||||
func dbExec(path, sqlStatement string) {
|
func dbExec(path, sqlStatement string) {
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
db, err := sql.Open("sqlite", path)
|
db, err := sql.Open("sqlite", path)
|
||||||
check.IfError(err)
|
check.IfError(err)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
_, err = db.Exec(sqlStatement)
|
_, err = db.Exec(sqlStatement)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
check.IfError(err)
|
check.IfError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select - select all hosts
|
// Select - select all hosts
|
||||||
func Select(path string) (dbHosts []models.Host) {
|
func Select(path string) (dbHosts []models.Host) {
|
||||||
db, _ := sql.Open("sqlite", path)
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
sqlStatement := `SELECT * FROM "now" ORDER BY DATE DESC`
|
sqlStatement := `SELECT * FROM "now" ORDER BY DATE DESC`
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
db, _ := sql.Open("sqlite", path)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
res, err := db.Query(sqlStatement)
|
res, err := db.Query(sqlStatement)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("ERROR: db_select: ", err)
|
log.Fatal("ERROR: db_select: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,6 @@ import (
|
||||||
"github.com/aceberg/WatchYourLAN/internal/auth"
|
"github.com/aceberg/WatchYourLAN/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Host - one host
|
|
||||||
type Host struct {
|
|
||||||
ID uint16
|
|
||||||
Name string
|
|
||||||
IP string
|
|
||||||
Mac string
|
|
||||||
Hw string
|
|
||||||
Date string
|
|
||||||
Known uint16
|
|
||||||
Now uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conf - app config
|
// Conf - app config
|
||||||
type Conf struct {
|
type Conf struct {
|
||||||
Iface string
|
Iface string
|
||||||
|
|
@ -33,6 +21,28 @@ type Conf struct {
|
||||||
Auth bool
|
Auth bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Host - one host
|
||||||
|
type Host struct {
|
||||||
|
ID uint16
|
||||||
|
Name string
|
||||||
|
IP string
|
||||||
|
Mac string
|
||||||
|
Hw string
|
||||||
|
Date string
|
||||||
|
Known uint16
|
||||||
|
Now uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// // History for hosts
|
||||||
|
// type History struct {
|
||||||
|
// ID int
|
||||||
|
// HostID int
|
||||||
|
// Name string
|
||||||
|
// IP string
|
||||||
|
// Date string
|
||||||
|
// State bool
|
||||||
|
// }
|
||||||
|
|
||||||
// GuiData - all data sent to html page
|
// GuiData - all data sent to html page
|
||||||
type GuiData struct {
|
type GuiData struct {
|
||||||
Config Conf
|
Config Conf
|
||||||
|
|
@ -40,4 +50,5 @@ type GuiData struct {
|
||||||
Themes []string
|
Themes []string
|
||||||
Version string
|
Version string
|
||||||
Auth auth.Conf
|
Auth auth.Conf
|
||||||
|
// HistLog []History
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,32 @@ import (
|
||||||
"github.com/aceberg/WatchYourLAN/internal/notify"
|
"github.com/aceberg/WatchYourLAN/internal/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hostInDB(appConfig models.Conf, host models.Host, dbHosts []models.Host) bool { // Check if host is already in DB
|
func hostsCompare(appConfig models.Conf) {
|
||||||
|
|
||||||
for _, oneHost := range dbHosts {
|
for _, oneHost := range dbHosts {
|
||||||
if host.Mac == oneHost.Mac && (appConfig.IgnoreIP == "yes" || host.IP == oneHost.IP) {
|
|
||||||
oneHost.IP = host.IP
|
host, exists := foundHostsMap[oneHost.Mac]
|
||||||
|
|
||||||
|
if exists && (appConfig.IgnoreIP == "yes" || host.IP == oneHost.IP) {
|
||||||
oneHost.Date = host.Date
|
oneHost.Date = host.Date
|
||||||
oneHost.Now = 1
|
oneHost.Now = 1
|
||||||
db.Update(appConfig.DbPath, oneHost)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func hostsCompare(appConfig models.Conf, foundHosts, dbHosts []models.Host) {
|
delete(foundHostsMap, oneHost.Mac)
|
||||||
for _, oneHost := range foundHosts {
|
|
||||||
if !(hostInDB(appConfig, oneHost, dbHosts)) {
|
db.Update(appConfig.DbPath, oneHost)
|
||||||
oneHost.Now = 1 // Mark host online
|
|
||||||
msg := fmt.Sprintf("UNKNOWN HOST IP: '%s', MAC: '%s', Hw: '%s'", oneHost.IP, oneHost.Mac, oneHost.Hw)
|
} else if oneHost.Now == 1 {
|
||||||
log.Println("WARN:", msg)
|
oneHost.Now = 0
|
||||||
notify.Shoutrrr(msg, appConfig.ShoutURL) // Notify through Shoutrrr
|
db.Update(appConfig.DbPath, oneHost)
|
||||||
db.Insert(appConfig.DbPath, oneHost)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, oneHost := range foundHostsMap {
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("UNKNOWN HOST IP: '%s', MAC: '%s', Hw: '%s'", oneHost.IP, oneHost.Mac, oneHost.Hw)
|
||||||
|
log.Println("WARN:", msg)
|
||||||
|
notify.Shoutrrr(msg, appConfig.ShoutURL) // Notify through Shoutrrr
|
||||||
|
|
||||||
|
db.Insert(appConfig.DbPath, oneHost)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,15 @@ import (
|
||||||
"github.com/aceberg/WatchYourLAN/internal/models"
|
"github.com/aceberg/WatchYourLAN/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var dbHosts, structHosts []models.Host
|
||||||
|
var foundHostsMap map[string]models.Host
|
||||||
|
|
||||||
// Start - start arp-scan goroutine
|
// Start - start arp-scan goroutine
|
||||||
func Start(appConfig models.Conf, quit chan bool) {
|
func Start(appConfig models.Conf, quit chan bool) {
|
||||||
var foundHosts []models.Host
|
|
||||||
var dbHosts []models.Host
|
|
||||||
var lastDate time.Time
|
var lastDate time.Time
|
||||||
|
|
||||||
|
db.Create(appConfig.DbPath)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-quit:
|
case <-quit:
|
||||||
|
|
@ -22,10 +25,11 @@ func Start(appConfig models.Conf, quit chan bool) {
|
||||||
plusDate := lastDate.Add(time.Duration(appConfig.Timeout) * time.Second)
|
plusDate := lastDate.Add(time.Duration(appConfig.Timeout) * time.Second)
|
||||||
|
|
||||||
if nowDate.After(plusDate) {
|
if nowDate.After(plusDate) {
|
||||||
foundHosts = arpScan(appConfig.Iface, appConfig.LogLevel)
|
structHosts = arpScan(appConfig.Iface, appConfig.LogLevel)
|
||||||
dbHosts = db.Select(appConfig.DbPath)
|
dbHosts = db.Select(appConfig.DbPath)
|
||||||
db.SetNow(appConfig.DbPath)
|
|
||||||
hostsCompare(appConfig, foundHosts, dbHosts)
|
toMap()
|
||||||
|
hostsCompare(appConfig) // compare.go
|
||||||
|
|
||||||
lastDate = time.Now()
|
lastDate = time.Now()
|
||||||
}
|
}
|
||||||
|
|
@ -34,3 +38,11 @@ func Start(appConfig models.Conf, quit chan bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toMap() {
|
||||||
|
foundHostsMap = make(map[string]models.Host)
|
||||||
|
|
||||||
|
for _, host := range structHosts {
|
||||||
|
foundHostsMap[host.Mac] = host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ import (
|
||||||
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var guiData models.GuiData
|
var guiData models.GuiData
|
||||||
|
|
||||||
|
AllHosts = db.Select(AppConfig.DbPath)
|
||||||
|
|
||||||
guiData.Config = AppConfig
|
guiData.Config = AppConfig
|
||||||
guiData.Hosts = AllHosts
|
guiData.Hosts = AllHosts
|
||||||
|
|
||||||
execTemplate(w, "index", guiData)
|
execTemplate(w, "index", guiData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func homeHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
AllHosts = db.Select(AppConfig.DbPath)
|
|
||||||
http.Redirect(w, r, "/", 302)
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/home/">Home</a>
|
<a class="nav-link active" href="/">Home</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/line?state=on">Online</a>
|
<a class="nav-link active" href="/line?state=on">Online</a>
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ func Gui(configPath, nodePath string) {
|
||||||
|
|
||||||
address := AppConfig.GuiIP + ":" + AppConfig.GuiPort
|
address := AppConfig.GuiIP + ":" + AppConfig.GuiPort
|
||||||
|
|
||||||
db.Create(AppConfig.DbPath)
|
|
||||||
|
|
||||||
QuitScan = make(chan bool)
|
QuitScan = make(chan bool)
|
||||||
|
|
||||||
go scan.Start(AppConfig, QuitScan)
|
go scan.Start(AppConfig, QuitScan)
|
||||||
|
|
@ -34,15 +32,14 @@ func Gui(configPath, nodePath string) {
|
||||||
log.Printf("Web GUI at http://%s", address)
|
log.Printf("Web GUI at http://%s", address)
|
||||||
log.Println("=================================== ")
|
log.Println("=================================== ")
|
||||||
|
|
||||||
http.HandleFunc("/login/", loginHandler)
|
http.HandleFunc("/login/", loginHandler) // login.go
|
||||||
|
|
||||||
http.HandleFunc("/", auth.Auth(indexHandler, &authConf))
|
http.HandleFunc("/", auth.Auth(indexHandler, &authConf))
|
||||||
http.HandleFunc("/auth_conf/", auth.Auth(authConfHandler, &authConf))
|
http.HandleFunc("/auth_conf/", auth.Auth(authConfHandler, &authConf)) // auth-conf.go
|
||||||
http.HandleFunc("/auth_save/", auth.Auth(saveAuthHandler, &authConf))
|
http.HandleFunc("/auth_save/", auth.Auth(saveAuthHandler, &authConf)) // auth-conf.go
|
||||||
http.HandleFunc("/clear/", auth.Auth(clearHandler, &authConf))
|
http.HandleFunc("/clear/", auth.Auth(clearHandler, &authConf)) // config.go
|
||||||
http.HandleFunc("/config/", auth.Auth(configHandler, &authConf))
|
http.HandleFunc("/config/", auth.Auth(configHandler, &authConf)) // config.go
|
||||||
http.HandleFunc("/del_host/", auth.Auth(delHandler, &authConf))
|
http.HandleFunc("/del_host/", auth.Auth(delHandler, &authConf))
|
||||||
http.HandleFunc("/home/", auth.Auth(homeHandler, &authConf))
|
|
||||||
http.HandleFunc("/host/", auth.Auth(hostHandler, &authConf))
|
http.HandleFunc("/host/", auth.Auth(hostHandler, &authConf))
|
||||||
http.HandleFunc("/line/", auth.Auth(lineHandler, &authConf))
|
http.HandleFunc("/line/", auth.Auth(lineHandler, &authConf))
|
||||||
http.HandleFunc("/port_scan/", auth.Auth(portHandler, &authConf))
|
http.HandleFunc("/port_scan/", auth.Auth(portHandler, &authConf))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue