Merge branch 'refs/heads/fix-get-shell-err'

This commit is contained in:
junleea 2025-06-11 14:34:54 +08:00
commit db9d56aa29
8 changed files with 251 additions and 1 deletions

View File

@ -98,3 +98,35 @@ func FindShellWillRunByServer(server string, uid uint) []Shell {
} }
return shells return shells
} }
func DeleteShellByID(id, authId uint) bool {
var db2 *gorm.DB
if proto.Config.SERVER_SQL_LOG {
db2 = DB
} else {
db2 = DB.Debug()
}
result := db2.Where("id = ? and auth_id = ?", id, authId).Delete(&Shell{})
if result.Error != nil {
log.Printf("DeleteShellByID failed: %v", result.Error)
return false
}
return true
}
func DeleteShellByIDV2(id uint) bool {
var db2 *gorm.DB
if proto.Config.SERVER_SQL_LOG {
db2 = DB
} else {
db2 = DB.Debug()
}
result := db2.Where("id = ? ", id).Delete(&Shell{})
if result.Error != nil {
log.Printf("DeleteShellByID failed: %v", result.Error)
return false
}
return true
}

View File

@ -2,6 +2,7 @@ package handler
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http"
"videoplayer/proto" "videoplayer/proto"
"videoplayer/service" "videoplayer/service"
) )
@ -32,12 +33,20 @@ type UpdateShellResp struct {
Status int `json:"status" form:"status"` Status int `json:"status" form:"status"`
} }
type DeleteShellRequestID struct {
ID uint `json:"id" form:"id" binding:"required"`
}
type DeleteShellRequest struct {
Shells []DeleteShellRequestID `json:"shells" form:"shells" binding:"required"`
}
func SetUpShellGroup(router *gin.Engine) { func SetUpShellGroup(router *gin.Engine) {
shellGroup := router.Group("/shell") //持续集成、部署 shellGroup := router.Group("/shell") //持续集成、部署
shellHandler := ShellHandler{} shellHandler := ShellHandler{}
shellGroup.POST("/create", shellHandler.CreateShell) shellGroup.POST("/create", shellHandler.CreateShell)
shellGroup.POST("/list", shellHandler.ListShell) shellGroup.POST("/list", shellHandler.ListShell)
shellGroup.POST("/update", shellHandler.UpdateShell) shellGroup.POST("/update", shellHandler.UpdateShell)
shellGroup.POST("/delete", shellHandler.DeleteShell)
shellGroup.POST("/server_will_run_list", shellHandler.ServerWillRun) shellGroup.POST("/server_will_run_list", shellHandler.ServerWillRun)
} }
@ -84,6 +93,41 @@ func (s *ShellHandler) UpdateShell(c *gin.Context) {
} }
} }
type DeleteShellResp struct {
Success []DeleteShellRequestID `json:"success" form:"success"`
Error []DeleteShellRequestID `json:"error" form:"error"`
}
func (s *ShellHandler) DeleteShell(c *gin.Context) {
userId, _ := c.Get("id")
id := int(userId.(float64))
var req DeleteShellRequest
var resp proto.GeneralResp
if err := c.ShouldBind(&req); err == nil {
var delSuccessIDs []DeleteShellRequestID
var delErrorIDs []DeleteShellRequestID
for _, v := range req.Shells {
delSuccess := service.DeleteShellByID(v.ID, uint(id))
if delSuccess {
delSuccessIDs = append(delSuccessIDs, v)
} else {
delErrorIDs = append(delErrorIDs, v)
}
}
var delResp DeleteShellResp
delResp.Success = delSuccessIDs
delResp.Error = delErrorIDs
resp.Code = proto.SuccessCode
resp.Data = delResp
resp.Message = "success"
} else {
resp.Code = proto.ParameterError
resp.Message = "参数解析错误:" + err.Error()
}
c.JSON(http.StatusOK, resp)
}
type ServerWillRunReq struct { type ServerWillRunReq struct {
Server string `json:"server"` Server string `json:"server"`
} }

View File

@ -52,10 +52,76 @@ func SetUpToolGroup(router *gin.Engine) {
toolGroup.POST("/file_del", DelFile) toolGroup.POST("/file_del", DelFile)
//服务器、设备状态接口 //服务器、设备状态接口
toolGroup.POST("/monitor", SetDeviceStatusV2) toolGroup.POST("/monitor", SetDeviceStatusV2)
toolGroup.GET("/get_monitor_list", GetMonitorList) //获取设备监控列表
toolGroup.POST("/update_monitor", UpdateMonitor) //设置设备状态
toolGroup.POST("/del_monitor", DelMonitor) //删除设备监控
//发送邮件 //发送邮件
toolGroup.POST("/send_mail", SendMailTool) toolGroup.POST("/send_mail", SendMailTool)
} }
func GetMonitorList(c *gin.Context) {
id, _ := c.Get("id")
userId := int(id.(float64))
var resp proto.GeneralResp
monitorDeviceList, err := service.GetMonitorDeviceListWithStatus(userId)
if err != nil {
resp.Code = proto.OperationFailed
resp.Message = err.Error()
} else {
resp.Code = proto.SuccessCode
resp.Message = "success"
resp.Data = monitorDeviceList
}
c.JSON(http.StatusOK, resp)
}
type UpdateMonitorDeviceStatusReq struct {
Devices []proto.GetMonitorDeviceStatus `json:"devices" form:"devices"` //设备状态列表
}
func UpdateMonitor(c *gin.Context) {
id, _ := c.Get("id")
id1 := int(id.(float64))
var req UpdateMonitorDeviceStatusReq
var resp proto.GeneralResp
if err := c.ShouldBind(&req); err == nil {
err2 := service.UpdateMonitorDeviceListWithStatus(id1, req.Devices)
if err2 != nil {
resp.Code = proto.OperationFailed
resp.Message = "更新设备状态失败:" + err2.Error()
} else {
resp.Code = proto.SuccessCode
resp.Message = "更新设备状态成功"
}
} else {
resp.Code = proto.ParameterError
resp.Message = "参数解析失败:" + err.Error()
}
c.JSON(http.StatusOK, resp)
}
func DelMonitor(c *gin.Context) {
id, _ := c.Get("id")
id1 := int(id.(float64))
var req UpdateMonitorDeviceStatusReq
var resp proto.GeneralResp
if err := c.ShouldBind(&req); err == nil {
delSuccess, err2 := service.DelMonitorDeviceListWithStatus(id1, req.Devices)
if err2 != nil {
resp.Code = proto.OperationFailed
resp.Message = "更新设备状态失败:" + err2.Error()
resp.Data = delSuccess
} else {
resp.Code = proto.SuccessCode
resp.Message = "更新设备状态成功"
resp.Data = delSuccess
}
} else {
resp.Code = proto.ParameterError
resp.Message = "参数解析失败:" + err.Error()
}
c.JSON(http.StatusOK, resp)
}
func SetDeviceStatusV2(c *gin.Context) { func SetDeviceStatusV2(c *gin.Context) {
// TODO // TODO
var req SetDeviceStatusReq var req SetDeviceStatusReq

View File

@ -82,6 +82,7 @@ type ConfigStruct struct {
MASTER_SERVER_DOMAIN string `json:"master_server_domain"` // 主服务器域名 MASTER_SERVER_DOMAIN string `json:"master_server_domain"` // 主服务器域名
USER_SYNC_TIME int `json:"user_sync_time"` // 用户数据同步时间,单位秒 USER_SYNC_TIME int `json:"user_sync_time"` // 用户数据同步时间,单位秒
SERVER_NAME string `json:"server_name"` // 服务器名称,用于区分不同服务器 SERVER_NAME string `json:"server_name"` // 服务器名称,用于区分不同服务器
MONITOR_SERVER_TOKEN string `json:"monitor_server_token"` // 监控服务器token,用于状态监控及邮件通知
} }
// 读取配置文件 // 读取配置文件

7
proto/resp.go Normal file
View File

@ -0,0 +1,7 @@
package proto
type GetMonitorDeviceStatus struct {
ID string `json:"id" form:"id"` //设备编码
Status string `json:"status" form:"status"` //设备状态
Expire int `json:"expire" form:"expire"` //设备过期时间,及更新时间
}

View File

@ -20,6 +20,14 @@ func FindShellByAuthID(id int) []dao.Shell {
return dao.FindShellByAuthID(id) return dao.FindShellByAuthID(id)
} }
func DeleteShellByID(id, authId uint) bool {
user := GetUserByIDFromUserCenter(int(authId))
if user.Role == "admin" {
return dao.DeleteShellByIDV2(id)
}
return dao.DeleteShellByID(id, authId)
}
func UpdateShellByID(id, authId uint, shellName, shellContent, server string, status int, shellResult string) bool { func UpdateShellByID(id, authId uint, shellName, shellContent, server string, status int, shellResult string) bool {
return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult) return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult)
} }
@ -84,7 +92,12 @@ func GetShellWillRunFromMaster(server string) ([]dao.Shell, error) {
url := "https://" + master + "/shell/server_will_run_list?super_id=1" url := "https://" + master + "/shell/server_will_run_list?super_id=1"
var req proto.SyncUserShellReq var req proto.SyncUserShellReq
req.Server = server req.Server = server
req.Token = worker.GetRedisSetMembers("super_permission_tokens")[0] superPermissions := worker.GetRedisSetMembers("super_permission_tokens")
if len(superPermissions) == 0 {
log.Println("get shell will run from master error: no super permission tokens found, please check the configuration or redis!")
return nil, errors.New("no super permission tokens found")
}
req.Token = superPermissions[0]
shells, err := worker.SyncDataFromMasterShellReq2(url, req) shells, err := worker.SyncDataFromMasterShellReq2(url, req)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,6 +1,7 @@
package service package service
import ( import (
"errors"
"fmt" "fmt"
"regexp" "regexp"
"time" "time"
@ -113,3 +114,73 @@ func CheckEmail(email string) bool {
reg := regexp.MustCompile(pattern) reg := regexp.MustCompile(pattern)
return reg.MatchString(email) return reg.MatchString(email)
} }
// 获取监控设备及状态
func GetMonitorDeviceListWithStatus(userId int) ([]proto.GetMonitorDeviceStatus, error) {
var deviceStatus []proto.GetMonitorDeviceStatus
user := GetUserByIDFromUserCenter(userId)
if user.Role != "admin" {
return deviceStatus, errors.New("user is not admin, can not get monitor device list")
} else {
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
for _, device := range devices {
status, expireIn := worker.GetRedisWithExpire("monitor_" + device)
var deviceInfo proto.GetMonitorDeviceStatus
deviceInfo.ID = device
deviceInfo.Expire = expireIn
if status == "" {
deviceInfo.Status = "offline"
} else {
deviceInfo.Status = status
}
deviceStatus = append(deviceStatus, deviceInfo)
}
}
return deviceStatus, nil
}
func UpdateMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) error {
user := GetUserByIDFromUserCenter(userId)
var err error
if user.Role != "admin" {
err = errors.New("user is not admin, can not update monitor device list")
return err
} else {
// 更新监控设备状态.如果在集合中则添加,不在则添加到集合中
devices := worker.GetRedisSetMembers(proto.Config.MONITOR_SERVER_TOKEN)
deviceMap := make(map[string]bool, len(devices))
for _, device := range devices {
deviceMap[device] = true
}
for _, device := range deviceReq {
if _, ok := deviceMap[device.ID]; ok {
// 如果设备在集合中,则更新状态
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
} else {
worker.SetRedisSetAdd(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
worker.SetRedisWithExpire("monitor_"+device.ID, device.Status, time.Duration(device.Expire)*time.Second)
}
}
}
return err
}
func DelMonitorDeviceListWithStatus(userId int, deviceReq []proto.GetMonitorDeviceStatus) ([]proto.GetMonitorDeviceStatus, error) {
user := GetUserByIDFromUserCenter(userId)
var err error
var delDevices []proto.GetMonitorDeviceStatus
if user.Role != "admin" {
err = errors.New("user is not admin, can not update monitor device list")
return delDevices, err
} else {
for _, device := range deviceReq {
if worker.IsContainSet(proto.Config.MONITOR_SERVER_TOKEN, device.ID) {
// 如果设备在集合中,则删除状态
worker.DelRedis("monitor_" + device.ID)
worker.SetRedisSetRemove(proto.Config.MONITOR_SERVER_TOKEN, device.ID)
delDevices = append(delDevices, device)
}
}
}
return delDevices, err
}

View File

@ -176,6 +176,22 @@ func GetRedis(key string) string {
return val return val
} }
func GetRedisWithExpire(key string) (string, int) {
ctx := context.Background()
val, err := RedisClient.Get(ctx, key).Result() // 从 Redis 读取键值, 如果键不存在则返回空字符串, 如果出现错误则返回错误
if err != nil {
//fmt.Println(key, " Error getting key: %v", err)
return "", 0
} else {
// 获取键的过期时间
ttl, err2 := RedisClient.TTL(ctx, key).Result()
if err2 != nil {
return val, -1
}
return val, int(ttl.Seconds())
}
}
// pop redis list from right,as stack // pop redis list from right,as stack
func PopRedisList(key string) string { func PopRedisList(key string) string {
ctx := context.Background() ctx := context.Background()