258 lines
6.5 KiB
Go
258 lines
6.5 KiB
Go
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,
|
|
})
|
|
}
|