328 lines
11 KiB
Go
328 lines
11 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"regexp"
|
|
"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
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
// 获取监控设备及状态
|
|
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
|
|
}
|
|
|
|
// 更新token密钥
|
|
func SyncTokenSecretFromUserCenter() {
|
|
secretSettings, err := GetTokenSecretFromUserCenter()
|
|
if err != nil {
|
|
log.Println("SyncTokenSecretFromUserCenter error:", err)
|
|
return
|
|
}
|
|
//写入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
|
|
|
|
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)
|
|
//如果当前密钥与配置文件中的密钥不一致,则需要更新配置文件中的密钥
|
|
proto.SigningKeyRWLock.Lock()
|
|
proto.SigningKey = []byte(secretSettings.Curr)
|
|
proto.Config.TOKEN_SECRET = secretSettings.Curr
|
|
proto.SigningKeyRWLock.Unlock()
|
|
proto.SigningKeyIsValid = true
|
|
//配置写回文件
|
|
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
|
|
proto.SigningKeyIsValid = true
|
|
|
|
//设置当前程序的密钥
|
|
//获取写锁
|
|
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))
|
|
req.DeviceApp = proto.Config.APP_ID
|
|
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
|
|
}
|
|
if respObject.Code != 0 {
|
|
if respObject.Code == proto.SigningKeyVersionIsTooOld {
|
|
proto.SigningKeyIsValid = false //设置当前密钥无效
|
|
}
|
|
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)
|
|
}
|
|
|
|
//对称加密密钥。通过密钥加 secret_key 取md5
|
|
secretKeyMd5 := worker.GenerateMD5(proto.Config.TOKEN_SECRET + "_sync_secret")
|
|
|
|
//解密返回数据
|
|
dataContent, err2 := worker.AESDecrypt(respObject.Data, []byte(secretKeyMd5))
|
|
if err2 != nil {
|
|
log.Println("GetTokenSecretFromUserCenter aes decrypt error:", err2, "\t, secret:", proto.Config.TOKEN_SECRET, "\t, secretKey:", secretKeyMd5, "\t, data:", respObject.Data)
|
|
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
|
|
}
|