diff --git a/dao/shell.go b/dao/shell.go index 8d1c5bd..b033a24 100644 --- a/dao/shell.go +++ b/dao/shell.go @@ -98,3 +98,35 @@ func FindShellWillRunByServer(server string, uid uint) []Shell { } 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 +} diff --git a/handler/shell.go b/handler/shell.go index 3f39d77..397857f 100644 --- a/handler/shell.go +++ b/handler/shell.go @@ -2,6 +2,7 @@ package handler import ( "github.com/gin-gonic/gin" + "net/http" "videoplayer/proto" "videoplayer/service" ) @@ -32,12 +33,20 @@ type UpdateShellResp struct { 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) { shellGroup := router.Group("/shell") //持续集成、部署 shellHandler := ShellHandler{} shellGroup.POST("/create", shellHandler.CreateShell) shellGroup.POST("/list", shellHandler.ListShell) shellGroup.POST("/update", shellHandler.UpdateShell) + shellGroup.POST("/delete", shellHandler.DeleteShell) 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 { Server string `json:"server"` } diff --git a/handler/tool.go b/handler/tool.go index 820854a..5743baa 100644 --- a/handler/tool.go +++ b/handler/tool.go @@ -52,10 +52,76 @@ func SetUpToolGroup(router *gin.Engine) { toolGroup.POST("/file_del", DelFile) //服务器、设备状态接口 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) } +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) { // TODO var req SetDeviceStatusReq diff --git a/proto/conf.go b/proto/conf.go index 0c6bb27..c79fba0 100644 --- a/proto/conf.go +++ b/proto/conf.go @@ -82,6 +82,7 @@ type ConfigStruct struct { MASTER_SERVER_DOMAIN string `json:"master_server_domain"` // 主服务器域名 USER_SYNC_TIME int `json:"user_sync_time"` // 用户数据同步时间,单位秒 SERVER_NAME string `json:"server_name"` // 服务器名称,用于区分不同服务器 + MONITOR_SERVER_TOKEN string `json:"monitor_server_token"` // 监控服务器token,用于状态监控及邮件通知 } // 读取配置文件 diff --git a/proto/resp.go b/proto/resp.go new file mode 100644 index 0000000..cb22ced --- /dev/null +++ b/proto/resp.go @@ -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"` //设备过期时间,及更新时间 +} diff --git a/service/shellService.go b/service/shellService.go index 2a00982..9818bc6 100644 --- a/service/shellService.go +++ b/service/shellService.go @@ -20,6 +20,14 @@ func FindShellByAuthID(id int) []dao.Shell { 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 { 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" var req proto.SyncUserShellReq 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) if err != nil { return nil, err diff --git a/service/toolService.go b/service/toolService.go index 754daed..5c9e9b9 100644 --- a/service/toolService.go +++ b/service/toolService.go @@ -1,6 +1,7 @@ package service import ( + "errors" "fmt" "regexp" "time" @@ -113,3 +114,73 @@ func CheckEmail(email string) bool { reg := regexp.MustCompile(pattern) 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 +} diff --git a/worker/redis.go b/worker/redis.go index b31735f..ad21ff8 100644 --- a/worker/redis.go +++ b/worker/redis.go @@ -176,6 +176,22 @@ func GetRedis(key string) string { 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 func PopRedisList(key string) string { ctx := context.Background()