2024-07-21 11:00:08 +08:00
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"
2024-07-21 11:00:08 +08:00
"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 {
2025-06-06 14:53:14 +08:00
status , expireIn := worker . GetRedisWithExpire ( "monitor_" + device )
2025-06-06 14:36:59 +08:00
var deviceInfo proto . GetMonitorDeviceStatus
deviceInfo . ID = device
2025-06-06 14:53:14 +08:00
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
}
2025-06-06 14:53:14 +08:00
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
}