From a639024b087735dceee715bec73470cecc9e113e Mon Sep 17 00:00:00 2001 From: thun888 <2238342947@qq.com> Date: Thu, 5 Oct 2023 13:31:37 +0800 Subject: [PATCH] history record --- config.json | 7 ++ go.mod | 15 ++++ go.sum | 26 +++++++ main.go | 114 ++++++++++++++++++------------ modules/config/base.go | 52 +++++++++----- modules/database/base.go | 147 +++++++++++++++++++++++++++++++++++++++ modules/tp/base.go | 4 +- 7 files changed, 302 insertions(+), 63 deletions(-) create mode 100644 modules/database/base.go diff --git a/config.json b/config.json index 18c7ebd..7cf102a 100644 --- a/config.json +++ b/config.json @@ -5,7 +5,14 @@ "ip": "192.168.31.1", "routerunit": false }], + "history": { + "enable": true, + "sampletime": 300, + "maxdeleted": 360, + "databasepath": "./database.db" + }, + "flushTokenTime": 1800, "tiny": false, "port": 6789, "debug": true diff --git a/go.mod b/go.mod index 9b32b8d..ccc37ac 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,24 @@ require ( github.com/labstack/echo/v4 v4.11.1 github.com/shirou/gopsutil v3.21.11+incompatible github.com/sirupsen/logrus v1.9.3 + gorm.io/gorm v1.25.2 ) require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect +) + +require ( + github.com/glebarez/sqlite v1.9.0 github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/labstack/gommon v0.4.0 // indirect diff --git a/go.sum b/go.sum index 481b910..7a1ce51 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,23 @@ 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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs= +github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= @@ -18,6 +31,9 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -58,3 +74,13 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= diff --git a/main.go b/main.go index d4f7520..e22ad99 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "main/modules/config" + "main/modules/database" "main/modules/download" login "main/modules/login" "main/modules/tp" @@ -25,37 +26,43 @@ import ( ) var ( - password string - key string - ip string - token string - tokens map[int]string - debug bool - port int - routerName string - routerNames map[int]string - hardware string - hardwares map[int]string - tiny bool - routerunit bool - dev []config.Dev - cpu_cmd *exec.Cmd - w24g_cmd *exec.Cmd - w5g_cmd *exec.Cmd - configPath string - basedirectory string - Version string + password string + key string + ip string + token string + tokens map[int]string + debug bool + port int + routerName string + routerNames map[int]string + hardware string + hardwares map[int]string + tiny bool + routerunit bool + dev []config.Dev + cpu_cmd *exec.Cmd + w24g_cmd *exec.Cmd + w5g_cmd *exec.Cmd + configPath string + basedirectory string + Version string + databasepath string + flushTokenTime int64 + maxdeleted int64 + historyEnable bool + sampletime int64 ) type Config struct { - Dev []config.Dev `json:"dev"` - Debug bool `json:"debug"` - Port int `json:"port"` - Tiny bool `json:"tiny"` + Dev []config.Dev `json:"dev"` + Debug bool `json:"debug"` + Port int `json:"port"` + Tiny bool `json:"tiny"` + Databasepath string `json:"databasepath"` } func init() { - dev, debug, port, tiny, basedirectory = config.Getconfig() + dev, debug, port, tiny, basedirectory, databasepath, flushTokenTime, maxdeleted, historyEnable, sampletime = config.GetConfigInfo() tokens = make(map[int]string) routerNames = make(map[int]string) hardwares = make(map[int]string) @@ -113,21 +120,21 @@ func main() { e.Use(middleware.CORS()) - e.GET("/:devnum/api/:apipath", func(c echo.Context) error { - devnum, err := strconv.Atoi(c.Param("devnum")) + e.GET("/:routernum/api/:apipath", func(c echo.Context) error { + routernum, err := strconv.Atoi(c.Param("routernum")) if err != nil { return c.JSON(http.StatusOK, map[string]interface{}{"code": 1100, "msg": "参数错误"}) } apipath := c.Param("apipath") - ip = dev[devnum].IP + ip = dev[routernum].IP switch apipath { case "xqsystem/router_name": - return c.JSON(http.StatusOK, map[string]interface{}{"code": 0, "routerName": routerNames[devnum]}) + return c.JSON(http.StatusOK, map[string]interface{}{"code": 0, "routerName": routerNames[routernum]}) case "misystem/status", "misystem/devicelist", "xqsystem/internet_connect", "xqsystem/fac_info", "misystem/messages": - url := fmt.Sprintf("http://%s/cgi-bin/luci/;stok=%s/api/%s", ip, tokens[devnum], apipath) + url := fmt.Sprintf("http://%s/cgi-bin/luci/;stok=%s/api/%s", ip, tokens[routernum], apipath) resp, err := http.Get(url) if err != nil { return c.JSON(http.StatusOK, map[string]interface{}{ @@ -156,13 +163,13 @@ func main() { } }) - e.GET("/:devnum/_api/gettemperature", func(c echo.Context) error { - devnum, err := strconv.Atoi(c.Param("devnum")) + e.GET("/:routernum/_api/gettemperature", func(c echo.Context) error { + routernum, err := strconv.Atoi(c.Param("routernum")) logrus.Debug(tokens) if err != nil { return c.JSON(http.StatusOK, map[string]interface{}{"code": 1100, "msg": "参数错误"}) } - status, cpu_tp, fanspeed, w24g_tp, w5g_tp := tp.GetTemperature(c, devnum, hardwares[devnum]) + status, cpu_tp, fanspeed, w24g_tp, w5g_tp := tp.GetTemperature(c, routernum, hardwares[routernum]) if status { return c.JSON(http.StatusOK, map[string]interface{}{ "code": 0, @@ -179,16 +186,16 @@ func main() { }) e.GET("/_api/getconfig", getconfig) - e.GET("/_api/quit", func(c echo.Context) error { - go func() { - time.Sleep(1 * time.Second) - defer os.Exit(0) - }() - return c.JSON(http.StatusOK, map[string]interface{}{ - "code": 0, - "msg": "正在关闭", - }) + + e.GET("/_api/gethistory", func(c echo.Context) error { + routernum, err := strconv.Atoi(c.QueryParam("routernum")) + if err != nil { + return c.JSON(http.StatusOK, map[string]interface{}{"code": 1100, "msg": "参数错误"}) + } + history := database.Getdata(databasepath, routernum) + return c.JSON(http.StatusOK, history) }) + e.GET("/_api/flushstatic", func(c echo.Context) error { err := download.DownloadStatic(basedirectory, true) if err != nil { @@ -204,6 +211,17 @@ func main() { }) }) + e.GET("/_api/quit", func(c echo.Context) error { + go func() { + time.Sleep(1 * time.Second) + defer os.Exit(0) + }() + return c.JSON(http.StatusOK, map[string]interface{}{ + "code": 0, + "msg": "正在关闭", + }) + }) + // var contentHandler = echo.WrapHandler(http.FileServer(http.FS(static))) // var contentRewrite = middleware.Rewrite(map[string]string{"/*": "/static/$1"}) @@ -217,12 +235,20 @@ func main() { e.Static("/", directory) } gettoken(dev) - + database.CheckDatabase(databasepath) go func() { - for range time.Tick(30 * time.Minute) { + for range time.Tick(time.Duration(flushTokenTime) * time.Second) { gettoken(dev) } }() + if historyEnable { + go func() { + for range time.Tick(time.Duration(sampletime) * time.Second) { + database.Savetodb(databasepath, dev, tokens, maxdeleted) + } + }() + } + e.Start(":" + fmt.Sprint(port)) quit := make(chan os.Signal, 1) diff --git a/modules/config/base.go b/modules/config/base.go index 4a99612..f9485cc 100644 --- a/modules/config/base.go +++ b/modules/config/base.go @@ -14,17 +14,22 @@ import ( ) var ( - password string - key string - ip string - debug bool - port int - tiny bool - routerunit bool - configPath string - basedirectory string - Version string - dev []Dev + password string + key string + ip string + debug bool + port int + tiny bool + routerunit bool + configPath string + basedirectory string + databasepath string + historyEnable bool + Version string + dev []Dev + maxdeleted int64 + flushTokenTime int64 + sampletime int64 ) type Dev struct { @@ -33,14 +38,22 @@ type Dev struct { IP string `json:"ip"` RouterUnit bool `json:"routerunit"` } +type History struct { + Enable bool `json:"enable"` + MaxDeleted int64 `json:"maxdeleted"` + Databasepath string `json:"databasepath"` + Sampletime int64 `json:"sampletime"` +} type Config struct { - Dev []Dev `json:"dev"` - Debug bool `json:"debug"` - Port int `json:"port"` - Tiny bool `json:"tiny"` + Dev []Dev `json:"dev"` + History History `json:"history"` + Debug bool `json:"debug"` + Port int `json:"port"` + Tiny bool `json:"tiny"` + FlushTokenTime int64 `json:"flushTokenTime"` } -func Getconfig() (dev []Dev, debug bool, port int, tiny bool, basedirectory string) { +func GetConfigInfo() (dev []Dev, debug bool, port int, tiny bool, basedirectory string, databasepath string, flushTokenTime int64, maxdeleted int64, historyEnable bool, sampletime int64) { flag.StringVar(&configPath, "config", "", "配置文件路径") flag.StringVar(&basedirectory, "basedirectory", "", "基础目录路径") flag.Parse() @@ -78,6 +91,11 @@ func Getconfig() (dev []Dev, debug bool, port int, tiny bool, basedirectory stri debug = config.Debug port = config.Port tiny = config.Tiny + databasepath = config.History.Databasepath + maxdeleted = config.History.MaxDeleted + historyEnable = config.History.Enable + sampletime = config.History.Sampletime + flushTokenTime = config.FlushTokenTime // logrus.Info(password) // logrus.Info(key) if tiny == false { @@ -95,7 +113,7 @@ func Getconfig() (dev []Dev, debug bool, port int, tiny bool, basedirectory stri time.Sleep(5 * time.Second) os.Exit(1) } - return dev, debug, port, tiny, basedirectory + return dev, debug, port, tiny, basedirectory, databasepath, flushTokenTime, maxdeleted, historyEnable, sampletime } func checkErr(err error) { diff --git a/modules/database/base.go b/modules/database/base.go new file mode 100644 index 0000000..a4d7ba0 --- /dev/null +++ b/modules/database/base.go @@ -0,0 +1,147 @@ +package database + +import ( + "io" + "math" + "strconv" + + "encoding/json" + "fmt" + "main/modules/config" + "net/http" + + "github.com/glebarez/sqlite" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +// For database +type History struct { + gorm.Model + Ip string + RouterNum int + CPU float64 + Cpu_tp int + Mem float64 + UpSpeed float64 + DownSpeed float64 + UpTotal float64 + DownTotal float64 + DeviceNum int +} + +type Dev struct { + Password string `json:"password"` + Key string `json:"key"` + IP string `json:"ip"` + RouterUnit bool `json:"routerunit"` +} + +// CheckDatabase checks the SQLite database file at the given path. +// +// Parameters: +// - databasepath: a string variable that holds the path to the SQLite database file. +// +// Returns: None. +func CheckDatabase(databasepath string) { + // databasepath is a variable that holds the path to the SQLite database file + db, err := gorm.Open(sqlite.Open(databasepath), &gorm.Config{}) + checkErr(err) + + // Check if the history table exists, if not, create it + err = db.AutoMigrate(&History{}) + checkErr(err) + + // Perform CRUD operations on the history table using db.Create, db.First, db.Update, db.Delete methods +} + +// Savetodb saves device statistics to the database. +// +// Parameters: +// - databasepath: the path to the database. +// - dev: an array of device configurations. +// - tokens: a map of token IDs to strings. +// - maxdeleted: the maximum number of records to delete. +func Savetodb(databasepath string, dev []config.Dev, tokens map[int]string, maxdeleted int64) { + db, err := gorm.Open(sqlite.Open(databasepath), &gorm.Config{}) + checkErr(err) + for i, d := range dev { + ip := d.IP + routerNum := i + cpu, cpu_tp, mem, upSpeed, downSpeed, upTotal, downTotal, deviceNum := getDeviceStats(i, tokens, ip) + var count int64 + db.Model(&History{}).Where("router_num = ?", routerNum).Count(&count) + if count >= maxdeleted { + logrus.Debug("删除历史数据") + db.Exec("DELETE FROM histories WHERE router_num = ? AND created_at = (SELECT MIN(created_at) FROM histories WHERE router_num = ? );", routerNum, routerNum) + + } + db.Create(&History{ + Ip: ip, + RouterNum: routerNum, + CPU: cpu, + Cpu_tp: cpu_tp, + Mem: mem, + UpSpeed: upSpeed, + DownSpeed: downSpeed, + UpTotal: upTotal, + DownTotal: downTotal, + DeviceNum: deviceNum, + }) + } +} + +func Getdata(databasepath string, routernum int) []History { + db, err := gorm.Open(sqlite.Open(databasepath), &gorm.Config{}) + checkErr(err) + var history []History + db.Where("router_num = ?", routernum).Find(&history) + return history +} + +// getDeviceStats retrieves the device statistics from the specified router. +// +// Parameters: +// - routernum: The router number. +// - tokens: A map containing the tokens. +// - ip: The IP address of the router. +// +// Returns: +// - cpuload: The CPU load. +// - cpu_tp: The CPU temperature. +// - memusage: The memory usage. +// - upspeed: The upload speed. +// - downspeed: The download speed. +// - uploadtotal: The total upload amount. +// - downloadtotal: The total download amount. +// - devicenum_now: The number of online devices. +func getDeviceStats(routernum int, tokens map[int]string, ip string) (float64, int, float64, float64, float64, float64, float64, int) { + url := fmt.Sprintf("http://%s/cgi-bin/luci/;stok=%s/api/misystem/status", ip, tokens[routernum]) + resp, err := http.Get(url) + checkErr(err) + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + var result map[string]interface{} + json.Unmarshal(body, &result) + + upspeed, _ := strconv.ParseFloat(result["wan"].(map[string]interface{})["upspeed"].(string), 64) + downspeed, _ := strconv.ParseFloat(result["wan"].(map[string]interface{})["downspeed"].(string), 64) + uploadtotal, _ := strconv.ParseFloat(result["wan"].(map[string]interface{})["upload"].(string), 64) + downloadtotal, _ := strconv.ParseFloat(result["wan"].(map[string]interface{})["download"].(string), 64) + cpuload := roundToOneDecimal(result["cpu"].(map[string]interface{})["load"].(float64) * 100) + cpu_tp := int(result["temperature"].(float64)) + memusage := roundToOneDecimal(result["mem"].(map[string]interface{})["usage"].(float64) * 100) + devicenum_now := int(result["count"].(map[string]interface{})["online"].(float64)) + + return cpuload, cpu_tp, memusage, upspeed, downspeed, uploadtotal, downloadtotal, devicenum_now +} + +func roundToOneDecimal(num float64) float64 { + return math.Round(num*100) / 100 +} + +func checkErr(err error) { + if err != nil { + logrus.Debug(err) + } +} diff --git a/modules/tp/base.go b/modules/tp/base.go index 803afb3..009a32f 100644 --- a/modules/tp/base.go +++ b/modules/tp/base.go @@ -18,8 +18,8 @@ var ( ) // 获取温度 -func GetTemperature(c echo.Context, devnum int, hardware string) (bool, string, string, string, string) { - if dev[devnum].RouterUnit == false { +func GetTemperature(c echo.Context, routernum int, hardware string) (bool, string, string, string, string) { + if dev[routernum].RouterUnit == false { return false, "-233", "-233", "-233", "-233" } var cpu_out, w24g_out, w5g_out []byte