1764 lines
48 KiB
Go
1764 lines
48 KiB
Go
package db
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
"xiawan/wx/api/req"
|
|
"xiawan/wx/clientsdk/baseinfo"
|
|
"xiawan/wx/db/table"
|
|
"xiawan/wx/protobuf/wechat"
|
|
pb "xiawan/wx/protobuf/wechat"
|
|
"xiawan/wx/srv"
|
|
"xiawan/wx/srv/srvconfig"
|
|
|
|
"github.com/go-sql-driver/mysql"
|
|
"github.com/jinzhu/gorm"
|
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
|
"github.com/lunny/log"
|
|
)
|
|
|
|
// MysqlDB MySQL数据库实例
|
|
var (
|
|
MysqlDB *gorm.DB
|
|
dbMutex sync.Mutex // 用于保护连接重置的互斥锁
|
|
contactMutex sync.Mutex // 联系人存储锁
|
|
mutexMap = make(map[string]*sync.Mutex) // 联系人存储锁
|
|
maxRetry = 10 // 最大重试次数
|
|
retryDelay = time.Second * 2 // 每次重试的间隔时间
|
|
)
|
|
|
|
// 联系人存储锁,uuid 区分
|
|
func getContactMutex(uuid string) *sync.Mutex {
|
|
contactMutex.Lock()
|
|
defer contactMutex.Unlock()
|
|
|
|
m, exists := mutexMap[uuid]
|
|
if !exists {
|
|
m = &sync.Mutex{}
|
|
mutexMap[uuid] = m
|
|
}
|
|
return m
|
|
}
|
|
|
|
// InitDB 初始化数据库
|
|
func InitDB() {
|
|
dbMutex.Lock() // 加锁,防止并发重连
|
|
defer dbMutex.Unlock()
|
|
var mysqlUrl = srvconfig.GlobalSetting.MysqlConnectStr
|
|
var err error
|
|
for i := 0; i < maxRetry; i++ {
|
|
MysqlDB, err = gorm.Open("mysql", mysqlUrl)
|
|
if err == nil {
|
|
break
|
|
}
|
|
fmt.Printf("Failed to connect MySQL, retrying... (%d/%d)\n", i+1, maxRetry)
|
|
time.Sleep(retryDelay)
|
|
}
|
|
if err != nil {
|
|
log.Errorf("Failed to connect MySQL after %d attempts: %v", maxRetry, err)
|
|
return
|
|
}
|
|
MysqlDB.DB().SetConnMaxLifetime(time.Minute * 5)
|
|
//设置连接池中的最大闲置连接数
|
|
MysqlDB.DB().SetMaxIdleConns(10)
|
|
//设置数据库的最大连接数量
|
|
MysqlDB.DB().SetMaxOpenConns(120)
|
|
|
|
fmt.Println("connect MySQL success")
|
|
MysqlDB.SingularTable(true)
|
|
MysqlDB.AutoMigrate(&table.UserInfoEntity{}) //用户信息 自动建表
|
|
MysqlDB.AutoMigrate(&table.DeviceInfoEntity{}) //设备信息 自动建表
|
|
MysqlDB.AutoMigrate(&table.UserLoginLog{}) //登录日志 自动建表
|
|
MysqlDB.AutoMigrate(&table.UserBusinessLog{}) //用户 自动建表
|
|
MysqlDB.AutoMigrate(&table.LicenseKey{}) //自动建表
|
|
MysqlDB.AutoMigrate(&table.UserMessageLog{}) //自动建表
|
|
MysqlDB.AutoMigrate(&table.Command{}) //自动建表
|
|
MysqlDB.AutoMigrate(&table.ModContactDB{}) //自动建表
|
|
MysqlDB.AutoMigrate(&table.AddMsgDB{}) //自动建表
|
|
MysqlDB.AutoMigrate(&table.ProxyMapping{}) //代理映射表 自动建表
|
|
MysqlDB.AutoMigrate(&table.MessageCallbackConfig{}) //消息回调配置表 自动建表
|
|
|
|
fmt.Println("auto create MySQL tables success")
|
|
MysqlDB.LogMode(false)
|
|
|
|
// 注意:回调配置的初始化移到了 InitAnewLogin 完成后
|
|
// 这样可以确保所有账号连接都已建立
|
|
}
|
|
|
|
// InitMessageCallbacks 初始化所有消息回调配置
|
|
func InitMessageCallbacks() {
|
|
// 账号已经初始化完成,稍微等待一下确保连接稳定
|
|
time.Sleep(3 * time.Second)
|
|
|
|
log.Infof("开始初始化消息回调配置...")
|
|
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
log.Errorf("Failed to initialize message callbacks: %v", err)
|
|
return
|
|
}
|
|
|
|
// 获取所有启用的回调配置
|
|
var configs []table.MessageCallbackConfig
|
|
result := MysqlDB.Where("enabled = ?", true).Find(&configs)
|
|
if result.Error != nil {
|
|
log.Errorf("Failed to query enabled callbacks: %v", result.Error)
|
|
return
|
|
}
|
|
|
|
if len(configs) == 0 {
|
|
log.Infof("未找到启用的消息回调配置")
|
|
return
|
|
}
|
|
|
|
log.Infof("找到 %d 个启用的回调配置,开始重新激活...", len(configs))
|
|
|
|
// 重新保存每个配置,相当于重新设置一遍,激活回调
|
|
successCount := 0
|
|
for _, config := range configs {
|
|
// 确保Key字段正确
|
|
if config.Key == "" {
|
|
config.Key = config.UUID
|
|
}
|
|
|
|
// 重新保存配置(相当于执行 SetCallback 操作)
|
|
err := SaveMessageCallbackConfig(&config)
|
|
if err != nil {
|
|
log.Errorf("✗ 重新激活回调失败 [UUID: %s]: %v", config.UUID, err)
|
|
} else {
|
|
log.Infof("✓ 重新激活回调成功 [UUID: %s] -> %s", config.UUID, config.CallbackURL)
|
|
successCount++
|
|
}
|
|
}
|
|
|
|
log.Infof("========================================")
|
|
log.Infof("回调配置激活完成: 成功 %d/%d", successCount, len(configs))
|
|
log.Infof("========================================")
|
|
}
|
|
|
|
// checkAndReconnect 检查并在需要时重新连接
|
|
func checkAndReconnect() error {
|
|
if MysqlDB == nil {
|
|
InitDB() // 初始化连接
|
|
}
|
|
|
|
// Ping数据库,验证连接是否有效
|
|
if err := MysqlDB.DB().Ping(); err != nil {
|
|
log.Error("Database connection lost, reconnecting...")
|
|
InitDB() // 重新连接
|
|
if MysqlDB == nil {
|
|
return errors.New("failed to reconnect to database")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Command 更新命令
|
|
func UpdateCommand(uuid string, key string, intValue int, strValue string) (bool, error) {
|
|
fmt.Println("UpdateCommand uuid:", uuid, "key:", key, "intValue:", intValue, "strValue:", strValue)
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return false, err
|
|
}
|
|
commandInfo := &table.Command{
|
|
UUID: uuid,
|
|
}
|
|
if err := MysqlDB.Model(commandInfo).Where("uuid = ?", uuid).First(&commandInfo).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
commandInfo.UUID = uuid
|
|
commandInfo.A301Str = ""
|
|
if err := MysqlDB.Create(&commandInfo).Error; err != nil {
|
|
// 创建失败
|
|
return false, err
|
|
}
|
|
// 创建成功,继续执行
|
|
}
|
|
// 错误
|
|
return false, err
|
|
}
|
|
// 记录找到
|
|
if key == "A101" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a101": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A102" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a102": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A103" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a103": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A104" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a104": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A104Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a104_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A105" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a105": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A106" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a106": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A107" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a107": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A109" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a109": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A111" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a111": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A116" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a116": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A116Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a116_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A118" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a118": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A118Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a118_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A301" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a301": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A301Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a301_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A401" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a401": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A402" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a402": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A403" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a403": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A601" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a601": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A801" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a801": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B001" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b001": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B001Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b001_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "A811" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"a811": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B002" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b002": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B002Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b002_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B003" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b003": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B003Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b003_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B004" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b004": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B004Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b004_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B005" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b005": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B005Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b005_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B006" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b006": intValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
if key == "B006Str" {
|
|
MysqlDB.Model(&table.Command{}).Where("uuid = ? ", uuid).Updates(map[string]interface{}{
|
|
"b006_str": strValue,
|
|
})
|
|
return true, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
// Command 根据 uuid 查询命令
|
|
func QueryCommand(uuid string) (table.Command, error) {
|
|
commandInfo := &table.Command{
|
|
UUID: uuid,
|
|
}
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return *commandInfo, err
|
|
}
|
|
|
|
if err := MysqlDB.Model(commandInfo).Where("uuid = ?", uuid).First(&commandInfo).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
commandInfo.UUID = uuid
|
|
commandInfo.A118Str = "词1,词2,词3"
|
|
commandInfo.A116Str = ""
|
|
commandInfo.A301Str = ""
|
|
commandInfo.B001Str = ""
|
|
commandInfo.B002Str = ""
|
|
commandInfo.B003Str = ""
|
|
if err := MysqlDB.Create(&commandInfo).Error; err != nil {
|
|
// 创建失败
|
|
return *commandInfo, err
|
|
}
|
|
// 创建成功,继续执行
|
|
}
|
|
// 错误
|
|
return *commandInfo, err
|
|
}
|
|
// 记录找到
|
|
return *commandInfo, nil
|
|
}
|
|
|
|
// 提交登录日志
|
|
func SetLoginLog(loginType string, acc *srv.WXAccount, errMsg string, state int32) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
var userName string
|
|
userInfo := acc.GetUserInfo()
|
|
if len(userInfo.LoginDataInfo.UserName) > 0 {
|
|
userName = userInfo.LoginDataInfo.UserName
|
|
} else {
|
|
userName = userInfo.WxId
|
|
}
|
|
|
|
// 更新登录时间信息
|
|
UpdateLoginTimeInfo(userInfo)
|
|
|
|
userLog := &table.UserLoginLog{
|
|
UUId: userInfo.UUID,
|
|
UserName: userName,
|
|
NickName: userInfo.NickName,
|
|
LoginType: loginType,
|
|
RetCode: state,
|
|
ErrMsg: errMsg,
|
|
}
|
|
userLog.TargetIp = srvconfig.GlobalSetting.TargetIp
|
|
MysqlDB.Save(userLog)
|
|
}
|
|
|
|
// UpdateLoginTimeInfo 更新用户的登录时间相关信息
|
|
func UpdateLoginTimeInfo(userInfo *baseinfo.UserInfo) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
_ = MysqlDB.Model(&table.UserInfoEntity{}).
|
|
Where("wxId = ? ", userInfo.WxId).
|
|
Updates(map[string]interface{}{
|
|
"device_create_time": userInfo.DeviceCreateTime,
|
|
"last_login_time": userInfo.LastLoginTime,
|
|
"last_auth_time": userInfo.LastAuthTime,
|
|
})
|
|
}
|
|
|
|
// 获取登录日志
|
|
func GetLoginJournal(userName string) []table.UserLoginLog {
|
|
|
|
logs := make([]table.UserLoginLog, 0)
|
|
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return logs
|
|
}
|
|
|
|
MysqlDB.Where("user_name=?", userName).Find(&logs)
|
|
|
|
return logs
|
|
}
|
|
|
|
// 获取登录错误信息
|
|
func GetUSerLoginErrMsg(userName string) string {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return ""
|
|
}
|
|
userInfoEntity := &table.UserInfoEntity{
|
|
WxId: userName,
|
|
}
|
|
MysqlDB.Model(userInfoEntity).First(userInfoEntity)
|
|
return userInfoEntity.ErrMsg
|
|
}
|
|
|
|
// 保存登录状态
|
|
func UpdateLoginStatus(userName string, state int32, errMsg string) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
data := make(map[string]interface{})
|
|
data["State"] = state //零值字段
|
|
data["ErrMsg"] = errMsg
|
|
v := GetUserInfoEntityByWxId(userName) // *table.UserInfoEntity
|
|
if v != nil && v.State != state {
|
|
MysqlDB.Model(&table.UserInfoEntity{
|
|
WxId: userName,
|
|
}).Update(data)
|
|
_ = PublishSyncMsgLoginState(userName, uint32(state))
|
|
}
|
|
}
|
|
|
|
// 保存初始化联系人结果
|
|
func UpdateInitContactStatus(uuid string, state int32) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
_ = MysqlDB.Model(&table.UserInfoEntity{}).
|
|
Where("uuid = ? ", uuid).
|
|
Updates(map[string]interface{}{
|
|
"initcontact": state,
|
|
})
|
|
}
|
|
|
|
// 查询初始化是否完成
|
|
func QueryInitContactStatus(uuid string) int32 {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return 1
|
|
}
|
|
|
|
var userInfoEntity table.UserInfoEntity
|
|
// 获取消息
|
|
if err := MysqlDB.Where("uuid = ?", uuid).First(&userInfoEntity).Error; err != nil {
|
|
return 1 // 发生其他错误
|
|
}
|
|
if userInfoEntity.InitContact == 0 {
|
|
fmt.Println("["+uuid+"]", "开始初始化联系人")
|
|
} else {
|
|
fmt.Println("["+uuid+"]", "无需初始化联系人")
|
|
}
|
|
return userInfoEntity.InitContact
|
|
}
|
|
|
|
// 更新同步消息Key
|
|
func UpdateSyncMsgKey() {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// 更新用户信息
|
|
func UpdateUserInfo(userInfo *baseinfo.UserInfo) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
if userInfo.WxId == "" {
|
|
userInfo.WxId = userInfo.GetUserName()
|
|
}
|
|
var userInfoEntity table.UserInfoEntity
|
|
SimpleCopyProperties(&userInfoEntity, userInfo)
|
|
userInfoEntity.AutoAuthKey = base64.StdEncoding.EncodeToString(userInfo.AutoAuthKey)
|
|
userInfoEntity.SyncKey = base64.StdEncoding.EncodeToString(userInfo.SyncKey)
|
|
userInfoEntity.FavSyncKey = base64.StdEncoding.EncodeToString(userInfo.FavSyncKey)
|
|
userInfoEntity.TargetIp = srvconfig.GlobalSetting.TargetIp
|
|
userInfoEntity.UserName = userInfo.LoginDataInfo.UserName
|
|
userInfoEntity.Password = userInfo.LoginDataInfo.PassWord
|
|
userInfoEntity.State = int32(userInfo.GetLoginState())
|
|
// userInfoEntity.Proxy = userInfo.ProxyInfo.ProxyUrl
|
|
userInfoEntity.ClientVersion = userInfo.ClientVersion
|
|
if !(int(userInfoEntity.ClientVersion) > 0) {
|
|
userInfoEntity.ClientVersion = baseinfo.ClientVersion
|
|
}
|
|
// log.Infof("更新用户信息:%v", userInfoEntity.ClientVersion)
|
|
MysqlDB.Model(new(table.UserInfoEntity)).Update(&userInfoEntity)
|
|
}
|
|
|
|
// 更新用户信息,手机号和微信号
|
|
func UpdateUserInfoByPhone(modUserInfo *wechat.ModUserInfo) {
|
|
// 用户信息为空
|
|
if modUserInfo == nil {
|
|
return
|
|
}
|
|
// 微信id 为空
|
|
if modUserInfo.GetUserName() == nil {
|
|
return
|
|
}
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
wxId := modUserInfo.GetUserName().GetStr()
|
|
bindmobile := ""
|
|
if modUserInfo.GetBindMobile() != nil {
|
|
bindmobile = modUserInfo.GetBindMobile().GetStr()
|
|
}
|
|
alias := modUserInfo.GetAlias()
|
|
MysqlDB.Model(new(table.UserInfoEntity)).Where("wxId = ?", wxId).Updates(map[string]interface{}{
|
|
"bindmobile": bindmobile,
|
|
"alias": alias,
|
|
})
|
|
// wx_id
|
|
MysqlDB.Model(new(table.LicenseKey)).Where("wx_id = ?", wxId).Updates(map[string]interface{}{
|
|
"bindmobile": bindmobile,
|
|
"alias": alias,
|
|
})
|
|
}
|
|
|
|
// SaveUserInfo 保存用户信息
|
|
func SaveUserInfo(userInfo *baseinfo.UserInfo) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
|
|
if userInfo.WxId == "" {
|
|
userInfo.WxId = userInfo.GetUserName()
|
|
}
|
|
var userInfoEntity table.UserInfoEntity
|
|
SimpleCopyProperties(&userInfoEntity, userInfo)
|
|
userInfoEntity.AutoAuthKey = base64.StdEncoding.EncodeToString(userInfo.AutoAuthKey)
|
|
userInfoEntity.SyncKey = base64.StdEncoding.EncodeToString(userInfo.SyncKey)
|
|
userInfoEntity.FavSyncKey = base64.StdEncoding.EncodeToString(userInfo.FavSyncKey)
|
|
userInfoEntity.TargetIp = srvconfig.GlobalSetting.TargetIp
|
|
userInfoEntity.UserName = userInfo.LoginDataInfo.UserName
|
|
userInfoEntity.Password = userInfo.LoginDataInfo.PassWord
|
|
|
|
MysqlDB.Save(&userInfoEntity)
|
|
//判断是62还是A16
|
|
if strings.HasPrefix(userInfo.LoginDataInfo.LoginData, "A") {
|
|
//A16存redis
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", userInfo.WxId)
|
|
error := SETExpirationObj(key, &userInfo.DeviceInfoA16, 60*60*24*15)
|
|
if error != nil {
|
|
log.Error("保存redis is error=" + error.Error())
|
|
}
|
|
} else {
|
|
//62存DB
|
|
var deviceInfoEntity table.DeviceInfoEntity
|
|
deviceInfoEntity.WxId = userInfo.WxId
|
|
SimpleCopyProperties(&deviceInfoEntity, userInfo.DeviceInfo)
|
|
deviceInfoEntity.SoftTypeXML = base64.StdEncoding.EncodeToString([]byte(deviceInfoEntity.SoftTypeXML))
|
|
deviceInfoEntity.ClientCheckDataXML = base64.StdEncoding.EncodeToString([]byte(deviceInfoEntity.ClientCheckDataXML))
|
|
MysqlDB.Save(&deviceInfoEntity)
|
|
}
|
|
}
|
|
|
|
// 获取所有登录用户
|
|
func QueryListUserInfo() []table.UserInfoEntity {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return make([]table.UserInfoEntity, 0)
|
|
}
|
|
// 判断 srvconfig.GlobalSetting.TargetIp 相同
|
|
var userInfoEntity = make([]table.UserInfoEntity, 0)
|
|
MysqlDB.Where("state = ? OR (state = 2 AND wxId IS NOT NULL AND wxId != '' AND autoauthkey IS NOT NULL AND autoauthkey != '')", 1).Find(&userInfoEntity)
|
|
for _, v := range userInfoEntity {
|
|
if v.State == 2 {
|
|
v.State = 1
|
|
}
|
|
}
|
|
// 过滤
|
|
var newUserInfoEntity = make([]table.UserInfoEntity, 0)
|
|
for _, v := range userInfoEntity {
|
|
if srvconfig.GlobalSetting.TargetIp == "" || v.TargetIp == srvconfig.GlobalSetting.TargetIp {
|
|
newUserInfoEntity = append(newUserInfoEntity, v)
|
|
}
|
|
}
|
|
return newUserInfoEntity
|
|
}
|
|
|
|
// 获取所有用户
|
|
func QueryUserList() []table.UserInfoEntity {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return make([]table.UserInfoEntity, 0)
|
|
}
|
|
var userInfoEntity = make([]table.UserInfoEntity, 0)
|
|
MysqlDB.Where("1=1").Find(&userInfoEntity)
|
|
return userInfoEntity
|
|
}
|
|
|
|
// GetUserInfoEntity 获取登录信息
|
|
func GetUserInfoEntity(uuid string) *table.UserInfoEntity {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
var userInfoEntity table.UserInfoEntity
|
|
if err := MysqlDB.Where("uuid=?", uuid).First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
return &userInfoEntity
|
|
}
|
|
|
|
// GetUserInfoEntity 获取登录信息
|
|
func GetUserInfoEntityByWxId(wxId string) *table.UserInfoEntity {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
var userInfoEntity table.UserInfoEntity
|
|
if err := MysqlDB.Where("wxId=?", wxId).First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
return &userInfoEntity
|
|
}
|
|
|
|
// GetUserInfo 从数据库获取UserInfo
|
|
func GetUserInfo(uuid string) *baseinfo.UserInfo {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
userInfo := &baseinfo.UserInfo{}
|
|
var userInfoEntity table.UserInfoEntity
|
|
userInfoEntity.UUID = uuid
|
|
if err := MysqlDB.First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
var deviceInfoEntity table.DeviceInfoEntity
|
|
deviceInfoEntity.WxId = userInfoEntity.WxId
|
|
if err := MysqlDB.First(&deviceInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", userInfoEntity.WxId)
|
|
//判断是62还是A16
|
|
exists, _ := Exists(key)
|
|
if exists {
|
|
//A16存redis
|
|
deviceInfoA16 := &baseinfo.AndroidDeviceInfo{}
|
|
error := GETObj(key, &deviceInfoA16)
|
|
if error != nil {
|
|
log.Error("保存redis is error=" + error.Error())
|
|
}
|
|
userInfo.DeviceInfoA16 = deviceInfoA16
|
|
} else {
|
|
deviceInfo := &baseinfo.DeviceInfo{}
|
|
SimpleCopyProperties(deviceInfo, deviceInfoEntity)
|
|
decodeSoftTypeXML, _ := base64.StdEncoding.DecodeString(deviceInfo.SoftTypeXML)
|
|
deviceInfo.SoftTypeXML = string(decodeSoftTypeXML)
|
|
decodeClientCheckDataXML, _ := base64.StdEncoding.DecodeString(deviceInfo.ClientCheckDataXML)
|
|
deviceInfo.ClientCheckDataXML = string(decodeClientCheckDataXML)
|
|
userInfo.DeviceInfo = deviceInfo
|
|
}
|
|
SimpleCopyProperties(userInfo, userInfoEntity)
|
|
userInfo.AutoAuthKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.AutoAuthKey)
|
|
userInfo.SyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.SyncKey)
|
|
userInfo.FavSyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.FavSyncKey)
|
|
return userInfo
|
|
}
|
|
|
|
func GetUSerInfoByUUID(uuid string) *baseinfo.UserInfo {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
|
|
userInfo := &baseinfo.UserInfo{}
|
|
var userInfoEntity table.UserInfoEntity
|
|
userInfoEntity.UUID = uuid
|
|
|
|
if srvconfig.GlobalSetting.TargetIp != "" {
|
|
userInfoEntity.TargetIp = srvconfig.GlobalSetting.TargetIp
|
|
}
|
|
|
|
if err := MysqlDB.Model(&table.UserInfoEntity{}).Where(&userInfoEntity).First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
//判断是62还是A16
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", userInfoEntity.WxId)
|
|
exists, _ := Exists(key)
|
|
if exists {
|
|
//A16存redis
|
|
deviceInfoA16 := &baseinfo.AndroidDeviceInfo{}
|
|
error := GETObj(key, &deviceInfoA16)
|
|
if error != nil {
|
|
log.Error("保存redis is error=" + error.Error())
|
|
}
|
|
userInfo.DeviceInfoA16 = deviceInfoA16
|
|
} else {
|
|
var deviceInfoEntity table.DeviceInfoEntity
|
|
deviceInfoEntity.WxId = userInfoEntity.WxId
|
|
if err := MysqlDB.First(&deviceInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
deviceInfo := &baseinfo.DeviceInfo{}
|
|
SimpleCopyProperties(deviceInfo, deviceInfoEntity)
|
|
decodeSoftTypeXML, _ := base64.StdEncoding.DecodeString(deviceInfo.SoftTypeXML)
|
|
deviceInfo.SoftTypeXML = string(decodeSoftTypeXML)
|
|
decodeClientCheckDataXML, _ := base64.StdEncoding.DecodeString(deviceInfo.ClientCheckDataXML)
|
|
deviceInfo.ClientCheckDataXML = string(decodeClientCheckDataXML)
|
|
userInfo.DeviceInfo = deviceInfo
|
|
}
|
|
|
|
SimpleCopyProperties(userInfo, userInfoEntity)
|
|
userInfo.AutoAuthKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.AutoAuthKey)
|
|
userInfo.SyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.SyncKey)
|
|
userInfo.FavSyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.FavSyncKey)
|
|
userInfo.SetLoginState(uint32(userInfoEntity.State))
|
|
|
|
userInfo.ClientVersion = userInfoEntity.ClientVersion
|
|
if !(int(userInfo.ClientVersion) > 0) {
|
|
userInfo.ClientVersion = baseinfo.ClientVersion
|
|
userInfoEntity.ClientVersion = baseinfo.ClientVersion
|
|
}
|
|
return userInfo
|
|
}
|
|
|
|
// GetUserInfoByWXID 从数据库获取UserInfo
|
|
func GetUserInfoByWXID(wxID string) *baseinfo.UserInfo {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
userInfo := &baseinfo.UserInfo{}
|
|
var userInfoEntity table.UserInfoEntity
|
|
userInfoEntity.WxId = wxID
|
|
if err := MysqlDB.First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", wxID)
|
|
exists, _ := Exists(key)
|
|
if exists {
|
|
//A16存redis
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", wxID)
|
|
deviceInfoA16 := &baseinfo.AndroidDeviceInfo{}
|
|
error := GETObj(key, &deviceInfoA16)
|
|
if error != nil {
|
|
log.Error("获取redis is error=" + error.Error())
|
|
}
|
|
userInfo.DeviceInfoA16 = deviceInfoA16
|
|
} else {
|
|
var deviceInfoEntity table.DeviceInfoEntity
|
|
deviceInfoEntity.WxId = userInfoEntity.WxId
|
|
if err := MysqlDB.First(&deviceInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
deviceInfo := &baseinfo.DeviceInfo{}
|
|
SimpleCopyProperties(deviceInfo, deviceInfoEntity)
|
|
decodeSoftTypeXML, _ := base64.StdEncoding.DecodeString(deviceInfo.SoftTypeXML)
|
|
deviceInfo.SoftTypeXML = string(decodeSoftTypeXML)
|
|
decodeClientCheckDataXML, _ := base64.StdEncoding.DecodeString(deviceInfo.ClientCheckDataXML)
|
|
deviceInfo.ClientCheckDataXML = string(decodeClientCheckDataXML)
|
|
userInfo.DeviceInfo = deviceInfo
|
|
}
|
|
SimpleCopyProperties(userInfo, userInfoEntity)
|
|
userInfo.AutoAuthKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.AutoAuthKey)
|
|
userInfo.SyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.SyncKey)
|
|
userInfo.FavSyncKey, _ = base64.StdEncoding.DecodeString(userInfoEntity.FavSyncKey)
|
|
return userInfo
|
|
}
|
|
|
|
// GetDeviceInfo 根据URLkey查询DeviceInfo 查不到返回nil
|
|
func GetDeviceInfo(queryKey string) *baseinfo.DeviceInfo {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
var userInfoEntity table.UserInfoEntity
|
|
MysqlDB.Where("querykey = ?", "queryKey").First(&userInfoEntity)
|
|
var count int
|
|
MysqlDB.Model(&table.UserInfoEntity{}).Where("querykey = ?", "queryKey").Count(&count)
|
|
if count == 0 {
|
|
return nil
|
|
}
|
|
|
|
deviceInfo := &baseinfo.DeviceInfo{}
|
|
_ = SimpleCopyProperties(deviceInfo, userInfoEntity)
|
|
return deviceInfo
|
|
}
|
|
|
|
// SimpleCopyProperties 拷贝属性
|
|
func SimpleCopyProperties(dst, src interface{}) (err error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
// 防止意外panic
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
err = fmt.Errorf("%v", e)
|
|
}
|
|
}()
|
|
|
|
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
|
|
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
|
|
|
|
// dst必须结构体指针类型
|
|
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
|
|
return errors.New("dst type should be a struct pointer")
|
|
}
|
|
|
|
// src必须为结构体或者结构体指针
|
|
if srcType.Kind() == reflect.Ptr {
|
|
srcType, srcValue = srcType.Elem(), srcValue.Elem()
|
|
}
|
|
if srcType.Kind() != reflect.Struct {
|
|
return errors.New("src type should be a struct or a struct pointer")
|
|
}
|
|
|
|
// 取具体内容
|
|
dstType, dstValue = dstType.Elem(), dstValue.Elem()
|
|
|
|
// 属性个数
|
|
propertyNums := dstType.NumField()
|
|
|
|
for i := 0; i < propertyNums; i++ {
|
|
// 属性
|
|
property := dstType.Field(i)
|
|
// 待填充属性值
|
|
propertyValue := srcValue.FieldByName(property.Name)
|
|
|
|
// 无效,说明src没有这个属性 || 属性同名但类型不同
|
|
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
|
|
// 确保 propertyValue 是有效的并且类型支持 Name() 方法
|
|
if propertyValue.IsValid() && propertyValue.Kind() == reflect.Struct {
|
|
if propertyValue.Type().Name() == "LocalTime" {
|
|
// 数据库字段为 LocalTime 类型结构体
|
|
if !dstValue.Field(i).CanSet() {
|
|
continue
|
|
}
|
|
dstValue.Field(i).Set(propertyValue.Field(0))
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if dstValue.Field(i).CanSet() {
|
|
dstValue.Field(i).Set(propertyValue)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsLicenseBind 查询许可证是否绑定
|
|
func IsLicenseBind(license string) (*table.LicenseKey, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
var licenseKey table.LicenseKey
|
|
result := MysqlDB.Where("license = ? AND status = 1", license).First(&licenseKey)
|
|
if result.Error != nil {
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
return nil, nil
|
|
}
|
|
return nil, result.Error
|
|
}
|
|
return &licenseKey, nil
|
|
}
|
|
|
|
// UpdateLicenseBindStatus 更新许可证绑定状态
|
|
func UpdateLicenseBindStatus(deviceToken, license string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
result := MysqlDB.Model(&table.LicenseKey{}).Where("license = ? ", license).Updates(map[string]interface{}{
|
|
"device_token": deviceToken,
|
|
})
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 如果没有过期时间,则生成过期时间
|
|
func UpdateLicenseExpiryDate(license string) (*table.LicenseKey, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
var licenseKey table.LicenseKey
|
|
|
|
resultObj := MysqlDB.Where("license = ?", license).First(&licenseKey)
|
|
if resultObj.Error != nil {
|
|
if resultObj.Error == gorm.ErrRecordNotFound {
|
|
return &licenseKey, nil
|
|
}
|
|
return &licenseKey, resultObj.Error
|
|
}
|
|
if licenseKey.ExpiryDate == "" {
|
|
// 生成过期时间
|
|
licenseKey.ExpiryDate = generateExpiryDate3(licenseKey.Type)
|
|
// 生成开始时间
|
|
licenseKey.StartDate = time.Now().Format("2006-01-02 15:04:05")
|
|
result := MysqlDB.Model(&table.LicenseKey{}).Where("license = ?", license).Updates(map[string]interface{}{
|
|
"expiry_date": licenseKey.ExpiryDate,
|
|
"start_date": licenseKey.StartDate,
|
|
})
|
|
|
|
if result.Error != nil {
|
|
return &licenseKey, result.Error
|
|
}
|
|
}
|
|
|
|
return &licenseKey, nil
|
|
}
|
|
|
|
// 绑定微信
|
|
func UpdateLicenseBindWxid(wxid, nickName, license string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
MysqlDB.Model(&table.LicenseKey{}).Where("license = ? AND status = 0", license).Updates(map[string]interface{}{
|
|
"status": 1,
|
|
"wx_id": wxid,
|
|
"nick_name": nickName,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// HasLicense 查询是否存在许可证
|
|
func HasLicense(license string) (*table.LicenseKey, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
var licenseKey table.LicenseKey
|
|
result := MysqlDB.Where("license = ?", license).First(&licenseKey)
|
|
if result.Error != nil {
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
return nil, nil
|
|
}
|
|
return nil, result.Error
|
|
}
|
|
return &licenseKey, nil
|
|
}
|
|
|
|
// CheckExpiry 检查日期是否过期
|
|
func CheckExpiry(expiryDateString string, itype int) bool {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return false
|
|
}
|
|
//1日 7 周 30月 90季 180 半年 365年 30000
|
|
types := []int{1, 7, 30, 90, 180, 365, 30000}
|
|
// 判断 itype 在 types 中
|
|
isType := false
|
|
for _, t := range types {
|
|
if t == itype {
|
|
isType = true
|
|
break
|
|
}
|
|
}
|
|
// type 类型存在 同时 不存在 过期时间
|
|
if isType && expiryDateString == "" {
|
|
return false
|
|
}
|
|
// 将字符串解析为时间对象
|
|
expiryDate, err := time.Parse("2006-01-02", expiryDateString)
|
|
if err != nil {
|
|
fmt.Println("Error parsing expiry date:", err)
|
|
return false
|
|
}
|
|
|
|
// 获取当前时间
|
|
currentTime := time.Now()
|
|
|
|
// 比较过期日期和当前日期
|
|
if expiryDate.Before(currentTime) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func generateExpiryDate(expiryDays int) string {
|
|
// 获取当前日期
|
|
currentDate := time.Now()
|
|
// 计算有效期后的日期
|
|
expiryDate := currentDate.AddDate(0, 0, expiryDays)
|
|
// 格式化日期字符串
|
|
expiryDateStr := expiryDate.Format("2006-01-02")
|
|
return expiryDateStr
|
|
}
|
|
|
|
// generateExpiryDate 根据特定时间段生成有效期日期
|
|
func generateExpiryDate3(duration int) string {
|
|
// 获取当前日期
|
|
currentDate := time.Now()
|
|
|
|
var expiryDate time.Time
|
|
|
|
// 根据输入的周期计算有效期后的日期
|
|
switch duration {
|
|
case 1:
|
|
expiryDate = currentDate.AddDate(0, 0, 1)
|
|
case 7:
|
|
expiryDate = currentDate.AddDate(0, 0, 7)
|
|
case 30:
|
|
expiryDate = currentDate.AddDate(0, 1, 0)
|
|
case 90:
|
|
expiryDate = currentDate.AddDate(0, 3, 0)
|
|
case 180:
|
|
expiryDate = currentDate.AddDate(0, 6, 0)
|
|
case 365:
|
|
expiryDate = currentDate.AddDate(1, 0, 0)
|
|
case 30000:
|
|
expiryDate = currentDate.AddDate(100, 0, 0)
|
|
default:
|
|
// 默认过期,时间为当前日期的前10天
|
|
expiryDate = currentDate.AddDate(0, 0, -10)
|
|
}
|
|
|
|
// 格式化日期字符串
|
|
expiryDateStr := expiryDate.Format("2006-01-02")
|
|
return expiryDateStr
|
|
}
|
|
|
|
//func generateActivationCode(length int, count int) []string {
|
|
// activationCodes := make([]string, count)
|
|
//
|
|
// for i := 0; i < count; i++ {
|
|
// code := generateSingleActivationCode()
|
|
// activationCodes[i] = code
|
|
// }
|
|
//
|
|
// return activationCodes
|
|
//}
|
|
|
|
func generateSingleActivationCode() string {
|
|
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
var sb strings.Builder
|
|
for i := 0; i < 20; i++ {
|
|
sb.WriteByte(chars[rand.Intn(len(chars))])
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// generateRandomString 生成指定长度的随机字符串
|
|
func generateRandomString(length int) string {
|
|
// 设置种子(仅需设置一次)
|
|
rand.Seed(time.Now().UnixNano())
|
|
// 定义字符集
|
|
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
var builder strings.Builder
|
|
for i := 0; i < length; i++ {
|
|
builder.WriteByte(charset[rand.Intn(len(charset))]) // 从字符集中随机选择一个字符
|
|
}
|
|
return builder.String()
|
|
}
|
|
|
|
func CreateLicense(count, expiryDays int) string {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return ""
|
|
}
|
|
ExpiryDate := generateExpiryDate(expiryDays)
|
|
licenses := make([]string, 0, count)
|
|
for {
|
|
if count == 0 {
|
|
break
|
|
}
|
|
if len(licenses) >= count {
|
|
break
|
|
}
|
|
//key := generateSingleActivationCode()
|
|
// key := guuid.New().String()
|
|
key := "HB" + generateRandomString(10)
|
|
licenseKey := table.LicenseKey{
|
|
Status: 0,
|
|
License: key,
|
|
ExpiryDate: ExpiryDate,
|
|
}
|
|
result := MysqlDB.Create(&licenseKey)
|
|
if result.Error != nil {
|
|
if mysqlErr, ok := result.Error.(*mysql.MySQLError); ok {
|
|
if mysqlErr.Number == 1062 {
|
|
// 唯一性 License 冲突
|
|
fmt.Println("License key already exists!")
|
|
continue
|
|
}
|
|
}
|
|
fmt.Println("failed to create license key")
|
|
break
|
|
}
|
|
|
|
licenses = append(licenses, key)
|
|
}
|
|
return strings.Join(licenses, "\n\t")
|
|
}
|
|
|
|
func CreateLicense3(count, itype int) string {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return ""
|
|
}
|
|
// ExpiryDate := generateExpiryDate(itype)
|
|
licenses := make([]string, 0, count)
|
|
for {
|
|
if count == 0 {
|
|
break
|
|
}
|
|
if len(licenses) >= count {
|
|
break
|
|
}
|
|
//key := generateSingleActivationCode()
|
|
// key := guuid.New().String()
|
|
key := "HB" + generateRandomString(10)
|
|
licenseKey := table.LicenseKey{
|
|
Status: 0,
|
|
License: key,
|
|
ExpiryDate: "",
|
|
Type: itype,
|
|
}
|
|
result := MysqlDB.Create(&licenseKey)
|
|
if result.Error != nil {
|
|
if mysqlErr, ok := result.Error.(*mysql.MySQLError); ok {
|
|
if mysqlErr.Number == 1062 {
|
|
// 唯一性 License 冲突
|
|
fmt.Println("License key already exists!")
|
|
continue
|
|
}
|
|
}
|
|
fmt.Println("failed to create license key")
|
|
break
|
|
}
|
|
|
|
licenses = append(licenses, key)
|
|
}
|
|
return strings.Join(licenses, "\n\t")
|
|
|
|
}
|
|
|
|
func DelayLicense(m req.DelayAuthKeyModel) (string, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return "", err
|
|
}
|
|
origin, err := HasLicense(m.Key)
|
|
if origin == nil || err != nil {
|
|
return "", errors.New(fmt.Sprintf("%s 该 key 无效! 请 检查正确性 或 联系管理员生成", m.Key))
|
|
}
|
|
|
|
expiryDateStr := origin.ExpiryDate
|
|
if m.Days > 0 {
|
|
// 获取当前的过期日期
|
|
originDate, err := time.Parse("2006-01-02", origin.ExpiryDate)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// 计算延期后的日期
|
|
expiryDate := originDate.AddDate(0, 0, m.Days)
|
|
// 格式化日期字符串
|
|
expiryDateStr = expiryDate.Format("2006-01-02")
|
|
} else {
|
|
expiryDateStr = m.ExpiryDate
|
|
}
|
|
|
|
result := MysqlDB.Model(&table.LicenseKey{}).
|
|
Where("license = ?", origin.License).
|
|
Updates(map[string]interface{}{
|
|
"expiry_date": expiryDateStr,
|
|
})
|
|
|
|
if result.Error != nil {
|
|
return "", result.Error
|
|
}
|
|
return expiryDateStr, nil
|
|
}
|
|
|
|
func DeleteLicense(key string, opt int) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
has, err := HasLicense(key)
|
|
if has == nil || err != nil {
|
|
return errors.New(fmt.Sprintf("%s 该 key 无效! 请 检查正确性 或 联系管理员生成", key))
|
|
}
|
|
|
|
// 目前仅支持 0 1 2 三个删除操作 新增不删除授权码 删除userinfo deviceinfo 以及 登录日志3
|
|
if opt < 0 || opt > 3 {
|
|
return errors.New("不存在该授权码 删除操作")
|
|
}
|
|
|
|
if opt != 3 {
|
|
// 删除 license_key 数据库表的授权码信息
|
|
err = MysqlDB.Where("license = ?", key).Delete(&table.LicenseKey{}).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if opt == 0 { // 仅删除 License 信息
|
|
return err
|
|
}
|
|
|
|
// op=1 时, 删除该 key 授权码对应的 UserInfoEntity DeviceInfoEntity
|
|
if has.Status == 0 || len(strings.TrimSpace(has.WxId)) == 0 {
|
|
// 该授权码还没有绑定微信号
|
|
return nil
|
|
}
|
|
|
|
// 删除 user_info_entity 数据库表的数据
|
|
_ = MysqlDB.Where("wxId = ?", has.WxId).Delete(&table.UserInfoEntity{}).Error
|
|
// 删除 device_info_entity 数据库表的数据
|
|
_ = MysqlDB.Where("wxid = ?", has.WxId).Delete(&table.DeviceInfoEntity{}).Error
|
|
|
|
if opt == 1 {
|
|
return nil
|
|
}
|
|
|
|
// 删除 UserLoginLog 数据库表的数据
|
|
_ = MysqlDB.Where("user_name = ?", has.WxId).Delete(&table.UserLoginLog{}).Error
|
|
|
|
return nil
|
|
}
|
|
|
|
// 禁用1 启用0
|
|
func DisableLicense(key string, opt int) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
result := MysqlDB.Model(&table.LicenseKey{}).
|
|
Where("license = ?", key).
|
|
Updates(map[string]interface{}{
|
|
"is_banned": opt,
|
|
})
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 创建黑名单
|
|
func CreateSB(owner string, blacker map[string]string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
blackerJSON, err := json.Marshal(blacker)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 在这里执行 SQL 查询,直接将 blackerJSON 作为参数赋值给 Blacker 字段
|
|
record := table.BlackList{Owner: owner, Blacker: string(blackerJSON)}
|
|
result := MysqlDB.Create(&record)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
key := owner + "_blacklist"
|
|
SETExpirationObj(key, blacker, -1)
|
|
return nil
|
|
}
|
|
|
|
// 查询黑名单
|
|
func QuerySB(owner string) (*table.BlackList, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
var record table.BlackList
|
|
result := MysqlDB.Where("owner = ?", owner).First(&record)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
return &record, nil
|
|
}
|
|
|
|
// 更新黑名单
|
|
func UpdateSB(owner string, blacker map[string]string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
record, err := QuerySB(owner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if record == nil {
|
|
CreateSB(owner, blacker)
|
|
return nil
|
|
}
|
|
blackerJSON, err := json.Marshal(blacker)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result := MysqlDB.Model(record).Update("Blacker", string(blackerJSON))
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
key := owner + "_blacklist"
|
|
SETExpirationObj(key, blacker, -1)
|
|
return nil
|
|
}
|
|
|
|
// 联系人操作
|
|
func SaveOrUpdateContact(contact *pb.ModContact, uuid string) error {
|
|
// 捕获 panic,防止程序崩溃
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
fmt.Printf("Recovered from panic: %v\n", r)
|
|
// 这里可以记录日志或者执行其他的恢复操作
|
|
}
|
|
}()
|
|
if contact == nil {
|
|
return errors.New("contact cannot be nil")
|
|
}
|
|
|
|
if contact.UserName == nil || contact.UserName.GetStr() == "" {
|
|
return errors.New("userName cannot be nil or empty")
|
|
}
|
|
|
|
contactJson, err := json.Marshal(contact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
m := getContactMutex(uuid)
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
|
|
combinedKey := uuid + "-" + *contact.UserName.Str
|
|
|
|
// 进行更新或插入操作
|
|
err = MysqlDB.Where(table.ModContactDB{UserUUIDCombined: combinedKey}).
|
|
Assign(table.ModContactDB{Data: string(contactJson), UUID: uuid, UserName: *contact.UserName.Str}).
|
|
FirstOrCreate(&table.ModContactDB{}).Error
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GetContact(userName string, uuid string) *pb.ModContact {
|
|
// m := getContactMutex(uuid)
|
|
// m.Lock()
|
|
// defer m.Unlock()
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
var contactDB table.ModContactDB
|
|
combinedKey := uuid + "-" + userName
|
|
|
|
result := MysqlDB.First(&contactDB, "user_uuid_combined = ?", combinedKey)
|
|
|
|
if gorm.IsRecordNotFoundError(result.Error) {
|
|
return nil
|
|
}
|
|
if result.Error != nil {
|
|
return nil
|
|
}
|
|
|
|
var contact pb.ModContact
|
|
err := json.Unmarshal([]byte(contactDB.Data), &contact)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &contact
|
|
}
|
|
|
|
// 删除联系人
|
|
func DeleteContact(userName string, uuid string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
combinedKey := uuid + "-" + userName
|
|
|
|
result := MysqlDB.Where("user_uuid_combined = ?", combinedKey).Delete(&table.ModContactDB{})
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 消息操作
|
|
func SaveMsg(msg pb.AddMsg, uuid string) error {
|
|
if msg.NewMsgId == nil {
|
|
return errors.New("NewMsgId cannot be nil")
|
|
}
|
|
|
|
// 序列化消息为 JSON
|
|
msgJson, err := json.Marshal(msg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
|
|
combinedKey := uuid + fmt.Sprintf("-%d", *msg.NewMsgId)
|
|
|
|
// m := getContactMutex(uuid + "-msg")
|
|
// m.Lock()
|
|
// defer m.Unlock()
|
|
|
|
// 检查消息是否已存在
|
|
var existingMsg table.AddMsgDB
|
|
// 如果没有找到记录,会返回 gorm.ErrRecordNotFound
|
|
err = MysqlDB.Where("msg_uuid_combined = ?", combinedKey).First(&existingMsg).Error
|
|
if err == nil {
|
|
return nil // 已存在,不更新,直接返回
|
|
}
|
|
if !gorm.IsRecordNotFoundError(err) {
|
|
return err // 返回数据库操作中的其他错误
|
|
}
|
|
|
|
// 保存新消息
|
|
newMsg := &table.AddMsgDB{
|
|
UUID: uuid,
|
|
NewMsgId: msg.GetNewMsgId(),
|
|
MsgUUIDCombined: combinedKey,
|
|
Data: string(msgJson),
|
|
CreateTime: msg.GetCreateTime(),
|
|
}
|
|
|
|
if err := MysqlDB.Create(newMsg).Error; err != nil {
|
|
return err // 返回创建消息时的任何错误
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GetAndDeleteMsg(newMsgId int64, uuid string) *pb.AddMsg {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
combinedKey := uuid + fmt.Sprintf("-%d", newMsgId)
|
|
|
|
// m := getContactMutex(combinedKey)
|
|
// m.Lock()
|
|
// defer m.Unlock()
|
|
|
|
var msgDB table.AddMsgDB
|
|
// 获取消息
|
|
if err := MysqlDB.Where("msg_uuid_combined = ?", combinedKey).First(&msgDB).Error; err != nil {
|
|
if gorm.IsRecordNotFoundError(err) {
|
|
return nil // 消息不存在
|
|
}
|
|
return nil // 发生其他错误
|
|
}
|
|
|
|
// 删除消息
|
|
if err := MysqlDB.Delete(&msgDB).Error; err != nil {
|
|
return nil // 发生删除错误
|
|
}
|
|
|
|
// 解析消息内容
|
|
var msg pb.AddMsg
|
|
if err := json.Unmarshal([]byte(msgDB.Data), &msg); err != nil {
|
|
return nil // 解析错误
|
|
}
|
|
|
|
return &msg
|
|
}
|
|
|
|
// StartCleanupTask 定时清理消息
|
|
func StartCleanupTask() {
|
|
// 多个协议,启动一个即可
|
|
if srvconfig.GlobalSetting.OpenClearMsg == false {
|
|
return
|
|
}
|
|
ticker := time.NewTicker(3 * time.Minute)
|
|
go func() {
|
|
for range ticker.C {
|
|
cleanupOldMessages()
|
|
}
|
|
}()
|
|
}
|
|
|
|
func cleanupOldMessages() {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
cutoffTime := uint32(time.Now().Add(-3 * time.Minute).Unix())
|
|
|
|
tx := MysqlDB.Begin()
|
|
if tx.Error != nil {
|
|
return
|
|
}
|
|
|
|
if err := tx.Where("create_time < ?", cutoffTime).Delete(&table.AddMsgDB{}).Error; err != nil {
|
|
tx.Rollback()
|
|
return
|
|
}
|
|
|
|
tx.Commit()
|
|
log.Println("Old messages cleaned up successfully.")
|
|
}
|
|
|
|
// 消息回调配置相关操作
|
|
|
|
// SaveMessageCallbackConfig 保存或更新消息回调配置
|
|
func SaveMessageCallbackConfig(config *table.MessageCallbackConfig) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 确保UUID和Key字段为相同的值
|
|
if config.UUID == "" {
|
|
return errors.New("UUID字段不能为空")
|
|
}
|
|
// 设置Key字段和UUID保持一致
|
|
config.Key = config.UUID
|
|
|
|
var existingConfig table.MessageCallbackConfig
|
|
result := MysqlDB.Where("uuid = ?", config.UUID).First(&existingConfig)
|
|
|
|
if result.Error != nil {
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
// 记录不存在,创建新记录
|
|
log.Infof("[回调调试] 创建新配置记录 [UUID: %s]", config.UUID)
|
|
newConfig := table.MessageCallbackConfig{
|
|
UUID: config.UUID,
|
|
Key: config.UUID, // 确保Key和UUID相同
|
|
CallbackURL: config.CallbackURL,
|
|
Enabled: config.Enabled,
|
|
}
|
|
return MysqlDB.Create(&newConfig).Error
|
|
}
|
|
return result.Error
|
|
}
|
|
return MysqlDB.Model(&existingConfig).Updates(map[string]interface{}{
|
|
"key": config.UUID, // 更新Key字段
|
|
"callback_url": config.CallbackURL,
|
|
"enabled": config.Enabled,
|
|
}).Error
|
|
}
|
|
|
|
// GetMessageCallbackConfig 获取消息回调配置
|
|
func GetMessageCallbackConfig(uuid string) (*table.MessageCallbackConfig, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var config table.MessageCallbackConfig
|
|
result := MysqlDB.Where("uuid = ?", uuid).First(&config)
|
|
if result.Error != nil {
|
|
if result.Error == gorm.ErrRecordNotFound {
|
|
log.Debugf("[回调调试] 数据库中未找到配置 [UUID: %s]", uuid)
|
|
return nil, nil
|
|
}
|
|
log.Errorf("[回调调试] 查询配置出错 [UUID: %s]: %v", uuid, result.Error)
|
|
return nil, result.Error
|
|
}
|
|
return &config, nil
|
|
}
|
|
|
|
// DeleteMessageCallbackConfig 删除消息回调配置
|
|
func DeleteMessageCallbackConfig(uuid string) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return MysqlDB.Where("uuid = ?", uuid).Delete(&table.MessageCallbackConfig{}).Error
|
|
}
|
|
|
|
// GetAllEnabledCallbacks 获取所有启用的回调配置
|
|
func GetAllEnabledCallbacks() ([]table.MessageCallbackConfig, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var configs []table.MessageCallbackConfig
|
|
result := MysqlDB.Where("enabled = ?", true).Find(&configs)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return configs, nil
|
|
}
|
|
|
|
// GetActiveLicenseKeys 获取所有激活状态的卡密
|
|
func GetActiveLicenseKeys() ([]*table.LicenseKey, error) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var licenseKeys []*table.LicenseKey
|
|
err := MysqlDB.Where("status = ?", 1).Find(&licenseKeys).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return licenseKeys, nil
|
|
}
|
|
|
|
// SaveShortLinkStatusToDB 将短连接状态保存到数据库
|
|
func SaveShortLinkStatusToDB(uuid string, isEnabled bool) {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return
|
|
}
|
|
|
|
data := make(map[string]interface{})
|
|
data["short_link_enabled"] = isEnabled
|
|
|
|
// 更新用户信息表的短连接状态
|
|
_ = MysqlDB.Model(&table.UserInfoEntity{}).
|
|
Where("uuid = ? ", uuid).
|
|
Updates(data)
|
|
|
|
// 同时更新缓存
|
|
SaveShortLinkStatus(uuid, isEnabled)
|
|
}
|
|
|
|
// LoadShortLinkStatusFromDB 从数据库加载短连接状态
|
|
func LoadShortLinkStatusFromDB(uuid string) *ShortLinkStatus {
|
|
// 先尝试从缓存中获取
|
|
status := GetShortLinkStatus(uuid)
|
|
if status != nil {
|
|
return status
|
|
}
|
|
|
|
// 缓存中不存在,从数据库加载
|
|
if err := checkAndReconnect(); err != nil {
|
|
return nil
|
|
}
|
|
|
|
var userInfoEntity table.UserInfoEntity
|
|
if err := MysqlDB.Where("uuid = ?", uuid).First(&userInfoEntity).Error; err != nil {
|
|
return nil
|
|
}
|
|
|
|
// 创建短连接状态对象并缓存
|
|
status = &ShortLinkStatus{
|
|
IsEnabled: userInfoEntity.ShortLinkEnabled,
|
|
}
|
|
SaveShortLinkStatus(uuid, status.IsEnabled)
|
|
return status
|
|
}
|
|
|
|
// SaveDeviceInfo 保存设备信息到数据库
|
|
func SaveDeviceInfo(deviceInfo *table.DeviceInfoEntity) error {
|
|
// 检查并重新连接数据库
|
|
if err := checkAndReconnect(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 使用 Upsert 操作,如果记录存在则更新,不存在则插入
|
|
result := MysqlDB.Save(deviceInfo)
|
|
return result.Error
|
|
}
|