nezha/cmd/dashboard/controller/common_page.go
2021-07-16 11:14:07 +08:00

142 lines
3.3 KiB
Go

package controller
import (
"errors"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"golang.org/x/crypto/bcrypt"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/service/dao"
)
type commonPage struct {
r *gin.Engine
}
func (cp *commonPage) serve() {
cr := cp.r.Group("")
cr.Use(mygin.Authorize(mygin.AuthorizeOption{}))
cr.POST("/view-password", cp.issueViewPassword)
cr.Use(cp.checkViewPassword) // 前端查看密码鉴权
cr.GET("/", cp.home)
cr.GET("/service", cp.service)
cr.GET("/ws", cp.ws)
}
type viewPasswordForm struct {
Password string
}
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 {
err = errors.New("查看密码错误")
}
if err == nil {
hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
}
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Title: "出现错误",
Msg: fmt.Sprintf("请求错误:%s", err),
}, true)
c.Abort()
return
}
c.SetCookie(dao.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 == "" {
c.Next()
return
}
if _, authorized := c.Get(model.CtxKeyAuthorizedUser); authorized {
c.Next()
return
}
// 验证查看密码
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{
"Title": "验证查看密码",
"CustomCode": dao.Conf.Site.CustomCode,
}))
c.Abort()
return
}
c.Next()
}
func (p *commonPage) service(c *gin.Context) {
msm := dao.ServiceSentinelShared.LoadStats()
c.HTML(http.StatusOK, "theme-"+dao.Conf.Site.Theme+"/service", mygin.CommonEnvironment(c, gin.H{
"Title": "服务状态",
"Services": msm,
"CustomCode": dao.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,
}))
}
var upgrader = websocket.Upgrader{}
type Data struct {
Now int64 `json:"now,omitempty"`
Servers []*model.Server `json:"servers,omitempty"`
}
func (cp *commonPage) ws(c *gin.Context) {
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: "网络错误",
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
}, true)
return
}
defer conn.Close()
count := 0
for {
dao.SortedServerLock.RLock()
err = conn.WriteJSON(Data{
Now: time.Now().Unix() * 1000,
Servers: dao.SortedServerList,
})
dao.SortedServerLock.RUnlock()
if err != nil {
break
}
count += 1
if count%4 == 0 {
err = conn.WriteMessage(websocket.PingMessage, []byte{})
if err != nil {
break
}
}
time.Sleep(time.Second * 2)
}
}