diff --git a/README.md b/README.md index e400037..4ac4f2f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
LOGO designed by 熊大 .

-    +   

:trollface: 哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,计划任务和在线终端。

@@ -14,11 +14,11 @@ \>> [我们的用户](https://www.google.com/search?q="powered+by+哪吒监控"&filter=0) (Google) -| 默认主题 | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru | -| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------- | -| ![默认主题](resource/template/theme-default/screenshot.png) | ![daynight](resource/template/theme-daynight/screenshot.png) | | -|
默认主题魔改 [教程]
| | | -| ![默认主题魔改](https://cdn.jsdelivr.net/gh/idarku/img@main/me/1631120192341.webp) | | | +| 默认主题 | DayNight [@JackieSung](https://github.com/JackieSung4ev) | hotaru | +| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | +| ![默认主题](resource/template/theme-default/screenshot.png) | | | +|
默认主题魔改 [教程]
|
Neko Mdui @MikoyChinese
| | +| ![默认主题魔改](https://cdn.jsdelivr.net/gh/idarku/img@main/me/1631120192341.webp) | ![Neko Mdui](resource/template/theme-mdui/screenshot.png) | | ## 安装脚本 diff --git a/cmd/dashboard/controller/common_page.go b/cmd/dashboard/controller/common_page.go index ba78c85..e318bf4 100644 --- a/cmd/dashboard/controller/common_page.go +++ b/cmd/dashboard/controller/common_page.go @@ -17,7 +17,7 @@ import ( "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/mygin" "github.com/naiba/nezha/proto" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type terminalContext struct { @@ -54,7 +54,7 @@ func (p *commonPage) issueViewPassword(c *gin.Context) { var vpf viewPasswordForm err := c.ShouldBind(&vpf) var hash []byte - if err == nil && vpf.Password != dao.Conf.Site.ViewPassword { + if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword { err = errors.New("查看密码错误") } if err == nil { @@ -69,12 +69,12 @@ func (p *commonPage) issueViewPassword(c *gin.Context) { c.Abort() return } - c.SetCookie(dao.Conf.Site.CookieName+"-vp", string(hash), 60*60*24, "", "", false, false) + c.SetCookie(singleton.Conf.Site.CookieName+"-vp", string(hash), 60*60*24, "", "", false, false) c.Redirect(http.StatusFound, c.Request.Referer()) } func (p *commonPage) checkViewPassword(c *gin.Context) { - if dao.Conf.Site.ViewPassword == "" { + if singleton.Conf.Site.ViewPassword == "" { c.Next() return } @@ -84,11 +84,11 @@ func (p *commonPage) checkViewPassword(c *gin.Context) { } // 验证查看密码 - viewPassword, _ := c.Cookie(dao.Conf.Site.CookieName + "-vp") - if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(dao.Conf.Site.ViewPassword)); err != nil { - c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{ + viewPassword, _ := c.Cookie(singleton.Conf.Site.CookieName + "-vp") + if err := bcrypt.CompareHashAndPassword([]byte(viewPassword), []byte(singleton.Conf.Site.ViewPassword)); err != nil { + c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/viewpassword", mygin.CommonEnvironment(c, gin.H{ "Title": "验证查看密码", - "CustomCode": dao.Conf.Site.CustomCode, + "CustomCode": singleton.Conf.Site.CustomCode, })) c.Abort() return @@ -98,22 +98,22 @@ func (p *commonPage) checkViewPassword(c *gin.Context) { } func (p *commonPage) service(c *gin.Context) { - dao.AlertsLock.RLock() - defer dao.AlertsLock.RUnlock() - c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{ + singleton.AlertsLock.RLock() + defer singleton.AlertsLock.RUnlock() + c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{ "Title": "服务状态", - "Services": dao.ServiceSentinelShared.LoadStats(), - "CycleTransferStats": dao.AlertsCycleTransferStatsStore, - "CustomCode": dao.Conf.Site.CustomCode, + "Services": singleton.ServiceSentinelShared.LoadStats(), + "CycleTransferStats": singleton.AlertsCycleTransferStatsStore, + "CustomCode": singleton.Conf.Site.CustomCode, })) } func (cp *commonPage) home(c *gin.Context) { - dao.SortedServerLock.RLock() - defer dao.SortedServerLock.RUnlock() - c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/home", mygin.CommonEnvironment(c, gin.H{ - "Servers": dao.SortedServerList, - "CustomCode": dao.Conf.Site.CustomCode, + singleton.SortedServerLock.RLock() + defer singleton.SortedServerLock.RUnlock() + c.HTML(http.StatusOK, "theme-"+singleton.Conf.Site.Theme+"/home", mygin.CommonEnvironment(c, gin.H{ + "Servers": singleton.SortedServerList, + "CustomCode": singleton.Conf.Site.CustomCode, })) } @@ -142,12 +142,12 @@ func (cp *commonPage) ws(c *gin.Context) { defer conn.Close() count := 0 for { - dao.SortedServerLock.RLock() + singleton.SortedServerLock.RLock() err = conn.WriteJSON(Data{ Now: time.Now().Unix() * 1000, - Servers: dao.SortedServerList, + Servers: singleton.SortedServerList, }) - dao.SortedServerLock.RUnlock() + singleton.SortedServerLock.RUnlock() if err != nil { break } @@ -190,9 +190,9 @@ func (cp *commonPage) terminal(c *gin.Context) { var isAgent bool if _, authorized := c.Get(model.CtxKeyAuthorizedUser); !authorized { - dao.ServerLock.RLock() - _, hasID := dao.SecretToID[c.Request.Header.Get("Secret")] - dao.ServerLock.RUnlock() + singleton.ServerLock.RLock() + _, hasID := singleton.SecretToID[c.Request.Header.Get("Secret")] + singleton.ServerLock.RUnlock() if !hasID { mygin.ShowErrorPage(c, mygin.ErrInfo{ Code: http.StatusForbidden, @@ -225,9 +225,9 @@ func (cp *commonPage) terminal(c *gin.Context) { } isAgent = true } else { - dao.ServerLock.RLock() - server := dao.ServerList[terminal.serverID] - dao.ServerLock.RUnlock() + singleton.ServerLock.RLock() + server := singleton.ServerList[terminal.serverID] + singleton.ServerLock.RUnlock() if server == nil || server.TaskStream == nil { mygin.ShowErrorPage(c, mygin.ErrInfo{ Code: http.StatusForbidden, @@ -407,9 +407,9 @@ func (cp *commonPage) createTerminal(c *gin.Context) { return } - dao.ServerLock.RLock() - server := dao.ServerList[createTerminalReq.ID] - dao.ServerLock.RUnlock() + singleton.ServerLock.RLock() + server := singleton.ServerList[createTerminalReq.ID] + singleton.ServerLock.RUnlock() if server == nil || server.TaskStream == nil { mygin.ShowErrorPage(c, mygin.ErrInfo{ Code: http.StatusForbidden, diff --git a/cmd/dashboard/controller/controller.go b/cmd/dashboard/controller/controller.go index 7f0cafb..d80f9e5 100644 --- a/cmd/dashboard/controller/controller.go +++ b/cmd/dashboard/controller/controller.go @@ -14,13 +14,13 @@ import ( "github.com/gin-gonic/gin" "github.com/naiba/nezha/pkg/mygin" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) func ServeWeb(port uint) *http.Server { gin.SetMode(gin.ReleaseMode) r := gin.Default() - if dao.Conf.Debug { + if singleton.Conf.Debug { gin.SetMode(gin.DebugMode) pprof.Register(r) } diff --git a/cmd/dashboard/controller/guest_page.go b/cmd/dashboard/controller/guest_page.go index c5db724..8512d15 100644 --- a/cmd/dashboard/controller/guest_page.go +++ b/cmd/dashboard/controller/guest_page.go @@ -4,9 +4,10 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/mygin" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type guestPage struct { @@ -34,7 +35,7 @@ func (gp *guestPage) serve() { func (gp *guestPage) login(c *gin.Context) { LoginType := "GitHub" RegistrationLink := "https://github.com/join" - if dao.Conf.Oauth2.Type == model.ConfigTypeGitee { + if singleton.Conf.Oauth2.Type == model.ConfigTypeGitee { LoginType = "Gitee" RegistrationLink = "https://gitee.com/signup" } diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 854de73..195e369 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -16,7 +16,7 @@ import ( "github.com/naiba/nezha/pkg/mygin" "github.com/naiba/nezha/pkg/utils" "github.com/naiba/nezha/proto" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type memberAPI struct { @@ -59,53 +59,53 @@ func (ma *memberAPI) delete(c *gin.Context) { var err error switch c.Param("model") { case "server": - err = dao.DB.Unscoped().Delete(&model.Server{}, "id = ?", id).Error + err = singleton.DB.Unscoped().Delete(&model.Server{}, "id = ?", id).Error if err == nil { // 删除服务器 - dao.ServerLock.Lock() - delete(dao.SecretToID, dao.ServerList[id].Secret) - delete(dao.ServerList, id) - dao.ServerLock.Unlock() - dao.ReSortServer() + singleton.ServerLock.Lock() + delete(singleton.SecretToID, singleton.ServerList[id].Secret) + delete(singleton.ServerList, id) + singleton.ServerLock.Unlock() + singleton.ReSortServer() // 删除循环流量状态中的此服务器相关的记录 - dao.AlertsLock.Lock() - for i := 0; i < len(dao.Alerts); i++ { - if dao.AlertsCycleTransferStatsStore[dao.Alerts[i].ID] != nil { - delete(dao.AlertsCycleTransferStatsStore[dao.Alerts[i].ID].ServerName, id) - delete(dao.AlertsCycleTransferStatsStore[dao.Alerts[i].ID].Transfer, id) - delete(dao.AlertsCycleTransferStatsStore[dao.Alerts[i].ID].NextUpdate, id) + singleton.AlertsLock.Lock() + for i := 0; i < len(singleton.Alerts); i++ { + if singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID] != nil { + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].ServerName, id) + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].Transfer, id) + delete(singleton.AlertsCycleTransferStatsStore[singleton.Alerts[i].ID].NextUpdate, id) } } - dao.AlertsLock.Unlock() + singleton.AlertsLock.Unlock() // 删除服务器相关循环流量记录 - dao.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id) + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ?", id) } case "notification": - err = dao.DB.Unscoped().Delete(&model.Notification{}, "id = ?", id).Error + err = singleton.DB.Unscoped().Delete(&model.Notification{}, "id = ?", id).Error if err == nil { - dao.OnDeleteNotification(id) + singleton.OnDeleteNotification(id) } case "monitor": - err = dao.DB.Unscoped().Delete(&model.Monitor{}, "id = ?", id).Error + err = singleton.DB.Unscoped().Delete(&model.Monitor{}, "id = ?", id).Error if err == nil { - dao.ServiceSentinelShared.OnMonitorDelete(id) - err = dao.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ?", id).Error + singleton.ServiceSentinelShared.OnMonitorDelete(id) + err = singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "monitor_id = ?", id).Error } case "cron": - err = dao.DB.Unscoped().Delete(&model.Cron{}, "id = ?", id).Error + err = singleton.DB.Unscoped().Delete(&model.Cron{}, "id = ?", id).Error if err == nil { - dao.CronLock.RLock() - defer dao.CronLock.RUnlock() - cr := dao.Crons[id] + singleton.CronLock.RLock() + defer singleton.CronLock.RUnlock() + cr := singleton.Crons[id] if cr != nil && cr.CronJobID != 0 { - dao.Cron.Remove(cr.CronJobID) + singleton.Cron.Remove(cr.CronJobID) } - delete(dao.Crons, id) + delete(singleton.Crons, id) } case "alert-rule": - err = dao.DB.Unscoped().Delete(&model.AlertRule{}, "id = ?", id).Error + err = singleton.DB.Unscoped().Delete(&model.AlertRule{}, "id = ?", id).Error if err == nil { - dao.OnDeleteAlert(id) + singleton.OnDeleteAlert(id) } } if err != nil { @@ -129,7 +129,7 @@ type searchResult struct { func (ma *memberAPI) searchServer(c *gin.Context) { var servers []model.Server likeWord := "%" + c.Query("word") + "%" - dao.DB.Select("id,name").Where("id = ? OR name LIKE ? OR tag LIKE ? OR note LIKE ?", + singleton.DB.Select("id,name").Where("id = ? OR name LIKE ? OR tag LIKE ? OR note LIKE ?", c.Query("word"), likeWord, likeWord, likeWord).Find(&servers) var resp []searchResult @@ -172,10 +172,10 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) { if s.ID == 0 { s.Secret = utils.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, admin.ID)) s.Secret = s.Secret[:18] - err = dao.DB.Create(&s).Error + err = singleton.DB.Create(&s).Error } else { isEdit = true - err = dao.DB.Save(&s).Error + err = singleton.DB.Save(&s).Error } } if err != nil { @@ -186,26 +186,26 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) { return } if isEdit { - dao.ServerLock.Lock() - s.CopyFromRunningServer(dao.ServerList[s.ID]) + singleton.ServerLock.Lock() + s.CopyFromRunningServer(singleton.ServerList[s.ID]) // 如果修改了 Secret - if s.Secret != dao.ServerList[s.ID].Secret { + if s.Secret != singleton.ServerList[s.ID].Secret { // 删除旧 Secret-ID 绑定关系 - dao.SecretToID[s.Secret] = s.ID + singleton.SecretToID[s.Secret] = s.ID // 设置新的 Secret-ID 绑定关系 - delete(dao.SecretToID, dao.ServerList[s.ID].Secret) + delete(singleton.SecretToID, singleton.ServerList[s.ID].Secret) } - dao.ServerList[s.ID] = &s - dao.ServerLock.Unlock() + singleton.ServerList[s.ID] = &s + singleton.ServerLock.Unlock() } else { s.Host = &model.Host{} s.State = &model.HostState{} - dao.ServerLock.Lock() - dao.SecretToID[s.Secret] = s.ID - dao.ServerList[s.ID] = &s - dao.ServerLock.Unlock() + singleton.ServerLock.Lock() + singleton.SecretToID[s.Secret] = s.ID + singleton.ServerList[s.ID] = &s + singleton.ServerLock.Unlock() } - dao.ReSortServer() + singleton.ReSortServer() c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, }) @@ -238,13 +238,13 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { } if err == nil { if m.ID == 0 { - err = dao.DB.Create(&m).Error + err = singleton.DB.Create(&m).Error } else { - err = dao.DB.Save(&m).Error + err = singleton.DB.Save(&m).Error } } if err == nil { - err = dao.ServiceSentinelShared.OnMonitorUpdate(m) + err = singleton.ServiceSentinelShared.OnMonitorUpdate(m) } if err != nil { c.JSON(http.StatusOK, model.Response{ @@ -282,7 +282,7 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { cr.Cover = cf.Cover err = json.Unmarshal([]byte(cf.ServersRaw), &cr.Servers) } - tx := dao.DB.Begin() + tx := singleton.DB.Begin() if err == nil { if cf.ID == 0 { err = tx.Create(&cr).Error @@ -291,7 +291,7 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { } } if err == nil { - cr.CronJobID, err = dao.Cron.AddFunc(cr.Scheduler, dao.CronTrigger(cr)) + cr.CronJobID, err = singleton.Cron.AddFunc(cr.Scheduler, singleton.CronTrigger(cr)) } if err == nil { err = tx.Commit().Error @@ -306,15 +306,15 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { return } - dao.CronLock.Lock() - defer dao.CronLock.Unlock() - crOld := dao.Crons[cr.ID] + singleton.CronLock.Lock() + defer singleton.CronLock.Unlock() + crOld := singleton.Crons[cr.ID] if crOld != nil && crOld.CronJobID != 0 { - dao.Cron.Remove(crOld.CronJobID) + singleton.Cron.Remove(crOld.CronJobID) } - delete(dao.Crons, cr.ID) - dao.Crons[cr.ID] = &cr + delete(singleton.Crons, cr.ID) + singleton.Crons[cr.ID] = &cr c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, @@ -323,7 +323,7 @@ func (ma *memberAPI) addOrEditCron(c *gin.Context) { func (ma *memberAPI) manualTrigger(c *gin.Context) { var cr model.Cron - if err := dao.DB.First(&cr, "id = ?", c.Param("id")).Error; err != nil { + if err := singleton.DB.First(&cr, "id = ?", c.Param("id")).Error; err != nil { c.JSON(http.StatusOK, model.Response{ Code: http.StatusBadRequest, Message: err.Error(), @@ -331,7 +331,7 @@ func (ma *memberAPI) manualTrigger(c *gin.Context) { return } - dao.ManualTrigger(cr) + singleton.ManualTrigger(cr) c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, @@ -351,9 +351,9 @@ func (ma *memberAPI) forceUpdate(c *gin.Context) { var executeResult bytes.Buffer for i := 0; i < len(forceUpdateServers); i++ { - dao.ServerLock.RLock() - server := dao.ServerList[forceUpdateServers[i]] - dao.ServerLock.RUnlock() + singleton.ServerLock.RLock() + server := singleton.ServerList[forceUpdateServers[i]] + singleton.ServerLock.RUnlock() if server != nil && server.TaskStream != nil { if err := server.TaskStream.Send(&proto.Task{ Type: model.TaskTypeUpgrade, @@ -402,9 +402,9 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) { } if err == nil { if n.ID == 0 { - err = dao.DB.Create(&n).Error + err = singleton.DB.Create(&n).Error } else { - err = dao.DB.Save(&n).Error + err = singleton.DB.Save(&n).Error } } if err != nil { @@ -414,7 +414,7 @@ func (ma *memberAPI) addOrEditNotification(c *gin.Context) { }) return } - dao.OnRefreshOrAddNotification(n) + singleton.OnRefreshOrAddNotification(n) c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, }) @@ -453,9 +453,9 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) { r.Enable = &enable r.ID = arf.ID if r.ID == 0 { - err = dao.DB.Create(&r).Error + err = singleton.DB.Create(&r).Error } else { - err = dao.DB.Save(&r).Error + err = singleton.DB.Save(&r).Error } } if err != nil { @@ -465,7 +465,7 @@ func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) { }) return } - dao.OnRefreshOrAddAlert(r) + singleton.OnRefreshOrAddAlert(r) c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, }) @@ -492,7 +492,7 @@ func (ma *memberAPI) logout(c *gin.Context) { }) return } - dao.DB.Model(admin).UpdateColumns(model.User{ + singleton.DB.Model(admin).UpdateColumns(model.User{ Token: "", TokenExpired: time.Now(), }) @@ -522,16 +522,16 @@ func (ma *memberAPI) updateSetting(c *gin.Context) { }) return } - dao.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on" - dao.Conf.Cover = sf.Cover - dao.Conf.GRPCHost = sf.GRPCHost - dao.Conf.IgnoredIPNotification = sf.IgnoredIPNotification - dao.Conf.Site.Brand = sf.Title - dao.Conf.Site.Theme = sf.Theme - dao.Conf.Site.CustomCode = sf.CustomCode - dao.Conf.Site.ViewPassword = sf.ViewPassword - dao.Conf.Oauth2.Admin = sf.Admin - if err := dao.Conf.Save(); err != nil { + singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on" + singleton.Conf.Cover = sf.Cover + singleton.Conf.GRPCHost = sf.GRPCHost + singleton.Conf.IgnoredIPNotification = sf.IgnoredIPNotification + singleton.Conf.Site.Brand = sf.Title + singleton.Conf.Site.Theme = sf.Theme + singleton.Conf.Site.CustomCode = sf.CustomCode + singleton.Conf.Site.ViewPassword = sf.ViewPassword + singleton.Conf.Oauth2.Admin = sf.Admin + if err := singleton.Conf.Save(); err != nil { c.JSON(http.StatusOK, model.Response{ Code: http.StatusBadRequest, Message: fmt.Sprintf("请求错误:%s", err), diff --git a/cmd/dashboard/controller/member_page.go b/cmd/dashboard/controller/member_page.go index 577a43c..ff84ce5 100644 --- a/cmd/dashboard/controller/member_page.go +++ b/cmd/dashboard/controller/member_page.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/mygin" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type memberPage struct { @@ -30,24 +30,24 @@ func (mp *memberPage) serve() { } func (mp *memberPage) server(c *gin.Context) { - dao.SortedServerLock.RLock() - defer dao.SortedServerLock.RUnlock() + singleton.SortedServerLock.RLock() + defer singleton.SortedServerLock.RUnlock() c.HTML(http.StatusOK, "dashboard/server", mygin.CommonEnvironment(c, gin.H{ "Title": "服务器管理", - "Servers": dao.SortedServerList, + "Servers": singleton.SortedServerList, })) } func (mp *memberPage) monitor(c *gin.Context) { c.HTML(http.StatusOK, "dashboard/monitor", mygin.CommonEnvironment(c, gin.H{ "Title": "服务监控", - "Monitors": dao.ServiceSentinelShared.Monitors(), + "Monitors": singleton.ServiceSentinelShared.Monitors(), })) } func (mp *memberPage) cron(c *gin.Context) { var crons []model.Cron - dao.DB.Find(&crons) + singleton.DB.Find(&crons) c.HTML(http.StatusOK, "dashboard/cron", mygin.CommonEnvironment(c, gin.H{ "Title": "计划任务", "Crons": crons, @@ -56,9 +56,9 @@ func (mp *memberPage) cron(c *gin.Context) { func (mp *memberPage) notification(c *gin.Context) { var nf []model.Notification - dao.DB.Find(&nf) + singleton.DB.Find(&nf) var ar []model.AlertRule - dao.DB.Find(&ar) + singleton.DB.Find(&ar) c.HTML(http.StatusOK, "dashboard/notification", mygin.CommonEnvironment(c, gin.H{ "Title": "报警通知", "Notifications": nf, diff --git a/cmd/dashboard/controller/oauth2.go b/cmd/dashboard/controller/oauth2.go index f9d25b4..aebe78a 100644 --- a/cmd/dashboard/controller/oauth2.go +++ b/cmd/dashboard/controller/oauth2.go @@ -15,7 +15,7 @@ import ( "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/mygin" "github.com/naiba/nezha/pkg/utils" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type oauth2controller struct { @@ -28,10 +28,10 @@ func (oa *oauth2controller) serve() { } func (oa *oauth2controller) getCommonOauth2Config(c *gin.Context) *oauth2.Config { - if dao.Conf.Oauth2.Type == model.ConfigTypeGitee { + if singleton.Conf.Oauth2.Type == model.ConfigTypeGitee { return &oauth2.Config{ - ClientID: dao.Conf.Oauth2.ClientID, - ClientSecret: dao.Conf.Oauth2.ClientSecret, + ClientID: singleton.Conf.Oauth2.ClientID, + ClientSecret: singleton.Conf.Oauth2.ClientSecret, Scopes: []string{}, Endpoint: oauth2.Endpoint{ AuthURL: "https://gitee.com/oauth/authorize", @@ -41,8 +41,8 @@ func (oa *oauth2controller) getCommonOauth2Config(c *gin.Context) *oauth2.Config } } else { return &oauth2.Config{ - ClientID: dao.Conf.Oauth2.ClientID, - ClientSecret: dao.Conf.Oauth2.ClientSecret, + ClientID: singleton.Conf.Oauth2.ClientID, + ClientSecret: singleton.Conf.Oauth2.ClientSecret, Scopes: []string{}, Endpoint: GitHubOauth2.Endpoint, } @@ -59,7 +59,7 @@ func (oa *oauth2controller) getRedirectURL(c *gin.Context) string { func (oa *oauth2controller) login(c *gin.Context) { state := utils.RandStringBytesMaskImprSrcUnsafe(6) - dao.Cache.Set(fmt.Sprintf("%s%s", model.CacheKeyOauth2State, c.ClientIP()), state, 0) + singleton.Cache.Set(fmt.Sprintf("%s%s", model.CacheKeyOauth2State, c.ClientIP()), state, 0) url := oa.getCommonOauth2Config(c).AuthCodeURL(state, oauth2.AccessTypeOnline) c.Redirect(http.StatusFound, url) } @@ -67,7 +67,7 @@ func (oa *oauth2controller) login(c *gin.Context) { func (oa *oauth2controller) callback(c *gin.Context) { var err error // 验证登录跳转时的 State - state, ok := dao.Cache.Get(fmt.Sprintf("%s%s", model.CacheKeyOauth2State, c.ClientIP())) + state, ok := singleton.Cache.Get(fmt.Sprintf("%s%s", model.CacheKeyOauth2State, c.ClientIP())) if !ok || state.(string) != c.Query("state") { err = errors.New("非法的登录方式") } @@ -80,7 +80,7 @@ func (oa *oauth2controller) callback(c *gin.Context) { var client *GitHubAPI.Client if err == nil { oc := oauth2Config.Client(ctx, otk) - if dao.Conf.Oauth2.Type == model.ConfigTypeGitee { + if singleton.Conf.Oauth2.Type == model.ConfigTypeGitee { client, err = GitHubAPI.NewEnterpriseClient("https://gitee.com/api/v5/", "https://gitee.com/api/v5/", oc) } else { client = GitHubAPI.NewClient(oc) @@ -99,7 +99,7 @@ func (oa *oauth2controller) callback(c *gin.Context) { return } var isAdmin bool - for _, admin := range strings.Split(dao.Conf.Oauth2.Admin, ",") { + for _, admin := range strings.Split(singleton.Conf.Oauth2.Admin, ",") { if admin != "" && gu.GetLogin() == admin { isAdmin = true break @@ -115,8 +115,8 @@ func (oa *oauth2controller) callback(c *gin.Context) { } user := model.NewUserFromGitHub(gu) user.IssueNewToken() - dao.DB.Save(&user) - c.SetCookie(dao.Conf.Site.CookieName, user.Token, 60*60*24, "", "", false, false) + singleton.DB.Save(&user) + c.SetCookie(singleton.Conf.Site.CookieName, user.Token, 60*60*24, "", "", false, false) c.Status(http.StatusOK) c.Writer.WriteString("") } diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index 9645944..66d7f5a 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -16,7 +16,7 @@ import ( "github.com/naiba/nezha/cmd/dashboard/controller" "github.com/naiba/nezha/cmd/dashboard/rpc" "github.com/naiba/nezha/model" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) func init() { @@ -26,62 +26,62 @@ func init() { } // 初始化 dao 包 - dao.Conf = &model.Config{} - dao.Cron = cron.New(cron.WithSeconds(), cron.WithLocation(shanghai)) - dao.Crons = make(map[uint64]*model.Cron) - dao.ServerList = make(map[uint64]*model.Server) - dao.SecretToID = make(map[string]uint64) + singleton.Conf = &model.Config{} + singleton.Cron = cron.New(cron.WithSeconds(), cron.WithLocation(shanghai)) + singleton.Crons = make(map[uint64]*model.Cron) + singleton.ServerList = make(map[uint64]*model.Server) + singleton.SecretToID = make(map[string]uint64) - err = dao.Conf.Read("data/config.yaml") + err = singleton.Conf.Read("data/config.yaml") if err != nil { panic(err) } - dao.DB, err = gorm.Open(sqlite.Open("data/sqlite.db"), &gorm.Config{ + singleton.DB, err = gorm.Open(sqlite.Open("data/sqlite.db"), &gorm.Config{ CreateBatchSize: 200, }) if err != nil { panic(err) } - if dao.Conf.Debug { - dao.DB = dao.DB.Debug() + if singleton.Conf.Debug { + singleton.DB = singleton.DB.Debug() } - if dao.Conf.GRPCPort == 0 { - dao.Conf.GRPCPort = 5555 + if singleton.Conf.GRPCPort == 0 { + singleton.Conf.GRPCPort = 5555 } - dao.Cache = cache.New(5*time.Minute, 10*time.Minute) + singleton.Cache = cache.New(5*time.Minute, 10*time.Minute) initSystem() } func initSystem() { - dao.DB.AutoMigrate(model.Server{}, model.User{}, + singleton.DB.AutoMigrate(model.Server{}, model.User{}, model.Notification{}, model.AlertRule{}, model.Monitor{}, model.MonitorHistory{}, model.Cron{}, model.Transfer{}) - dao.LoadNotifications() + singleton.LoadNotifications() loadServers() //加载服务器列表 loadCrons() //加载计划任务 // 清理 服务请求记录 和 流量记录 的旧数据 - _, err := dao.Cron.AddFunc("0 30 3 * * *", cleanMonitorHistory) + _, err := singleton.Cron.AddFunc("0 30 3 * * *", cleanMonitorHistory) if err != nil { panic(err) } // 流量记录打点 - _, err = dao.Cron.AddFunc("0 0 * * * *", recordTransferHourlyUsage) + _, err = singleton.Cron.AddFunc("0 0 * * * *", recordTransferHourlyUsage) if err != nil { panic(err) } } func recordTransferHourlyUsage() { - dao.ServerLock.Lock() - defer dao.ServerLock.Unlock() + singleton.ServerLock.Lock() + defer singleton.ServerLock.Unlock() now := time.Now() nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, time.Local) var txs []model.Transfer - for id, server := range dao.ServerList { + for id, server := range singleton.ServerList { tx := model.Transfer{ ServerID: id, In: server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn), @@ -98,19 +98,19 @@ func recordTransferHourlyUsage() { if len(txs) == 0 { return } - log.Println("NEZHA>> Cron 流量统计入库", len(txs), dao.DB.Create(txs).Error) + log.Println("NEZHA>> Cron 流量统计入库", len(txs), singleton.DB.Create(txs).Error) } func cleanMonitorHistory() { // 清理无效数据 - dao.DB.Unscoped().Delete(&model.MonitorHistory{}, "created_at < ? OR monitor_id NOT IN (SELECT `id` FROM monitors)", time.Now().AddDate(0, 0, -30)) - dao.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (SELECT `id` FROM servers)") + singleton.DB.Unscoped().Delete(&model.MonitorHistory{}, "created_at < ? OR monitor_id NOT IN (SELECT `id` FROM monitors)", time.Now().AddDate(0, 0, -30)) + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (SELECT `id` FROM servers)") // 计算可清理流量记录的时长 var allServerKeep time.Time specialServerKeep := make(map[uint64]time.Time) var specialServerIDs []uint64 var alerts []model.AlertRule - dao.DB.Find(&alerts) + singleton.DB.Find(&alerts) for i := 0; i < len(alerts); i++ { for j := 0; j < len(alerts[i].Rules); j++ { // 是不是流量记录规则 @@ -136,31 +136,31 @@ func cleanMonitorHistory() { } } for id, couldRemove := range specialServerKeep { - dao.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND created_at < ?", id, couldRemove) + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND created_at < ?", id, couldRemove) } if allServerKeep.IsZero() { - dao.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs) + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs) } else { - dao.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND created_at < ?", specialServerIDs, allServerKeep) + singleton.DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND created_at < ?", specialServerIDs, allServerKeep) } } func loadServers() { var servers []model.Server - dao.DB.Find(&servers) + singleton.DB.Find(&servers) for _, s := range servers { innerS := s innerS.Host = &model.Host{} innerS.State = &model.HostState{} - dao.ServerList[innerS.ID] = &innerS - dao.SecretToID[innerS.Secret] = innerS.ID + singleton.ServerList[innerS.ID] = &innerS + singleton.SecretToID[innerS.Secret] = innerS.ID } - dao.ReSortServer() + singleton.ReSortServer() } func loadCrons() { var crons []model.Cron - dao.DB.Find(&crons) + singleton.DB.Find(&crons) var err error errMsg := new(bytes.Buffer) for i := 0; i < len(crons); i++ { @@ -171,9 +171,9 @@ func loadCrons() { crIgnoreMap[cr.Servers[j]] = true } - cr.CronJobID, err = dao.Cron.AddFunc(cr.Scheduler, dao.CronTrigger(cr)) + cr.CronJobID, err = singleton.Cron.AddFunc(cr.Scheduler, singleton.CronTrigger(cr)) if err == nil { - dao.Crons[cr.ID] = &cr + singleton.Crons[cr.ID] = &cr } else { if errMsg.Len() == 0 { errMsg.WriteString("调度失败的计划任务:[") @@ -183,20 +183,20 @@ func loadCrons() { } if errMsg.Len() > 0 { msg := errMsg.String() - dao.SendNotification(msg[:len(msg)-1]+"] 这些任务将无法正常执行,请进入后点重新修改保存。", false) + singleton.SendNotification(msg[:len(msg)-1]+"] 这些任务将无法正常执行,请进入后点重新修改保存。", false) } - dao.Cron.Start() + singleton.Cron.Start() } func main() { cleanMonitorHistory() - go rpc.ServeRPC(dao.Conf.GRPCPort) + go rpc.ServeRPC(singleton.Conf.GRPCPort) serviceSentinelDispatchBus := make(chan model.Monitor) go rpc.DispatchTask(serviceSentinelDispatchBus) go rpc.DispatchKeepalive() - go dao.AlertSentinelStart() - dao.NewServiceSentinel(serviceSentinelDispatchBus) - srv := controller.ServeWeb(dao.Conf.HTTPPort) + go singleton.AlertSentinelStart() + singleton.NewServiceSentinel(serviceSentinelDispatchBus) + srv := controller.ServeWeb(singleton.Conf.HTTPPort) graceful.Graceful(func() error { return srv.ListenAndServe() }, func(c context.Context) error { diff --git a/cmd/dashboard/rpc/rpc.go b/cmd/dashboard/rpc/rpc.go index 03dfaab..2820c95 100644 --- a/cmd/dashboard/rpc/rpc.go +++ b/cmd/dashboard/rpc/rpc.go @@ -8,8 +8,8 @@ import ( "github.com/naiba/nezha/model" pb "github.com/naiba/nezha/proto" - "github.com/naiba/nezha/service/dao" rpcService "github.com/naiba/nezha/service/rpc" + "github.com/naiba/nezha/service/singleton" ) func ServeRPC(port uint) { @@ -29,45 +29,45 @@ func DispatchTask(serviceSentinelDispatchBus <-chan model.Monitor) { for task := range serviceSentinelDispatchBus { round := 0 endIndex := workedServerIndex - dao.SortedServerLock.RLock() + singleton.SortedServerLock.RLock() // 如果已经轮了一整圈又轮到自己,没有合适机器去请求,跳出循环 for round < 1 || workedServerIndex < endIndex { // 如果到了圈尾,再回到圈头,圈数加一,游标重置 - if workedServerIndex >= len(dao.SortedServerList) { + if workedServerIndex >= len(singleton.SortedServerList) { workedServerIndex = 0 round++ continue } // 如果服务器不在线,跳过这个服务器 - if dao.SortedServerList[workedServerIndex].TaskStream == nil { + if singleton.SortedServerList[workedServerIndex].TaskStream == nil { workedServerIndex++ continue } // 如果此任务不可使用此服务器请求,跳过这个服务器(有些 IPv6 only 开了 NAT64 的机器请求 IPv4 总会出问题) - if (task.Cover == model.MonitorCoverAll && task.SkipServers[dao.SortedServerList[workedServerIndex].ID]) || - (task.Cover == model.MonitorCoverIgnoreAll && !task.SkipServers[dao.SortedServerList[workedServerIndex].ID]) { + if (task.Cover == model.MonitorCoverAll && task.SkipServers[singleton.SortedServerList[workedServerIndex].ID]) || + (task.Cover == model.MonitorCoverIgnoreAll && !task.SkipServers[singleton.SortedServerList[workedServerIndex].ID]) { workedServerIndex++ continue } // 找到合适机器执行任务,跳出循环 - dao.SortedServerList[workedServerIndex].TaskStream.Send(task.PB()) + singleton.SortedServerList[workedServerIndex].TaskStream.Send(task.PB()) workedServerIndex++ break } - dao.SortedServerLock.RUnlock() + singleton.SortedServerLock.RUnlock() } } func DispatchKeepalive() { - dao.Cron.AddFunc("@every 60s", func() { - dao.SortedServerLock.RLock() - defer dao.SortedServerLock.RUnlock() - for i := 0; i < len(dao.SortedServerList); i++ { - if dao.SortedServerList[i] == nil || dao.SortedServerList[i].TaskStream == nil { + singleton.Cron.AddFunc("@every 60s", func() { + singleton.SortedServerLock.RLock() + defer singleton.SortedServerLock.RUnlock() + for i := 0; i < len(singleton.SortedServerList); i++ { + if singleton.SortedServerList[i] == nil || singleton.SortedServerList[i].TaskStream == nil { continue } - dao.SortedServerList[i].TaskStream.Send(&pb.Task{Type: model.TaskTypeKeepalive}) + singleton.SortedServerList[i].TaskStream.Send(&pb.Task{Type: model.TaskTypeKeepalive}) } }) } diff --git a/go.mod b/go.mod index 1091f4c..20b2847 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( code.cloudfoundry.org/bytefmt v0.0.0-20211005130812-5bb3c17173e5 - github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4 // indirect + github.com/Erope/goss v0.0.0-20211230093305-df3c03fd1ed4 github.com/artdarek/go-unzip v1.0.0 github.com/blang/semver v3.5.1+incompatible github.com/creack/pty v1.1.17 @@ -25,7 +25,6 @@ require ( github.com/ory/graceful v0.1.1 github.com/p14yground/go-github-selfupdate v0.0.0-20210520015421-eddf14461293 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil/v3 v3.21.10 github.com/spf13/pflag v1.0.5 diff --git a/pkg/mygin/auth.go b/pkg/mygin/auth.go index 8233a7f..38123f8 100644 --- a/pkg/mygin/auth.go +++ b/pkg/mygin/auth.go @@ -8,7 +8,7 @@ import ( "github.com/gin-gonic/gin" "github.com/naiba/nezha/model" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type AuthorizeOption struct { @@ -38,11 +38,11 @@ func Authorize(opt AuthorizeOption) func(*gin.Context) { var isLogin bool // 用户鉴权 - token, _ := c.Cookie(dao.Conf.Site.CookieName) + token, _ := c.Cookie(singleton.Conf.Site.CookieName) token = strings.TrimSpace(token) if token != "" { var u model.User - if err := dao.DB.Where("token = ?", token).First(&u).Error; err == nil { + if err := singleton.DB.Where("token = ?", token).First(&u).Error; err == nil { isLogin = u.TokenExpired.After(time.Now()) } if isLogin { diff --git a/pkg/mygin/mygin.go b/pkg/mygin/mygin.go index 9199063..80c53a5 100644 --- a/pkg/mygin/mygin.go +++ b/pkg/mygin/mygin.go @@ -7,7 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/naiba/nezha/model" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) var adminPage = map[string]bool{ @@ -20,15 +20,15 @@ var adminPage = map[string]bool{ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H { data["MatchedPath"] = c.MustGet("MatchedPath") - data["Version"] = dao.Version - data["Conf"] = dao.Conf + data["Version"] = singleton.Version + data["Conf"] = singleton.Conf // 是否是管理页面 data["IsAdminPage"] = adminPage[data["MatchedPath"].(string)] // 站点标题 if t, has := data["Title"]; !has { - data["Title"] = dao.Conf.Site.Brand + data["Title"] = singleton.Conf.Site.Brand } else { - data["Title"] = fmt.Sprintf("%s - %s", t, dao.Conf.Site.Brand) + data["Title"] = fmt.Sprintf("%s - %s", t, singleton.Conf.Site.Brand) } u, ok := c.Get(model.CtxKeyAuthorizedUser) if ok { diff --git a/service/rpc/auth.go b/service/rpc/auth.go index 155ce3f..88d9017 100644 --- a/service/rpc/auth.go +++ b/service/rpc/auth.go @@ -3,10 +3,11 @@ package rpc import ( "context" - "github.com/naiba/nezha/service/dao" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + + "github.com/naiba/nezha/service/singleton" ) type AuthHandler struct { @@ -32,13 +33,13 @@ func (a *AuthHandler) Check(ctx context.Context) (uint64, error) { clientSecret = value[0] } - dao.ServerLock.RLock() - defer dao.ServerLock.RUnlock() - clientID, hasID := dao.SecretToID[clientSecret] + singleton.ServerLock.RLock() + defer singleton.ServerLock.RUnlock() + clientID, hasID := singleton.SecretToID[clientSecret] if !hasID { return 0, status.Errorf(codes.Unauthenticated, "客户端认证失败") } - _, hasServer := dao.ServerList[clientID] + _, hasServer := singleton.ServerList[clientID] if !hasServer { return 0, status.Errorf(codes.Unauthenticated, "客户端认证失败") } diff --git a/service/rpc/nezha.go b/service/rpc/nezha.go index f8b6811..6a4930f 100644 --- a/service/rpc/nezha.go +++ b/service/rpc/nezha.go @@ -8,7 +8,7 @@ import ( "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/utils" pb "github.com/naiba/nezha/proto" - "github.com/naiba/nezha/service/dao" + "github.com/naiba/nezha/service/singleton" ) type NezhaHandler struct { @@ -23,25 +23,25 @@ func (s *NezhaHandler) ReportTask(c context.Context, r *pb.TaskResult) (*pb.Rece } if r.GetType() == model.TaskTypeCommand { // 处理上报的计划任务 - dao.CronLock.RLock() - defer dao.CronLock.RUnlock() - cr := dao.Crons[r.GetId()] + singleton.CronLock.RLock() + defer singleton.CronLock.RUnlock() + cr := singleton.Crons[r.GetId()] if cr != nil { - dao.ServerLock.RLock() - defer dao.ServerLock.RUnlock() + singleton.ServerLock.RLock() + defer singleton.ServerLock.RUnlock() if cr.PushSuccessful && r.GetSuccessful() { - dao.SendNotification(fmt.Sprintf("[任务成功] %s ,服务器:%s,日志:\n%s", cr.Name, dao.ServerList[clientID].Name, r.GetData()), false) + singleton.SendNotification(fmt.Sprintf("[任务成功] %s ,服务器:%s,日志:\n%s", cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false) } if !r.GetSuccessful() { - dao.SendNotification(fmt.Sprintf("[任务失败] %s ,服务器:%s,日志:\n%s", cr.Name, dao.ServerList[clientID].Name, r.GetData()), false) + singleton.SendNotification(fmt.Sprintf("[任务失败] %s ,服务器:%s,日志:\n%s", cr.Name, singleton.ServerList[clientID].Name, r.GetData()), false) } - dao.DB.Model(cr).Updates(model.Cron{ + singleton.DB.Model(cr).Updates(model.Cron{ LastExecutedAt: time.Now().Add(time.Second * -1 * time.Duration(r.GetDelay())), LastResult: r.GetSuccessful(), }) } } else if model.IsServiceSentinelNeeded(r.GetType()) { - dao.ServiceSentinelShared.Dispatch(dao.ReportData{ + singleton.ServiceSentinelShared.Dispatch(singleton.ReportData{ Data: r, Reporter: clientID, }) @@ -56,14 +56,14 @@ func (s *NezhaHandler) RequestTask(h *pb.Host, stream pb.NezhaService_RequestTas return err } closeCh := make(chan error) - dao.ServerLock.RLock() + singleton.ServerLock.RLock() // 修复不断的请求 task 但是没有 return 导致内存泄漏 - if dao.ServerList[clientID].TaskClose != nil { - close(dao.ServerList[clientID].TaskClose) + if singleton.ServerList[clientID].TaskClose != nil { + close(singleton.ServerList[clientID].TaskClose) } - dao.ServerList[clientID].TaskStream = stream - dao.ServerList[clientID].TaskClose = closeCh - dao.ServerLock.RUnlock() + singleton.ServerList[clientID].TaskStream = stream + singleton.ServerList[clientID].TaskClose = closeCh + singleton.ServerLock.RUnlock() return <-closeCh } @@ -74,15 +74,15 @@ func (s *NezhaHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.Re return nil, err } state := model.PB2State(r) - dao.ServerLock.RLock() - defer dao.ServerLock.RUnlock() - dao.ServerList[clientID].LastActive = time.Now() - dao.ServerList[clientID].State = &state + singleton.ServerLock.RLock() + defer singleton.ServerLock.RUnlock() + singleton.ServerList[clientID].LastActive = time.Now() + singleton.ServerList[clientID].State = &state // 如果从未记录过,先打点,等到小时时间点时入库 - if dao.ServerList[clientID].PrevHourlyTransferIn == 0 || dao.ServerList[clientID].PrevHourlyTransferOut == 0 { - dao.ServerList[clientID].PrevHourlyTransferIn = int64(state.NetInTransfer) - dao.ServerList[clientID].PrevHourlyTransferOut = int64(state.NetOutTransfer) + if singleton.ServerList[clientID].PrevHourlyTransferIn == 0 || singleton.ServerList[clientID].PrevHourlyTransferOut == 0 { + singleton.ServerList[clientID].PrevHourlyTransferIn = int64(state.NetInTransfer) + singleton.ServerList[clientID].PrevHourlyTransferOut = int64(state.NetOutTransfer) } return &pb.Receipt{Proced: true}, nil @@ -95,26 +95,26 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece return nil, err } host := model.PB2Host(r) - dao.ServerLock.RLock() - defer dao.ServerLock.RUnlock() - if dao.Conf.EnableIPChangeNotification && - ((dao.Conf.Cover == model.ConfigCoverAll && !dao.Conf.IgnoredIPNotificationServerIDs[clientID]) || - (dao.Conf.Cover == model.ConfigCoverIgnoreAll && dao.Conf.IgnoredIPNotificationServerIDs[clientID])) && - dao.ServerList[clientID].Host != nil && - dao.ServerList[clientID].Host.IP != "" && + singleton.ServerLock.RLock() + defer singleton.ServerLock.RUnlock() + if singleton.Conf.EnableIPChangeNotification && + ((singleton.Conf.Cover == model.ConfigCoverAll && !singleton.Conf.IgnoredIPNotificationServerIDs[clientID]) || + (singleton.Conf.Cover == model.ConfigCoverIgnoreAll && singleton.Conf.IgnoredIPNotificationServerIDs[clientID])) && + singleton.ServerList[clientID].Host != nil && + singleton.ServerList[clientID].Host.IP != "" && host.IP != "" && - dao.ServerList[clientID].Host.IP != host.IP { - dao.SendNotification(fmt.Sprintf( + singleton.ServerList[clientID].Host.IP != host.IP { + singleton.SendNotification(fmt.Sprintf( "[IP变更] %s ,旧IP:%s,新IP:%s。", - dao.ServerList[clientID].Name, utils.IPDesensitize(dao.ServerList[clientID].Host.IP), utils.IPDesensitize(host.IP)), true) + singleton.ServerList[clientID].Name, utils.IPDesensitize(singleton.ServerList[clientID].Host.IP), utils.IPDesensitize(host.IP)), true) } // 判断是否是机器重启,如果是机器重启要录入最后记录的流量里面 - if dao.ServerList[clientID].Host.BootTime < host.BootTime { - dao.ServerList[clientID].PrevHourlyTransferIn = dao.ServerList[clientID].PrevHourlyTransferIn - int64(dao.ServerList[clientID].State.NetInTransfer) - dao.ServerList[clientID].PrevHourlyTransferOut = dao.ServerList[clientID].PrevHourlyTransferOut - int64(dao.ServerList[clientID].State.NetOutTransfer) + if singleton.ServerList[clientID].Host.BootTime < host.BootTime { + singleton.ServerList[clientID].PrevHourlyTransferIn = singleton.ServerList[clientID].PrevHourlyTransferIn - int64(singleton.ServerList[clientID].State.NetInTransfer) + singleton.ServerList[clientID].PrevHourlyTransferOut = singleton.ServerList[clientID].PrevHourlyTransferOut - int64(singleton.ServerList[clientID].State.NetOutTransfer) } - dao.ServerList[clientID].Host = &host + singleton.ServerList[clientID].Host = &host return &pb.Receipt{Proced: true}, nil } diff --git a/service/dao/alertsentinel.go b/service/singleton/alertsentinel.go similarity index 99% rename from service/dao/alertsentinel.go rename to service/singleton/alertsentinel.go index 17760a0..326180f 100644 --- a/service/dao/alertsentinel.go +++ b/service/singleton/alertsentinel.go @@ -1,4 +1,4 @@ -package dao +package singleton import ( "fmt" diff --git a/service/dao/notification.go b/service/singleton/notification.go similarity index 99% rename from service/dao/notification.go rename to service/singleton/notification.go index b5736e5..d9f9d08 100644 --- a/service/dao/notification.go +++ b/service/singleton/notification.go @@ -1,4 +1,4 @@ -package dao +package singleton import ( "crypto/md5" // #nosec diff --git a/service/dao/servicesentinel.go b/service/singleton/servicesentinel.go similarity index 99% rename from service/dao/servicesentinel.go rename to service/singleton/servicesentinel.go index b9cced5..f3465a0 100644 --- a/service/dao/servicesentinel.go +++ b/service/singleton/servicesentinel.go @@ -1,4 +1,4 @@ -package dao +package singleton import ( "fmt" diff --git a/service/dao/dao.go b/service/singleton/singleton.go similarity index 95% rename from service/dao/dao.go rename to service/singleton/singleton.go index e049f35..15627b1 100644 --- a/service/dao/dao.go +++ b/service/singleton/singleton.go @@ -1,4 +1,4 @@ -package dao +package singleton import ( "fmt" @@ -13,7 +13,7 @@ import ( pb "github.com/naiba/nezha/proto" ) -var Version = "v0.12.3" // !!记得修改 README 中的 badge 版本!! +var Version = "v0.12.6" // !!记得修改 README 中的 badge 版本!! var ( Conf *model.Config