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() //配置写回文件 go proto.WriteConfigToFile() log.Println("SyncTokenSecretFromUserCenter current secret updated successfully") } if secretSettings.Next == "" { log.Println("SyncTokenSecretFromUserCenter secret is empty") return } 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.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 { 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 }