videoplayer/service/toolService.go

353 lines
12 KiB
Go
Raw Permalink Normal View History

package service
import (
2025-07-31 21:03:49 +08:00
"encoding/json"
2025-06-06 14:36:59 +08:00
"errors"
2025-01-02 15:39:05 +08:00
"fmt"
2025-07-31 21:03:49 +08:00
"log"
2025-01-02 15:39:05 +08:00
"regexp"
2025-07-31 21:03:49 +08:00
"strconv"
"time"
"videoplayer/proto"
"videoplayer/worker"
)
func SetToolRedisList(key string, value string, expire int) (code int, message string) {
if expire == 0 {
if worker.PushRedisList(key, value) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "push redis list failed"
}
} else if expire > 0 {
if worker.PushRedisListWithExpire(key, value, time.Duration(expire)) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "push redis list with expire failed"
}
} else {
return proto.ParameterError, "expire time can not be negative"
}
}
func SetToolRedisSet(key string, value string, expire int) (code int, message string) {
if expire == 0 {
if worker.SetRedis(key, value) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "set redis failed"
}
} else if expire > 0 {
if worker.SetRedisWithExpire(key, value, time.Duration(expire)) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "set redis with expire failed"
}
} else {
return proto.ParameterError, "expire time can not be negative"
}
}
func SetToolRedisKV(key string, value string, expire int) (code int, message string) {
if expire == 0 {
if worker.SetRedis(key, value) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "set redis failed"
}
} else if expire > 0 {
if worker.SetRedisWithExpire(key, value, time.Duration(expire)) {
return proto.SuccessCode, "success"
} else {
return proto.OperationFailed, "set redis with expire failed"
}
} else {
return proto.ParameterError, "expire time can not be negative"
}
}
func GetToolRedis(key string) (code int, message string) {
val := worker.GetRedis(key)
if val == "" {
return proto.OperationFailed, "get redis failed"
} else {
return proto.SuccessCode, val
}
}
2024-12-21 17:16:38 +08:00
func GetAllRedis() (code int, msg string, data []worker.RedisInfo) {
data, err := worker.GetAllRedisInfo()
if err != nil {
return proto.OperationFailed, err.Error(), nil
}
return proto.SuccessCode, "success", data
}
2025-01-02 15:39:05 +08:00
func SendEmail(email, subject, body string) {
//捕获异常
defer func() {
if err := recover(); err != nil {
fmt.Errorf("tool send mail error: %s", err)
}
}()
// TODO
// 发送邮件
// 邮件内容
// 邮件标题
// 收件人
// 发送邮件
// 发送邮件通知
// 发送邮件通知
var em worker.MyEmail
em.SmtpPassword = "nihzazdkmucnbhid"
em.SmtpHost = "pop.qq.com:587"
em.SmtpUserName = "354425203@qq.com"
em.SmtpPort = 587
em.ImapPort = 993
err := em.Send(subject, body, []string{email})
if err != nil {
fmt.Println("send mail error:", err)
}
}
// 地址校验
func CheckEmail(email string) bool {
//正则表达式判断是否是邮箱
pattern := `^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(email)
}
2025-06-06 14:36:59 +08:00
// 获取监控设备及状态
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)
2025-06-06 14:36:59 +08:00
var deviceInfo proto.GetMonitorDeviceStatus
deviceInfo.ID = device
deviceInfo.Expire = expireIn
2025-06-06 14:36:59 +08:00
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
}
2025-06-06 14:59:25 +08:00
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
}
2025-07-31 21:03:49 +08:00
// 更新token密钥
func SyncTokenSecretFromUserCenter() {
secretSettings, err := GetTokenSecretFromUserCenter()
2025-08-02 15:39:32 +08:00
if err != nil {
log.Println("SyncTokenSecretFromUserCenter error:", err)
return
}
2025-07-31 21:03:49 +08:00
//写入redis
secretSettingsBytes, err2 := json.Marshal(secretSettings)
if err2 != nil {
log.Println("SyncTokenSecretFromUserCenter json marshal error:", err2)
return
}
if proto.SyncSecretReqLog%100 == 0 {
log.Println("SyncTokenSecretFromUserCenter req data:", string(secretSettingsBytes))
}
worker.SetRedis("secret_sync_settings", string(secretSettingsBytes)) //将密钥信息存入redis
2025-08-02 15:39:32 +08:00
if secretSettings.Curr != "" && secretSettings.Curr != proto.Config.TOKEN_SECRET && secretSettings.Next == "" { //如果当前密钥不为空且不等于配置文件中的密钥,并且下一个密钥为空,则需要更新配置文件中的密钥
log.Printf("SyncTokenSecretFromUserCenter current secret is not equal to config secret, current: %s, config: %s\n", secretSettings.Curr, proto.Config.TOKEN_SECRET)
2025-07-31 21:03:49 +08:00
//如果当前密钥与配置文件中的密钥不一致,则需要更新配置文件中的密钥
proto.SigningKeyRWLock.Lock()
proto.SigningKey = []byte(secretSettings.Curr)
proto.Config.TOKEN_SECRET = secretSettings.Curr
proto.SigningKeyRWLock.Unlock()
2025-08-10 14:01:45 +08:00
proto.SigningKeyIsValid = true
2025-07-31 21:03:49 +08:00
//配置写回文件
go proto.WriteConfigToFile()
log.Println("SyncTokenSecretFromUserCenter current secret updated successfully")
}
if secretSettings.Next == "" {
log.Println("SyncTokenSecretFromUserCenter secret is empty")
} else if proto.SyncSecretReqLog%100 == 0 {
go SetNextSecretToCurrent(*secretSettings) //异步设置下一个密钥为当前密钥
}
proto.SyncSecretReqLog++ //记录同步密钥请求次数
}
func SetNextSecretToCurrent(secret_copy proto.SecretSyncSettings) {
var secret_sync_settings proto.SecretSyncSettings
redisKey := "secret_sync_settings"
settingsStr := worker.GetRedis(redisKey)
err := json.Unmarshal([]byte(settingsStr), &secret_sync_settings)
if err != nil {
log.Println("Error decoding secret sync settings:", err)
} else {
//如果当前密钥的下一个密钥与传入的密钥不一致,则不进行设置
if secret_copy.Next != secret_sync_settings.Next {
return
}
//获取需要等待时间
waitTime := secret_sync_settings.NextStartTimestamp - worker.GetCurrentTimestamp()
if waitTime > 0 {
log.Printf("Waiting for %d seconds before setting the next secret as current secret\n", waitTime)
time.Sleep(time.Duration(waitTime) * time.Second) //等待时间
} else {
log.Println("No need to wait, setting the next secret as current secret immediately")
}
//设置下一个密钥为当前密钥
secret_sync_settings.Prev = secret_sync_settings.Curr
secret_sync_settings.PrevEndTimestamp = worker.GetCurrentTimestamp()
secret_sync_settings.Curr = secret_sync_settings.Next
secret_sync_settings.Next = ""
secret_sync_settings.CurrStartTimestamp = secret_sync_settings.PrevEndTimestamp
2025-08-10 14:01:45 +08:00
proto.SigningKeyIsValid = true
2025-07-31 21:03:49 +08:00
//设置当前程序的密钥
//获取写锁
proto.SigningKeyRWLock.Lock()
defer proto.SigningKeyRWLock.Unlock()
proto.SigningKey = []byte(secret_sync_settings.Curr)
proto.Config.TOKEN_SECRET = secret_sync_settings.Curr
//配置写回文件
go proto.WriteConfigToFile()
}
settinsStr, err2 := json.Marshal(secret_sync_settings)
if err2 != nil {
log.Println("Error encoding set secret sync settings:", err2)
return
}
worker.SetRedis(redisKey, string(settinsStr)) //将当前的密钥信息存入redis
}
// 获取token密钥请求
func GetTokenSecretFromUserCenter() (*proto.SecretSyncSettings, error) {
url := "https://uc.ljsea.top/tool/sync_system_config"
var req proto.SyncSystemConfigRequest
proto.SigningKeyRWLock.Lock()
defer proto.SigningKeyRWLock.Unlock()
req.SecretKeyMd5 = worker.GenerateMD5(string(proto.SigningKey))
2025-08-01 20:41:22 +08:00
req.DeviceApp = proto.Config.APP_ID
2025-07-31 21:03:49 +08:00
req.Timestamp = worker.GetCurrentTimestamp()
req.Sign = worker.GenerateMD5(req.SecretKeyMd5 + req.DeviceApp + strconv.FormatInt(req.Timestamp, 10))
reqBytes, err2 := json.Marshal(req)
if err2 != nil {
log.Println("GetTokenSecretFromUserCenter json marshal error:", err2)
return nil, err2
}
err, resp := worker.DoPostRequestJSON(url, reqBytes, nil)
if err != nil {
log.Println("GetTokenSecretFromUserCenter post request error:", err)
return nil, err
}
var respObject proto.RequestSyncSecretResp
err = json.Unmarshal(resp, &respObject)
if err != nil {
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
return nil, err
}
2025-08-02 15:39:32 +08:00
if respObject.Code != 0 {
2025-08-10 13:59:43 +08:00
if respObject.Code == proto.SigningKeyVersionIsTooOld {
proto.SigningKeyIsValid = false //设置当前密钥无效
}
2025-08-02 15:39:32 +08:00
log.Println("GetTokenSecretFromUserCenter error code:", respObject.Code, "\t, message:", respObject.Message)
return nil, fmt.Errorf("GetTokenSecretFromUserCenter error code: %d, message: %s", respObject.Code, respObject.Message)
}
2025-07-31 21:03:49 +08:00
//对称加密密钥。通过密钥加 secret_key 取md5
2025-08-02 15:39:32 +08:00
secretKeyMd5 := worker.GenerateMD5(proto.Config.TOKEN_SECRET + "_sync_secret")
2025-07-31 21:03:49 +08:00
//解密返回数据
dataContent, err2 := worker.AESDecrypt(respObject.Data, []byte(secretKeyMd5))
if err2 != nil {
2025-08-02 15:39:32 +08:00
log.Println("GetTokenSecretFromUserCenter aes decrypt error:", err2, "\t, secret:", proto.Config.TOKEN_SECRET, "\t, secretKey:", secretKeyMd5, "\t, data:", respObject.Data)
2025-07-31 21:03:49 +08:00
return nil, err2
}
var secretResp proto.SecretSyncSettings
err = json.Unmarshal(dataContent, &secretResp)
if err != nil {
log.Println("GetTokenSecretFromUserCenter json unmarshal error:", err)
return nil, err
}
return &secretResp, nil
}
// 获取cid正在运行
func GetCIDRunningList(user_id int, req_type int) ([]proto.CIDRunning, error) {
var err error
var resp []proto.CIDRunning
if req_type == 0 {
proto.CID_RunningMutex.RLock()
resp = proto.CID_Running_Map[user_id]
proto.CID_RunningMutex.RUnlock()
} else if req_type == 1 {
user := GetUserByIDFromUserCenter(user_id)
if user.Role != "admin" {
err = errors.New("no permission")
} else {
proto.CID_RunningMutex.RLock()
for _, v := range proto.CID_Running_Map {
resp = append(resp, v...)
}
proto.CID_RunningMutex.RUnlock()
}
} else {
err = errors.New("request type is error")
}
return resp, err
}