mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 20:58:14 -05:00
remove old sources
This commit is contained in:
parent
d7012e36bf
commit
40c811c143
@ -1,257 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/hashicorp/go-uuid"
|
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
|
||||||
"github.com/naiba/nezha/pkg/utils"
|
|
||||||
"github.com/naiba/nezha/pkg/websocketx"
|
|
||||||
"github.com/naiba/nezha/proto"
|
|
||||||
"github.com/naiba/nezha/service/rpc"
|
|
||||||
"github.com/naiba/nezha/service/singleton"
|
|
||||||
)
|
|
||||||
|
|
||||||
type commonPage struct {
|
|
||||||
r *gin.Engine
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *commonPage) serve() {
|
|
||||||
cr := cp.r.Group("")
|
|
||||||
// TODO: 界面直接跳转使用该接口
|
|
||||||
cr.GET("/network/:id", cp.network)
|
|
||||||
cr.GET("/network", cp.network)
|
|
||||||
cr.GET("/file", cp.createFM)
|
|
||||||
cr.GET("/file/:id", cp.fm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *commonPage) network(c *gin.Context) {
|
|
||||||
var (
|
|
||||||
monitorHistory *model.ServiceHistory
|
|
||||||
servers []model.Server
|
|
||||||
serverIdsWithMonitor []uint64
|
|
||||||
monitorInfos = []byte("{}")
|
|
||||||
id uint64
|
|
||||||
)
|
|
||||||
if len(singleton.SortedServerList) > 0 {
|
|
||||||
id = singleton.SortedServerList[0].ID
|
|
||||||
}
|
|
||||||
if err := singleton.DB.Model(&model.ServiceHistory{}).Select("monitor_id, server_id").
|
|
||||||
Where("monitor_id != 0 and server_id != 0").Limit(1).First(&monitorHistory).Error; err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "请求参数有误:" + "server monitor history not found",
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
if monitorHistory == nil || monitorHistory.ServerID == 0 {
|
|
||||||
if len(singleton.SortedServerList) > 0 {
|
|
||||||
id = singleton.SortedServerList[0].ID
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
id = monitorHistory.ServerID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
idStr := c.Param("id")
|
|
||||||
if idStr != "" {
|
|
||||||
var err error
|
|
||||||
id, err = strconv.ParseUint(idStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "请求参数有误:" + err.Error(),
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, ok := singleton.ServerList[id]
|
|
||||||
if !ok {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "请求参数有误:" + "server id not found",
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, isMember := c.Get(model.CtxKeyAuthorizedUser)
|
|
||||||
var isViewPasswordVerfied bool
|
|
||||||
|
|
||||||
if err := singleton.DB.Model(&model.ServiceHistory{}).
|
|
||||||
Select("distinct(server_id)").
|
|
||||||
Where("server_id != 0").
|
|
||||||
Find(&serverIdsWithMonitor).
|
|
||||||
Error; err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "请求参数有误:" + "no server with monitor histories",
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if isMember || isViewPasswordVerfied {
|
|
||||||
for _, server := range singleton.SortedServerList {
|
|
||||||
for _, id := range serverIdsWithMonitor {
|
|
||||||
if server.ID == id {
|
|
||||||
servers = append(servers, *server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, server := range singleton.SortedServerListForGuest {
|
|
||||||
for _, id := range serverIdsWithMonitor {
|
|
||||||
if server.ID == id {
|
|
||||||
servers = append(servers, *server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
serversBytes, _ := utils.Json.Marshal(model.StreamServerData{
|
|
||||||
Now: time.Now().Unix() * 1000,
|
|
||||||
// Servers: servers,
|
|
||||||
})
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "", gin.H{
|
|
||||||
"Servers": string(serversBytes),
|
|
||||||
"MonitorInfos": string(monitorInfos),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *commonPage) fm(c *gin.Context) {
|
|
||||||
streamId := c.Param("id")
|
|
||||||
if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "无权访问",
|
|
||||||
// Msg: "FM会话不存在",
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回首页",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
|
|
||||||
|
|
||||||
wsConn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
|
||||||
if err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusInternalServerError,
|
|
||||||
// // Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
|
|
||||||
// // MessageID: "NetworkError",
|
|
||||||
// // }),
|
|
||||||
// Msg: "Websocket协议切换失败",
|
|
||||||
// Link: "/",
|
|
||||||
// Btn: "返回首页",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer wsConn.Close()
|
|
||||||
conn := websocketx.NewConn(wsConn)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
// PING 保活
|
|
||||||
for {
|
|
||||||
if err = conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second * 10)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = rpc.NezhaHandlerSingleton.UserConnected(streamId, conn); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.NezhaHandlerSingleton.StartStream(streamId, time.Second*10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *commonPage) createFM(c *gin.Context) {
|
|
||||||
IdString := c.Query("id")
|
|
||||||
if _, authorized := c.Get(model.CtxKeyAuthorizedUser); !authorized {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "无权访问",
|
|
||||||
// Msg: "用户未登录",
|
|
||||||
// Link: "/login",
|
|
||||||
// Btn: "去登录",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
streamId, err := uuid.GenerateUUID()
|
|
||||||
if err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusInternalServerError,
|
|
||||||
// // Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
|
|
||||||
// // MessageID: "SystemError",
|
|
||||||
// // }),
|
|
||||||
// Msg: "生成会话ID失败",
|
|
||||||
// Link: "/server",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.NezhaHandlerSingleton.CreateStream(streamId)
|
|
||||||
|
|
||||||
serverId, err := strconv.Atoi(IdString)
|
|
||||||
if err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "请求参数有误:" + err.Error(),
|
|
||||||
// Link: "/server",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
singleton.ServerLock.RLock()
|
|
||||||
server := singleton.ServerList[uint64(serverId)]
|
|
||||||
singleton.ServerLock.RUnlock()
|
|
||||||
if server == nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "服务器不存在或处于离线状态",
|
|
||||||
// Link: "/server",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmData, _ := utils.Json.Marshal(&model.TaskFM{
|
|
||||||
StreamID: streamId,
|
|
||||||
})
|
|
||||||
if err := server.TaskStream.Send(&proto.Task{
|
|
||||||
Type: model.TaskTypeFM,
|
|
||||||
Data: string(fmData),
|
|
||||||
}); err != nil {
|
|
||||||
// mygin.ShowErrorPage(c, mygin.ErrInfo{
|
|
||||||
// Code: http.StatusForbidden,
|
|
||||||
// Title: "请求失败",
|
|
||||||
// Msg: "Agent信令下发失败",
|
|
||||||
// Link: "/server",
|
|
||||||
// Btn: "返回重试",
|
|
||||||
// }, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
"SessionID": streamId,
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,636 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/jinzhu/copier"
|
|
||||||
"golang.org/x/net/idna"
|
|
||||||
|
|
||||||
"github.com/naiba/nezha/model"
|
|
||||||
"github.com/naiba/nezha/pkg/utils"
|
|
||||||
"github.com/naiba/nezha/proto"
|
|
||||||
"github.com/naiba/nezha/service/singleton"
|
|
||||||
)
|
|
||||||
|
|
||||||
type memberAPI struct {
|
|
||||||
r gin.IRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) serve() {
|
|
||||||
mr := ma.r.Group("")
|
|
||||||
// mr.Use(mygin.Authorize(mygin.AuthorizeOption{
|
|
||||||
// MemberOnly: true,
|
|
||||||
// IsPage: false,
|
|
||||||
// Msg: "访问此接口需要登录",
|
|
||||||
// Btn: "点此登录",
|
|
||||||
// Redirect: "/login",
|
|
||||||
// }))
|
|
||||||
mr.POST("/cron", ma.addOrEditCron)
|
|
||||||
mr.GET("/cron/:id/manual", ma.manualTrigger)
|
|
||||||
mr.POST("/force-update", ma.forceUpdate)
|
|
||||||
mr.POST("/batch-update-server-group", ma.batchUpdateServerGroup)
|
|
||||||
mr.POST("/notification", ma.addOrEditNotification)
|
|
||||||
mr.POST("/ddns", ma.addOrEditDDNS)
|
|
||||||
mr.POST("/nat", ma.addOrEditNAT)
|
|
||||||
mr.POST("/alert-rule", ma.addOrEditAlertRule)
|
|
||||||
mr.POST("/setting", ma.updateSetting)
|
|
||||||
mr.DELETE("/:model/:id", ma.delete)
|
|
||||||
mr.POST("/logout", ma.logout)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) delete(c *gin.Context) {
|
|
||||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
||||||
if id < 1 {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: "错误的 Server ID",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
switch c.Param("model") {
|
|
||||||
|
|
||||||
case "cron":
|
|
||||||
err = singleton.DB.Unscoped().Delete(&model.Cron{}, "id = ?", id).Error
|
|
||||||
if err == nil {
|
|
||||||
singleton.CronLock.RLock()
|
|
||||||
defer singleton.CronLock.RUnlock()
|
|
||||||
cr := singleton.Crons[id]
|
|
||||||
if cr != nil && cr.CronJobID != 0 {
|
|
||||||
singleton.Cron.Remove(cr.CronJobID)
|
|
||||||
}
|
|
||||||
delete(singleton.Crons, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("数据库错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type cronForm struct {
|
|
||||||
ID uint64
|
|
||||||
TaskType uint8 // 0:计划任务 1:触发任务
|
|
||||||
Name string
|
|
||||||
Scheduler string
|
|
||||||
Command string
|
|
||||||
ServersRaw string
|
|
||||||
Cover uint8
|
|
||||||
PushSuccessful string
|
|
||||||
NotificationTag string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) addOrEditCron(c *gin.Context) {
|
|
||||||
var cf cronForm
|
|
||||||
var cr model.Cron
|
|
||||||
err := c.ShouldBindJSON(&cf)
|
|
||||||
if err == nil {
|
|
||||||
cr.TaskType = cf.TaskType
|
|
||||||
cr.Name = cf.Name
|
|
||||||
cr.Scheduler = cf.Scheduler
|
|
||||||
cr.Command = cf.Command
|
|
||||||
cr.ServersRaw = cf.ServersRaw
|
|
||||||
cr.PushSuccessful = cf.PushSuccessful == "on"
|
|
||||||
//cr.NotificationTag = cf.NotificationTag
|
|
||||||
cr.ID = cf.ID
|
|
||||||
cr.Cover = cf.Cover
|
|
||||||
err = utils.Json.Unmarshal([]byte(cf.ServersRaw), &cr.Servers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计划任务类型不得使用触发服务器执行方式
|
|
||||||
if cr.TaskType == model.CronTypeCronTask && cr.Cover == model.CronCoverAlertTrigger {
|
|
||||||
err = errors.New("计划任务类型不得使用触发服务器执行方式")
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tx := singleton.DB.Begin()
|
|
||||||
if err == nil {
|
|
||||||
// 保证NotificationTag不为空
|
|
||||||
//if cr.NotificationTag == "" {
|
|
||||||
// cr.NotificationTag = "default"
|
|
||||||
//}
|
|
||||||
if cf.ID == 0 {
|
|
||||||
err = tx.Create(&cr).Error
|
|
||||||
} else {
|
|
||||||
err = tx.Save(&cr).Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = tx.Commit().Error
|
|
||||||
} else {
|
|
||||||
tx.Rollback()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
singleton.CronLock.Lock()
|
|
||||||
defer singleton.CronLock.Unlock()
|
|
||||||
crOld := singleton.Crons[cr.ID]
|
|
||||||
if crOld != nil && crOld.CronJobID != 0 {
|
|
||||||
singleton.Cron.Remove(crOld.CronJobID)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(singleton.Crons, cr.ID)
|
|
||||||
singleton.Crons[cr.ID] = &cr
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) manualTrigger(c *gin.Context) {
|
|
||||||
var cr model.Cron
|
|
||||||
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(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//singleton.ManualTrigger(cr)
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type BatchUpdateServerGroupRequest struct {
|
|
||||||
Servers []uint64
|
|
||||||
Group string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) batchUpdateServerGroup(c *gin.Context) {
|
|
||||||
var req BatchUpdateServerGroupRequest
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: err.Error(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := singleton.DB.Model(&model.Server{}).Where("id in (?)", req.Servers).Update("tag", req.Group).Error; err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: err.Error(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
singleton.ServerLock.Lock()
|
|
||||||
|
|
||||||
for i := 0; i < len(req.Servers); i++ {
|
|
||||||
serverId := req.Servers[i]
|
|
||||||
var s model.Server
|
|
||||||
copier.Copy(&s, singleton.ServerList[serverId])
|
|
||||||
// s.Tag = req.Group
|
|
||||||
// // 如果修改了Ta
|
|
||||||
// oldTag := singleton.ServerList[serverId].Tag
|
|
||||||
// newTag := s.Tag
|
|
||||||
// if newTag != oldTag {
|
|
||||||
// index := -1
|
|
||||||
// for i := 0; i < len(singleton.ServerTagToIDList[oldTag]); i++ {
|
|
||||||
// if singleton.ServerTagToIDList[oldTag][i] == s.ID {
|
|
||||||
// index = i
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if index > -1 {
|
|
||||||
// // 删除旧 Tag-ID 绑定关系
|
|
||||||
// singleton.ServerTagToIDList[oldTag] = append(singleton.ServerTagToIDList[oldTag][:index], singleton.ServerTagToIDList[oldTag][index+1:]...)
|
|
||||||
// if len(singleton.ServerTagToIDList[oldTag]) == 0 {
|
|
||||||
// delete(singleton.ServerTagToIDList, oldTag)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 设置新的 Tag-ID 绑定关系
|
|
||||||
// singleton.ServerTagToIDList[newTag] = append(singleton.ServerTagToIDList[newTag], s.ID)
|
|
||||||
// }
|
|
||||||
singleton.ServerList[s.ID] = &s
|
|
||||||
}
|
|
||||||
|
|
||||||
singleton.ServerLock.Unlock()
|
|
||||||
|
|
||||||
singleton.ReSortServer()
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) forceUpdate(c *gin.Context) {
|
|
||||||
var forceUpdateServers []uint64
|
|
||||||
if err := c.ShouldBindJSON(&forceUpdateServers); err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: err.Error(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var executeResult bytes.Buffer
|
|
||||||
|
|
||||||
for i := 0; i < len(forceUpdateServers); i++ {
|
|
||||||
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,
|
|
||||||
}); err != nil {
|
|
||||||
executeResult.WriteString(fmt.Sprintf("%d 下发指令失败 %+v<br/>", forceUpdateServers[i], err))
|
|
||||||
} else {
|
|
||||||
executeResult.WriteString(fmt.Sprintf("%d 下发指令成功<br/>", forceUpdateServers[i]))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
executeResult.WriteString(fmt.Sprintf("%d 离线<br/>", forceUpdateServers[i]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
Message: executeResult.String(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type notificationForm struct {
|
|
||||||
ID uint64
|
|
||||||
Name string
|
|
||||||
URL string
|
|
||||||
RequestMethod int
|
|
||||||
RequestType int
|
|
||||||
RequestHeader string
|
|
||||||
RequestBody string
|
|
||||||
VerifySSL string
|
|
||||||
SkipCheck string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) addOrEditNotification(c *gin.Context) {
|
|
||||||
var nf notificationForm
|
|
||||||
var n model.Notification
|
|
||||||
err := c.ShouldBindJSON(&nf)
|
|
||||||
if err == nil {
|
|
||||||
n.Name = nf.Name
|
|
||||||
n.RequestMethod = nf.RequestMethod
|
|
||||||
n.RequestType = nf.RequestType
|
|
||||||
n.RequestHeader = nf.RequestHeader
|
|
||||||
n.RequestBody = nf.RequestBody
|
|
||||||
n.URL = nf.URL
|
|
||||||
//verifySSL := nf.VerifySSL == "on"
|
|
||||||
//n.VerifySSL = &verifySSL
|
|
||||||
n.ID = nf.ID
|
|
||||||
ns := model.NotificationServerBundle{
|
|
||||||
Notification: &n,
|
|
||||||
Server: nil,
|
|
||||||
Loc: singleton.Loc,
|
|
||||||
}
|
|
||||||
// 勾选了跳过检查
|
|
||||||
if nf.SkipCheck != "on" {
|
|
||||||
err = ns.Send("这是测试消息")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
if n.ID == 0 {
|
|
||||||
err = singleton.DB.Create(&n).Error
|
|
||||||
} else {
|
|
||||||
err = singleton.DB.Save(&n).Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
singleton.OnRefreshOrAddNotification(&n)
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type ddnsForm struct {
|
|
||||||
ID uint64
|
|
||||||
MaxRetries uint64
|
|
||||||
EnableIPv4 string
|
|
||||||
EnableIPv6 string
|
|
||||||
Name string
|
|
||||||
Provider string
|
|
||||||
DomainsRaw string
|
|
||||||
AccessID string
|
|
||||||
AccessSecret string
|
|
||||||
WebhookURL string
|
|
||||||
WebhookMethod uint8
|
|
||||||
WebhookRequestType uint8
|
|
||||||
WebhookRequestBody string
|
|
||||||
WebhookHeaders string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) addOrEditDDNS(c *gin.Context) {
|
|
||||||
var df ddnsForm
|
|
||||||
var p model.DDNSProfile
|
|
||||||
err := c.ShouldBindJSON(&df)
|
|
||||||
if err == nil {
|
|
||||||
if df.MaxRetries < 1 || df.MaxRetries > 10 {
|
|
||||||
err = errors.New("重试次数必须为大于 1 且不超过 10 的整数")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
p.Name = df.Name
|
|
||||||
p.ID = df.ID
|
|
||||||
enableIPv4 := df.EnableIPv4 == "on"
|
|
||||||
enableIPv6 := df.EnableIPv6 == "on"
|
|
||||||
p.EnableIPv4 = &enableIPv4
|
|
||||||
p.EnableIPv6 = &enableIPv6
|
|
||||||
p.MaxRetries = df.MaxRetries
|
|
||||||
p.Provider = df.Provider
|
|
||||||
p.DomainsRaw = df.DomainsRaw
|
|
||||||
p.Domains = strings.Split(p.DomainsRaw, ",")
|
|
||||||
p.AccessID = df.AccessID
|
|
||||||
p.AccessSecret = df.AccessSecret
|
|
||||||
p.WebhookURL = df.WebhookURL
|
|
||||||
p.WebhookMethod = df.WebhookMethod
|
|
||||||
p.WebhookRequestType = df.WebhookRequestType
|
|
||||||
p.WebhookRequestBody = df.WebhookRequestBody
|
|
||||||
p.WebhookHeaders = df.WebhookHeaders
|
|
||||||
|
|
||||||
for n, domain := range p.Domains {
|
|
||||||
// IDN to ASCII
|
|
||||||
domainValid, domainErr := idna.Lookup.ToASCII(domain)
|
|
||||||
if domainErr != nil {
|
|
||||||
err = fmt.Errorf("域名 %s 解析错误: %v", domain, domainErr)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p.Domains[n] = domainValid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
if p.ID == 0 {
|
|
||||||
err = singleton.DB.Create(&p).Error
|
|
||||||
} else {
|
|
||||||
err = singleton.DB.Save(&p).Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//singleton.OnDDNSUpdate()
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type natForm struct {
|
|
||||||
ID uint64
|
|
||||||
Name string
|
|
||||||
ServerID uint64
|
|
||||||
Host string
|
|
||||||
Domain string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) addOrEditNAT(c *gin.Context) {
|
|
||||||
var nf natForm
|
|
||||||
var n model.NAT
|
|
||||||
err := c.ShouldBindJSON(&nf)
|
|
||||||
if err == nil {
|
|
||||||
n.Name = nf.Name
|
|
||||||
n.ID = nf.ID
|
|
||||||
n.Domain = nf.Domain
|
|
||||||
n.Host = nf.Host
|
|
||||||
n.ServerID = nf.ServerID
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
if n.ID == 0 {
|
|
||||||
err = singleton.DB.Create(&n).Error
|
|
||||||
} else {
|
|
||||||
err = singleton.DB.Save(&n).Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//singleton.OnNATUpdate()
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type alertRuleForm struct {
|
|
||||||
ID uint64
|
|
||||||
Name string
|
|
||||||
RulesRaw string
|
|
||||||
FailTriggerTasksRaw string // 失败时触发的任务id
|
|
||||||
RecoverTriggerTasksRaw string // 恢复时触发的任务id
|
|
||||||
NotificationTag string
|
|
||||||
TriggerMode int
|
|
||||||
Enable string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) addOrEditAlertRule(c *gin.Context) {
|
|
||||||
var arf alertRuleForm
|
|
||||||
var r model.AlertRule
|
|
||||||
err := c.ShouldBindJSON(&arf)
|
|
||||||
if err == nil {
|
|
||||||
err = utils.Json.Unmarshal([]byte(arf.RulesRaw), &r.Rules)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
if len(r.Rules) == 0 {
|
|
||||||
err = errors.New("至少定义一条规则")
|
|
||||||
} else {
|
|
||||||
for i := 0; i < len(r.Rules); i++ {
|
|
||||||
if !r.Rules[i].IsTransferDurationRule() {
|
|
||||||
if r.Rules[i].Duration < 3 {
|
|
||||||
err = errors.New("错误:Duration 至少为 3")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if r.Rules[i].CycleInterval < 1 {
|
|
||||||
err = errors.New("错误: cycle_interval 至少为 1")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if r.Rules[i].CycleStart == nil {
|
|
||||||
err = errors.New("错误: cycle_start 未设置")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if r.Rules[i].CycleStart.After(time.Now()) {
|
|
||||||
err = errors.New("错误: cycle_start 是个未来值")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
r.Name = arf.Name
|
|
||||||
r.RulesRaw = arf.RulesRaw
|
|
||||||
r.FailTriggerTasksRaw = arf.FailTriggerTasksRaw
|
|
||||||
r.RecoverTriggerTasksRaw = arf.RecoverTriggerTasksRaw
|
|
||||||
//r.NotificationTag = arf.NotificationTag
|
|
||||||
enable := arf.Enable == "on"
|
|
||||||
r.TriggerMode = arf.TriggerMode
|
|
||||||
r.Enable = &enable
|
|
||||||
r.ID = arf.ID
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = utils.Json.Unmarshal([]byte(arf.FailTriggerTasksRaw), &r.FailTriggerTasks)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = utils.Json.Unmarshal([]byte(arf.RecoverTriggerTasksRaw), &r.RecoverTriggerTasks)
|
|
||||||
}
|
|
||||||
//保证NotificationTag不为空
|
|
||||||
if err == nil {
|
|
||||||
//if r.NotificationTag == "" {
|
|
||||||
// r.NotificationTag = "default"
|
|
||||||
//}
|
|
||||||
if r.ID == 0 {
|
|
||||||
err = singleton.DB.Create(&r).Error
|
|
||||||
} else {
|
|
||||||
err = singleton.DB.Save(&r).Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//singleton.OnRefreshOrAddAlert(r)
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type logoutForm struct {
|
|
||||||
ID uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) logout(c *gin.Context) {
|
|
||||||
admin := c.MustGet(model.CtxKeyAuthorizedUser).(*model.User)
|
|
||||||
var lf logoutForm
|
|
||||||
if err := c.ShouldBindJSON(&lf); err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if lf.ID != admin.ID {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", "用户ID不匹配"),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
singleton.DB.Model(admin).UpdateColumns(model.User{
|
|
||||||
// Token: "",
|
|
||||||
// TokenExpired: time.Now(),
|
|
||||||
})
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
|
|
||||||
// if oidcLogoutUrl := singleton.Conf.Oauth2.OidcLogoutURL; oidcLogoutUrl != "" {
|
|
||||||
// // 重定向到 OIDC 退出登录地址。不知道为什么,这里的重定向不生效
|
|
||||||
// c.Redirect(http.StatusOK, oidcLogoutUrl)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
type settingForm struct {
|
|
||||||
SiteName string
|
|
||||||
Language string
|
|
||||||
CustomNameservers string
|
|
||||||
IgnoredIPNotification string
|
|
||||||
IPChangeNotificationTag string // IP变更提醒的通知组
|
|
||||||
InstallHost string
|
|
||||||
Cover uint8
|
|
||||||
|
|
||||||
EnableIPChangeNotification string
|
|
||||||
EnablePlainIPInNotification string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ma *memberAPI) updateSetting(c *gin.Context) {
|
|
||||||
var sf settingForm
|
|
||||||
if err := c.ShouldBind(&sf); err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if _, yes := model.Themes[sf.Theme]; !yes {
|
|
||||||
// c.JSON(http.StatusOK, model.Response{
|
|
||||||
// Code: http.StatusBadRequest,
|
|
||||||
// Message: fmt.Sprintf("前台主题不存在:%s", sf.Theme),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if _, yes := model.DashboardThemes[sf.DashboardTheme]; !yes {
|
|
||||||
// c.JSON(http.StatusOK, model.Response{
|
|
||||||
// Code: http.StatusBadRequest,
|
|
||||||
// Message: fmt.Sprintf("后台主题不存在:%s", sf.DashboardTheme),
|
|
||||||
// })
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
|
||||||
singleton.Conf.Language = sf.Language
|
|
||||||
singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on"
|
|
||||||
singleton.Conf.EnablePlainIPInNotification = sf.EnablePlainIPInNotification == "on"
|
|
||||||
singleton.Conf.Cover = sf.Cover
|
|
||||||
singleton.Conf.InstallHost = sf.InstallHost
|
|
||||||
singleton.Conf.IgnoredIPNotification = sf.IgnoredIPNotification
|
|
||||||
singleton.Conf.IPChangeNotificationTag = sf.IPChangeNotificationTag
|
|
||||||
singleton.Conf.SiteName = sf.SiteName
|
|
||||||
singleton.Conf.DNSServers = sf.CustomNameservers
|
|
||||||
// 保证NotificationTag不为空
|
|
||||||
if singleton.Conf.IPChangeNotificationTag == "" {
|
|
||||||
singleton.Conf.IPChangeNotificationTag = "default"
|
|
||||||
}
|
|
||||||
if err := singleton.Conf.Save(); err != nil {
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
Message: fmt.Sprintf("请求错误:%s", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 更新DNS服务器
|
|
||||||
singleton.OnNameserverUpdate()
|
|
||||||
c.JSON(http.StatusOK, model.Response{
|
|
||||||
Code: http.StatusOK,
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/naiba/nezha/model"
|
|
||||||
"github.com/naiba/nezha/service/singleton"
|
|
||||||
)
|
|
||||||
|
|
||||||
type memberPage struct {
|
|
||||||
r *gin.Engine
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) serve() {
|
|
||||||
mr := mp.r.Group("")
|
|
||||||
// mr.Use(mygin.Authorize(mygin.AuthorizeOption{
|
|
||||||
// MemberOnly: true,
|
|
||||||
// IsPage: true,
|
|
||||||
// // Msg: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "YouAreNotAuthorized"}),
|
|
||||||
// // Btn: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
|
|
||||||
// Redirect: "/login",
|
|
||||||
// }))
|
|
||||||
mr.GET("/cron", mp.cron)
|
|
||||||
mr.GET("/notification", mp.notification)
|
|
||||||
mr.GET("/ddns", mp.ddns)
|
|
||||||
mr.GET("/nat", mp.nat)
|
|
||||||
mr.GET("/setting", mp.setting)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) cron(c *gin.Context) {
|
|
||||||
var crons []model.Cron
|
|
||||||
singleton.DB.Find(&crons)
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
|
|
||||||
"Crons": crons,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) notification(c *gin.Context) {
|
|
||||||
var nf []model.Notification
|
|
||||||
singleton.DB.Find(&nf)
|
|
||||||
var ar []model.AlertRule
|
|
||||||
singleton.DB.Find(&ar)
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Notification"}),
|
|
||||||
"Notifications": nf,
|
|
||||||
"AlertRules": ar,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) ddns(c *gin.Context) {
|
|
||||||
var data []model.DDNSProfile
|
|
||||||
singleton.DB.Find(&data)
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "DDNS"}),
|
|
||||||
"DDNS": data,
|
|
||||||
//"ProviderMap": model.ProviderMap,
|
|
||||||
//"ProviderList": model.ProviderList,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) nat(c *gin.Context) {
|
|
||||||
var data []model.NAT
|
|
||||||
singleton.DB.Find(&data)
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NAT"}),
|
|
||||||
"NAT": data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *memberPage) setting(c *gin.Context) {
|
|
||||||
c.HTML(http.StatusOK, "dashboard-", gin.H{
|
|
||||||
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
|
|
||||||
//"Languages": model.Languages,
|
|
||||||
//"DashboardThemes": model.DashboardThemes,
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user