初始化项目
This commit is contained in:
8
trunk/framework/.idea/.gitignore
generated
vendored
Normal file
8
trunk/framework/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
9
trunk/framework/.idea/Framework.iml
generated
Normal file
9
trunk/framework/.idea/Framework.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
5
trunk/framework/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
5
trunk/framework/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" />
|
||||
</settings>
|
||||
</component>
|
||||
6
trunk/framework/.idea/misc.xml
generated
Normal file
6
trunk/framework/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
</project>
|
||||
8
trunk/framework/.idea/modules.xml
generated
Normal file
8
trunk/framework/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Framework.iml" filepath="$PROJECT_DIR$/.idea/Framework.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
trunk/framework/.idea/vcs.xml
generated
Normal file
6
trunk/framework/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
17
trunk/framework/README
Normal file
17
trunk/framework/README
Normal file
@@ -0,0 +1,17 @@
|
||||
v1.0版本,支持以下功能:
|
||||
1、项目中的各种基础功能;
|
||||
2、其中的managecenterMgr兼容旧版本的ManageCenter(2019-12-01之前)。
|
||||
3、新增日志记录功能(LogMgr 2020-03-09)
|
||||
4、新增监控功能(MonitorNewMgr 2020-03-09)
|
||||
5、新增短链功能(ShortUrlMgr 2020-03-09)
|
||||
|
||||
v2.0版本,支持以下功能:
|
||||
1、新的ManageCenter版本(2019-12-01之后)
|
||||
|
||||
v2.0.0.1
|
||||
LogMgr里面Log日志消息先进行base64编码之后再发送到mq,因为原消息有特殊符号,
|
||||
直接发送消息会导致消息返送之后,在腾讯mq收到消息之后数据会丢失,导致验签失败
|
||||
|
||||
v2.0.1.1
|
||||
新增屏蔽字处理forbidWordsMgr
|
||||
新增gameServerMgr
|
||||
9
trunk/framework/bash.exe.stackdump
Normal file
9
trunk/framework/bash.exe.stackdump
Normal file
@@ -0,0 +1,9 @@
|
||||
Stack trace:
|
||||
Frame Function Args
|
||||
000FFFFA328 0018006021E (00180252DED, 001802340A6, 000FFFFA328, 000FFFF9220)
|
||||
000FFFFA328 00180048859 (00000000000, 00000000000, 00000000000, 00000000000)
|
||||
000FFFFA328 00180048892 (00180252EA9, 000FFFFA1D8, 000FFFFA328, 00000000000)
|
||||
000FFFFA328 001800AF0D8 (00000000000, 00000000000, 00000000000, 00000000000)
|
||||
000FFFFA328 001800AF25D (000FFFFA340, 00000000000, 00000000000, 00000000000)
|
||||
000FFFFA5B0 001800B0673 (000FFFFA340, 00000000000, 00000000000, 00000000000)
|
||||
End of stack trace
|
||||
34
trunk/framework/configMgr/configMgr.go
Normal file
34
trunk/framework/configMgr/configMgr.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package configMgr
|
||||
|
||||
import (
|
||||
"goutil/configUtil"
|
||||
)
|
||||
|
||||
// 配置管理对象
|
||||
type ConfigManager struct {
|
||||
// 初始化方法列表
|
||||
initFuncList []func(*configUtil.XmlConfig) error
|
||||
}
|
||||
|
||||
// 注册初始化方法
|
||||
func (this *ConfigManager) RegisterInitFunc(initFunc func(*configUtil.XmlConfig) error) {
|
||||
this.initFuncList = append(this.initFuncList, initFunc)
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *ConfigManager) Init(configObj *configUtil.XmlConfig) error {
|
||||
for _, initFunc := range this.initFuncList {
|
||||
if err := initFunc(configObj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建配置管理对象
|
||||
func NewConfigManager() *ConfigManager {
|
||||
return &ConfigManager{
|
||||
initFuncList: make([]func(*configUtil.XmlConfig) error, 0, 8),
|
||||
}
|
||||
}
|
||||
13
trunk/framework/contextcheckMgr/resultmodel.go
Normal file
13
trunk/framework/contextcheckMgr/resultmodel.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package contextcheckMgr
|
||||
|
||||
type ResultModel struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Result ResultDetail `json:"result"`
|
||||
}
|
||||
|
||||
type ResultDetail struct {
|
||||
TaskId string `json:"taskId"`
|
||||
Action int `json:"action"`
|
||||
CensorType int `json:"censorType"`
|
||||
}
|
||||
126
trunk/framework/contextcheckMgr/textcheck.go
Normal file
126
trunk/framework/contextcheckMgr/textcheck.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package contextcheckMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
"goutil/securityUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
//接口密钥Id
|
||||
msecretId string = "c98276c73c122eaa65163fe431cbf7d4"
|
||||
//接口密钥key
|
||||
msecretKey string = "3d2b39f824fa2f992494e17be500e303"
|
||||
//业务ID
|
||||
mbusinessId string = "9559ce74b5c5d24f6b124799a53c7431"
|
||||
//接口请求地址
|
||||
mapiurl string = "http://as.dun.163.com/v3/text/check"
|
||||
//版本号
|
||||
mversion string = "v3.1"
|
||||
)
|
||||
|
||||
//参数设置
|
||||
func SetPara(secretId, secretKey, businessId, apiurl, version string) {
|
||||
msecretId = secretId
|
||||
msecretKey = secretKey
|
||||
mbusinessId = businessId
|
||||
mapiurl = apiurl
|
||||
mversion = version
|
||||
}
|
||||
|
||||
//content:用户发表内容
|
||||
//account:玩家账号(用户唯一标识)
|
||||
//nickname:角色名称
|
||||
//extStr1:角色区服名称
|
||||
//extStr2:UserId
|
||||
//ip:用户IP地址,建议抄送,辅助机审策略精准调优
|
||||
//extLon1:区服ID
|
||||
//返回值 code: 0:通过, 1:嫌疑,2:不通过
|
||||
//文本内容检测
|
||||
func TextCheck(content, account, nickname, extStr1, extStr2, ip string, extLon1 int64) (code int, err error) {
|
||||
//构造请求参数
|
||||
postDataDict := make(map[string]string)
|
||||
postDataDict["secretId"] = msecretId
|
||||
postDataDict["businessId"] = mbusinessId
|
||||
postDataDict["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
postDataDict["nonce"] = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(10000000000), 10)
|
||||
rawString := fmt.Sprintf("%v%v%v", account, postDataDict["timestamp"], content)
|
||||
postDataDict["dataId"] = securityUtil.Md5String(rawString, false)
|
||||
postDataDict["content"] = content
|
||||
postDataDict["version"] = mversion
|
||||
postDataDict["account"] = account
|
||||
postDataDict["nickname"] = nickname
|
||||
postDataDict["extLon1"] = strconv.FormatInt(extLon1, 10)
|
||||
// postDataDict["extLon2"] = extLon2
|
||||
postDataDict["extStr1"] = extStr1
|
||||
postDataDict["extStr2"] = extStr2
|
||||
postDataDict["ip"] = ip
|
||||
postDataDict["signature"] = getSignature(postDataDict)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
//请求接口
|
||||
statusCode, result, err := webUtil.PostMapData(mapiurl, postDataDict, header, transport)
|
||||
//定义错误信息
|
||||
var logMessage string
|
||||
|
||||
//post请求错误
|
||||
if err != nil {
|
||||
logMessage = fmt.Sprintf("TextCheck:,错误信息为:%s", err.Error())
|
||||
logUtil.ErrorLog(logMessage)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logMessage = fmt.Sprintf("TextCheck:%d is wrong", statusCode)
|
||||
logUtil.ErrorLog(logMessage)
|
||||
err = fmt.Errorf("TextCheck:%d is wrong", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
//反序列化结果
|
||||
var checkResponseObj *ResultModel
|
||||
err = json.Unmarshal(result, &checkResponseObj)
|
||||
if err != nil {
|
||||
logMessage = fmt.Sprintf("json.Unmarshal(checkResponseObj),err:%s", err.Error())
|
||||
logUtil.ErrorLog(logMessage)
|
||||
return
|
||||
}
|
||||
|
||||
//判断接口是否调用成功
|
||||
if checkResponseObj.Code != 200 {
|
||||
logMessage = fmt.Sprintf("TextCheck接口调用失败,ResultStatus %d", checkResponseObj.Code)
|
||||
err = fmt.Errorf("TextCheck接口调用失败,code:%d", checkResponseObj.Code)
|
||||
return
|
||||
}
|
||||
|
||||
//返回检测结果
|
||||
code = checkResponseObj.Result.Action
|
||||
return
|
||||
}
|
||||
|
||||
//生成签名字符串
|
||||
func getSignature(postDataDict map[string]string) string {
|
||||
var paramStr string
|
||||
keys := make([]string, 0, len(postDataDict))
|
||||
for k := range postDataDict {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
paramStr += key + postDataDict[key]
|
||||
}
|
||||
paramStr += msecretKey
|
||||
|
||||
return securityUtil.Md5String(paramStr, false)
|
||||
}
|
||||
49
trunk/framework/contextcheckMgr/textcheck_test.go
Normal file
49
trunk/framework/contextcheckMgr/textcheck_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package contextcheckMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCheck(t *testing.T) {
|
||||
//content, account, nickname, extLon1, extLon2, extStr1, extStr2, ip
|
||||
var content = "文本检查测试"
|
||||
var account = "000e6a6e-7cfc-4da7-81a2-ef3a5d24c586"
|
||||
var nickname = "不仅仅是喜欢"
|
||||
var extLon1 int64 = 10001
|
||||
//var extLon2 = "游戏内聊天"
|
||||
var extStr1 = "10001铁血丹心"
|
||||
var extStr2 = "5DF67DD225640567D4D0B6FE273262B5"
|
||||
var ip = "113.116.66.45"
|
||||
//设置完全正确的参数
|
||||
code, err := TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("检测完成,状态码为:%d\n", code)
|
||||
|
||||
content = "修炼发轮功"
|
||||
|
||||
code, err = TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("检测完成,状态码为:%d\n", code)
|
||||
|
||||
content = ""
|
||||
|
||||
code, err = TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("检测完成,状态码为:%d\n", code)
|
||||
}
|
||||
13
trunk/framework/dataSyncMgr/mysqlSync/doc.go
Normal file
13
trunk/framework/dataSyncMgr/mysqlSync/doc.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package mysqlSync
|
||||
|
||||
/*
|
||||
提供数据同步到mysql的方法。基本逻辑如下:
|
||||
1、对外接收数据,以追加的方式保存到大文件中。数据的格式为:header(4bytes)+content。
|
||||
2、启动独立的goroutine来从大文件中读取数据,并保存到数据库中。
|
||||
3、使用syncInfo.txt文件保存当前已经处理的文件的路径,以及下一次将要读取的文件的Offset。为了降低向syncInfo.txt文件中写入失败,
|
||||
导致需要从头开始同步数据,所以采用了在指定数目的范围内以追加形式来写入数据的方式;只有达到了指定数量才会将整个文件清空。
|
||||
|
||||
对于错误的处理方式,分为以下两种:
|
||||
1、文件错误:由于文件系统是本系统的核心,所以如果出现文件的读写出错,则需要终止整个进程,所以需要抛出panic。
|
||||
2、数据库错误:当数据库不可访问时,为了不影响整个外部进程的运行,故而不抛出panic,而只是通过monitorNewMgr.Report的方式来报告故障。
|
||||
*/
|
||||
100
trunk/framework/dataSyncMgr/mysqlSync/errorHandle.go
Normal file
100
trunk/framework/dataSyncMgr/mysqlSync/errorHandle.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package mysqlSync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"goutil/fileUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
// 记录错误sql命令的文件名
|
||||
con_Error_FileName = "errorFile.txt"
|
||||
)
|
||||
|
||||
// 定义处理错误命令的文件对象
|
||||
type errorFile struct {
|
||||
// 错误文件
|
||||
file *os.File
|
||||
|
||||
// 文件路径
|
||||
filePath string
|
||||
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
}
|
||||
|
||||
// 保存命令到错误文件
|
||||
// command: sql命令
|
||||
func (this *errorFile) SaveCommand(command string) {
|
||||
this.open()
|
||||
defer this.close()
|
||||
|
||||
// 覆盖写入
|
||||
this.file.Seek(0, 0)
|
||||
|
||||
// 写入命令
|
||||
_, err := this.file.WriteString(command)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.SaveCommand")
|
||||
err = fmt.Errorf("%s-Write %s to file failed:%s", prefix, command, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 清理残留数据
|
||||
this.file.Truncate(int64(len(command)))
|
||||
}
|
||||
|
||||
// 读取文件中命令
|
||||
func (this *errorFile) ReadCommand() string {
|
||||
this.open()
|
||||
defer this.close()
|
||||
|
||||
this.file.Seek(0, 0)
|
||||
content, err := ioutil.ReadAll(this.file)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.ReadCommand")
|
||||
err = fmt.Errorf("%s-Read command failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
return string(content)
|
||||
}
|
||||
|
||||
// 打开文件
|
||||
func (this *errorFile) open() {
|
||||
// 打开errorFile文件, 如果没有就创建
|
||||
var err error
|
||||
this.file, err = os.OpenFile(this.filePath, os.O_CREATE|os.O_RDWR, os.ModePerm|os.ModeTemporary)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.newErrorFile.os.OpenFile")
|
||||
err = fmt.Errorf("%s-Open File failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭文件
|
||||
func (this *errorFile) close() {
|
||||
this.file.Close()
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
func (this *errorFile) Delete() {
|
||||
fileUtil.DeleteFile(this.filePath)
|
||||
}
|
||||
|
||||
// 构造错误文件对象
|
||||
// _dirPath:文件路径
|
||||
// _identifier:唯一标识
|
||||
func newErrorFile(_dirPath string, _identifier string) *errorFile {
|
||||
_filePath := filepath.Join(_dirPath, con_Error_FileName)
|
||||
return &errorFile{
|
||||
filePath: _filePath,
|
||||
identifier: _identifier,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package logSqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 错误信息记录表是否已经初始化
|
||||
var ifSyncErrorInfoTableInited bool = false
|
||||
|
||||
// 同步的错误信息处理对象
|
||||
type syncErrorInfo struct {
|
||||
// 数据库连接对象
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// 初始化表信息
|
||||
func (this *syncErrorInfo) init() error {
|
||||
// 初始化表结构
|
||||
if ifSyncErrorInfoTableInited == false {
|
||||
err := this.initTable(this.db)
|
||||
if err == nil {
|
||||
ifSyncErrorInfoTableInited = true
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 把同步信息更新到数据库
|
||||
// data:待更新的数据
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncErrorInfo) AddErrorSql(tran *sql.Tx, data string, errMsg string) error {
|
||||
updateSql := "INSERT INTO `sync_error_info` (`SqlString`,`ExecuteTime`,`RetryCount`,`ErrMessage`) VALUES(?,?,?,?);"
|
||||
|
||||
var err error
|
||||
if tran != nil {
|
||||
_, err = tran.Exec(updateSql, data, time.Now(), 0, errMsg)
|
||||
} else {
|
||||
_, err = this.db.Exec(updateSql, data, time.Now(), 0, errMsg)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.AddErrorSql Error:%s", err.Error()))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化同步信息表结构
|
||||
// db:数据库连接对象
|
||||
func (this *syncErrorInfo) initTable(db *sql.DB) error {
|
||||
// 创建同步信息表
|
||||
createTableSql := `CREATE TABLE IF NOT EXISTS sync_error_info (
|
||||
Id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增Id',
|
||||
SqlString varchar(1024) NOT NULL COMMENT '执行的sql',
|
||||
ExecuteTime datetime NOT NULL COMMENT '最近一次执行时间',
|
||||
RetryCount int NOT NULL COMMENT '重试次数',
|
||||
ErrMessage text NULL COMMENT '执行错误的信息',
|
||||
PRIMARY KEY (Id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='未执行成功的sql数据';`
|
||||
if _, err := db.Exec(createTableSql); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.initTable Error:%s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建同步信息对象
|
||||
// _db:数据库连接对象
|
||||
// 返回值:
|
||||
// 同步信息对象
|
||||
func newSyncErrorInfoObject(_db *sql.DB) (result *syncErrorInfo, err error) {
|
||||
result = &syncErrorInfo{
|
||||
db: _db,
|
||||
}
|
||||
|
||||
err = result.init()
|
||||
|
||||
return result, err
|
||||
}
|
||||
204
trunk/framework/dataSyncMgr/mysqlSync/logSqlSync/syncObject.go
Normal file
204
trunk/framework/dataSyncMgr/mysqlSync/logSqlSync/syncObject.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package logSqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"Framework/dataSyncMgr/mysqlSync/sqlSync"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 同步对象定义
|
||||
type SyncObject struct {
|
||||
// 服务器组Id
|
||||
serverGroupId int32
|
||||
|
||||
// 同步数据的存储路径
|
||||
dirPath string
|
||||
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
|
||||
// 数据库对象
|
||||
dbObj *sql.DB
|
||||
|
||||
// 同步信息对象
|
||||
syncingInfoObj *syncingInfo
|
||||
|
||||
// 错误处理对象
|
||||
errorHandleObj *syncErrorInfo
|
||||
|
||||
// 同步对象
|
||||
syncObj *sqlSync.SyncObject
|
||||
}
|
||||
|
||||
// 初始化
|
||||
// baseObj:基础同步对象
|
||||
func (this *SyncObject) Init(baseObj *sqlSync.SyncObject) {
|
||||
this.syncObj = baseObj
|
||||
|
||||
// 初始化同步信息对象
|
||||
syncingInfoObj, err := newSyncingInfoObject(this.serverGroupId, this.dbObj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//// 初始化错误处理对象
|
||||
errorHandleObj, err := newSyncErrorInfoObject(this.dbObj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
this.syncingInfoObj = syncingInfoObj
|
||||
this.errorHandleObj = errorHandleObj
|
||||
|
||||
// 初始化当前处理的文件
|
||||
fileList := sqlSync.GetDataFileList(this.dirPath)
|
||||
filePath, _ := this.syncingInfoObj.GetSyncingInfo()
|
||||
if len(filePath) < 0 && len(fileList) > 0 {
|
||||
this.syncingInfoObj.Update(fileList[0], 0, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取正在同步的信息
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
func (this *SyncObject) GetSyncingInfo() (filePath string, offset int64) {
|
||||
return this.syncingInfoObj.GetSyncingInfo()
|
||||
}
|
||||
|
||||
// 更新
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
// tran:事务对象
|
||||
// 返回值:
|
||||
// error:错误对象
|
||||
func (this *SyncObject) Update(filePath string, offset int64, tx *sql.Tx) error {
|
||||
return this.syncingInfoObj.Update(filePath, offset, tx)
|
||||
}
|
||||
|
||||
// 同步一条sql语句
|
||||
// command:待执行的命令
|
||||
// filePath:保存路径
|
||||
// offset:文件偏移量
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) SyncOneSql(command string, filePath string, offset int64) {
|
||||
var err error
|
||||
for {
|
||||
err = sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) {
|
||||
// 保存sql到数据库
|
||||
err = this.syncToMysql(command, tran)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 保存进度信息到数据库
|
||||
err = this.syncingInfoObj.Update(filePath, offset, tran)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
isCommit = true
|
||||
return
|
||||
})
|
||||
|
||||
// 如果是连接出错,则仍然循环执行
|
||||
if err != nil {
|
||||
if sqlSync.CheckIfConnectionError(err.Error()) {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是数据库连接出错,则算是执行完成
|
||||
break
|
||||
}
|
||||
|
||||
// 如果存在错误,则循环尝试执行
|
||||
if err != nil {
|
||||
this.recordSqlError(command, filePath, offset, err.Error())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 同步数据到mysql中
|
||||
// command:sql语句
|
||||
// tx:事务处理对象
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) syncToMysql(command string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(command)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/logSqlSync/syncObject.syncToMysql error:%s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 错误处理
|
||||
// cmd:待执行的命令
|
||||
// filePath:保存路径
|
||||
// offset:文件偏移量
|
||||
// errMsg:错误信息
|
||||
func (this *SyncObject) recordSqlError(command string, filePath string, offset int64, errMsg string) {
|
||||
errMsg = sqlSync.GetSimpleErrorMessage(errMsg)
|
||||
|
||||
for {
|
||||
err := sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) {
|
||||
// 保存sql到数据库
|
||||
err = this.errorHandleObj.AddErrorSql(tran, command, errMsg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 保存进度信息到数据库
|
||||
err = this.syncingInfoObj.Update(filePath, offset, tran)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
isCommit = true
|
||||
return
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// 创新新的mysql同步对象
|
||||
// dirPath:存放数据的目录
|
||||
// identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// dbObj:数据库对象
|
||||
// syncingInfoObj:同步信息记录对象
|
||||
// errorHandleObj:错误处理对象
|
||||
// 返回值:
|
||||
// mysql同步对象
|
||||
func NewSyncObject(serverGroupId int32, dirPath, identifier string, dbObj *sql.DB) *SyncObject {
|
||||
dirPath = filepath.Join(dirPath, identifier)
|
||||
|
||||
// 创建更新目录
|
||||
err := os.MkdirAll(dirPath, os.ModePerm|os.ModeTemporary)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s-%s-make dir failed:%s", identifier, "SyncObject.newSyncObject.os.MkdirAll", err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 构造同步信息对象
|
||||
result := &SyncObject{
|
||||
serverGroupId: serverGroupId,
|
||||
dirPath: dirPath,
|
||||
identifier: identifier,
|
||||
dbObj: dbObj,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
186
trunk/framework/dataSyncMgr/mysqlSync/logSqlSync/syncingInfo.go
Normal file
186
trunk/framework/dataSyncMgr/mysqlSync/logSqlSync/syncingInfo.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package logSqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 同步信息表是否已经被初始化
|
||||
var ifSyncingTableInited bool = false
|
||||
|
||||
// 同步信息项,保存已经处理过的文件的信息
|
||||
type syncingModel struct {
|
||||
// 服务器组Id
|
||||
ServerGroupId int32
|
||||
|
||||
// 待处理文件的绝对路径
|
||||
FilePath string
|
||||
|
||||
// 待处理文件的偏移量
|
||||
FileOffset int64
|
||||
|
||||
// 更新时间
|
||||
UpdateTime time.Time
|
||||
}
|
||||
|
||||
// 同步信息对象
|
||||
type syncingInfo struct {
|
||||
// 服务器组Id
|
||||
ServerGroupId int32
|
||||
|
||||
// 同步信息项
|
||||
item *syncingModel
|
||||
|
||||
// 数据库连接对象
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// 获取同步信息
|
||||
// filePath:正在同步的文件
|
||||
// fileOffset:同步到的位置
|
||||
func (this *syncingInfo) GetSyncingInfo() (filePath string, fileOffset int64) {
|
||||
return this.item.FilePath, this.item.FileOffset
|
||||
}
|
||||
|
||||
// 更新正在同步的位置和文件信息
|
||||
// filePath:文件路径
|
||||
// offset:当前同步到的位置
|
||||
// tran:事务对象,可以为nil
|
||||
// 返回值:
|
||||
// error:处理的错误信息
|
||||
func (this *syncingInfo) Update(filePath string, offset int64, tran *sql.Tx) error {
|
||||
this.item.FilePath = filePath
|
||||
this.item.FileOffset = offset
|
||||
this.item.UpdateTime = time.Now()
|
||||
|
||||
// 更新到数据库
|
||||
return this.update(this.item, tran)
|
||||
}
|
||||
|
||||
// 初始化同步信息
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncingInfo) init() error {
|
||||
// 数据表初始化
|
||||
if ifSyncingTableInited == false {
|
||||
if err := this.initSyncingInfoTable(this.db); err == nil {
|
||||
ifSyncingTableInited = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 获取此表的同步信息
|
||||
data, exist, err := this.get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 如果同步信息不存在,则初始化一条到此表
|
||||
if exist == false {
|
||||
data = &syncingModel{
|
||||
ServerGroupId: this.ServerGroupId,
|
||||
FilePath: "",
|
||||
FileOffset: 0,
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
this.item = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// 初始化同步信息表结构
|
||||
// db:数据库连接对象
|
||||
func (this *syncingInfo) initSyncingInfoTable(db *sql.DB) error {
|
||||
// 创建同步信息表
|
||||
createTableSql := `CREATE TABLE IF NOT EXISTS syncing_info (
|
||||
ServerGroupId int NOT NULL COMMENT '服务器组Id',
|
||||
FilePath varchar(500) NOT NULL COMMENT '正在同步的文件路径',
|
||||
FileOffset bigint(20) NOT NULL COMMENT '偏移量',
|
||||
UpdateTime datetime NOT NULL COMMENT '最后一次更新时间',
|
||||
PRIMARY KEY (ServerGroupId)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在同步的文件信息';`
|
||||
if _, err := db.Exec(createTableSql); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.initSyncingInfoTable Error:%s", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从数据库获取数据
|
||||
// 返回值:
|
||||
// data:获取到的数据
|
||||
// exist:是否存在此数据
|
||||
// err:错误信息
|
||||
func (this *syncingInfo) get() (data *syncingModel, exist bool, err error) {
|
||||
//// 从数据库查询
|
||||
querySql := fmt.Sprintf("SELECT FilePath,FileOffset,UpdateTime FROM syncing_info WHERE ServerGroupId ='%v'", this.ServerGroupId)
|
||||
var rows *sql.Rows
|
||||
rows, err = this.db.Query(querySql)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() == false {
|
||||
exist = false
|
||||
return
|
||||
}
|
||||
exist = true
|
||||
|
||||
// 读取数据
|
||||
data = &syncingModel{
|
||||
ServerGroupId: this.ServerGroupId,
|
||||
}
|
||||
err = rows.Scan(&data.FilePath, &data.FileOffset, &data.UpdateTime)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 把同步信息更新到数据库
|
||||
// data:待更新的数据
|
||||
// tran:事务处理对象
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncingInfo) update(data *syncingModel, tran *sql.Tx) error {
|
||||
updateSql := "REPLACE INTO `syncing_info` SET `ServerGroupId` = ?, `FilePath` = ?,`FileOffset` = ?, `UpdateTime` = ?;"
|
||||
var err error
|
||||
if tran != nil {
|
||||
_, err = tran.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
|
||||
} else {
|
||||
_, err = this.db.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.update ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建同步信息对象
|
||||
// _dirPath:目录的路径
|
||||
// _identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// _db:数据库连接对象
|
||||
// 返回值:
|
||||
// 同步信息对象
|
||||
func newSyncingInfoObject(serverGroupId int32, _db *sql.DB) (result *syncingInfo, err error) {
|
||||
result = &syncingInfo{
|
||||
ServerGroupId: serverGroupId,
|
||||
db: _db,
|
||||
}
|
||||
|
||||
err = result.init()
|
||||
|
||||
return result, err
|
||||
}
|
||||
62
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/dal.go
Normal file
62
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/dal.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/jinzhu/gorm"
|
||||
"Framework/dataSyncMgr/mysqlSync"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var _ = mysql.DeregisterLocalFile
|
||||
|
||||
var (
|
||||
connectionString = "root:moqikaka3309@tcp(10.1.0.10:3309)/develop_liujun?charset=utf8&parseTime=true&loc=Local&timeout=60s"
|
||||
maxOpenConns = 10
|
||||
maxIdleConns = 10
|
||||
|
||||
syncFileSize = 1024 * 1024
|
||||
)
|
||||
|
||||
var (
|
||||
// 数据库对象
|
||||
dbObj *gorm.DB
|
||||
|
||||
// 同步管理对象
|
||||
syncMgr *mysqlSync.SyncMgr
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 初始化数据库连接
|
||||
dbObj = initMysql()
|
||||
|
||||
// 构造同步管理对象
|
||||
syncMgr = mysqlSync.NewLogSyncMgr(1, "Sync", syncFileSize, dbObj.DB())
|
||||
}
|
||||
|
||||
// 初始化Mysql
|
||||
func initMysql() *gorm.DB {
|
||||
dbObj, err := gorm.Open("mysql", connectionString)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("初始化数据库:%s失败,错误信息为:%s", connectionString, err))
|
||||
}
|
||||
logUtil.DebugLog(fmt.Sprintf("连接mysql:%s成功", connectionString))
|
||||
|
||||
if maxOpenConns > 0 && maxIdleConns > 0 {
|
||||
dbObj.DB().SetMaxOpenConns(maxOpenConns)
|
||||
dbObj.DB().SetMaxIdleConns(maxIdleConns)
|
||||
}
|
||||
|
||||
return dbObj
|
||||
}
|
||||
|
||||
// 注册同步对象
|
||||
func registerSyncObj(identifier string) {
|
||||
syncMgr.RegisterSyncObj(identifier)
|
||||
}
|
||||
|
||||
// 保存sql数据
|
||||
func save(identifier string, command string) {
|
||||
syncMgr.Save(identifier, command)
|
||||
}
|
||||
82
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/main.go
Normal file
82
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/main.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
func init() {
|
||||
wg.Add(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
playerMgr := newPlayerMgr()
|
||||
|
||||
// insert
|
||||
go func() {
|
||||
for {
|
||||
id := stringUtil.GetNewGUID()
|
||||
name := fmt.Sprintf("Hero_%s", id)
|
||||
obj := newPlayer(id, name)
|
||||
playerMgr.insert(obj)
|
||||
|
||||
insert(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
/*
|
||||
// update
|
||||
go func() {
|
||||
for {
|
||||
obj := playerMgr.randomSelect()
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
suffix := mathUtil.GetRandInt(1000)
|
||||
newName := fmt.Sprintf("Hero_%d", suffix)
|
||||
obj.resetName(newName)
|
||||
|
||||
update(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// delete
|
||||
go func() {
|
||||
for {
|
||||
obj := playerMgr.randomSelect()
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
playerMgr.delete(obj)
|
||||
|
||||
clear(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// errorFile
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(1 * time.Hour)
|
||||
id := stringUtil.GetNewGUID()
|
||||
name := fmt.Sprintf("Hero_%s%s", id, id)
|
||||
obj := newPlayer(id, name)
|
||||
playerMgr.insert(obj)
|
||||
print("errorFile")
|
||||
|
||||
insert(obj)
|
||||
}
|
||||
|
||||
}()
|
||||
*/
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
64
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/player.go
Normal file
64
trunk/framework/dataSyncMgr/mysqlSync/logSyncTest/player.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type player struct {
|
||||
// 玩家id
|
||||
Id string `gorm:"column:Id;primary_key"`
|
||||
|
||||
// 玩家名称
|
||||
Name string `gorm:"column:Name"`
|
||||
}
|
||||
|
||||
func (this *player) resetName(name string) {
|
||||
this.Name = name
|
||||
}
|
||||
|
||||
func (this *player) tableName() string {
|
||||
return "player"
|
||||
}
|
||||
|
||||
func newPlayer(id, name string) *player {
|
||||
return &player{
|
||||
Id: id,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
type playerMgr struct {
|
||||
playerMap map[string]*player
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (this *playerMgr) insert(obj *player) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.playerMap[obj.Id] = obj
|
||||
}
|
||||
|
||||
func (this *playerMgr) delete(obj *player) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
delete(this.playerMap, obj.Id)
|
||||
}
|
||||
|
||||
func (this *playerMgr) randomSelect() *player {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
for _, obj := range this.playerMap {
|
||||
return obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newPlayerMgr() *playerMgr {
|
||||
return &playerMgr{
|
||||
playerMap: make(map[string]*player),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//package test
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
con_player_tableName = "player"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerSyncObj(con_player_tableName)
|
||||
}
|
||||
|
||||
func insert(obj *player) {
|
||||
command := fmt.Sprintf("INSERT INTO `%s` (`Id`,`Name`) VALUES ('%v','%v') ", con_player_tableName, obj.Id, obj.Name)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
|
||||
func update(obj *player) {
|
||||
command := fmt.Sprintf("UPDATE `%s` SET `Name` = '%v' WHERE `Id` = '%v';", con_player_tableName, obj.Name, obj.Id)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
|
||||
func clear(obj *player) {
|
||||
command := fmt.Sprintf("DELETE FROM %s where Id = '%v';", con_player_tableName, obj.Id)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package sqlSync
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"goutil/fileUtil"
|
||||
"goutil/intAndBytesUtil"
|
||||
)
|
||||
|
||||
const (
|
||||
// 头部字节长度
|
||||
con_Header_Length = 4
|
||||
)
|
||||
|
||||
var (
|
||||
// 字节的大小端顺序
|
||||
byteOrder = binary.LittleEndian
|
||||
)
|
||||
|
||||
// 按照指定方式读取文本内容
|
||||
// fileObj:大文件对象
|
||||
// data:待写入的数据
|
||||
// 返回值:
|
||||
// error:写入是否存在异常
|
||||
func Write(fileObj *fileUtil.BigFile, data string) error {
|
||||
// 获得数据内容的长度
|
||||
dataLength := len(data)
|
||||
|
||||
// 将长度转化为字节数组
|
||||
header := intAndBytesUtil.Int32ToBytes(int32(dataLength), byteOrder)
|
||||
|
||||
// 将头部与内容组合在一起
|
||||
message := append(header, data...)
|
||||
|
||||
// 写入数据
|
||||
return fileObj.WriteMessage(message)
|
||||
}
|
||||
|
||||
// 从文件读取一条数据
|
||||
// fileObj:文件对象
|
||||
// 返回值:
|
||||
// result:读取到的字符串
|
||||
// err:错误信息
|
||||
func Read(fileObj *os.File) (result string, readLen int64, err error) {
|
||||
// 1. 读取头部内容
|
||||
header := make([]byte, 4)
|
||||
var n int
|
||||
n, err = fileObj.Read(header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n < con_Header_Length {
|
||||
err = errors.New("can not read 4 byte for read len")
|
||||
readLen = int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
dataLength := intAndBytesUtil.BytesToInt32(header, byteOrder)
|
||||
|
||||
// 2. 读取指定长度的内容
|
||||
data := make([]byte, dataLength)
|
||||
n, err = fileObj.Read(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
readLen = int64(len(header) + int(dataLength))
|
||||
result = string(data)
|
||||
return
|
||||
}
|
||||
139
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/sqlFile.go
Normal file
139
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/sqlFile.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package sqlSync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"goutil/fileUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
const (
|
||||
// 第一个文件名
|
||||
con_Default_FileName = "00000000"
|
||||
|
||||
// 文件名后缀
|
||||
con_FileName_Suffix = "data"
|
||||
)
|
||||
|
||||
// 同步数据对象(用于往文件中写入sql语句)
|
||||
type SqlFile struct {
|
||||
// 存放同步数据的文件夹路径
|
||||
dirPath string
|
||||
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
|
||||
// 保存数据的大文件对象
|
||||
bigFileObj *fileUtil.BigFile
|
||||
|
||||
// 数据同步对象
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// 将数据写入同步数据对象
|
||||
// data:待写入的数据
|
||||
func (this *SqlFile) Write(data string) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
// 写入数据
|
||||
err := Write(this.bigFileObj, data)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SqlFile.write.bigFileObj.WriteMessage")
|
||||
err = fmt.Errorf("%s-Write message to big file object failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取大文件对象的文件绝对路径
|
||||
func (this *SqlFile) FileFullName() string {
|
||||
return filepath.Join(this.dirPath, this.bigFileObj.FileName())
|
||||
}
|
||||
|
||||
// 当前读写的文件名
|
||||
func (this *SqlFile) FileName() string {
|
||||
return this.bigFileObj.FileName()
|
||||
}
|
||||
|
||||
// 创建同步数据对象
|
||||
// _dirPath:目录的路径
|
||||
// _identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// _maxFileSize:每个大文件的最大写入值(单位:Byte)
|
||||
// 返回值:
|
||||
// 同步数据对象
|
||||
func NewSqlFile(dirPath, identifier, fileName string, maxFileSize int) *SqlFile {
|
||||
result := &SqlFile{
|
||||
dirPath: dirPath,
|
||||
identifier: identifier,
|
||||
}
|
||||
|
||||
// 初始化大文件对象
|
||||
if fileName == "" {
|
||||
fileName = con_Default_FileName
|
||||
}
|
||||
bigFileObj, err := fileUtil.NewBigFileWithNewFileNameFunc2(dirPath, "", fileName, maxFileSize, NewFileName)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", result.identifier, "SqlFile.newSqlFile.fileUtil.NewBigFileWithNewFileNameFunc")
|
||||
err = fmt.Errorf("%s-Create big file object failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
result.bigFileObj = bigFileObj
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 根据当前文件名生成下一个sql文件名
|
||||
// prefix:文件名前缀
|
||||
// path:当前文件的路径
|
||||
// 返回值:
|
||||
// string:下一个文件的完整路径
|
||||
func NewFileName(prefix, path string) string {
|
||||
fullName := filepath.Base(path)
|
||||
curFileName := strings.Split(fullName, ".")[0]
|
||||
curFileId, err := strconv.Atoi(curFileName)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s-Convert newFileName:%s to int failed:%s", prefix, curFileName, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
newFileId := curFileId + 1
|
||||
newFileName := fmt.Sprintf("%08d", newFileId)
|
||||
|
||||
// 加上文件后缀
|
||||
newFileName = fmt.Sprintf("%s.%s", newFileName, con_FileName_Suffix)
|
||||
|
||||
return newFileName
|
||||
}
|
||||
|
||||
// 获取文件夹下所有的sql文件
|
||||
// dirPath:指定要获取的文件夹路径
|
||||
// 返回值:
|
||||
// []string:sql文件列表
|
||||
func GetDataFileList(dirPath string) []string {
|
||||
// 获取当前目录中所有的数据文件列表
|
||||
fileList, err := fileUtil.GetFileList2(dirPath, "", con_FileName_Suffix)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
} else {
|
||||
err = fmt.Errorf("%s/*.%s-Get file list failed:%s", dirPath, con_FileName_Suffix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果文件数量大于1,则进行排序,以便于后续处理
|
||||
if len(fileList) > 1 {
|
||||
sort.Strings(fileList)
|
||||
}
|
||||
|
||||
return fileList
|
||||
}
|
||||
271
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/syncObject.go
Normal file
271
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/syncObject.go
Normal file
@@ -0,0 +1,271 @@
|
||||
package sqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"goutil/debugUtil"
|
||||
"goutil/fileUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 同步对象定义
|
||||
type SyncObject struct {
|
||||
// 同步数据的存储路径
|
||||
dirPath string
|
||||
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
|
||||
// 数据库对象
|
||||
dbObj *sql.DB
|
||||
|
||||
// 处理数据写入的文件
|
||||
sqlFileObj *SqlFile
|
||||
|
||||
// 同步处理对象
|
||||
syncHandleObj SyncHandler
|
||||
}
|
||||
|
||||
// 进行同步对象初始化
|
||||
// maxFileSize:每个大文件的最大写入值(单位:Byte)
|
||||
func (this *SyncObject) Init(maxFileSize int) {
|
||||
// 启动时同步所有数据(然后才能从数据库中查询数据,以免数据丢失)
|
||||
this.syncHandleObj.Init(this)
|
||||
|
||||
// 构造同步数据对象
|
||||
fileName, _ := this.syncHandleObj.GetSyncingInfo()
|
||||
this.sqlFileObj = NewSqlFile(this.dirPath, this.identifier, fileName, maxFileSize)
|
||||
|
||||
// 当前没有正在同步的文件,则指向当前正在写的文件
|
||||
if len(fileName) <= 0 {
|
||||
this.syncHandleObj.Update(this.sqlFileObj.FileFullName(), 0, nil)
|
||||
}
|
||||
|
||||
// 启动一个新goroutine来负责同步数据
|
||||
go func() {
|
||||
/* 此处不使用goroutineMgr.Monitor/ReleaseMonitor,因为此处不能捕获panic,需要让外部进程终止执行,
|
||||
因为此模块的文件读写为核心逻辑,一旦出现问题必须停止进程,否则会造成脏数据
|
||||
*/
|
||||
this.Sync()
|
||||
}()
|
||||
}
|
||||
|
||||
// 保存数据到本地文件
|
||||
// command:待保存的指令
|
||||
func (this *SyncObject) Save(command string) {
|
||||
this.sqlFileObj.Write(command)
|
||||
}
|
||||
|
||||
// 循环同步多个文件
|
||||
func (this *SyncObject) Sync() {
|
||||
// 开始循环同步
|
||||
for {
|
||||
// 同步当前文件
|
||||
this.syncOneFile()
|
||||
|
||||
// 当前文件同步完成,记录同步日志
|
||||
nowFilePath, _ := this.syncHandleObj.GetSyncingInfo()
|
||||
|
||||
// 删除已同步完成的文件
|
||||
WaitForOk(func() bool {
|
||||
fileExist, err := fileUtil.IsFileExists(nowFilePath)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncObject IsFileExists error:%s", err.Error()))
|
||||
return false
|
||||
}
|
||||
if fileExist == false {
|
||||
return true
|
||||
}
|
||||
|
||||
err = fileUtil.DeleteFile(nowFilePath)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncObject delete file error:%s", err.Error()))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}, 10*time.Second)
|
||||
|
||||
// 当前文件同步完成,获取下个文件
|
||||
nextFileName := NewFileName("", nowFilePath)
|
||||
filePath := filepath.Join(this.dirPath, nextFileName)
|
||||
exist, err := fileUtil.IsFileExists(filePath)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncObject IsFileExists error:%s", err.Error()))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 如果文件不存在,退出
|
||||
if !exist {
|
||||
// fmt.Println("协程退出了")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新同步的位置信息 此处忽略错误是因为,哪怕是出错了,也不会影响整体逻辑
|
||||
this.syncHandleObj.Update(filePath, 0, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// 同步单个文件
|
||||
func (this *SyncObject) syncOneFile() {
|
||||
// 获取信息同步项对象
|
||||
filePath, offset := this.syncHandleObj.GetSyncingInfo()
|
||||
|
||||
// 打开待读取的文件
|
||||
f, exist := this.openFile(filePath)
|
||||
if exist == false {
|
||||
// logUtil.WarnLog(fmt.Sprintf("待同步的文件不存在,跳过此文件:%s", filePath),"")
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
for {
|
||||
// 移动到需要读取的位置
|
||||
if _, err := f.Seek(offset, io.SeekStart); err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SyncObject.Seek")
|
||||
err = fmt.Errorf("%s-Seek offset for header failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
command, readLen, err := Read(f)
|
||||
if err != nil {
|
||||
// 如果读取到文件末尾,判断是否等待
|
||||
if err == io.EOF {
|
||||
if this.sqlFileObj != nil && strings.Contains(filePath, this.sqlFileObj.FileName()) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果该文件是空文件,同步更新信息
|
||||
return
|
||||
}
|
||||
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SyncObject.syncOneFile.f.Read")
|
||||
err = fmt.Errorf("%s-Read header failed:%s", prefix, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 3. 同步到mysql中,并更新同步位置
|
||||
this.syncHandleObj.SyncOneSql(command, filePath, offset+readLen)
|
||||
|
||||
// 4. 更新内存中的同步位置
|
||||
offset += readLen
|
||||
}
|
||||
}
|
||||
|
||||
// 打开待读取的文件
|
||||
// filePath:待打开的文件
|
||||
// 返回值:
|
||||
// *os.File:文件句柄,
|
||||
func (this *SyncObject) openFile(filePath string) (f *os.File, exist bool) {
|
||||
var err error
|
||||
for {
|
||||
exist, err = fileUtil.IsFileExists(filePath)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("check file error,filePath:%v error:%v", filePath, err.Error())
|
||||
logUtil.ErrorLog(err.Error())
|
||||
time.Sleep(time.Second * 5)
|
||||
continue
|
||||
}
|
||||
if exist == false {
|
||||
// 如果文件不存在,则跳过此文件
|
||||
logUtil.WarnLog(fmt.Sprintf("file no exist, skip file:%v", filePath))
|
||||
exist = false
|
||||
return
|
||||
}
|
||||
exist = true
|
||||
|
||||
// 打开当前处理文件
|
||||
f, err = os.OpenFile(filePath, os.O_RDONLY, os.ModePerm|os.ModeTemporary)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SyncObject.syncOneFile.os.OpenFile")
|
||||
err = fmt.Errorf("%s-Open file:%s failed:%s", prefix, filePath, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 同步数据到mysql中
|
||||
// command:sql语句
|
||||
// tx:事务处理对象
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) syncToMysql(command string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(command)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SyncObject.syncToMysql")
|
||||
err = fmt.Errorf("%s-%s Update to mysql failed:%s", prefix, command, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
debugUtil.Printf("fatal Error:%v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创新新的mysql同步对象
|
||||
// dirPath:存放数据的目录
|
||||
// identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// dbObj:数据库对象
|
||||
// _syncHandleObj:同步处理对象
|
||||
// 返回值:
|
||||
// mysql同步对象
|
||||
func NewSyncObject(dirPath, identifier string, dbObj *sql.DB, _syncHandleObj SyncHandler) *SyncObject {
|
||||
dirPath = filepath.Join(dirPath, identifier)
|
||||
|
||||
// 创建更新目录
|
||||
err := os.MkdirAll(dirPath, os.ModePerm|os.ModeTemporary)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s-%s-make dir failed:%s", identifier, "SyncObject.newSyncObject.os.MkdirAll", err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 构造同步信息对象
|
||||
result := &SyncObject{
|
||||
dirPath: dirPath,
|
||||
identifier: identifier,
|
||||
dbObj: dbObj,
|
||||
syncHandleObj: _syncHandleObj,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 同步处理接口
|
||||
type SyncHandler interface {
|
||||
// 初始化
|
||||
Init(baseObj *SyncObject)
|
||||
|
||||
// 获取正在同步的信息
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
GetSyncingInfo() (filePath string, offset int64)
|
||||
|
||||
// 更新
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
// tran:事务对象
|
||||
// 返回值:
|
||||
// error:错误对象
|
||||
Update(filePath string, offset int64, tran *sql.Tx) error
|
||||
|
||||
// 同步一条sql
|
||||
// command:指令数据
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
SyncOneSql(command string, filePath string, offset int64)
|
||||
}
|
||||
99
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/utility.go
Normal file
99
trunk/framework/dataSyncMgr/mysqlSync/sqlSync/utility.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package sqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 以事务的方式执行
|
||||
// db:数据库对象
|
||||
// funcObj:对应的具体处理函数
|
||||
// 返回值:
|
||||
// error:处理是否存在错误
|
||||
func ExecuteByTran(db *sql.DB, funcObj func(tran *sql.Tx) (isCommit bool, err error)) error {
|
||||
tran, err := db.Begin()
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("start transaction error:%v", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
// 事务处理
|
||||
isCommit := false
|
||||
defer func() {
|
||||
if isCommit {
|
||||
err = tran.Commit()
|
||||
} else {
|
||||
err = tran.Rollback()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("transaction end error:%v", err.Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
isCommit, err = funcObj(tran)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 循环执行知道返回成功为止
|
||||
// funcObj:待执行的函数
|
||||
// interval:执行间隔时间
|
||||
func WaitForOk(funcObj func() bool, interval time.Duration) {
|
||||
for {
|
||||
if funcObj() == false {
|
||||
time.Sleep(interval)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否是连接错误
|
||||
// errMsg:错误信息
|
||||
// 返回值:
|
||||
// bool:true:连接错误 false:其他异常
|
||||
func CheckIfConnectionError(errMsg string) bool {
|
||||
//// 连接被关闭
|
||||
ifConnectionClose := strings.Contains(errMsg, "A connection attempt failed because the connected party did not properly respond")
|
||||
if ifConnectionClose {
|
||||
return true
|
||||
}
|
||||
|
||||
// 使用过程中连接断开
|
||||
ifConnectionClose = strings.Contains(errMsg, "No connection could be made")
|
||||
if ifConnectionClose {
|
||||
return true
|
||||
}
|
||||
|
||||
// 事务处理过程中连接断开的提示
|
||||
ifConnectionClose = strings.Contains(errMsg, "bad connection")
|
||||
if ifConnectionClose {
|
||||
return true
|
||||
}
|
||||
|
||||
// socket压根儿连不上的处理
|
||||
ifConnectionClose = strings.Contains(errMsg, "A socket operation was attempted to an unreachable network")
|
||||
if ifConnectionClose {
|
||||
return true
|
||||
}
|
||||
|
||||
// 用户无法访问
|
||||
return strings.Contains(errMsg, "Access denied for user")
|
||||
}
|
||||
|
||||
// 获取比较简洁的错误信息
|
||||
// errMsg:错误信息
|
||||
// 返回值:
|
||||
// string:比较简洁的错误信息
|
||||
func GetSimpleErrorMessage(errMsg string) string {
|
||||
if strings.Contains(errMsg, "Error 1064: You have an error in your SQL syntax") {
|
||||
return "SqlError"
|
||||
}
|
||||
|
||||
return errMsg
|
||||
}
|
||||
119
trunk/framework/dataSyncMgr/mysqlSync/syncMgr.go
Normal file
119
trunk/framework/dataSyncMgr/mysqlSync/syncMgr.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package mysqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"Framework/dataSyncMgr/mysqlSync/logSqlSync"
|
||||
"Framework/dataSyncMgr/mysqlSync/sqlSync"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 数据同步管理
|
||||
type SyncMgr struct {
|
||||
// 服务器组Id
|
||||
serverGroupId int32
|
||||
|
||||
// 同步数据的存储路径
|
||||
dirPath string
|
||||
|
||||
// 大文件对象size
|
||||
maxFileSize int
|
||||
|
||||
// 数据库对象
|
||||
dbObj *sql.DB
|
||||
|
||||
// 同步对象集合
|
||||
syncObjMap map[string]*sqlSync.SyncObject
|
||||
|
||||
// 同步对象锁
|
||||
mutex sync.RWMutex
|
||||
|
||||
// 新建实例对象的函数
|
||||
newInstanceFunc func(mgr *SyncMgr, identifier string) *sqlSync.SyncObject
|
||||
}
|
||||
|
||||
// 注册同步对象
|
||||
// identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
func (this *SyncMgr) RegisterSyncObj(identifier string) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
// 判断是否设置了相同的唯一标识,以免弄混淆
|
||||
if _, exists := this.syncObjMap[identifier]; exists {
|
||||
prefix := fmt.Sprintf("%s-%s", identifier, "SyncMgr.RegisterSyncObj")
|
||||
err := fmt.Errorf("%s has already existed, please change another identifier", prefix)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
syncObj := this.newInstanceFunc(this, identifier)
|
||||
syncObj.Init(this.maxFileSize)
|
||||
this.syncObjMap[identifier] = syncObj
|
||||
|
||||
if debugUtil.IsDebug() {
|
||||
fmt.Printf("%s同步对象成功注册进SyncMgr, 当前有%d个同步对象\n", identifier, len(this.syncObjMap))
|
||||
}
|
||||
}
|
||||
|
||||
// 保存数据
|
||||
// identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// command:sql命令
|
||||
func (this *SyncMgr) Save(identifier string, command string) {
|
||||
this.mutex.RLock()
|
||||
defer this.mutex.RUnlock()
|
||||
|
||||
syncObj, exists := this.syncObjMap[identifier]
|
||||
if !exists {
|
||||
err := fmt.Errorf("syncObj:%s does not existed, please register first", identifier)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
syncObj.Save(command)
|
||||
}
|
||||
|
||||
// 构造同步管理对象
|
||||
// serverGroupId:服务器组Id
|
||||
// dirPath: 文件目录
|
||||
// maxFileSize: 大文件对象大小
|
||||
// survivalTime: 同步数据存活时间 (单位:hour)
|
||||
// dbObj: 数据库对象
|
||||
func NewSyncMgr(serverGroupId int32, dirPath string, maxFileSize int, survivalTime int, dbObj *sql.DB) *SyncMgr {
|
||||
result := &SyncMgr{
|
||||
serverGroupId: serverGroupId,
|
||||
dirPath: dirPath,
|
||||
maxFileSize: maxFileSize,
|
||||
dbObj: dbObj,
|
||||
syncObjMap: make(map[string]*sqlSync.SyncObject),
|
||||
newInstanceFunc: func(mgr *SyncMgr, identifier string) *sqlSync.SyncObject {
|
||||
handler := newSyncObject(mgr.dirPath, identifier, mgr.dbObj)
|
||||
return sqlSync.NewSyncObject(mgr.dirPath, identifier, mgr.dbObj, handler)
|
||||
},
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 新建日志同步管理对象
|
||||
// serverGroupId:服务器组Id
|
||||
// dirPath: 文件目录
|
||||
// maxFileSize: 大文件对象大小
|
||||
// dbObj: 数据库对象
|
||||
func NewLogSyncMgr(serverGroupId int32, dirPath string, maxFileSize int, dbObj *sql.DB) *SyncMgr {
|
||||
result := &SyncMgr{
|
||||
serverGroupId: serverGroupId,
|
||||
dirPath: dirPath,
|
||||
maxFileSize: maxFileSize,
|
||||
dbObj: dbObj,
|
||||
syncObjMap: make(map[string]*sqlSync.SyncObject),
|
||||
newInstanceFunc: func(mgr *SyncMgr, identifier string) *sqlSync.SyncObject {
|
||||
handler := logSqlSync.NewSyncObject(mgr.serverGroupId, mgr.dirPath, identifier, mgr.dbObj)
|
||||
return sqlSync.NewSyncObject(mgr.dirPath, identifier, mgr.dbObj, handler)
|
||||
},
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
210
trunk/framework/dataSyncMgr/mysqlSync/syncObject.go
Normal file
210
trunk/framework/dataSyncMgr/mysqlSync/syncObject.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package mysqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"Framework/dataSyncMgr/mysqlSync/sqlSync"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 同步对象定义
|
||||
type SyncObject struct {
|
||||
// 同步数据的存储路径
|
||||
dirPath string
|
||||
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
|
||||
// 数据库对象
|
||||
dbObj *sql.DB
|
||||
|
||||
// 同步信息对象
|
||||
syncingInfoObj *syncingInfo
|
||||
|
||||
// 错误处理对象
|
||||
errorHandleObj *errorFile
|
||||
|
||||
// 同步对象
|
||||
syncObj *sqlSync.SyncObject
|
||||
}
|
||||
|
||||
// 进行同步对象初始化
|
||||
// maxFileSize:每个大文件的最大写入值(单位:Byte)
|
||||
func (this *SyncObject) Init(baseObj *sqlSync.SyncObject) {
|
||||
this.syncObj = baseObj
|
||||
|
||||
// 创建同步信息记录对象
|
||||
syncingInfoObj, err := newSyncingInfoObject(this.identifier, this.dbObj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
this.syncingInfoObj = syncingInfoObj
|
||||
|
||||
// 启动时同步所有数据(然后才能从数据库中查询数据,以免数据丢失)
|
||||
this.syncOldData()
|
||||
}
|
||||
|
||||
// 同步完成之前未同步完的数据
|
||||
func (this *SyncObject) syncOldData() {
|
||||
// 获取文件列表(有序的列表)
|
||||
fileList := sqlSync.GetDataFileList(this.dirPath)
|
||||
filePath, _ := this.syncingInfoObj.GetSyncingInfo()
|
||||
|
||||
// 判断是否有文件
|
||||
if len(fileList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 判断当前文件是否为空,如果为空则将第一个文件赋给它
|
||||
if filePath == "" {
|
||||
this.syncingInfoObj.Update(fileList[0], 0, nil)
|
||||
}
|
||||
|
||||
// 开始同步数据
|
||||
this.syncObj.Sync()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取正在同步的信息
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
func (this *SyncObject) GetSyncingInfo() (filePath string, offset int64) {
|
||||
return this.syncingInfoObj.GetSyncingInfo()
|
||||
}
|
||||
|
||||
// 更新
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
// tran:事务对象
|
||||
// 返回值:
|
||||
// error:错误对象
|
||||
func (this *SyncObject) Update(filePath string, offset int64, tran *sql.Tx) error {
|
||||
return this.syncingInfoObj.Update(filePath, offset, tran)
|
||||
}
|
||||
|
||||
// 同步一条sql语句
|
||||
// command:待执行的命令
|
||||
// filePath:保存路径
|
||||
// offset:文件偏移量
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) SyncOneSql(command string, filePath string, offset int64) {
|
||||
err := this.syncOneSqlDetail(command, filePath, offset)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 发送监控报警
|
||||
this.handleError(command, filePath, offset, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 同步一条sql语句的具体逻辑
|
||||
// command:待执行的命令
|
||||
// filePath:保存路径
|
||||
// offset:文件偏移量
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) syncOneSqlDetail(command string, filePath string, offset int64) error {
|
||||
return sqlSync.ExecuteByTran(this.dbObj, func(tx *sql.Tx) (isCommit bool, err error) {
|
||||
// 保存sql到数据库
|
||||
err = this.syncToMysql(command, tx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 保存进度信息到数据库
|
||||
err = this.syncingInfoObj.Update(filePath, offset, tx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
// 同步数据到mysql中
|
||||
// command:待执行的命令
|
||||
// tx:事务对象
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *SyncObject) syncToMysql(command string, tx *sql.Tx) error {
|
||||
_, err := tx.Exec(command)
|
||||
if err != nil {
|
||||
prefix := fmt.Sprintf("%s-%s", this.identifier, "SyncObject.syncToMysql")
|
||||
err = fmt.Errorf("%s-%s Update to mysql failed:%s", prefix, command, err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
debugUtil.Printf("fatal Error:%v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 进行错误处理
|
||||
// command:存在异常的数据
|
||||
// filePath:文件路径
|
||||
// offset:文件偏移量
|
||||
// err:错误信息
|
||||
func (this *SyncObject) handleError(command string, filePath string, offset int64, err error) {
|
||||
defer this.errorHandleObj.Delete()
|
||||
|
||||
// 保存当前sql命令
|
||||
this.errorHandleObj.SaveCommand(command)
|
||||
|
||||
// 循环处理当前命令,直到没有错误
|
||||
beginTime := time.Now().Unix()
|
||||
for {
|
||||
// 每隔5分钟,发送警报
|
||||
if time.Now().Unix()-beginTime > 5*60 {
|
||||
beginTime = time.Now().Unix()
|
||||
}
|
||||
|
||||
// 每次循环休眠20秒
|
||||
time.Sleep(5 * time.Second)
|
||||
command = this.errorHandleObj.ReadCommand()
|
||||
err = this.syncOneSqlDetail(command, filePath, offset)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 创新新的mysql同步对象
|
||||
// dirPath:存放数据的目录
|
||||
// identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// dbObj:数据库对象
|
||||
// syncingInfoObj:同步信息记录对象
|
||||
// errorHandleObj:错误处理对象
|
||||
// 返回值:
|
||||
// mysql同步对象
|
||||
func newSyncObject(dirPath, identifier string, dbObj *sql.DB) *SyncObject {
|
||||
dirPath = filepath.Join(dirPath, identifier)
|
||||
|
||||
// 创建更新目录
|
||||
err := os.MkdirAll(dirPath, os.ModePerm|os.ModeTemporary)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s-%s-make dir failed:%s", identifier, "SyncObject.newSyncObject.os.MkdirAll", err)
|
||||
logUtil.ErrorLog(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 构造同步信息对象
|
||||
result := &SyncObject{
|
||||
dirPath: dirPath,
|
||||
identifier: identifier,
|
||||
dbObj: dbObj,
|
||||
errorHandleObj: newErrorFile(dirPath, identifier),
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
62
trunk/framework/dataSyncMgr/mysqlSync/syncTest/dal.go
Normal file
62
trunk/framework/dataSyncMgr/mysqlSync/syncTest/dal.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/jinzhu/gorm"
|
||||
"Framework/dataSyncMgr/mysqlSync"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var _ = mysql.DeregisterLocalFile
|
||||
|
||||
var (
|
||||
connectionString = "root:moqikaka3309@tcp(10.1.0.10:3309)/develop_liujun?charset=utf8&parseTime=true&loc=Local&timeout=60s"
|
||||
maxOpenConns = 10
|
||||
maxIdleConns = 10
|
||||
|
||||
syncFileSize = 1024 * 1024
|
||||
)
|
||||
|
||||
var (
|
||||
// 数据库对象
|
||||
dbObj *gorm.DB
|
||||
|
||||
// 同步管理对象
|
||||
syncMgr *mysqlSync.SyncMgr
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 初始化数据库连接
|
||||
dbObj = initMysql()
|
||||
|
||||
// 构造同步管理对象
|
||||
syncMgr = mysqlSync.NewSyncMgr(1, "Sync", syncFileSize, 1, dbObj.DB())
|
||||
}
|
||||
|
||||
// 初始化Mysql
|
||||
func initMysql() *gorm.DB {
|
||||
dbObj, err := gorm.Open("mysql", connectionString)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("初始化数据库:%s失败,错误信息为:%s", connectionString, err))
|
||||
}
|
||||
logUtil.DebugLog(fmt.Sprintf("连接mysql:%s成功", connectionString))
|
||||
|
||||
if maxOpenConns > 0 && maxIdleConns > 0 {
|
||||
dbObj.DB().SetMaxOpenConns(maxOpenConns)
|
||||
dbObj.DB().SetMaxIdleConns(maxIdleConns)
|
||||
}
|
||||
|
||||
return dbObj
|
||||
}
|
||||
|
||||
// 注册同步对象
|
||||
func registerSyncObj(identifier string) {
|
||||
syncMgr.RegisterSyncObj(identifier)
|
||||
}
|
||||
|
||||
// 保存sql数据
|
||||
func save(identifier string, command string) {
|
||||
syncMgr.Save(identifier, command)
|
||||
}
|
||||
82
trunk/framework/dataSyncMgr/mysqlSync/syncTest/main.go
Normal file
82
trunk/framework/dataSyncMgr/mysqlSync/syncTest/main.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"goutil/mathUtil"
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
func init() {
|
||||
wg.Add(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
playerMgr := newPlayerMgr()
|
||||
|
||||
// insert
|
||||
go func() {
|
||||
for {
|
||||
id := stringUtil.GetNewGUID()
|
||||
name := fmt.Sprintf("Hero_%s", id)
|
||||
obj := newPlayer(id, name)
|
||||
playerMgr.insert(obj)
|
||||
|
||||
insert(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// update
|
||||
go func() {
|
||||
for {
|
||||
obj := playerMgr.randomSelect()
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
suffix := mathUtil.GetRand().GetRandInt(1000)
|
||||
newName := fmt.Sprintf("Hero_%d", suffix)
|
||||
obj.resetName(newName)
|
||||
|
||||
update(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// delete
|
||||
go func() {
|
||||
for {
|
||||
obj := playerMgr.randomSelect()
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
playerMgr.delete(obj)
|
||||
|
||||
clear(obj)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// errorFile
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(1 * time.Hour)
|
||||
id := stringUtil.GetNewGUID()
|
||||
name := fmt.Sprintf("Hero_%s%s", id, id)
|
||||
obj := newPlayer(id, name)
|
||||
playerMgr.insert(obj)
|
||||
print("errorFile")
|
||||
|
||||
insert(obj)
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
64
trunk/framework/dataSyncMgr/mysqlSync/syncTest/player.go
Normal file
64
trunk/framework/dataSyncMgr/mysqlSync/syncTest/player.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type player struct {
|
||||
// 玩家id
|
||||
Id string `gorm:"column:Id;primary_key"`
|
||||
|
||||
// 玩家名称
|
||||
Name string `gorm:"column:Name"`
|
||||
}
|
||||
|
||||
func (this *player) resetName(name string) {
|
||||
this.Name = name
|
||||
}
|
||||
|
||||
func (this *player) tableName() string {
|
||||
return "player"
|
||||
}
|
||||
|
||||
func newPlayer(id, name string) *player {
|
||||
return &player{
|
||||
Id: id,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
type playerMgr struct {
|
||||
playerMap map[string]*player
|
||||
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
func (this *playerMgr) insert(obj *player) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.playerMap[obj.Id] = obj
|
||||
}
|
||||
|
||||
func (this *playerMgr) delete(obj *player) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
delete(this.playerMap, obj.Id)
|
||||
}
|
||||
|
||||
func (this *playerMgr) randomSelect() *player {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
for _, obj := range this.playerMap {
|
||||
return obj
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newPlayerMgr() *playerMgr {
|
||||
return &playerMgr{
|
||||
playerMap: make(map[string]*player),
|
||||
}
|
||||
}
|
||||
29
trunk/framework/dataSyncMgr/mysqlSync/syncTest/player_dal.go
Normal file
29
trunk/framework/dataSyncMgr/mysqlSync/syncTest/player_dal.go
Normal file
@@ -0,0 +1,29 @@
|
||||
//package test
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
con_player_tableName = "player"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerSyncObj(con_player_tableName)
|
||||
}
|
||||
|
||||
func insert(obj *player) {
|
||||
command := fmt.Sprintf("INSERT INTO `%s` (`Id`,`Name`) VALUES ('%v','%v') ", con_player_tableName, obj.Id, obj.Name)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
|
||||
func update(obj *player) {
|
||||
command := fmt.Sprintf("UPDATE `%s` SET `Name` = '%v' WHERE `Id` = '%v';", con_player_tableName, obj.Name, obj.Id)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
|
||||
func clear(obj *player) {
|
||||
command := fmt.Sprintf("DELETE FROM %s where Id = '%v';", con_player_tableName, obj.Id)
|
||||
save(con_player_tableName, command)
|
||||
}
|
||||
222
trunk/framework/dataSyncMgr/mysqlSync/syncingInfo.go
Normal file
222
trunk/framework/dataSyncMgr/mysqlSync/syncingInfo.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package mysqlSync
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
// 是否已经初始化了正在同步的表信息
|
||||
ifSyncingInfoTableInited = false
|
||||
|
||||
// 表初始化错误信息
|
||||
initTableError error = nil
|
||||
|
||||
// 表是否已经初始化
|
||||
isTableInited bool = false
|
||||
)
|
||||
|
||||
// 同步信息项,保存已经处理过的文件的信息
|
||||
type syncingModel struct {
|
||||
// 唯一标识
|
||||
Identifier string
|
||||
|
||||
// 待处理文件的绝对路径
|
||||
FilePath string
|
||||
|
||||
// 待处理文件的偏移量
|
||||
FileOffset int64
|
||||
|
||||
// 更新时间
|
||||
UpdateTime time.Time
|
||||
}
|
||||
|
||||
// 同步信息对象
|
||||
type syncingInfo struct {
|
||||
// 同步数据对象的唯一标识,用于进行重复判断
|
||||
identifier string
|
||||
|
||||
// 同步信息项
|
||||
item *syncingModel
|
||||
|
||||
// 数据库连接对象
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// 获取同步信息
|
||||
// filePath:正在同步的文件
|
||||
// fileOffset:同步到的位置
|
||||
func (this *syncingInfo) GetSyncingInfo() (filePath string, fileOffset int64) {
|
||||
return this.item.FilePath, this.item.FileOffset
|
||||
}
|
||||
|
||||
// 更新正在同步的位置和文件信息
|
||||
// filePath:文件路径
|
||||
// offset:当前同步到的位置
|
||||
// tran:事务对象,可以为nil
|
||||
// 返回值:
|
||||
// error:处理的错误信息
|
||||
func (this *syncingInfo) Update(filePath string, offset int64, tran *sql.Tx) error {
|
||||
this.item.FilePath = filePath
|
||||
this.item.FileOffset = offset
|
||||
this.item.UpdateTime = time.Now()
|
||||
|
||||
// 更新到数据库
|
||||
return this.update(this.item, tran)
|
||||
}
|
||||
|
||||
// 初始化同步信息
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncingInfo) init() error {
|
||||
if ifSyncingInfoTableInited == false {
|
||||
err := initSyncingInfoTable(this.db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ifSyncingInfoTableInited = true
|
||||
}
|
||||
|
||||
// 获取此表的同步信息
|
||||
data, exist, err := this.get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 如果同步信息不存在,则初始化一条到此表
|
||||
if exist == false {
|
||||
data = &syncingModel{
|
||||
Identifier: this.identifier,
|
||||
FilePath: "",
|
||||
FileOffset: 0,
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
|
||||
err = this.insert(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
this.item = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从数据库获取数据
|
||||
// 返回值:
|
||||
// data:获取到的数据
|
||||
// exist:是否存在此数据
|
||||
// err:错误信息
|
||||
func (this *syncingInfo) get() (data *syncingModel, exist bool, err error) {
|
||||
//// 从数据库查询
|
||||
querySql := fmt.Sprintf("SELECT FilePath,FileOffset,UpdateTime FROM syncing_info WHERE Identifier ='%v';", this.identifier)
|
||||
var rows *sql.Rows
|
||||
rows, err = this.db.Query(querySql)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncingInfo get.query error:%v", err.Error()))
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() == false {
|
||||
exist = false
|
||||
return
|
||||
}
|
||||
exist = true
|
||||
|
||||
// 读取数据
|
||||
data = &syncingModel{
|
||||
Identifier: this.identifier,
|
||||
}
|
||||
err = rows.Scan(&data.FilePath, &data.FileOffset, &data.UpdateTime)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncingInfo get.scan error:%v", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 把同步信息写入到数据库
|
||||
// data:待插入的数据
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncingInfo) insert(data *syncingModel) error {
|
||||
insertSql := "INSERT INTO syncing_info(Identifier,FilePath,FileOffset,UpdateTime) VALUES(?,?,?,?);"
|
||||
_, err := this.db.Exec(insertSql, data.Identifier, data.FilePath, data.FileOffset, data.UpdateTime)
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncingInfo insert error:%v", err.Error()))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 把同步信息更新到数据库
|
||||
// data:待更新的数据
|
||||
// tran:事务对象
|
||||
// 返回值:
|
||||
// error:错误信息
|
||||
func (this *syncingInfo) update(data *syncingModel, tran *sql.Tx) error {
|
||||
updateSql := "UPDATE syncing_info SET FilePath=?, FileOffset=?, UpdateTime=? WHERE Identifier=?;"
|
||||
var err error
|
||||
if tran != nil {
|
||||
_, err = tran.Exec(updateSql, data.FilePath, data.FileOffset, data.UpdateTime, data.Identifier)
|
||||
} else {
|
||||
_, err = this.db.Exec(updateSql, data.FilePath, data.FileOffset, data.UpdateTime, data.Identifier)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncingInfo update error:%v", err.Error()))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建同步信息对象
|
||||
// _dirPath:目录的路径
|
||||
// _identifier:当前数据的唯一标识(可以使用数据库表名)
|
||||
// _db:数据库连接对象
|
||||
// 返回值:
|
||||
// 同步信息对象
|
||||
func newSyncingInfoObject(identifier string, _db *sql.DB) (result *syncingInfo, err error) {
|
||||
result = &syncingInfo{
|
||||
identifier: identifier,
|
||||
db: _db,
|
||||
}
|
||||
|
||||
err = result.init()
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 初始化同步信息表结构
|
||||
// db:数据库连接对象
|
||||
func initSyncingInfoTable(db *sql.DB) error {
|
||||
if isTableInited {
|
||||
return initTableError
|
||||
}
|
||||
|
||||
defer func() {
|
||||
isTableInited = true
|
||||
}()
|
||||
|
||||
// 创建同步信息表
|
||||
createTableSql := `CREATE TABLE IF NOT EXISTS syncing_info (
|
||||
Identifier varchar(30) NOT NULL COMMENT '同步唯一标识(数据库表名)',
|
||||
FilePath varchar(500) NOT NULL COMMENT '正在同步的文件路径',
|
||||
FileOffset bigint NOT NULL COMMENT '文件偏移量',
|
||||
UpdateTime datetime NOT NULL COMMENT '最后一次更新时间',
|
||||
PRIMARY KEY (Identifier)
|
||||
) COMMENT 'P表同步信息';`
|
||||
if _, initTableError = db.Exec(createTableSql); initTableError != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/syncingInfo initSyncingInfoTable error:%v", initTableError.Error()))
|
||||
return initTableError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
6
trunk/framework/exitMgr/doc.go
Normal file
6
trunk/framework/exitMgr/doc.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package exitMgr
|
||||
|
||||
// 程序退出包,提供程序退出时的功能
|
||||
// 使用方法:
|
||||
// 1、先调用RegisterExitFunc方法,将系统退出时需要调用的方法进行注册。
|
||||
// 2、在程序退出时调用Exit()方法
|
||||
33
trunk/framework/exitMgr/exit.go
Normal file
33
trunk/framework/exitMgr/exit.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package exitMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
exitFuncMap = make(map[string]func())
|
||||
)
|
||||
|
||||
// RegisterExitFunc ...注册Exit方法
|
||||
// funcName:方法名称
|
||||
// exitFunc:exit方法
|
||||
func RegisterExitFunc(funcName string, exitFunc func()) {
|
||||
if _, exists := exitFuncMap[funcName]; exists {
|
||||
panic(fmt.Sprintf("%s已经存在,请重新取名", funcName))
|
||||
}
|
||||
|
||||
exitFuncMap[funcName] = exitFunc
|
||||
logUtil.InfoLog("RegisterExitFunc funcName:%s,当前共有%d个注册", funcName, len(exitFuncMap))
|
||||
}
|
||||
|
||||
// Exit ...退出程序
|
||||
// 返回值:
|
||||
// 无
|
||||
func Exit() {
|
||||
for funcName, exitFunc := range exitFuncMap {
|
||||
exitFunc()
|
||||
logUtil.InfoLog("Call ExitFunc:%s Finish.", funcName)
|
||||
}
|
||||
}
|
||||
256
trunk/framework/forbidWordsMgr/forbidWordsUtil.go
Normal file
256
trunk/framework/forbidWordsMgr/forbidWordsUtil.go
Normal file
@@ -0,0 +1,256 @@
|
||||
package forbidWordsMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"Framework/goroutineMgr"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/dfaUtil"
|
||||
"goutil/logUtil"
|
||||
"goutil/mathUtil"
|
||||
"goutil/webUtil"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
type ForbidWords struct {
|
||||
//游戏ID
|
||||
GameId int
|
||||
//屏蔽字
|
||||
Words string
|
||||
}
|
||||
|
||||
// 请求屏蔽字库地址
|
||||
const GetForbidWordURL string = "http://forbidword.7qule.com/Query"
|
||||
|
||||
//const GetForbidWordURL string = "http://10.253.0.186:10090/Query"
|
||||
|
||||
var (
|
||||
mHashValue string
|
||||
mDFAUtil *dfaUtil.DFAUtil
|
||||
mGameId int
|
||||
rand *mathUtil.Rand
|
||||
mGameOnly bool = false
|
||||
)
|
||||
|
||||
// 获取屏蔽字
|
||||
func refreshForbidWord() error {
|
||||
|
||||
//定义参数
|
||||
requestParamMap := make(map[string]string, 0)
|
||||
requestParamMap["GameId"] = strconv.Itoa(mGameId)
|
||||
requestParamMap["HashValue"] = mHashValue
|
||||
requestParamMap["DataType"] = "0"
|
||||
requestParamMap["IsResultCompressed"] = "true"
|
||||
if mGameOnly {
|
||||
requestParamMap["GameOnly"] = "true"
|
||||
}
|
||||
//data, _ := json.Marshal(requestParamMap)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 1000)
|
||||
|
||||
statusCode, returnBytesTemp, err := webUtil.PostMapData(GetForbidWordURL, requestParamMap, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(GetForbidWordURL, requestParamMap, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取屏蔽字出错,url:%s,错误信息为:%s", GetForbidWordURL, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取屏蔽字出错,url:%s,错误码为:%d", GetForbidWordURL, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
//解压
|
||||
returnBytes, err := zlibUtil.Decompress(returnBytesTemp)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog("返回结果解压失败")
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取屏蔽字反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
msg := fmt.Sprintf("获取屏蔽字出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else if returnObj.Code == 0 && len(returnObj.HashValue) == 0 { //表示没有更新
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
var tmpForbidWordList []*ForbidWords
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取屏蔽字出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpForbidWordList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取屏蔽字反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//缓存hasvalue
|
||||
mHashValue = returnObj.HashValue
|
||||
|
||||
//获取屏蔽字数组
|
||||
var temWordArray []string
|
||||
for _, item := range tmpForbidWordList {
|
||||
temWordArray = append(temWordArray, strings.ToUpper(item.Words))
|
||||
}
|
||||
//dfa
|
||||
mDFAUtil = dfaUtil.NewDFAUtil(temWordArray)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否包含屏蔽字
|
||||
func IsSensitiveWords(input string) (exist bool) {
|
||||
input = strings.ToUpper(input)
|
||||
exist = mDFAUtil.IsMatch(input)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 取出屏蔽字及开始位置
|
||||
func SensitiveWords(input string) (words []string, pos []int, exist bool) {
|
||||
input2 := strings.ToUpper(input)
|
||||
inputRune := []rune(input)
|
||||
startIndexList, endIndexList := mDFAUtil.SearchSentence(input2)
|
||||
if len(startIndexList) > 0 {
|
||||
exist = true
|
||||
words = make([]string, 0, len(startIndexList))
|
||||
pos = make([]int, 0, len(startIndexList))
|
||||
for i := 0; i < len(startIndexList); i++ {
|
||||
start := startIndexList[i]
|
||||
end := endIndexList[i]
|
||||
words = append(words, string(inputRune[start:end+1]))
|
||||
pos = append(pos, start)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 取出屏蔽字及开始及结束位置
|
||||
func SensitiveWordsEndStartPos(input string) (words []string, starts, ends []int, exist bool) {
|
||||
input2 := strings.ToUpper(input)
|
||||
inputRune := []rune(input)
|
||||
startIndexList, endIndexList := mDFAUtil.SearchSentence(input2)
|
||||
if len(startIndexList) > 0 {
|
||||
exist = true
|
||||
words = make([]string, 0, len(startIndexList))
|
||||
starts = startIndexList
|
||||
ends = endIndexList
|
||||
for i := 0; i < len(startIndexList); i++ {
|
||||
start := startIndexList[i]
|
||||
end := endIndexList[i]
|
||||
words = append(words, string(inputRune[start:end+1]))
|
||||
//pos = append(pos, start)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据用户输入的替换词替换敏感词
|
||||
func ReplaceSendsitiveWords(input, replaceStr string) (newStr string) {
|
||||
words, _, _, exist := SensitiveWordsEndStartPos(input)
|
||||
newStr = input
|
||||
//如果不存在敏感词,则直接返回
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
//循环替换
|
||||
for _, sendsitiveWord := range words {
|
||||
newStr = strings.Replace(newStr, sendsitiveWord, replaceStr, -1)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 判断服务器是否存在
|
||||
func IfServerExists() (exist bool) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 处理屏蔽字
|
||||
func HandleSendsitiveWords(input string) (newStr string) {
|
||||
newStr = mDFAUtil.HandleWord(input, rune('*'))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 处理敏感字-xjChat
|
||||
func HandleSendsitiveWordsUseStr(input string, replaceCh string) (newStr string) {
|
||||
newStr = mDFAUtil.HandleWordUseStr(input, replaceCh)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 定时刷新屏蔽字库
|
||||
func StartRefreshForbidWordListTread(gameId int) {
|
||||
rand = mathUtil.GetRand()
|
||||
mGameId = gameId
|
||||
// 定时刷新数据
|
||||
go func() {
|
||||
goroutineName := "forbidWordsMgr.StartRefreshForbidWordListTread"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
|
||||
func() {
|
||||
// 防止panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
}
|
||||
}()
|
||||
|
||||
// 刷新屏蔽字
|
||||
refreshForbidWord()
|
||||
|
||||
}()
|
||||
|
||||
// 每5分钟刷新一次
|
||||
time.Sleep(time.Duration(rand.GetRandRangeInt64(120, 300)) * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 定时刷新屏蔽字库(排除公共字库,只刷新游戏内的)
|
||||
func StartRefreshForbidWordListTreadExcludeComm(gameId int) {
|
||||
rand = mathUtil.GetRand()
|
||||
mGameId = gameId
|
||||
mGameOnly = true
|
||||
// 定时刷新数据
|
||||
go func() {
|
||||
goroutineName := "forbidWordsMgr.StartRefreshForbidWordListTread"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
// 刷新屏蔽字
|
||||
refreshForbidWord()
|
||||
|
||||
// 每5分钟刷新一次
|
||||
time.Sleep(time.Duration(rand.GetRandRangeInt64(120, 300)) * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
61
trunk/framework/forbidWordsMgr/forbidWords_test.go
Normal file
61
trunk/framework/forbidWordsMgr/forbidWords_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package forbidWordsMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// type Persion struct {
|
||||
// name string
|
||||
// }
|
||||
|
||||
// 屏蔽字详细信息
|
||||
func Test1(t *testing.T) {
|
||||
//启动获取屏蔽字
|
||||
refreshForbidWord()
|
||||
|
||||
words, pos, exist := SensitiveWords("测试,测试")
|
||||
if exist {
|
||||
t.Log(words, pos)
|
||||
}
|
||||
|
||||
t.Log("END")
|
||||
}
|
||||
|
||||
func TestForbidWord(t *testing.T) {
|
||||
// //启动获取屏蔽字
|
||||
// refreshForbidWord()
|
||||
|
||||
// //判断是否有屏蔽字
|
||||
// str := "好多花姑凉"
|
||||
|
||||
// isExist := IsSensitiveWords(str)
|
||||
|
||||
// fmt.Println("是否有敏感字:", isExist)
|
||||
|
||||
// //处理屏蔽字
|
||||
// if isExist {
|
||||
// newstr := HandleSendsitiveWords(str)
|
||||
|
||||
// fmt.Println("newStr:", newstr)
|
||||
// }
|
||||
|
||||
// persionSlice := make([]*Persion, 0, 5)
|
||||
// //var persionSlice []*Persion
|
||||
// for i := 0; i < 10; i++ {
|
||||
// p := &Persion{
|
||||
// name: "append",
|
||||
// }
|
||||
// persionSlice = append(persionSlice, p)
|
||||
// fmt.Println(&persionSlice)
|
||||
// }
|
||||
|
||||
///fmt.Println(IfServerExists())
|
||||
StartRefreshForbidWordListTread(27)
|
||||
time.Sleep(10 * time.Second)
|
||||
fmt.Println(IsSensitiveWords("g点双享器"))
|
||||
fmt.Println(IsSensitiveWords("G点双享器"))
|
||||
time.Sleep(5 * time.Hour)
|
||||
|
||||
}
|
||||
80
trunk/framework/gameLogMgr/gameLog.go
Normal file
80
trunk/framework/gameLogMgr/gameLog.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package gameLogMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Shopify/sarama"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtilPlus"
|
||||
)
|
||||
|
||||
var (
|
||||
producer sarama.AsyncProducer
|
||||
)
|
||||
|
||||
// 启动生产者
|
||||
// 参数:
|
||||
// brokerList:Broker地址
|
||||
// userId:用户名(可默认为空字符串)
|
||||
// passWard:密码(可默认为空字符串)
|
||||
// 返回值:
|
||||
// 无
|
||||
func Start(brokerList []string, userId string, passWard string) {
|
||||
/*
|
||||
设置 acks = all。acks 是 Producer 的一个参数,代表了你对“已提交”消息的定义。如果设置成 all,则表明所有副本 Broker 都要接收到消息,该消息才算是“已提交”。这是最高等级的“已提交”定义。
|
||||
对于游戏日志,设置为WaitForLocal即可;如果是游戏数据,则应设置为WaitForAll
|
||||
设置 retries 为一个较大的值。这里的 retries 同样是 Producer 的参数,对应前面提到的 Producer 自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了 retries > 0 的 Producer 能够自动重试消息发送,避免消息丢失。
|
||||
*/
|
||||
var err error
|
||||
config := sarama.NewConfig()
|
||||
|
||||
config.Net.SASL.User = userId
|
||||
config.Net.SASL.Password = passWard
|
||||
config.Producer.Return.Successes = false
|
||||
config.Producer.Return.Errors = true
|
||||
config.Producer.Retry.Max = 10
|
||||
config.Producer.RequiredAcks = sarama.WaitForLocal
|
||||
producer, err = sarama.NewAsyncProducer(brokerList, config)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Kafka Start failed. Error: %v\n", err))
|
||||
}
|
||||
|
||||
go func() {
|
||||
for err := range producer.Errors() {
|
||||
debugUtil.Printf("Send message to kafka failed. Error: %v\n", err.Err)
|
||||
logUtilPlus.ErrorLog("Send message to kafka failed. Error: %v\n", err.Err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
if producer != nil {
|
||||
err := producer.Close()
|
||||
if err != nil {
|
||||
debugUtil.Printf("Stop kafka failed. Error: %v\n", err)
|
||||
logUtilPlus.ErrorLog("Stop kafka failed. Error: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 写入游戏日志
|
||||
// 参数:
|
||||
// serverGroupId: 游戏服务器组Id
|
||||
// key: 标识
|
||||
// message: 日志
|
||||
// 返回值: 无
|
||||
func Write(topic string, serverGroupId int32, message string) {
|
||||
if producer == nil {
|
||||
debugUtil.Printf("Send message to kafka failed. producer is nil")
|
||||
logUtilPlus.ErrorLog("Send message to kafka failed. producer is nil")
|
||||
return
|
||||
}
|
||||
|
||||
msg := &sarama.ProducerMessage{}
|
||||
msg.Topic = topic
|
||||
msg.Key = sarama.StringEncoder(fmt.Sprintf("%d", serverGroupId))
|
||||
msg.Value = sarama.ByteEncoder(message)
|
||||
|
||||
// Send to kafka
|
||||
producer.Input() <- msg
|
||||
}
|
||||
67
trunk/framework/gameLogMgr/gameLog_test.go
Normal file
67
trunk/framework/gameLogMgr/gameLog_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package gameLogMgr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"goutil/debugUtil"
|
||||
"goutil/stringUtil"
|
||||
"goutil/timeUtil"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
debugUtil.SetDebug(true)
|
||||
|
||||
brokerList := []string{"10.1.0.202:9092", "10.1.0.204:9092", "10.1.0.205:9092"}
|
||||
Start(brokerList, "", "")
|
||||
|
||||
topic := "test2"
|
||||
serverGroupId := int32(20011)
|
||||
for i := 0; i < 5; i++ {
|
||||
Write(topic, serverGroupId, getGameLog(i))
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
Stop()
|
||||
}
|
||||
|
||||
func BenchmarkWrite(b *testing.B) {
|
||||
debugUtil.SetDebug(true)
|
||||
topic := "test2"
|
||||
serverGroupId := int32(20011)
|
||||
|
||||
brokerList := []string{"10.1.0.202:9092", "10.1.0.204:9092", "10.1.0.205:9092"}
|
||||
Start(brokerList, "", "")
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Write(topic, serverGroupId, getGameLog(i))
|
||||
}
|
||||
b.StopTimer()
|
||||
|
||||
Stop()
|
||||
}
|
||||
|
||||
func getGameLog(int2 int) string {
|
||||
//kafkaLog组装
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("{")
|
||||
buffer.WriteString(fmt.Sprintf("\"#account_id\":\"%s\"", "123456789123456789"))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"#time\":\"%s\"", time.Now().Format("2006-01-02 15:04:05")))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"#uuid\":\"%s\"", stringUtil.GetNewGUID()))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"#event_id\":\"\""))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"#type\":\"track\""))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"#event_name\":\"achievement_change_log\""))
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString(fmt.Sprintf("\"properties\":{\"PartnerId\":%d,\"ServerId\":%d,\"Crtime\":\"%s\",\"Crdate\":\"%s\"}", 600021, int2, timeUtil.ToDateTimeString2(time.Now()), timeUtil.ToDateString2(time.Now())))
|
||||
buffer.WriteString("}")
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
14
trunk/framework/gameLogMgr/model.go
Normal file
14
trunk/framework/gameLogMgr/model.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package gameLogMgr
|
||||
|
||||
// 游戏日志对象
|
||||
type GameLog struct {
|
||||
ServerGroupId int32 // 服务器组Id
|
||||
LogSql string // 日志Sql
|
||||
}
|
||||
|
||||
func newGameLog(serverGroupId int32, logSql string) *GameLog {
|
||||
return &GameLog{
|
||||
ServerGroupId: serverGroupId,
|
||||
LogSql: logSql,
|
||||
}
|
||||
}
|
||||
76
trunk/framework/gameServerMgr/area.go
Normal file
76
trunk/framework/gameServerMgr/area.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
. "Framework/managecenterModel"
|
||||
)
|
||||
|
||||
var (
|
||||
mAreaList = make([]*Area, 0)
|
||||
)
|
||||
|
||||
// 解析大区信息
|
||||
func ParseAreaInfo(areaList []*Area) {
|
||||
mAreaList = areaList
|
||||
}
|
||||
|
||||
// 根据服务器组id获取大区Id
|
||||
func GetAreaIdByGroupId(groupId int32) (areaId int32) {
|
||||
areaId = 0
|
||||
|
||||
//如果没有大区数据,返回0
|
||||
if mAreaList == nil || len(mAreaList) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, area := range mAreaList {
|
||||
if area.CheckServerIdIsInRange(groupId) {
|
||||
areaId = area.AreaId
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据服务器组id获取大区对象数据
|
||||
func GetAreaDBByGroupId(groupId int32) (areaDB *Area, exist bool) {
|
||||
//如果没有大区数据,返回空
|
||||
exist = false
|
||||
if mAreaList == nil || len(mAreaList) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, area := range mAreaList {
|
||||
if area.CheckServerIdIsInRange(groupId) {
|
||||
areaDB = area
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 根据大区ID获取大区信息
|
||||
func GetAreaDBbyAreaID(areaId int32) (areaDB *Area, exist bool) {
|
||||
//如果没有大区数据,返回空
|
||||
exist = false
|
||||
if mAreaList == nil || len(mAreaList) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, area := range mAreaList {
|
||||
if area.AreaId == areaId {
|
||||
areaDB = area
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有大区信息
|
||||
func GetAllAreaDB() []*Area {
|
||||
tempList := mAreaList
|
||||
return tempList
|
||||
}
|
||||
33
trunk/framework/gameServerMgr/chargeConfig.go
Normal file
33
trunk/framework/gameServerMgr/chargeConfig.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
)
|
||||
|
||||
var (
|
||||
mChargeConfigMap = make(map[int32][]*ChargeConfig, 0)
|
||||
)
|
||||
|
||||
//解析充值配置信息
|
||||
func ParseChargeConfigInfo(partnerList []*Partner) {
|
||||
tmpChargeConfigMap := make(map[int32][]*ChargeConfig, 0)
|
||||
|
||||
//循环解析所有合作商里面的充值配置信息
|
||||
for _, partner := range partnerList {
|
||||
var chargeConfigList []*ChargeConfig
|
||||
if err := json.Unmarshal([]byte(partner.ChargeConfig), &chargeConfigList); err == nil {
|
||||
tmpChargeConfigMap[partner.Id] = chargeConfigList
|
||||
}
|
||||
}
|
||||
|
||||
mChargeConfigMap = tmpChargeConfigMap
|
||||
}
|
||||
|
||||
// 根据合作商Id获取合作商充值配置对象
|
||||
func GetChargeConfigList(partnerId int32) (chargeConfigList []*ChargeConfig, exist bool) {
|
||||
chargeConfigList, exist = mChargeConfigMap[partnerId]
|
||||
|
||||
return
|
||||
}
|
||||
433
trunk/framework/gameServerMgr/chargeUtil.go
Normal file
433
trunk/framework/gameServerMgr/chargeUtil.go
Normal file
@@ -0,0 +1,433 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/securityUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
type ChargeUtil struct{}
|
||||
|
||||
//获取Int32型的充值金额(充值金额必须大于1,否则可能就会无效)
|
||||
func (this *ChargeUtil) GetInt32ChargeMoney(money float32) int32 {
|
||||
return int32(money)
|
||||
}
|
||||
|
||||
//获取排好序的充值配置列表
|
||||
func (this *ChargeUtil) GetOrderedChargeConfigList(partnerId int32, isMonthCard bool) (list []*ChargeConfig, exist bool) {
|
||||
var tempList []*ChargeConfig
|
||||
tempList, exist = GetChargeConfigList(partnerId)
|
||||
|
||||
//如果不存在,则返回空集合
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
//循环遍历集合,找出是月卡的数据
|
||||
for _, item := range tempList {
|
||||
if item.IsMonthCard == isMonthCard {
|
||||
list = append(list, item)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 生成充值订单号
|
||||
// url:生成订单号的服务器地址
|
||||
// productId:产品Id
|
||||
// partnerId:合作商Id
|
||||
// serverId:服务器Id
|
||||
// userId:平台用户Id
|
||||
// playerId:玩家Id
|
||||
// mac:mac
|
||||
// idfa:idfa
|
||||
// ip:ip
|
||||
// imei:imei
|
||||
// extra:extra
|
||||
// isMonthCard:是否月卡
|
||||
// 返回值:
|
||||
// 订单号
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) GenerateOrderId(url, productId string, partnerId, serverId int32,
|
||||
userId, playerId, mac, idfa, ip, imei, extra string,
|
||||
isMonthCard bool) (orderId string, err error) {
|
||||
|
||||
if extra == "" {
|
||||
extra = "FromGameServer"
|
||||
}
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["ProductId"] = productId
|
||||
postDict["PartnerId"] = fmt.Sprintf("%d", partnerId)
|
||||
postDict["ServerId"] = fmt.Sprintf("%d", serverId)
|
||||
postDict["UserId"] = userId
|
||||
postDict["PlayerId"] = playerId
|
||||
postDict["MAC"] = mac
|
||||
postDict["IDFA"] = idfa
|
||||
postDict["IP"] = ip
|
||||
postDict["IMEI"] = imei
|
||||
postDict["Extra"] = extra
|
||||
postDict["IsMonthCard"] = strconv.FormatBool(isMonthCard)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err1 := webUtil.PostMapData(url, postDict, header, transport)
|
||||
if err1 != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("生成充值订单号出错,url:%s,错误信息为:%s", url, err1))
|
||||
err = err1
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("生成充值订单号出错,url:%s,错误码为:%d", url, statusCode))
|
||||
err = fmt.Errorf("生成充值订单号出错,url:%s,错误码为:%d", url, statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
orderId = string(returnBytes)
|
||||
if orderId == "" {
|
||||
err = fmt.Errorf("Order Is Empty")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//生成支付订单信息
|
||||
func (this *ChargeUtil) GeneratePayOrderInfo(url string, partnerId int32, jsonBase64Data string) (returnObject ReturnObject, err error) {
|
||||
//String requestParam = String.Format(@"PartnerId={0}&JsonBase64Data={1}", partnerId, jsonBase64Data);
|
||||
postDict := make(map[string]string)
|
||||
postDict["PartnerId"] = fmt.Sprintf("%d", partnerId)
|
||||
postDict["JsonBase64Data"] = jsonBase64Data
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
//通过POST方式请求数据
|
||||
statusCode, returnBytes, err1 := webUtil.PostMapData(url, postDict, header, transport)
|
||||
if err1 != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("生成支付订单信息错误:%s,错误信息为:%s", url, err1))
|
||||
err = err1
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("生成支付订单信息出错,url:%s,错误码为:%d", url, statusCode))
|
||||
err = fmt.Errorf("生成支付订单信息出错,url:%s,错误码为:%d", url, statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(returnBytes, &returnObject)
|
||||
|
||||
return
|
||||
//return JsonUtil.Deserialize<ReturnObject>(WebUtil.PostWebData(generateOrderIdUrl, requestParam, DataCompress.NotCompress));
|
||||
}
|
||||
|
||||
// 获取充值配置列表
|
||||
// partnerId:合作商Id
|
||||
// vipLv:玩家VIP等级
|
||||
// isMonthCard:是否月卡
|
||||
// filter:过滤器
|
||||
// 返回值:
|
||||
// 充值配置列表
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) GetChargeConfigList(partnerId int32, vipLv byte, isMonthCard bool,
|
||||
filter func(*ChargeConfig) bool) (chargeConfigList []*ChargeConfig, exists bool, err error) {
|
||||
|
||||
// 获取排好序的充值配置列表
|
||||
var tmpList []*ChargeConfig
|
||||
tmpList, exists, err = this.getSortedChargeConfigList(partnerId, isMonthCard)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
// 根据vip和filter进行筛选
|
||||
for _, item := range tmpList {
|
||||
if filter != nil {
|
||||
if vipLv >= item.VipLv && filter(item) {
|
||||
chargeConfigList = append(chargeConfigList, item)
|
||||
}
|
||||
} else {
|
||||
if vipLv >= item.VipLv {
|
||||
chargeConfigList = append(chargeConfigList, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有符合条件的数据
|
||||
if len(chargeConfigList) == 0 {
|
||||
exists = false
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取有序的充值配置列表
|
||||
// partnerId:合作商Id
|
||||
// isMonthCard:是否月卡
|
||||
// 返回值:
|
||||
// 充值配置列表
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) getSortedChargeConfigList(partnerId int32, isMonthCard bool) (chargeConfigList []*ChargeConfig, exists bool, err error) {
|
||||
// 判断合作商是否存在
|
||||
//var partnerObj *Partner
|
||||
//partnerObj, exists = managecenterMgr.GetPartner(partnerId)
|
||||
//if !exists {
|
||||
//return
|
||||
//}
|
||||
|
||||
// 反序列化充值配置
|
||||
var tmpChargeConfigList []*ChargeConfig
|
||||
tmpChargeConfigList, exists = GetChargeConfigList(partnerId)
|
||||
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
//if err = json.Unmarshal([]byte(partnerObj.ChargeConfig), &tmpChargeConfigList); err != nil {
|
||||
//return
|
||||
//}
|
||||
|
||||
// 根据isMonthCard进行筛选
|
||||
for _, item := range tmpChargeConfigList {
|
||||
if item.IsMonthCard == isMonthCard {
|
||||
chargeConfigList = append(chargeConfigList, item)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有符合条件的数据
|
||||
if len(chargeConfigList) == 0 {
|
||||
exists = false
|
||||
return
|
||||
}
|
||||
|
||||
// 按默认规则进行排序
|
||||
sort.Slice(chargeConfigList, func(i, j int) bool {
|
||||
return chargeConfigList[i].SortByChargePointAsc(chargeConfigList[j])
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取充值配置项
|
||||
// partnerId:合作商Id
|
||||
// vipLv:玩家VIP等级
|
||||
// isMonthCard:是否月卡
|
||||
// money:充值金额
|
||||
// 返回值:
|
||||
// 充值配置项
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) GetChargeConfigItem(partnerId int32, vipLv byte, isMonthCard bool, money float64) (chargeConfigItem *ChargeConfig, exists bool, err error) {
|
||||
// 获取排好序的充值配置列表
|
||||
var tmpList []*ChargeConfig
|
||||
tmpList, exists, err = this.getSortedChargeConfigList(partnerId, isMonthCard)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取满足充值金额和VIP条件的最后一条数据
|
||||
for _, item := range tmpList {
|
||||
if vipLv >= item.VipLv && money >= item.ChargePoint {
|
||||
chargeConfigItem = item
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有符合条件的,则选择第一条配置
|
||||
if chargeConfigItem == nil {
|
||||
chargeConfigItem = tmpList[0]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 计算充值获得的游戏点数
|
||||
// partnerId:合作商Id
|
||||
// vipLv:玩家VIP等级
|
||||
// isMonthCard:是否月卡
|
||||
// money:充值金额
|
||||
// 返回值:
|
||||
// 充值获得的游戏点数
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) CalcChargeGamePoint(partnerId int32, vipLv byte, isMonthCard bool, money float64, productId string) (chargeGamePoint int, exists bool, err error) {
|
||||
// 获取排好序的充值配置列表
|
||||
chargeGamePoint = 0
|
||||
|
||||
tmpList := make([]*ChargeConfig, 0, 8)
|
||||
tmpList, exists, err = this.getSortedChargeConfigList(partnerId, isMonthCard)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
var chargeConfigItem *ChargeConfig
|
||||
|
||||
if money > 0 {
|
||||
// 获取满足充值金额和VIP条件的最后一条数据
|
||||
for _, item := range tmpList {
|
||||
if vipLv >= item.VipLv && money >= item.ChargePoint {
|
||||
chargeConfigItem = item
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到对应的档位,则选择最低金额档位
|
||||
if chargeConfigItem == nil {
|
||||
chargeConfigItem = tmpList[0]
|
||||
}
|
||||
|
||||
// 计算充值对应的ProductId,以及获得的游戏货币
|
||||
if money == chargeConfigItem.ChargePoint {
|
||||
chargeGamePoint = chargeConfigItem.GamePoint
|
||||
} else {
|
||||
chargeGamePoint = int(math.Ceil(money * chargeConfigItem.Ratio))
|
||||
}
|
||||
return
|
||||
} else {
|
||||
for _, item := range tmpList {
|
||||
if item.ProductId == productId && item.VipLv <= vipLv {
|
||||
chargeConfigItem = item
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if chargeConfigItem != nil {
|
||||
chargeGamePoint = chargeConfigItem.GamePoint
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 计算充值获得的所有游戏点数
|
||||
// partnerId:合作商Id
|
||||
// vipLv:玩家VIP等级
|
||||
// isMonthCard:是否月卡
|
||||
// money:充值金额
|
||||
// activityMoney:活动金额
|
||||
// isFirstCharge:是否首充
|
||||
// 返回值:
|
||||
// 充值获得的游戏点数
|
||||
// 充值赠送获得的游戏内货币数量
|
||||
// 充值活动获得的游戏内货币数量
|
||||
// 总的元宝数量
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func (this *ChargeUtil) CalcChargeAllGamePoint(partnerId int32, vipLv byte, isMonthCard bool,
|
||||
money, activityMoney float64, productId string, isFirstCharge bool) (
|
||||
chargeGamePoint int, giveGamePoint int, activityGamePoint int, totalGamePoint int,
|
||||
exists bool, err error) {
|
||||
|
||||
// 获取排好序的充值配置列表
|
||||
tmpList := make([]*ChargeConfig, 0, 8)
|
||||
tmpList, exists, err = this.getSortedChargeConfigList(partnerId, isMonthCard)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
var chargeConfigItem *ChargeConfig
|
||||
|
||||
if money > 0 {
|
||||
// 获取满足充值金额和VIP条件的最后一条数据
|
||||
for _, item := range tmpList {
|
||||
if vipLv >= item.VipLv && money >= item.ChargePoint {
|
||||
chargeConfigItem = item
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到对应的档位,则选择最低金额档位
|
||||
if chargeConfigItem == nil {
|
||||
chargeConfigItem = tmpList[0]
|
||||
}
|
||||
|
||||
// 计算充值对应的ProductId,以及获得的游戏货币
|
||||
if money == chargeConfigItem.ChargePoint {
|
||||
chargeGamePoint = chargeConfigItem.GamePoint
|
||||
if isFirstCharge {
|
||||
giveGamePoint = chargeConfigItem.FirstGiveGamePoint
|
||||
} else {
|
||||
giveGamePoint = chargeConfigItem.GiveGamePoint
|
||||
}
|
||||
} else {
|
||||
chargeGamePoint = int(math.Ceil(money * chargeConfigItem.Ratio))
|
||||
if isFirstCharge {
|
||||
giveGamePoint = chargeConfigItem.FirstGiveGamePoint
|
||||
} else {
|
||||
giveGamePoint = int(math.Ceil(money * chargeConfigItem.Ratio * chargeConfigItem.GiveRatio))
|
||||
}
|
||||
}
|
||||
|
||||
activityGamePoint = int(math.Ceil(activityMoney * chargeConfigItem.Ratio))
|
||||
} else {
|
||||
// 获取满足充值金额和VIP条件的最后一条数据
|
||||
for _, item := range tmpList {
|
||||
if vipLv >= item.VipLv && item.ProductId == productId {
|
||||
chargeConfigItem = item
|
||||
}
|
||||
}
|
||||
|
||||
if chargeConfigItem != nil {
|
||||
chargeGamePoint = chargeConfigItem.GamePoint
|
||||
if isFirstCharge {
|
||||
giveGamePoint = chargeConfigItem.FirstGiveGamePoint
|
||||
} else {
|
||||
giveGamePoint = chargeConfigItem.GiveGamePoint
|
||||
}
|
||||
|
||||
activityGamePoint = int(math.Ceil(activityMoney * chargeConfigItem.Ratio))
|
||||
}
|
||||
}
|
||||
|
||||
// 计算总和
|
||||
totalGamePoint = chargeGamePoint + giveGamePoint + activityGamePoint
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 验证充值签名
|
||||
// partnerId:合作商Id
|
||||
// serverId:区服Id
|
||||
// playerId:玩家Id
|
||||
// orderId:订单Id
|
||||
// productId:产品Id
|
||||
// deviceIdentifier:设备唯一标识
|
||||
// sign:签名
|
||||
// 返回值:
|
||||
// bool:签名验证情况
|
||||
func (this *ChargeUtil) CheckChargeSign(partnerId int32, serverId int32, playerId string, orderId string, productId string, deviceIdentifier string, sign string) bool {
|
||||
partnerObj, exist := GetPartnerItem(partnerId)
|
||||
if exist == false {
|
||||
return false
|
||||
}
|
||||
|
||||
rawString := fmt.Sprintf("%v%v%v%v%v%v%v", partnerId, serverId, playerId, orderId, productId, deviceIdentifier, partnerObj.LoginKey)
|
||||
if securityUtil.Md5String(rawString, false) != sign {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ------------------类型定义和业务逻辑的分隔符-------------------------
|
||||
|
||||
var (
|
||||
ChargeUtilObj = new(ChargeUtil)
|
||||
)
|
||||
410
trunk/framework/gameServerMgr/chargeUtil_test.go
Normal file
410
trunk/framework/gameServerMgr/chargeUtil_test.go
Normal file
@@ -0,0 +1,410 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"Framework/managecenterModel"
|
||||
"goutil/stringUtil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestChargeUtil_GetChargeConfigList(t *testing.T) {
|
||||
/*
|
||||
渠道充值配置:[{"ProductId":"fzxh_00060","ChargePoint":6,"GamePoint":60,"Ratio":10,"GiveGamePoint":6,"FirstGiveGamePoint":60,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00300","ChargePoint":30,"GamePoint":300,"Ratio":10,"GiveGamePoint":30,"FirstGiveGamePoint":300,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00500","ChargePoint":50,"GamePoint":550,"Ratio":11,"GiveGamePoint":110,"FirstGiveGamePoint":550,"GiveRatio":0.2,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00980","ChargePoint":98,"GamePoint":1470,"Ratio":15,"GiveGamePoint":441,"FirstGiveGamePoint":1470,"GiveRatio":0.3,"VipLv":5,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_restriction_18","ChargePoint":18,"GamePoint":90,"Ratio":5,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":3,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true},{"ProductId":"fzxh_restriction_50","ChargePoint":50,"GamePoint":300,"Ratio":6,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true}]
|
||||
*/
|
||||
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
var partnerId int32 = 1001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
type VipRange struct {
|
||||
MinVip byte
|
||||
MaxVip byte
|
||||
}
|
||||
|
||||
var isMonthCard = false
|
||||
var maxVip byte = 20
|
||||
|
||||
vipMap := make(map[VipRange][]float64)
|
||||
vipMap[VipRange{MinVip: 0, MaxVip: 0}] = []float64{6, 30}
|
||||
vipMap[VipRange{MinVip: 1, MaxVip: 4}] = []float64{6, 30, 50}
|
||||
vipMap[VipRange{MinVip: 5, MaxVip: maxVip}] = []float64{6, 30, 50, 98}
|
||||
|
||||
isExistsChargeConfig := func(configs []*managecenterModel.ChargeConfig, point float64) bool {
|
||||
for _, item := range configs {
|
||||
if item.ChargePoint == point {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//每个VIP等级都获取一遍充值档位
|
||||
for vipRange, points := range vipMap {
|
||||
for vip := vipRange.MinVip; vip <= vipRange.MaxVip; vip++ {
|
||||
showChargeList, exists, error := ChargeUtilObj.GetChargeConfigList(partnerId, vip, isMonthCard, func(config *managecenterModel.ChargeConfig) bool {
|
||||
if config.IfFirstShow == 1 && config.IfSecondShow == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
if error != nil {
|
||||
t.Fatalf("获取充值配置列表出现错误:%v", error)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatalf("PartnerId[%d],Vip[%d],IsMonthCard[%v],未找到充值配置列表", partnerId, vip, isMonthCard)
|
||||
}
|
||||
|
||||
for _, point := range points {
|
||||
if !isExistsChargeConfig(showChargeList, point) {
|
||||
t.Fatalf("PartnerId[%d],Vip[%d],IsMonthCard[%v],金额[%f]未找到充值配置", partnerId, vip, isMonthCard, point)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 测试生成订单号
|
||||
func TestChargeUtil_GenerateOrderId(t *testing.T) {
|
||||
var chargeServerUrl = "https://chargetest-xht.moqikaka.com/API/GenerateOrderId.ashx"
|
||||
var serverGroupId int32 = 20001
|
||||
var partnerId int32 = 1001
|
||||
var productId = "fzxh_00060"
|
||||
var userId = stringUtil.GetNewGUID()
|
||||
var playerId = stringUtil.GetNewGUID()
|
||||
var isMonthCard = true
|
||||
|
||||
//生成订单号
|
||||
orderId, error := ChargeUtilObj.GenerateOrderId(
|
||||
chargeServerUrl, productId, partnerId, serverGroupId, userId, playerId, "macmacmacmac", "idfa", "ip", "imei", "extra", isMonthCard)
|
||||
if error != nil {
|
||||
t.Fatalf("生成订单号[GenerateOrderId]出现错误:%v", error)
|
||||
}
|
||||
|
||||
t.Logf("生成订单号[GenerateOrderId]:%s", orderId)
|
||||
}
|
||||
|
||||
// 测试验证充值回调签名
|
||||
func TestChargeUtil_CheckChargeSign(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
var partnerId int32 = 1001
|
||||
var playerId = "04bade21-d7f7-4188-bc7c-8914c5330a23"
|
||||
var orderId = "1001_20001_1590394423_2"
|
||||
var productId = "fzxh_00060"
|
||||
var deviceIdentifier = "deviceIdentifier"
|
||||
//var loginKey = "a0482eaf-14e8-4a65-950e-864214f62da5"
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//充值服务器生成的签名
|
||||
var targetSign = "02bd33319fc0f520a3e801f725973017"
|
||||
|
||||
//验证充值回调签名是否正确
|
||||
if !ChargeUtilObj.CheckChargeSign(partnerId, serverGroupId, playerId, orderId, productId, deviceIdentifier, targetSign) {
|
||||
t.Fatalf("验证充值回调签名失败!目标签名:%s", targetSign)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取充值配置
|
||||
func TestChargeUtil_GetChargeConfigItem(t *testing.T) {
|
||||
/*
|
||||
渠道充值配置:[{"ProductId":"fzxh_00060","ChargePoint":6,"GamePoint":60,"Ratio":10,"GiveGamePoint":6,"FirstGiveGamePoint":60,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00300","ChargePoint":30,"GamePoint":300,"Ratio":10,"GiveGamePoint":30,"FirstGiveGamePoint":300,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00500","ChargePoint":50,"GamePoint":550,"Ratio":11,"GiveGamePoint":110,"FirstGiveGamePoint":550,"GiveRatio":0.2,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00980","ChargePoint":98,"GamePoint":1470,"Ratio":15,"GiveGamePoint":441,"FirstGiveGamePoint":1470,"GiveRatio":0.3,"VipLv":5,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_restriction_18","ChargePoint":18,"GamePoint":90,"Ratio":5,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":3,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true},{"ProductId":"fzxh_restriction_50","ChargePoint":50,"GamePoint":300,"Ratio":6,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true}]
|
||||
*/
|
||||
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
var partnerId int32 = 1001
|
||||
var maxVip byte = 20
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
type VipRange struct {
|
||||
MinVip byte
|
||||
MaxVip byte
|
||||
}
|
||||
|
||||
//#region 测试获取普通充值配置
|
||||
|
||||
isMonthCard := false
|
||||
vipMap := make(map[VipRange][]float64)
|
||||
vipMap[VipRange{MinVip: 0, MaxVip: 0}] = []float64{6, 30}
|
||||
vipMap[VipRange{MinVip: 1, MaxVip: 4}] = []float64{6, 30, 50}
|
||||
vipMap[VipRange{MinVip: 5, MaxVip: maxVip}] = []float64{6, 30, 50, 98}
|
||||
|
||||
//每个VIP等级都获取一遍充值档位
|
||||
for vipRange, points := range vipMap {
|
||||
for vip := vipRange.MinVip; vip <= vipRange.MaxVip; vip++ {
|
||||
for _, point := range points {
|
||||
//获取充值配置
|
||||
chargeConfig, exists, error := ChargeUtilObj.GetChargeConfigItem(partnerId, vip, isMonthCard, point)
|
||||
if error != nil {
|
||||
t.Fatalf("普通充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]获取充值档位出现错误:%v", vip, point, error)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatalf("普通充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]未找到充值档位配置", vip, point)
|
||||
}
|
||||
|
||||
if chargeConfig == nil {
|
||||
t.Fatalf("普通充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]找到的充值档位配置为nil", vip, point)
|
||||
}
|
||||
|
||||
if chargeConfig.ChargePoint != point {
|
||||
t.Fatalf("普通充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]找到的充值档位ChargePoint[%f]错误", vip, point, chargeConfig.ChargePoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region 测试获取月卡充值配置
|
||||
|
||||
isMonthCard = true
|
||||
vipMap = make(map[VipRange][]float64)
|
||||
vipMap[VipRange{MinVip: 1, MaxVip: 1}] = []float64{50}
|
||||
vipMap[VipRange{MinVip: 3, MaxVip: maxVip}] = []float64{18, 50}
|
||||
|
||||
//每个VIP等级都获取一遍充值档位
|
||||
for vipRange, points := range vipMap {
|
||||
for vip := vipRange.MinVip; vip <= vipRange.MaxVip; vip++ {
|
||||
for _, point := range points {
|
||||
//获取充值配置
|
||||
chargeConfig, exists, error := ChargeUtilObj.GetChargeConfigItem(partnerId, vip, isMonthCard, point)
|
||||
if error != nil {
|
||||
t.Fatalf("月卡充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]获取充值档位出现错误:%v", vip, point, error)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatalf("月卡充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]未找到充值档位配置", vip, point)
|
||||
}
|
||||
|
||||
if chargeConfig == nil {
|
||||
t.Fatalf("月卡充值,Vip[%d],Point[%f]找到的充值档位配置为nil", vip, point)
|
||||
}
|
||||
|
||||
if chargeConfig.ChargePoint != point {
|
||||
t.Fatalf("月卡充值,获取充值配置[GetChargeConfigItem],Vip[%d],Point[%f]找到的充值档位ChargePoint[%f]错误", vip, point, chargeConfig.ChargePoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
// 测试计算充值获得的游戏货币
|
||||
func TestChargeUtil_CalcChargeAllGamePoint(t *testing.T) {
|
||||
/*
|
||||
渠道充值配置:[{"ProductId":"fzxh_00060","ChargePoint":6,"GamePoint":60,"Ratio":10,"GiveGamePoint":6,"FirstGiveGamePoint":60,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00300","ChargePoint":30,"GamePoint":300,"Ratio":10,"GiveGamePoint":30,"FirstGiveGamePoint":300,"GiveRatio":0.1,"VipLv":0,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00500","ChargePoint":50,"GamePoint":550,"Ratio":11,"GiveGamePoint":110,"FirstGiveGamePoint":550,"GiveRatio":0.2,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_00980","ChargePoint":98,"GamePoint":1470,"Ratio":15,"GiveGamePoint":441,"FirstGiveGamePoint":1470,"GiveRatio":0.3,"VipLv":5,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":false},{"ProductId":"fzxh_restriction_18","ChargePoint":18,"GamePoint":90,"Ratio":5,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":3,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true},{"ProductId":"fzxh_restriction_50","ChargePoint":50,"GamePoint":300,"Ratio":6,"GiveGamePoint":0,"FirstGiveGamePoint":0,"GiveRatio":0,"VipLv":1,"IfFirstShow":1,"IfSecondShow":1,"IsMonthCard":true}]
|
||||
*/
|
||||
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
var partnerId int32 = 1001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//输入订单信息
|
||||
type OrderItem struct {
|
||||
Vip byte
|
||||
Money float64
|
||||
ActivityMoney float64
|
||||
ProductId string
|
||||
IsFirstCharge bool
|
||||
IsMonthCard bool
|
||||
}
|
||||
|
||||
//计算结果
|
||||
type GamePointResult struct {
|
||||
ChargeGamePoint int
|
||||
GiveGamePoint int
|
||||
ActivityGamePoint int
|
||||
TotalGamePoint int
|
||||
}
|
||||
|
||||
testOrderMap := make(map[OrderItem]GamePointResult)
|
||||
|
||||
//#region 普通充值
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 6,
|
||||
ActivityMoney: 1,
|
||||
ProductId: "fzxh_00060",
|
||||
IsFirstCharge: true,
|
||||
IsMonthCard: false,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 60, //GamePoint
|
||||
GiveGamePoint: 60, //FirstGiveGamePoint
|
||||
ActivityGamePoint: 10, //ActivityMoney*Ratio = 1*10
|
||||
TotalGamePoint: 130,
|
||||
} //首充6元,活动金额1元
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 6,
|
||||
ActivityMoney: 1,
|
||||
ProductId: "fzxh_00060",
|
||||
IsFirstCharge: false,
|
||||
IsMonthCard: false,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 60, //GamePoint
|
||||
GiveGamePoint: 6, //GiveGamePoint 6
|
||||
ActivityGamePoint: 10, //ActivityMoney*Ratio = 1*10
|
||||
TotalGamePoint: 76,
|
||||
} //非首充6元,活动金额1元
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 0,
|
||||
ActivityMoney: 1,
|
||||
ProductId: "fzxh_00060",
|
||||
IsFirstCharge: false,
|
||||
IsMonthCard: false,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 60, //Money*Ratio = 6*10
|
||||
GiveGamePoint: 6, //GiveGamePoint 6
|
||||
ActivityGamePoint: 10, //ActivityMoney*Ratio = 1*10
|
||||
TotalGamePoint: 76,
|
||||
} //无金额匹配6元,活动金额1元
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 10,
|
||||
ActivityMoney: 3,
|
||||
ProductId: "",
|
||||
IsFirstCharge: false,
|
||||
IsMonthCard: false,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 100, //Money*Ratio = 10*10
|
||||
GiveGamePoint: 10, //Money*Ratio*GiveRatio 10 * 10 * 0.1
|
||||
ActivityGamePoint: 30, //ActivityMoney*Ratio = 3*10
|
||||
TotalGamePoint: 140,
|
||||
} //无对应档位配置,模糊匹配10元,活动金额1元,实际匹配到6元档位
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 3,
|
||||
Money: 98,
|
||||
ActivityMoney: 3,
|
||||
ProductId: "",
|
||||
IsFirstCharge: false,
|
||||
IsMonthCard: false,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 1078, //Money*Ratio = 98*11
|
||||
GiveGamePoint: 216, //Money*Ratio*GiveRatio 98 * 11 * 0.2 = 215.6
|
||||
ActivityGamePoint: 33, //ActivityMoney*Ratio = 3*11
|
||||
TotalGamePoint: 1327,
|
||||
} //Vip限制,匹配98元,实际匹配到50档位,活动金额3元
|
||||
|
||||
//#endregion
|
||||
|
||||
for order, result := range testOrderMap {
|
||||
//计算充值获得的游戏币
|
||||
chargeGamePoint, giveGamePoint, activityGamePoint, totalGamePoint, exists, err := ChargeUtilObj.CalcChargeAllGamePoint(
|
||||
partnerId, order.Vip, order.IsMonthCard, order.Money, order.ActivityMoney, order.ProductId, order.IsFirstCharge)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],金额[%f] error:%v", order.Money, err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],金额[%f]未找到充值配置:%v", order.Money, exists)
|
||||
}
|
||||
|
||||
if chargeGamePoint != result.ChargeGamePoint {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],ChargeGamePoint计算结果不正确,金额[%f],期望[%d],结果[%d]", order.Money, result.ChargeGamePoint, chargeGamePoint)
|
||||
}
|
||||
|
||||
if giveGamePoint != result.GiveGamePoint {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],GiveGamePoint计算结果不正确,金额[%f],期望[%d],结果[%d]", order.Money, result.GiveGamePoint, giveGamePoint)
|
||||
}
|
||||
|
||||
if activityGamePoint != result.ActivityGamePoint {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],ActivityGamePoint计算结果不正确,金额[%f],期望[%d],结果[%d]", order.Money, result.ActivityGamePoint, activityGamePoint)
|
||||
}
|
||||
|
||||
if totalGamePoint != result.TotalGamePoint {
|
||||
t.Fatalf("普通充值,计算充值获得游戏币[CalcChargeAllGamePoint],TotalGamePoint计算结果不正确,金额[%f],期望[%d],结果[%d]", order.Money, result.TotalGamePoint, totalGamePoint)
|
||||
}
|
||||
}
|
||||
|
||||
//#region 月卡充值
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 3,
|
||||
Money: 18,
|
||||
ProductId: "fzxh_restriction_18",
|
||||
IsMonthCard: true,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 90, //GamePoint
|
||||
} //18元月卡
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 50,
|
||||
ProductId: "fzxh_restriction_50",
|
||||
IsMonthCard: true,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 250, //Money * Ratio = 50 * 5
|
||||
} //VIP限制,匹配50元月卡,实际匹配到18元月卡
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 1,
|
||||
Money: 0,
|
||||
ProductId: "fzxh_restriction_50",
|
||||
IsMonthCard: true,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 300, //GamePoint
|
||||
} //无金额匹配50元月卡
|
||||
|
||||
testOrderMap[OrderItem{
|
||||
Vip: 0,
|
||||
Money: 0,
|
||||
ProductId: "fzxh_restriction_50",
|
||||
IsMonthCard: true,
|
||||
}] = GamePointResult{
|
||||
ChargeGamePoint: 0, //匹配不成功
|
||||
} //VIP限制,无金额匹配50元月卡
|
||||
|
||||
for order, result := range testOrderMap {
|
||||
//计算充值获得的游戏币
|
||||
chargeGamePoint, exists, err := ChargeUtilObj.CalcChargeGamePoint(
|
||||
partnerId, order.Vip, order.IsMonthCard, order.Money, order.ProductId)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("月卡充值,计算充值获得游戏币[CalcChargeGamePoint],金额[%f] error:%v", order.Money, err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
t.Fatalf("月卡充值,计算充值获得游戏币[CalcChargeGamePoint],金额[%f]未找到充值配置:%v", order.Money, exists)
|
||||
}
|
||||
|
||||
if chargeGamePoint != result.ChargeGamePoint {
|
||||
t.Fatalf("月卡充值,计算充值获得游戏币[CalcChargeGamePoint],ChargeGamePoint计算结果不正确,金额[%f],期望[%d],结果[%d]", order.Money, result.ChargeGamePoint, chargeGamePoint)
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
15
trunk/framework/gameServerMgr/gameserver_test.go
Normal file
15
trunk/framework/gameServerMgr/gameserver_test.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestActive(t *testing.T) {
|
||||
err := ActiveServer("https://managecenterapitest-xxx.79yougame.com/API/ServerActivate.ashx", 20002)
|
||||
if err != nil {
|
||||
fmt.Println("xxx")
|
||||
}
|
||||
|
||||
CheckNewResourceVersion(1001, 20002, 100, "1584085505_769926880ac0ae89a31dcdfef5b94b1e")
|
||||
}
|
||||
131
trunk/framework/gameServerMgr/loginUtil.go
Normal file
131
trunk/framework/gameServerMgr/loginUtil.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/securityUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
// 登陆助手类
|
||||
type LoginUtil struct{}
|
||||
|
||||
// 验证登陆信息
|
||||
// partnerId:合作商Id
|
||||
// userId:合作商用户Id
|
||||
// loginInfo:登陆信息
|
||||
// isIntranet:是否是内网:true,内网;false:外网
|
||||
// 返回值:
|
||||
// 成功与否
|
||||
// 错误对象
|
||||
func (this *LoginUtil) CheckLoginInfo(partnerId int32, userId, loginInfo string, isIntranet bool) (success bool, err error) {
|
||||
// 验证用户合法性
|
||||
loginItemList := strings.Split(loginInfo, "_")
|
||||
if len(loginItemList) != 2 {
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s", partnerId, userId, loginInfo)
|
||||
return
|
||||
}
|
||||
|
||||
//将requestUrl地址进行拆分
|
||||
requestDomainList := strings.Split(loginItemList[1], ";")
|
||||
|
||||
//请求的主域名
|
||||
requestDomain := ""
|
||||
if isIntranet || len(requestDomainList) == 1 {
|
||||
requestDomain = requestDomainList[0]
|
||||
} else {
|
||||
requestDomain = requestDomainList[1]
|
||||
}
|
||||
|
||||
//构造请求url
|
||||
requestUrl := fmt.Sprintf("http://%s/API/CheckDynamicLoginKey.ashx", requestDomain)
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["UserId"] = userId
|
||||
postDict["LoginKey"] = loginItemList[0]
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err1 := webUtil.PostMapData(requestUrl, postDict, header, transport)
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, err:%s", partnerId, userId, loginInfo, err1)
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, statusCode:%d", partnerId, userId, loginInfo, statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, err:%s", partnerId, userId, loginInfo, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, Code:%d, Message:%s", partnerId, userId, loginInfo, returnObj.Code, returnObj.Message))
|
||||
return
|
||||
}
|
||||
|
||||
success = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 本地验证登陆信息
|
||||
// partnerId:合作商Id
|
||||
// userId:合作商用户Id
|
||||
// loginInfo:登陆信息
|
||||
// 返回值:
|
||||
// 成功与否
|
||||
// 错误对象
|
||||
func CheckDynamicTokenLocal(partnerId int32, userId, loginInfo string) (success bool, err error) {
|
||||
//1001直接返回true
|
||||
if partnerId == 1001 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
//非1001渠道验证
|
||||
if len(loginInfo) == 0 {
|
||||
success = false
|
||||
err = fmt.Errorf("Err:%s", "LoginInfo is null!")
|
||||
return
|
||||
}
|
||||
// 验证用户合法性
|
||||
loginItemList := strings.Split(loginInfo, "_")
|
||||
if len(loginItemList) != 2 {
|
||||
success = false
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. userId:%s, loginInfo:%s", userId, loginInfo)
|
||||
return
|
||||
}
|
||||
|
||||
//生成key
|
||||
localSign := securityUtil.Md5String(userId+GetSysConfig().DynamicLoginKey+loginItemList[1], true)
|
||||
|
||||
//判断签名是佛正确
|
||||
if localSign != loginItemList[0] {
|
||||
success = false
|
||||
err = fmt.Errorf("CheckLoginInfo Failed. Sign Check Failed! userId:%s,LocalSign:%s,loginInfo:%s", userId, localSign, loginInfo)
|
||||
return
|
||||
}
|
||||
|
||||
success = true
|
||||
return
|
||||
}
|
||||
|
||||
// ------------------类型定义和业务逻辑的分隔符-------------------------
|
||||
|
||||
var (
|
||||
LoginUtilObj = new(LoginUtil)
|
||||
)
|
||||
155
trunk/framework/gameServerMgr/manageUtil.go
Normal file
155
trunk/framework/gameServerMgr/manageUtil.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/webUtil"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
// 区服激活地址后缀
|
||||
const ActivateServer_URL_SUFFIX string = "/API/ServerActivate.ashx"
|
||||
|
||||
var (
|
||||
mManageCenterServerAPIUrl string
|
||||
mIsInit bool = true
|
||||
)
|
||||
|
||||
// 解析从ManagecenterServer中获取的服务器相关数据
|
||||
func ParseInfoFromManageCenterServer(serverGroupId int32, data string) {
|
||||
var deserializedData map[string]interface{}
|
||||
err := json.Unmarshal([]byte(data), &deserializedData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//解析服务器组
|
||||
var serverGroup *ServerGroup
|
||||
err = json.Unmarshal([]byte(deserializedData["ServerGroupInfo"].(string)), &serverGroup)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//解析合作商
|
||||
var partnerList []*Partner
|
||||
err = json.Unmarshal([]byte(deserializedData["PartnerList"].(string)), &partnerList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//解析服务器列表
|
||||
var serverList []*Server
|
||||
err = json.Unmarshal([]byte(deserializedData["ServerList"].(string)), &serverList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//解析资源包
|
||||
var resourceList []*ResourceVersion
|
||||
err = json.Unmarshal([]byte(deserializedData["ResourceVersionList"].(string)), &resourceList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//解析大区
|
||||
var areaList []*Area
|
||||
err = json.Unmarshal([]byte(deserializedData["AreaList"].(string)), &areaList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//判断是否需要更新数据(如果ServerGroupId不匹配,则不解析数据)
|
||||
if serverGroupId != serverGroup.Id {
|
||||
return
|
||||
}
|
||||
|
||||
//缓存服务器组
|
||||
ParseServerGroupInfo(serverGroup)
|
||||
|
||||
//缓存合作商
|
||||
ParsePartnerInfo(partnerList)
|
||||
|
||||
//缓存合作商对应的充值配置
|
||||
ParseChargeConfigInfo(partnerList)
|
||||
|
||||
//缓存服务器
|
||||
ParseServerInfo(serverList)
|
||||
|
||||
//缓存资源包
|
||||
ParseResourceVersionInfo(resourceList)
|
||||
|
||||
//缓存大区
|
||||
ParseAreaInfo(areaList)
|
||||
}
|
||||
|
||||
// 激活服务器
|
||||
func ActiveServer(manageCenterServerAPIUrl string, serverGroupId int32) error {
|
||||
if len(manageCenterServerAPIUrl) == 0 {
|
||||
return fmt.Errorf("ManageCenterServerAPI地址不能为空")
|
||||
}
|
||||
mManageCenterServerAPIUrl = manageCenterServerAPIUrl
|
||||
|
||||
//定义参数
|
||||
requestParamMap := make(map[string]string, 0)
|
||||
requestParamMap["ServerGroupID"] = strconv.Itoa(int(serverGroupId))
|
||||
|
||||
//构造请求url
|
||||
url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, ActivateServer_URL_SUFFIX)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true, //关闭证书校验
|
||||
}
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
return fmt.Errorf("StatusCode:%d", statusCode)
|
||||
}
|
||||
|
||||
//解压缩
|
||||
retBytes, err1 := zlibUtil.Decompress(returnBytes)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(retBytes, &returnObj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
return fmt.Errorf("code:%d,Message:%s", returnObj.Code, returnObj.Message)
|
||||
}
|
||||
|
||||
//解析得到的数据
|
||||
ParseInfoFromManageCenterServer(serverGroupId, returnObj.Data.(string))
|
||||
|
||||
//获取白名单
|
||||
GetWhiteListFromManageCenterServer()
|
||||
|
||||
//如果是初始化,则开启白名单刷新线程。避免游戏客户端刷新数据的时候重复开启线程
|
||||
if mIsInit {
|
||||
//启动白名单数据刷新线程
|
||||
StartRefreshWhiteListTread()
|
||||
|
||||
//启动刷新MC系统配置
|
||||
StartRefreshSysConfigTread()
|
||||
//初始化修改为fasle
|
||||
mIsInit = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
374
trunk/framework/gameServerMgr/manageUtil_test.go
Normal file
374
trunk/framework/gameServerMgr/manageUtil_test.go
Normal file
@@ -0,0 +1,374 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"goutil/timeUtil"
|
||||
"goutil/typeUtil"
|
||||
)
|
||||
|
||||
func TestActiveServer(t *testing.T) {
|
||||
var managecenterUrl = "https://managecenterapitest-ds3.7qule.com/"
|
||||
var serverGroupId int32 = 1000
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerGroup(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region测试获取服务器组
|
||||
serverGroup := GetServerGroup()
|
||||
if serverGroup == nil {
|
||||
t.Fatalf("获取服务器组[GetServerGroup]失败:serverGroup = nil")
|
||||
}
|
||||
|
||||
if serverGroup.Id != serverGroupId {
|
||||
t.Fatalf("获取服务器组[GetServerGroup]失败,期望[%d],结果[%d]", serverGroupId, serverGroup.Id)
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestGetDbConfig(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region测试获取服务器组
|
||||
serverGroup := GetServerGroup()
|
||||
if serverGroup == nil {
|
||||
t.Fatalf("获取服务器组[GetServerGroup]失败:serverGroup = nil")
|
||||
}
|
||||
|
||||
if serverGroup.Id != serverGroupId {
|
||||
t.Fatalf("获取服务器组[GetServerGroup]失败,期望[%d],结果[%d]", serverGroupId, serverGroup.Id)
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region 测试获取数据库配置
|
||||
/*
|
||||
{
|
||||
"GameDB": "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_player_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=20;maximumpoolsize=200;command timeout=60;",
|
||||
"LogDB": "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_log_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=20;maximumpoolsize=200;command timeout=60;",
|
||||
"GameModelDB": "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_model_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=10;maximumpoolsize=10;command timeout=60;"
|
||||
}
|
||||
*/
|
||||
gameDb := "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_player_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=20;maximumpoolsize=200;command timeout=60;"
|
||||
logDb := "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_log_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=20;maximumpoolsize=200;command timeout=60;"
|
||||
modelDb := "DataSource=10.1.0.4;port=3306;UserId=admin;Password=MOQIkaka$#@!1234;Database=h5xh_model_master;Allow Zero Datetime=true;charset=utf8;pooling=true;MinimumPoolSize=10;maximumpoolsize=10;command timeout=60;"
|
||||
|
||||
dbConfig, err := serverGroup.GetDBConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("获取服务器数据库配置[GetDBConfig]失败:%v", error)
|
||||
}
|
||||
|
||||
if dbConfig.GameDB != gameDb {
|
||||
t.Fatalf("获取服务器数据库配置[GetDBConfig]失败,GameDB,期望[%s],结果[%s]", gameDb, dbConfig.GameDB)
|
||||
}
|
||||
|
||||
if dbConfig.LogDB != logDb {
|
||||
t.Fatalf("获取服务器数据库配置[GetDBConfig]失败,LogDB,期望[%s],结果[%s]", logDb, dbConfig.LogDB)
|
||||
}
|
||||
|
||||
if dbConfig.GameModelDB != modelDb {
|
||||
t.Fatalf("获取服务器数据库配置[GetDBConfig]失败,GameModelDB,期望[%s],结果[%s]", modelDb, dbConfig.GameModelDB)
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestGetServerItem(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
var serverId = serverGroupId
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region测试获取服务器
|
||||
serverItem, exists := GetServerItem(partnerId, serverId)
|
||||
if !exists || serverItem == nil {
|
||||
t.Fatalf("获取服务器[GetServerItem][%d]失败,PartnerId[%d],服务器不存在!", partnerId, serverId)
|
||||
}
|
||||
|
||||
if serverItem.Id != serverId {
|
||||
t.Fatalf("获取服务器[GetServerItem]失败,期望[%d],结果[%d]", serverId, serverItem.Id)
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestGetServerName(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
var serverId = serverGroupId
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试获取服务器名称
|
||||
var expectServerName = "开发测试服"
|
||||
serverName := GetServerName(partnerId, serverId)
|
||||
if serverName != expectServerName {
|
||||
t.Fatalf("获取服务器名称[GetServerName]失败,期望[%s],结果[%s]", expectServerName, serverName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIfServerExists(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
var serverId = serverGroupId
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试服务器是否存在
|
||||
if !IfServerExists(partnerId, serverId) {
|
||||
t.Fatalf("判断服务器是否存在[IfServerExists]失败,PartnerId[%d],服务器[%d]不存在", partnerId, serverId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPartnerServerPairString(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//获取合作商、服务器的组合字符串
|
||||
expectStr := "1001_20001|6666001_20001|"
|
||||
partnerServerPairStr := GetPartnerServerPairString()
|
||||
if expectStr != partnerServerPairStr {
|
||||
t.Fatalf("获取合作商、服务器的组合字符串[GetPartnerServerPairString]失败,期望[%s],结果[%s]", expectStr, partnerServerPairStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLoginKey(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region测试获取登录密钥
|
||||
var expectStr = "a0482eaf-14e8-4a65-950e-864214f62da5"
|
||||
loginKey, exists := GetLoginKey(partnerId)
|
||||
if !exists {
|
||||
t.Fatalf("获取登录密钥[GetLoginKey]失败,未找到渠道[%d]配置", partnerId)
|
||||
}
|
||||
|
||||
if expectStr != loginKey {
|
||||
t.Fatalf("获取登录密钥[GetLoginKey]失败,期望[%s],结果[%s]", expectStr, loginKey)
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestGetServerOpenDate(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试获取开服日期 2020/4/21 20:19:56
|
||||
expectOpenDate := time.Date(2020, 4, 21, 20, 19, 56, 0, time.Local)
|
||||
openTimeTick := GetServerOpenDate()
|
||||
openDate, _ := typeUtil.DateTime(openTimeTick)
|
||||
if openDate != expectOpenDate {
|
||||
t.Fatalf("获取服务器开服日期[GetServerOpenDate]失败,期望[%s],结果[%s]", timeUtil.ToDateTimeString(expectOpenDate), timeUtil.ToDateTimeString(openDate))
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerOpenDays(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试获取服务器开服天数
|
||||
now := time.Now()
|
||||
nowDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
||||
expectOpenDate := time.Date(2020, 4, 21, 0, 0, 0, 0, time.Local)
|
||||
expectOpenDays := int32(nowDate.Sub(expectOpenDate).Hours()/24) + 1
|
||||
openDays := ServerOpenDays()
|
||||
if expectOpenDays != openDays {
|
||||
t.Fatalf("获取服务器开服天数[ServerOpenDays]失败,期望[%d],结果[%d]", expectOpenDays, openDays)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckMaintainStatus(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试服务器维护检查
|
||||
expectMsg := "维护中"
|
||||
maintainMessage, isMaintaining := CheckMaintainStatus()
|
||||
if isMaintaining && expectMsg != maintainMessage {
|
||||
t.Fatalf("服务器维护检查[CheckMaintainStatus]失败,期望维护消息[%s],结果维护消息[%s]", expectMsg, maintainMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckNewGameVersion(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
var serverId = serverGroupId
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region 测试检查是否有新版本
|
||||
|
||||
var gameVersionId int32 = 55 //老版本
|
||||
var expectGameVersionUrl = "testUrl" //已配置的游戏版本地址(IOS用)
|
||||
gameVersionUrl, exist := CheckNewGameVersion(partnerId, serverId, gameVersionId)
|
||||
if !exist {
|
||||
t.Fatalf("检查是否有新版本[CheckNewGameVersion]失败,未找到渠道[%d]配置或检查版本[%d]失败", partnerId, gameVersionId)
|
||||
} else if gameVersionUrl != expectGameVersionUrl {
|
||||
t.Fatalf("检查是否有新版本[CheckNewGameVersion]失败,期望版本地址[%s],结果版本地址[%s]", expectGameVersionUrl, gameVersionUrl)
|
||||
}
|
||||
|
||||
gameVersionId = 100 //当前版本
|
||||
_, exist = CheckNewGameVersion(partnerId, serverId, gameVersionId)
|
||||
if exist {
|
||||
t.Fatalf("检查是否有新版本[CheckNewGameVersion]失败,渠道[%d],版本[%d]不应有更新", partnerId, gameVersionId)
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestCheckNewResourceVersion(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
var serverId = serverGroupId
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region 测试检查新资源版本
|
||||
partnerId = 6666001
|
||||
var gameVersionId int32 = 100
|
||||
resourceVersionName := "1587372891_9eab40313feec913cace0adf0fe05341" //非最新资源版本号
|
||||
_, exist := CheckNewResourceVersion(partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
if !exist {
|
||||
t.Fatalf("检查新资源版本[CheckNewResourceVersion]失败,渠道[%d],服务器[%d],游戏版本Id[%d],资源版本号[%s],应有更新!", partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
}
|
||||
|
||||
gameVersionId = 100
|
||||
resourceVersionName = "1587374043_cee48a8611276d3e3450782a1585c1a3" //最新资源版本号
|
||||
_, exist = CheckNewResourceVersion(partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
if exist {
|
||||
t.Fatalf("检查新资源版本[CheckNewResourceVersion]失败,渠道[%d],服务器[%d],游戏版本Id[%d],资源版本号[%s],不应有更新!", partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
}
|
||||
|
||||
gameVersionId = 123456 //不存在的游戏版本
|
||||
resourceVersionName = "1587374043_cee48a8611276d3e3450782a1585c1a3"
|
||||
_, exist = CheckNewResourceVersion(partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
if exist {
|
||||
t.Fatalf("检查新资源版本[CheckNewResourceVersion]失败,渠道[%d],服务器[%d],游戏版本Id[%d],资源版本号[%s],不应有更新!", partnerId, serverId, gameVersionId, resourceVersionName)
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
func TestIsInWhiteList(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//测试白名单
|
||||
partnerId = 1001
|
||||
var userId = "446bfd6ccccd4229aa295686f9e5855b" //已配置的白名单用户Id
|
||||
if !IsInWhiteList(partnerId, userId) {
|
||||
t.Fatalf("检查是否用户在白名单中[IsInWhiteList]失败,渠道[%d],UserId[%s]", partnerId, userId)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取服务器组
|
||||
func TestGetOtherConfigInfo(t *testing.T) {
|
||||
var managecenterUrl = "http://managecenterapitest-xxx.79yougame.com/"
|
||||
var partnerId int32 = 1001
|
||||
var serverGroupId int32 = 20001
|
||||
|
||||
//激活器服务器,获取mc配置
|
||||
error := ActiveServer(managecenterUrl, serverGroupId)
|
||||
if error != nil {
|
||||
t.Fatalf("激活服务器出现错误:%v", error)
|
||||
}
|
||||
|
||||
//#region测试获取其他配置
|
||||
var configKey = "AppKey"
|
||||
var expectConfigValue = "a0482eaf-14e8-4a65-950e-864214f62da5" //已配置的配置值
|
||||
configValue, exist, error := GetOtherConfigInfo(partnerId, configKey)
|
||||
if error != nil {
|
||||
t.Fatalf("获取渠道其他配置[GetOtherConfigInfo]失败,渠道[%d],ConfigKey[%s]", partnerId, configKey)
|
||||
}
|
||||
if !exist {
|
||||
t.Fatalf("获取渠道其他配置[GetOtherConfigInfo]失败,渠道[%d],ConfigKey[%s],渠道或配置不存在!", partnerId, configKey)
|
||||
}
|
||||
|
||||
if configValue != expectConfigValue {
|
||||
t.Fatalf("获取渠道其他配置[GetOtherConfigInfo]失败,期望[%s],结果[%s]", expectConfigValue, configValue)
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
60
trunk/framework/gameServerMgr/partner.go
Normal file
60
trunk/framework/gameServerMgr/partner.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
. "Framework/managecenterModel"
|
||||
)
|
||||
|
||||
var (
|
||||
mPartnerMap = make(map[int32]*Partner, 0)
|
||||
)
|
||||
|
||||
//解析合作商信息
|
||||
func ParsePartnerInfo(partnerList []*Partner) {
|
||||
tmpPartnerMap := make(map[int32]*Partner, 0)
|
||||
|
||||
//循环解析所有合作商信息
|
||||
for _, partner := range partnerList {
|
||||
tmpPartnerMap[partner.Id] = partner
|
||||
}
|
||||
|
||||
mPartnerMap = tmpPartnerMap
|
||||
}
|
||||
|
||||
//根据渠道id获取渠道对象
|
||||
func GetPartnerItem(partnerId int32) (partner *Partner, exist bool) {
|
||||
|
||||
//判断渠道是否存在
|
||||
partner, exist = mPartnerMap[partnerId]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取渠道的登录加密key
|
||||
func GetLoginKey(partnerId int32) (loginKey string, exist bool) {
|
||||
partnerObj, exist := mPartnerMap[partnerId]
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
loginKey = partnerObj.LoginKey
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//根据渠道和key获取其他配置
|
||||
func GetOtherConfigInfo(partnerId int32, configKey string) (configValue string, exist bool, err error) {
|
||||
partnerObj, exist := GetPartnerItem(partnerId)
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
var otherConfigMap map[string]string
|
||||
otherConfigMap, err = partnerObj.ResolveOtherConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
configValue, exist = otherConfigMap[configKey]
|
||||
|
||||
return
|
||||
}
|
||||
57
trunk/framework/gameServerMgr/resourceversion.go
Normal file
57
trunk/framework/gameServerMgr/resourceversion.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
. "Framework/managecenterModel"
|
||||
)
|
||||
|
||||
var (
|
||||
mResourceVersionLit = make([]*ResourceVersion, 0)
|
||||
)
|
||||
|
||||
// 解析资源版本信息
|
||||
func ParseResourceVersionInfo(resourceVersionList []*ResourceVersion) {
|
||||
mResourceVersionLit = resourceVersionList
|
||||
}
|
||||
|
||||
//返回所有的资源包列表
|
||||
func GetResourceVersionList() (resourceVersionList []*ResourceVersion) {
|
||||
resourceVersionList = mResourceVersionLit
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//检测资源
|
||||
func CheckNewResourceVersion(partnerId, serverId, gameVersionId int32, resourceVersionName string) (availableResourceVersionMap map[string]interface{}, exist bool) {
|
||||
_, exist = GetServerItem(partnerId, serverId)
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
//获取服务所在大区Id
|
||||
areaId := GetAreaIdByGroupId(serverId)
|
||||
|
||||
//获取大区的资源列表
|
||||
var tempResourceVersionList []*ResourceVersion
|
||||
for _, resourceVerion := range mResourceVersionLit {
|
||||
if resourceVerion.AreaID == areaId {
|
||||
tempResourceVersionList = append(tempResourceVersionList, resourceVerion)
|
||||
}
|
||||
}
|
||||
|
||||
//获取服务器
|
||||
serverGroup := GetServerGroup()
|
||||
|
||||
//获取资源版本列表
|
||||
availableResourceVersionMap = GetAvailableResource(tempResourceVersionList, partnerId, gameVersionId, resourceVersionName, OfficialOrTest(serverGroup.OfficialOrTest))
|
||||
|
||||
//检测是否有新资源
|
||||
if len(availableResourceVersionMap) != 0 && availableResourceVersionMap["IsNewResource"] == true {
|
||||
exist = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
exist = false
|
||||
|
||||
return
|
||||
}
|
||||
166
trunk/framework/gameServerMgr/server.go
Normal file
166
trunk/framework/gameServerMgr/server.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
)
|
||||
|
||||
var (
|
||||
mServerMap = make(map[int32][]*Server, 0)
|
||||
)
|
||||
|
||||
//合作商、服务器组合列表
|
||||
type PartnerServer struct {
|
||||
//合作商Id
|
||||
mPartnerId int32
|
||||
|
||||
//服务器Id
|
||||
mServerId int32
|
||||
}
|
||||
|
||||
//解析服务器信息
|
||||
func ParseServerInfo(serverList []*Server) {
|
||||
tempServerMap := make(map[int32][]*Server, 0)
|
||||
for _, server := range serverList {
|
||||
_, exist := tempServerMap[server.PartnerId]
|
||||
if !exist {
|
||||
tempServerMap[server.PartnerId] = make([]*Server, 0)
|
||||
}
|
||||
tempServerMap[server.PartnerId] = append(tempServerMap[server.PartnerId], server)
|
||||
}
|
||||
mServerMap = tempServerMap
|
||||
}
|
||||
|
||||
//获取服务器对象
|
||||
func GetServerItem(partnerId, serverId int32) (server *Server, exist bool) {
|
||||
serverList, existServer := mServerMap[partnerId]
|
||||
if !existServer {
|
||||
return
|
||||
}
|
||||
for _, serverItem := range serverList {
|
||||
if serverItem.Id == serverId {
|
||||
server = serverItem
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//判断服务器是否存在
|
||||
func IfServerExists(partnerId, serverId int32) (exists bool) {
|
||||
_, exists = GetPartnerItem(partnerId)
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
_, exists = GetServerItem(partnerId, serverId)
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取服务器名称
|
||||
func GetServerName(partnerId, serverId int32) (serverName string) {
|
||||
_, existPartner := GetPartnerItem(partnerId)
|
||||
if !existPartner {
|
||||
return
|
||||
}
|
||||
server, existServer := GetServerItem(partnerId, serverId)
|
||||
if !existServer {
|
||||
return
|
||||
}
|
||||
serverName = server.Name
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//检测是否有游戏版本更新
|
||||
func CheckNewGameVersion(partnerId, serverId, gameVersionId int32) (gameVersionUrl string, exist bool) {
|
||||
server, existServer := GetServerItem(partnerId, serverId)
|
||||
if !existServer {
|
||||
exist = existServer
|
||||
return
|
||||
}
|
||||
|
||||
if gameVersionId < server.MinGameVersionId {
|
||||
partner, existPartner := GetPartnerItem(partnerId)
|
||||
if !existPartner {
|
||||
exist = existPartner
|
||||
return
|
||||
}
|
||||
exist = true
|
||||
gameVersionUrl = partner.GameVersionUrl
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取合作商、服务器的组合字符串
|
||||
//字符串格式:PartnerId_ServerId|PartnerId_ServerId|
|
||||
func GetPartnerServerPairString() (partnerServerPair string) {
|
||||
for _, ps := range GetPartnerServerPairList() {
|
||||
partnerServerPair += fmt.Sprintf("%d_%d|", ps.mPartnerId, ps.mServerId)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//获取合作商、服务器的组合列表
|
||||
func GetPartnerServerPairList() (partnerServerList []*PartnerServer) {
|
||||
for key := range mServerMap {
|
||||
for _, server := range mServerMap[key] {
|
||||
if server.GroupId == GetServerGroup().Id {
|
||||
var ps *PartnerServer = &PartnerServer{server.PartnerId, server.Id}
|
||||
partnerServerList = append(partnerServerList, ps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // 获取合作商、服务器的组合字符串
|
||||
// // serverGroupId:服务器组Id
|
||||
// // 返回值
|
||||
// // 合作商、服务器的组合字符串
|
||||
// func (this *ManageCenterUtil) GetPartnerServerPairString(serverGroupId int32) string {
|
||||
// var buf bytes.Buffer
|
||||
|
||||
// serverList := managecenterMgr.GetServerList(serverGroupId)
|
||||
// for _, item := range serverList {
|
||||
// buf.WriteString(fmt.Sprintf("%d_%d|", item.PartnerId, item.Id))
|
||||
// }
|
||||
|
||||
// return buf.String()
|
||||
// }
|
||||
|
||||
// // 是否是有效的合作商、服务器组合
|
||||
// // partnerId:合作商Id
|
||||
// // serverId:服务器Id
|
||||
// // parnterServerPairString:合作商、服务器的组合字符串,格式为:PartnerId_ServerId|PartnerId_ServerId|
|
||||
// // 返回值
|
||||
// // 是否有效
|
||||
// func (this *ManageCenterUtil) IfValidPartnerServerPair(partnerId, serverId int32, parnterServerPairString string) bool {
|
||||
// if parnterServerPairString == "" {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// partnerServerPairStringList := strings.Split(parnterServerPairString, "|")
|
||||
// if len(partnerServerPairStringList) == 0 {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// // 获得玩家的合作商、服务器组合字符串
|
||||
// partnerServerPair := fmt.Sprintf("%d_%d", partnerId, serverId)
|
||||
|
||||
// // 遍历寻找
|
||||
// for _, item := range partnerServerPairStringList {
|
||||
// if item == partnerServerPair {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false
|
||||
// }
|
||||
79
trunk/framework/gameServerMgr/serverGroup.go
Normal file
79
trunk/framework/gameServerMgr/serverGroup.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/timeUtil"
|
||||
"goutil/typeUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
mServerGroupObj *ServerGroup
|
||||
)
|
||||
|
||||
//解析服务器组信息
|
||||
func ParseServerGroupInfo(serverGroupObj *ServerGroup) {
|
||||
mServerGroupObj = serverGroupObj
|
||||
}
|
||||
|
||||
//获取服务器组对象
|
||||
func GetServerGroup() (serverGroupObj *ServerGroup) {
|
||||
serverGroupObj = mServerGroupObj
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//检查服务器是否在维护
|
||||
func CheckMaintainStatus() (maintainMessage string, isMaintaining bool) {
|
||||
serverGroupObj := GetServerGroup()
|
||||
nowTick := time.Now().Unix()
|
||||
if serverGroupObj.GroupState == int32(Con_GroupState_Maintain) || (serverGroupObj.MaintainBeginTimeTick <= nowTick && nowTick <= serverGroupObj.MaintainBeginTimeTick+int64(60*serverGroupObj.MaintainMinutes)) {
|
||||
maintainMessage = serverGroupObj.MaintainMessage
|
||||
isMaintaining = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取服务器维护开始时间时间戳
|
||||
func GetMaintainBeginTime() (maintainBeginTimeTick int64) {
|
||||
serverGroupObj := GetServerGroup()
|
||||
maintainBeginTimeTick = serverGroupObj.MaintainBeginTimeTick
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取服务器维护持续时间 单位分钟
|
||||
func GetMaintainMinutes() (maintainMinutes int32) {
|
||||
serverGroupObj := GetServerGroup()
|
||||
maintainMinutes = serverGroupObj.MaintainMinutes
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//获取服务器开服日期 时间戳
|
||||
func GetServerOpenDate() (openTimeTick int64) {
|
||||
serverGroupObj := GetServerGroup()
|
||||
openTimeTick = serverGroupObj.OpenTimeTick
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//当前服务器已开服天数(开服第几天)
|
||||
//当前开服天数 计算公式:(当前日期 - 开服日期)的总天数 + 1
|
||||
func ServerOpenDays() (days int32) {
|
||||
serverGroupObj := GetServerGroup()
|
||||
if serverGroupObj.IsOpen() == false {
|
||||
return 0
|
||||
}
|
||||
|
||||
//(当前日期 - 开服日期)的总天数 + 1
|
||||
openTimeTick := serverGroupObj.OpenTimeTick
|
||||
openDate, _ := typeUtil.DateTime(openTimeTick)
|
||||
days = int32(timeUtil.SubDay(time.Now(), openDate) + 1)
|
||||
|
||||
return
|
||||
}
|
||||
57
trunk/framework/gameServerMgr/serverGroupRegistration.go
Normal file
57
trunk/framework/gameServerMgr/serverGroupRegistration.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
//修改区服注册人数
|
||||
func UpdateRegisterCount(serverGroupId, registerCount int32) (err error, success bool) {
|
||||
success = false
|
||||
|
||||
//定义参数
|
||||
requestParamMap := make(map[string]string, 0)
|
||||
requestParamMap["ServerGroupId"] = strconv.Itoa(int(serverGroupId))
|
||||
requestParamMap["Registrations"] = strconv.Itoa(int(registerCount))
|
||||
|
||||
//构造请求url
|
||||
url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, "/API/RegistrationUpdate.ashx")
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
err = fmt.Errorf("StatusCode:%d", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("更新区服注册人数出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
err = fmt.Errorf("更新区服注册人数出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(fmt.Sprintf("更新区服注册人数出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message))
|
||||
return
|
||||
}
|
||||
|
||||
success = true
|
||||
return
|
||||
}
|
||||
105
trunk/framework/gameServerMgr/sysconfig.go
Normal file
105
trunk/framework/gameServerMgr/sysconfig.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"Framework/goroutineMgr"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
const SYSCONF_URL_SUFFIX string = "/API/SysConfig.ashx"
|
||||
|
||||
var (
|
||||
mSysConfig *SysConfig
|
||||
)
|
||||
|
||||
// 获取MC系统配置
|
||||
func GetSysConfigFromManageCenterServer() error {
|
||||
//定义参数
|
||||
requestParamMap := make(map[string]string, 0)
|
||||
requestParamMap["IsResultCompressed"] = "false"
|
||||
|
||||
//构造url
|
||||
url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, SYSCONF_URL_SUFFIX)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取MC系统配置出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
var tmpSysConfig *SysConfig
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取MC系统配置出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpSysConfig); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 赋值给最终的sysconfig
|
||||
mSysConfig = tmpSysConfig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 定时刷新MC系统配置
|
||||
func StartRefreshSysConfigTread() {
|
||||
// 定时刷新数据
|
||||
go func() {
|
||||
goroutineName := "gameServerMgr.StartRefreshSysConfigTread"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
// 每30秒刷新一次
|
||||
time.Sleep(30 * time.Second)
|
||||
|
||||
// MC系统配置
|
||||
GetSysConfigFromManageCenterServer()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
func GetSysConfig() *SysConfig {
|
||||
return mSysConfig
|
||||
}
|
||||
124
trunk/framework/gameServerMgr/userWhiteList.go
Normal file
124
trunk/framework/gameServerMgr/userWhiteList.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package gameServerMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"Framework/goroutineMgr"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
const URL_SUFFIX string = "/API/UserWhiteList.ashx"
|
||||
|
||||
var (
|
||||
mUserWhiteListMap = make(map[int32]map[string]*WhiteList, 0)
|
||||
mHashValue string
|
||||
)
|
||||
|
||||
// 获取白名单
|
||||
func GetWhiteListFromManageCenterServer() error {
|
||||
//定义参数
|
||||
requestParamMap := make(map[string]string, 0)
|
||||
requestParamMap["HashValue"] = mHashValue
|
||||
|
||||
//构造url
|
||||
url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, URL_SUFFIX)
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取白名单列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
var tmpWhiteList []*WhiteList
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取白名单列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpWhiteList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tmpWhiteListMap := make(map[int32]map[string]*WhiteList, 64)
|
||||
for _, item := range tmpWhiteList {
|
||||
if _, exist := tmpWhiteListMap[item.PartnerId]; !exist {
|
||||
tmpWhiteListMap[item.PartnerId] = make(map[string]*WhiteList, 8)
|
||||
}
|
||||
|
||||
tmpWhiteListMap[item.PartnerId][item.UserId] = item
|
||||
}
|
||||
|
||||
// 赋值给最终的whiteListMap
|
||||
mUserWhiteListMap = tmpWhiteListMap
|
||||
mHashValue = returnObj.HashValue
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断用户是否在白名单里面
|
||||
// partnerId: 合作商ID
|
||||
// userId: userId
|
||||
func IsInWhiteList(partnerId int32, userId string) bool {
|
||||
subWhiteListMap, exist := mUserWhiteListMap[partnerId]
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
|
||||
_, exist = subWhiteListMap[userId]
|
||||
return exist
|
||||
}
|
||||
|
||||
// 定时刷新白名单
|
||||
func StartRefreshWhiteListTread() {
|
||||
// 定时刷新数据
|
||||
go func() {
|
||||
goroutineName := "gameServerMgr.StartRefreshWhiteListTread"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
// 每30秒刷新一次
|
||||
time.Sleep(30 * time.Second)
|
||||
|
||||
// 刷新白名单
|
||||
GetWhiteListFromManageCenterServer()
|
||||
}
|
||||
}()
|
||||
}
|
||||
17
trunk/framework/go.mod
Normal file
17
trunk/framework/go.mod
Normal file
@@ -0,0 +1,17 @@
|
||||
module Framework
|
||||
|
||||
go 1.22.10
|
||||
|
||||
replace goutil => ../goutil
|
||||
|
||||
require (
|
||||
github.com/Shopify/sarama v1.29.1
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/rabbitmq/amqp091-go v1.8.1
|
||||
github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.230
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vms v1.0.230
|
||||
goutil v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
242
trunk/framework/go.sum
Normal file
242
trunk/framework/go.sum
Normal file
@@ -0,0 +1,242 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Shopify/sarama v1.29.1 h1:wBAacXbYVLmWieEA/0X/JagDdCZ8NVFOfS6l6+2u5S0=
|
||||
github.com/Shopify/sarama v1.29.1/go.mod h1:mdtqvCSg8JOxk8PmpTNGyo6wzd4BMm4QXSfDnTXmgkE=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 h1:OoL469zqSNrTLSz5zeVF/I6VOO7fiw2bzSzQe4J557c=
|
||||
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
|
||||
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
|
||||
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
|
||||
github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A=
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA=
|
||||
github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 h1:AJNDS0kP60X8wwWFvbLPwDuojxubj9pbfK7pjHw0vKg=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.230 h1:4n29EOxPk3fi0epVT+cY7Iwygep7vxn/LCq6RCBAwaM=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.230/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vms v1.0.230 h1:jIEph3MVl/7ex+4gK6LtBCpmeGwq+OUSRDmoPshWxpc=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vms v1.0.230/go.mod h1:zElyabRGi8DktckzhT3krsYChstFJdSrzDb7pwF2P58=
|
||||
github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
16
trunk/framework/goroutineMgr/doc.go
Normal file
16
trunk/framework/goroutineMgr/doc.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package goroutineMgr
|
||||
|
||||
/*
|
||||
goroutine的管理包,提供了对goroutine的监控机制
|
||||
对外提供的方法为:
|
||||
|
||||
// 监控指定的goroutine
|
||||
Monitor(goroutineName string)
|
||||
|
||||
// 只添加数量,不监控
|
||||
MonitorZero(goroutineName string)
|
||||
|
||||
// 释放监控
|
||||
ReleaseMonitor(goroutineName string)
|
||||
|
||||
*/
|
||||
93
trunk/framework/goroutineMgr/goroutineCount.go
Normal file
93
trunk/framework/goroutineMgr/goroutineCount.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package goroutineMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
goroutineCountMap = make(map[string]int)
|
||||
goroutineCountMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// 增加指定名称的goroutine的数量
|
||||
// goroutineName:goroutine名称
|
||||
func increaseCount(goroutineName string) {
|
||||
goroutineCountMutex.Lock()
|
||||
defer goroutineCountMutex.Unlock()
|
||||
|
||||
newCount := 1
|
||||
if currCount, exist := goroutineCountMap[goroutineName]; exist {
|
||||
newCount = currCount + 1
|
||||
}
|
||||
|
||||
goroutineCountMap[goroutineName] = newCount
|
||||
}
|
||||
|
||||
// 减少指定名称的goroutine的数量
|
||||
// goroutineName:goroutine名称
|
||||
func decreaseCount(goroutineName string) {
|
||||
goroutineCountMutex.Lock()
|
||||
defer goroutineCountMutex.Unlock()
|
||||
|
||||
newCount := -1
|
||||
if currCount, exist := goroutineCountMap[goroutineName]; exist {
|
||||
newCount = currCount - 1
|
||||
}
|
||||
|
||||
if newCount <= 0 {
|
||||
delete(goroutineCountMap, goroutineName)
|
||||
} else {
|
||||
goroutineCountMap[goroutineName] = newCount
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定名称的goroutine的数量
|
||||
// goroutineName:goroutine名称
|
||||
// 返回值:
|
||||
// 对应数量
|
||||
func getGoroutineCount(goroutineName string) int {
|
||||
goroutineCountMutex.RLock()
|
||||
defer goroutineCountMutex.RUnlock()
|
||||
|
||||
if currCount, exist := goroutineCountMap[goroutineName]; exist {
|
||||
return currCount
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// 转化成字符串
|
||||
func toString() string {
|
||||
goroutineCountMutex.RLock()
|
||||
defer goroutineCountMutex.RUnlock()
|
||||
|
||||
keys := make([]string, 0, 16)
|
||||
for key := range goroutineCountMap {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] < keys[j]
|
||||
})
|
||||
|
||||
str := fmt.Sprintf("Goroutine Info:(%s,%d)", "NumGoroutine", runtime.NumGoroutine())
|
||||
for _, key := range keys {
|
||||
str += fmt.Sprintf("(%s,%d)", key, goroutineCountMap[key])
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// 记录goroutine数量信息
|
||||
func logGoroutineCountInfo() {
|
||||
logUtil.DebugLog(toString())
|
||||
}
|
||||
|
||||
func Test() {
|
||||
logGoroutineCountInfo()
|
||||
}
|
||||
75
trunk/framework/goroutineMgr/goroutineInfo.go
Normal file
75
trunk/framework/goroutineMgr/goroutineInfo.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package goroutineMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"framework/monitorNewMgr"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
goroutineInfoMap map[string]int = make(map[string]int)
|
||||
goroutineInfoMutex sync.RWMutex
|
||||
goroutineWarnCount int = 50
|
||||
)
|
||||
|
||||
func init() {
|
||||
monitorNewMgr.RegisterMonitorFunc(monitor)
|
||||
}
|
||||
|
||||
// 设置系统协程上报阈值
|
||||
func SetGoroutineWarnCount(warnCount int) {
|
||||
goroutineWarnCount = warnCount
|
||||
}
|
||||
|
||||
func registerGoroutineInfo(goroutineName string, count int) {
|
||||
goroutineInfoMutex.Lock()
|
||||
defer goroutineInfoMutex.Unlock()
|
||||
|
||||
goroutineInfoMap[goroutineName] = count
|
||||
}
|
||||
|
||||
// 监控指定的goroutine
|
||||
func Monitor(goroutineName string) {
|
||||
increaseCount(goroutineName)
|
||||
registerGoroutineInfo(goroutineName, 1)
|
||||
}
|
||||
|
||||
// 只添加数量,不监控
|
||||
func MonitorZero(goroutineName string) {
|
||||
increaseCount(goroutineName)
|
||||
}
|
||||
|
||||
// 释放监控
|
||||
func ReleaseMonitor(goroutineName string) {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
}
|
||||
|
||||
decreaseCount(goroutineName)
|
||||
}
|
||||
|
||||
func monitor() error {
|
||||
// 判断当前goroutine数量是否达到打印条件(数量查过设置的值就打印)
|
||||
if goroutineWarnCount >= runtime.NumGoroutine() {
|
||||
return nil
|
||||
}
|
||||
/*
|
||||
先记录活跃的goroutine的数量信息
|
||||
然后再判断数量是否匹配
|
||||
*/
|
||||
logGoroutineCountInfo()
|
||||
|
||||
goroutineInfoMutex.RLock()
|
||||
defer goroutineInfoMutex.RUnlock()
|
||||
|
||||
for goroutineName, expectedCount := range goroutineInfoMap {
|
||||
if currCount := getGoroutineCount(goroutineName); currCount != expectedCount {
|
||||
return fmt.Errorf("%s需要%d个goroutine,现在有%d个", goroutineName, expectedCount, currCount)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
81
trunk/framework/handleMgr/doc.go
Normal file
81
trunk/framework/handleMgr/doc.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 全局操作接口管理API类
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-23 16:24:59
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
/*
|
||||
用于提供全局操作接口管理API类
|
||||
*/
|
||||
|
||||
/*
|
||||
接口说明
|
||||
|
||||
接口1:
|
||||
// RegisterNewModule
|
||||
// @description: 注册方法
|
||||
// parameter:
|
||||
// @moduleName:模块名
|
||||
// @structObject:模块对象
|
||||
// @monitorTime:监控日志超时时间,传入0是用默认值100
|
||||
// return:
|
||||
|
||||
示例:RegisterNewModule("test", new(testBll), 0)
|
||||
|
||||
接口2:
|
||||
// Done
|
||||
// @description: 执行访问
|
||||
// parameter:
|
||||
// @logicalId:逻辑实例Id-同一串行错误类的唯一标识
|
||||
// @moduleName:模块名
|
||||
// @funcName:执行方法名称
|
||||
// @parameter:方法参数
|
||||
// @isHaveResult:是否处理返回值
|
||||
// return:
|
||||
// @data:返还对象
|
||||
// @code:错误码-0未无错误
|
||||
// @message:错误说明-空字符串为无错误
|
||||
|
||||
示例:data,code,mes := Done("test", "testBll", "Add", parameter, false)
|
||||
|
||||
注意:
|
||||
注册的类实现的方法返回值必须是*ResponseObject为返回对象
|
||||
示例:
|
||||
|
||||
type testBll struct {
|
||||
}
|
||||
|
||||
// TestAdd
|
||||
// @description:测试添加
|
||||
// parameter:
|
||||
// @receiver t:
|
||||
// @x:
|
||||
// @y:
|
||||
// return:
|
||||
// @*ResponseObject:
|
||||
func (t testBll) TestAdd(x, y int) *ResponseObject {
|
||||
responseObj := GetInitResponseObj()
|
||||
data[x] = y
|
||||
z := x + y
|
||||
|
||||
responseObj.SetData(z)
|
||||
responseObj.SetResultStatus("错误码")
|
||||
return responseObj
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
// 注册类
|
||||
RegisterNewModule("test", new(testBll), 10)
|
||||
|
||||
// 调用方法
|
||||
data, code, mes := Done("test", "testBll", "TestAdd", parameter, false)
|
||||
|
||||
// 可以重复注册多个类,逻辑实例Id保持一致即可
|
||||
RegisterNewModule("test", new(test2Bll), 10)
|
||||
data, code, mes := Done("test", "test2Bll", "TestAdd", parameter, false)
|
||||
}
|
||||
*/
|
||||
131
trunk/framework/handleMgr/handleMgr.go
Normal file
131
trunk/framework/handleMgr/handleMgr.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 全局操作接口管理
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-21 15:53:59
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"Framework/goroutineMgr"
|
||||
"goutil/logUtil"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
handleData = make(map[string]*HandleObj)
|
||||
)
|
||||
|
||||
// RegisterNewModule
|
||||
// @description: 注册调用方法
|
||||
// parameter:
|
||||
// @logicalId:逻辑实例Id-同一串行错误类的唯一标识
|
||||
// @structObject:模块对象
|
||||
// @monitorTime:监控日志超时时间,传入0是用默认值100
|
||||
// return:
|
||||
func RegisterNewModule(logicalId string, structObject interface{}, monitorTime int64) {
|
||||
// 注册模块,开启线程
|
||||
_, isExists := handleData[logicalId]
|
||||
if isExists == false {
|
||||
newHandleObj := NewHandleObj(logicalId)
|
||||
handleData[logicalId] = newHandleObj
|
||||
|
||||
// 设置监控默认值
|
||||
if monitorTime == 0 {
|
||||
monitorTime = 100
|
||||
}
|
||||
|
||||
// 开启监控-channel
|
||||
go func() {
|
||||
registerName := fmt.Sprintf("handleMgr.RegisterNewModule.logicalId=%s", logicalId)
|
||||
goroutineMgr.MonitorZero(registerName)
|
||||
defer goroutineMgr.ReleaseMonitor(registerName)
|
||||
defer logErrorRecover()
|
||||
|
||||
ret := 0
|
||||
for {
|
||||
select {
|
||||
case c := <-newHandleObj.HandleChannel:
|
||||
start := time.Now().UnixMilli()
|
||||
responseObject := CallFunction(c)
|
||||
end := time.Now().UnixMilli()
|
||||
|
||||
if c.IsHaveResult == true {
|
||||
c.ResultChan <- responseObject
|
||||
}
|
||||
if end-start > monitorTime {
|
||||
message := fmt.Sprintf("方法执行时间超长,logicalId:%s,moduleName:%s,MethodName:%s,消耗时间过程,总耗时:%d,需要检查代码!!!!!", logicalId, c.ModuleName, c.MethodName, end-start)
|
||||
logUtil.ErrorLog(message)
|
||||
}
|
||||
|
||||
ret++
|
||||
if ret == 100 {
|
||||
num := len(newHandleObj.HandleChannel)
|
||||
if num > 500 {
|
||||
message := fmt.Sprintf("时间戳:%d,channel监控,内部待执行操作过多,logicalId:%s,当前待执行数量:%d,需要检查代码!!!!!", time.Now().UnixMilli(), logicalId, num)
|
||||
logUtil.ErrorLog(message)
|
||||
}
|
||||
}
|
||||
default:
|
||||
// 如果找不到数据则休眠5ms
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 注册对象
|
||||
RegisterFunction(structObject)
|
||||
}
|
||||
|
||||
// Done
|
||||
// @description: 执行访问
|
||||
// parameter:
|
||||
// @logicalId:逻辑实例Id-同一串行错误类的唯一标识
|
||||
// @moduleName:模块名
|
||||
// @funcName:执行方法名称
|
||||
// @parameter:方法参数
|
||||
// @isHaveResult:是否处理返回值
|
||||
// return:
|
||||
// @data:返还对象
|
||||
// @code:错误码-0未无错误
|
||||
// @message:错误说明-空字符串为无错误
|
||||
func Done(logicalId string, moduleName string, funcName string, parameter []interface{}, isHaveResult bool) (data interface{}, code int, message string) {
|
||||
responseObj := NewRequestObject(moduleName, funcName, parameter, isHaveResult)
|
||||
handleObj, isExists := handleData[logicalId]
|
||||
if isExists == false {
|
||||
message := fmt.Sprintf("未注册模块,moduleName:%s", moduleName)
|
||||
logUtil.ErrorLog(message)
|
||||
return nil, -1, message
|
||||
}
|
||||
handleObj.HandleChannel <- responseObj
|
||||
if responseObj.IsHaveResult == false {
|
||||
return nil, 0, ""
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case responseObject := <-responseObj.ResultChan:
|
||||
// 处理返回值
|
||||
return responseObject.Data, 0, responseObject.Message
|
||||
default:
|
||||
// 如果找不到数据则休眠5ms
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// logErrorRecover
|
||||
// @description: 打印日志
|
||||
// parameter:
|
||||
// return:
|
||||
func logErrorRecover() {
|
||||
if err := recover(); err != nil {
|
||||
msg := fmt.Sprintf("err msg:%s stack:%s", err, debug.Stack())
|
||||
logUtil.ErrorLog(msg)
|
||||
}
|
||||
}
|
||||
26
trunk/framework/handleMgr/handleObj.go
Normal file
26
trunk/framework/handleMgr/handleObj.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: HandleObj 操作对象
|
||||
// @author: zhaoxin
|
||||
// @revision history:
|
||||
// @create date: 2022-02-21 16:52:44
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
// HandleObj 操作对象
|
||||
type HandleObj struct {
|
||||
// 模块命名
|
||||
ModuleName string
|
||||
|
||||
// 操作channel
|
||||
HandleChannel chan *RequestObject
|
||||
}
|
||||
|
||||
// NewHandleObj 初始化
|
||||
func NewHandleObj(moduleName string) *HandleObj {
|
||||
return &HandleObj{
|
||||
ModuleName: moduleName,
|
||||
HandleChannel: make(chan *RequestObject, 1000),
|
||||
}
|
||||
}
|
||||
351
trunk/framework/handleMgr/reflect.go
Normal file
351
trunk/framework/handleMgr/reflect.go
Normal file
@@ -0,0 +1,351 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 反射类
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-23 16:33:27
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"goutil/logUtil"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// 定义用于分隔模块名称和方法名称的分隔符
|
||||
con_DelimeterOfObjAndMethod = "_"
|
||||
)
|
||||
|
||||
var (
|
||||
// 定义存放所有方法映射的变量
|
||||
methodMap = make(map[string]*ReflectMethod, 4)
|
||||
|
||||
// 函数返回值类型
|
||||
responseType reflect.Type = reflect.TypeOf(new(ResponseObject))
|
||||
)
|
||||
|
||||
// getStructName
|
||||
// @description: 获取结构体类型的名称
|
||||
// parameter:
|
||||
// @structType:结构体类型
|
||||
// return:
|
||||
// @string:结构体类型的名称
|
||||
func getStructName(structType reflect.Type) string {
|
||||
reflectTypeStr := structType.String()
|
||||
reflectTypeArr := strings.Split(reflectTypeStr, ".")
|
||||
|
||||
return reflectTypeArr[len(reflectTypeArr)-1]
|
||||
}
|
||||
|
||||
// getFullMethodName
|
||||
// @description: 获取完整的方法名称
|
||||
// parameter:
|
||||
// @structName:结构体名称
|
||||
// @methodName:方法名称
|
||||
// return:
|
||||
// @string:完整的方法名称
|
||||
func getFullMethodName(structName, methodName string) string {
|
||||
return structName + con_DelimeterOfObjAndMethod + methodName
|
||||
}
|
||||
|
||||
// resolveMethodInOutParams
|
||||
// @description: 解析方法的输入输出参数
|
||||
// parameter:
|
||||
// @method:方法对应的反射值
|
||||
// return:
|
||||
// @inTypes:输入参数类型集合
|
||||
// @outTypes:输出参数类型集合
|
||||
func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) {
|
||||
methodType := method.Type()
|
||||
for i := 0; i < methodType.NumIn(); i++ {
|
||||
inTypes = append(inTypes, methodType.In(i))
|
||||
}
|
||||
|
||||
for i := 0; i < methodType.NumOut(); i++ {
|
||||
outTypes = append(outTypes, methodType.Out(i))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterFunction
|
||||
// @description: 对象注册
|
||||
// parameter:
|
||||
// @structObject:对象
|
||||
// return:
|
||||
func RegisterFunction(structObject interface{}) {
|
||||
// 获取structObject对应的反射 Type 和 Value
|
||||
reflectValue := reflect.ValueOf(structObject)
|
||||
reflectType := reflect.TypeOf(structObject)
|
||||
|
||||
// 提取对象类型名称
|
||||
structName := getStructName(reflectType)
|
||||
|
||||
// 获取structObject中返回值为responseObject的方法
|
||||
for i := 0; i < reflectType.NumMethod(); i++ {
|
||||
// 获得方法名称
|
||||
methodName := reflectType.Method(i).Name
|
||||
|
||||
// 获得方法及其输入参数的类型列表
|
||||
method := reflectValue.MethodByName(methodName)
|
||||
inTypes, outTypes := resolveMethodInOutParams(method)
|
||||
|
||||
// 判断输出参数数量是否正确
|
||||
if len(outTypes) != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 判断返回值是否为responseObject
|
||||
if outTypes[0] != responseType {
|
||||
continue
|
||||
}
|
||||
|
||||
// 添加到列表中
|
||||
methodMap[getFullMethodName(structName, methodName)] = NewReflectMethod(method, inTypes, outTypes)
|
||||
}
|
||||
}
|
||||
|
||||
// CallFunction
|
||||
// @description: 调用方法
|
||||
// parameter:
|
||||
// @requestObject:请求对象
|
||||
// return:
|
||||
// @responseObj:返还对象
|
||||
func CallFunction(requestObject *RequestObject) (responseObj *ResponseObject) {
|
||||
responseObj = GetInitResponseObj()
|
||||
|
||||
var reflectMethod *ReflectMethod
|
||||
var ok bool
|
||||
|
||||
// 根据传入的ModuleName和MethodName找到对应的方法对象
|
||||
key := getFullMethodName(requestObject.ModuleName, requestObject.MethodName)
|
||||
if reflectMethod, ok = methodMap[key]; !ok {
|
||||
message := fmt.Sprintf("找不到指定的方法:%s", key)
|
||||
logUtil.ErrorLog(message)
|
||||
responseObj.SetResultStatus(-2, message)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断参数数量是否相同
|
||||
inTypesLength := len(reflectMethod.InTypes)
|
||||
paramLength := len(requestObject.Parameters)
|
||||
if paramLength != inTypesLength {
|
||||
message := fmt.Sprintf("传入的参数数量不符,本地方法%s的参数数量:%d,传入的参数数量为:%d", key, inTypesLength, paramLength)
|
||||
logUtil.ErrorLog(message)
|
||||
responseObj.SetResultStatus(-3, message)
|
||||
return
|
||||
}
|
||||
|
||||
// 构造参数
|
||||
in := make([]reflect.Value, inTypesLength)
|
||||
for i := 0; i < inTypesLength; i++ {
|
||||
inTypeItem := reflectMethod.InTypes[i]
|
||||
paramItem := requestObject.Parameters[i]
|
||||
|
||||
// 已支持类型:Client,Player(非基本类型)
|
||||
// 已支持类型:Bool,Int,Int8,Int16,Int32,Int64,Uint,Uint8,Uint16,Uint32,Uint64,Float32,Float64,String
|
||||
// 已支持类型:以及上面所列出类型的Slice类型
|
||||
// 未支持类型:Uintptr,Complex64,Complex128,Array,Chan,Func,Interface,Map,Ptr,Struct,UnsafePointer
|
||||
// 由于byte与int8同义,rune与int32同义,所以并不需要单独处理
|
||||
// 枚举参数的类型,并进行类型转换
|
||||
switch inTypeItem.Kind() {
|
||||
case reflect.Bool:
|
||||
if paramBool, ok := paramItem.(bool); ok {
|
||||
in[i] = reflect.ValueOf(paramBool)
|
||||
}
|
||||
case reflect.Int:
|
||||
if paramFloat64, ok := paramItem.(int); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Int8:
|
||||
if paramFloat64, ok := paramItem.(int8); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Int16:
|
||||
if paramFloat64, ok := paramItem.(int16); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Int32:
|
||||
if paramFloat64, ok := paramItem.(int32); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Int64:
|
||||
if paramFloat64, ok := paramItem.(int64); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Uint:
|
||||
if paramFloat64, ok := paramItem.(uint); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Uint8:
|
||||
if paramFloat64, ok := paramItem.(uint8); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if paramFloat64, ok := paramItem.(uint16); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if paramFloat64, ok := paramItem.(uint32); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Uint64:
|
||||
if paramFloat64, ok := paramItem.(uint64); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Float32:
|
||||
if paramFloat64, ok := paramItem.(float32); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.Float64:
|
||||
if paramFloat64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(paramFloat64)
|
||||
}
|
||||
case reflect.String:
|
||||
if paramString, ok := paramItem.(string); ok {
|
||||
in[i] = reflect.ValueOf(paramString)
|
||||
}
|
||||
case reflect.Slice:
|
||||
// 如果是Slice类型,则需要对其中的项再次进行类型判断及类型转换
|
||||
if paramInterface, ok := paramItem.([]interface{}); ok {
|
||||
switch inTypeItem.String() {
|
||||
case "[]bool":
|
||||
paramsInner := make([]bool, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramBool, ok := paramInterface[i].(bool); ok {
|
||||
paramsInner[i] = paramBool
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]int":
|
||||
paramsInner := make([]int, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(int); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]int8":
|
||||
paramsInner := make([]int8, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(int8); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]int16":
|
||||
paramsInner := make([]int16, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(int16); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]int32":
|
||||
paramsInner := make([]int32, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(int32); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]int64":
|
||||
paramsInner := make([]int64, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(int64); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]uint":
|
||||
paramsInner := make([]uint, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(uint); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
// case "[]uint8": 特殊处理
|
||||
case "[]uint16":
|
||||
paramsInner := make([]uint16, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(uint16); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]uint32":
|
||||
paramsInner := make([]uint32, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(uint32); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]uint64":
|
||||
paramsInner := make([]uint64, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(uint64); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]float32":
|
||||
paramsInner := make([]float32, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(float32); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]float64":
|
||||
paramsInner := make([]float64, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramFloat64, ok := paramInterface[i].(float64); ok {
|
||||
paramsInner[i] = paramFloat64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
case "[]string":
|
||||
paramsInner := make([]string, len(paramInterface))
|
||||
for i := 0; i < len(paramInterface); i++ {
|
||||
if paramString, ok := paramInterface[i].(string); ok {
|
||||
paramsInner[i] = paramString
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(paramsInner)
|
||||
}
|
||||
} else if inTypeItem.String() == "[]uint8" { // 由于[]uint8在传输过程中会被转化成字符串,所以单独处理;
|
||||
if paramString, ok := paramItem.(string); ok {
|
||||
paramUint8 := ([]uint8)(paramString)
|
||||
in[i] = reflect.ValueOf(paramUint8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有无效的参数(传入的参数类型和方法定义的类型不匹配导致没有赋值)
|
||||
for _, item := range in {
|
||||
if reflect.Value.IsValid(item) == false {
|
||||
message := fmt.Sprintf("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObject.Parameters)
|
||||
logUtil.ErrorLog(message)
|
||||
responseObj.SetResultStatus(-1, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
out := reflectMethod.Method.Call(in)
|
||||
|
||||
// 并输出结果到客户端(由于只有一个返回值,所以取out[0])
|
||||
if responseObj, ok = (&out[0]).Interface().(*ResponseObject); !ok {
|
||||
message := fmt.Sprintf("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0]))
|
||||
logUtil.ErrorLog(message)
|
||||
responseObj.SetResultStatus(-1, message)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
41
trunk/framework/handleMgr/reflectMethod.go
Normal file
41
trunk/framework/handleMgr/reflectMethod.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 反射类-反射的方法和输入、输出参数类型组合类型
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-23 16:33:43
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ReflectMethod 反射的方法和输入、输出参数类型组合类型
|
||||
type ReflectMethod struct {
|
||||
// 反射出来的对应方法对象
|
||||
Method reflect.Value
|
||||
|
||||
// 反射出来的方法的输入参数的类型集合
|
||||
InTypes []reflect.Type
|
||||
|
||||
// 反射出来的方法的输出参数的类型集合
|
||||
OutTypes []reflect.Type
|
||||
}
|
||||
|
||||
// NewReflectMethod
|
||||
// @description:创建反射的方法和输入、输出参数类型组合类型
|
||||
// parameter:
|
||||
// @_method:反射出来的对应方法对象
|
||||
// @_inTypes:反射出来的方法的输入参数的类型集合
|
||||
// @_outTypes:反射出来的方法的输出参数的类型集合
|
||||
// return:
|
||||
// @*ReflectMethod:
|
||||
func NewReflectMethod(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *ReflectMethod {
|
||||
return &ReflectMethod{
|
||||
Method: _method,
|
||||
InTypes: _inTypes,
|
||||
OutTypes: _outTypes,
|
||||
}
|
||||
}
|
||||
46
trunk/framework/handleMgr/requestObject.go
Normal file
46
trunk/framework/handleMgr/requestObject.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 反射类-请求对象
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-23 16:33:53
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
// RequestObject 请求对象
|
||||
type RequestObject struct {
|
||||
// 请求的模块名称
|
||||
ModuleName string
|
||||
|
||||
// 请求的方法名称
|
||||
MethodName string
|
||||
|
||||
// 请求的参数数组
|
||||
Parameters []interface{}
|
||||
|
||||
// 是否处理返回值
|
||||
IsHaveResult bool
|
||||
|
||||
// 执行完成,返回chan监控
|
||||
ResultChan chan *ResponseObject
|
||||
}
|
||||
|
||||
// NewRequestObject
|
||||
// @description:
|
||||
// parameter:
|
||||
// @moduleName:模块名名称
|
||||
// @methodName:执行方法名称
|
||||
// @parameters:方法参数
|
||||
// @isHaveResult:是否处理返回值
|
||||
// return:
|
||||
// @*RequestObject:
|
||||
func NewRequestObject(moduleName string, methodName string, parameters []interface{}, isHaveResult bool) *RequestObject {
|
||||
return &RequestObject{
|
||||
ModuleName: moduleName,
|
||||
MethodName: methodName,
|
||||
Parameters: parameters,
|
||||
IsHaveResult: isHaveResult,
|
||||
ResultChan: make(chan *ResponseObject, 1),
|
||||
}
|
||||
}
|
||||
63
trunk/framework/handleMgr/responseObject.go
Normal file
63
trunk/framework/handleMgr/responseObject.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// ************************************
|
||||
// @package: handleMgr
|
||||
// @description: 反射类-响应对象
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-23 16:34:08
|
||||
// ************************************
|
||||
|
||||
package handleMgr
|
||||
|
||||
// ResponseObject 响应对象
|
||||
type ResponseObject struct {
|
||||
// 错误码
|
||||
Code int
|
||||
|
||||
// 响应结果的状态值所对应的描述信息
|
||||
Message string
|
||||
|
||||
// 响应结果的数据
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
// SetResultStatus
|
||||
// @description: 设置响应结果的状态值
|
||||
// parameter:
|
||||
// @receiver r:
|
||||
// @code:响应结果的错误码
|
||||
// @message:响应结果的字符串
|
||||
// return:响应结果对象
|
||||
// @*ResponseObject:
|
||||
func (r *ResponseObject) SetResultStatus(code int, message string) *ResponseObject {
|
||||
r.Code = code
|
||||
r.Message = message
|
||||
return r
|
||||
}
|
||||
|
||||
// SetData
|
||||
// @description: 设置响应结果的状态值
|
||||
// parameter:
|
||||
// @receiver r:
|
||||
// @message:响应结果的字符串
|
||||
// return:响应结果对象
|
||||
// @*ResponseObject:
|
||||
func (r *ResponseObject) SetData(data interface{}) *ResponseObject {
|
||||
r.Data = data
|
||||
return r
|
||||
}
|
||||
|
||||
// GetInitResponseObj
|
||||
// @description: 初始化
|
||||
// parameter:
|
||||
// @moduleName:模块名名称
|
||||
// @methodName:执行方法名称
|
||||
// @parameters:方法参数
|
||||
// @isHaveResult:是否处理返回值
|
||||
// return:
|
||||
// @*ResponseObject:GetInitResponseObj
|
||||
func GetInitResponseObj() *ResponseObject {
|
||||
return &ResponseObject{
|
||||
Message: "",
|
||||
Data: nil,
|
||||
}
|
||||
}
|
||||
133
trunk/framework/handleMgr/test_test.go
Normal file
133
trunk/framework/handleMgr/test_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package handleMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ---------------申请示例实例--------------
|
||||
var (
|
||||
data = make(map[int]int, 0)
|
||||
)
|
||||
|
||||
type testBll struct {
|
||||
}
|
||||
|
||||
// TestAdd
|
||||
// @description:测试添加
|
||||
// parameter:
|
||||
// @receiver t:
|
||||
// @x:
|
||||
// @y:
|
||||
// return:
|
||||
// @*ResponseObject:
|
||||
func (t testBll) TestAdd(x, y int) *ResponseObject {
|
||||
responseObj := GetInitResponseObj()
|
||||
data[x] = y
|
||||
z := x + y
|
||||
|
||||
print(x)
|
||||
|
||||
responseObj.SetData(z)
|
||||
responseObj.SetResultStatus(-11111, "错误码")
|
||||
return responseObj
|
||||
}
|
||||
|
||||
// See1
|
||||
// @description:测试添加
|
||||
// parameter:
|
||||
// @receiver t:
|
||||
// @x:
|
||||
// return:
|
||||
// @*ResponseObject:
|
||||
func (t testBll) See1(x int) *ResponseObject {
|
||||
responseObj := GetInitResponseObj()
|
||||
fmt.Print(x)
|
||||
return responseObj
|
||||
}
|
||||
|
||||
// See2
|
||||
// @description:测试添加
|
||||
// parameter:
|
||||
// @receiver t:
|
||||
// @x:
|
||||
// return:
|
||||
// @*ResponseObject:
|
||||
func (t testBll) See2(x int) *ResponseObject {
|
||||
responseObj := GetInitResponseObj()
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
fmt.Print(x)
|
||||
return responseObj
|
||||
}
|
||||
|
||||
func (t testBll) ReMove(x int) *ResponseObject {
|
||||
responseObj := GetInitResponseObj()
|
||||
delete(data, x)
|
||||
return responseObj
|
||||
}
|
||||
|
||||
// ---------------测试方法--------------
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
var paramItem interface{}
|
||||
paramItem = 123
|
||||
paramFloat64, ok := paramItem.(int)
|
||||
if ok {
|
||||
x := reflect.ValueOf(int(paramFloat64))
|
||||
t.Log(x)
|
||||
}
|
||||
t.Log(paramFloat64)
|
||||
t.Log(ok)
|
||||
|
||||
//t.Log("A")
|
||||
//RegisterNewModule("test", new(testBll), 10)
|
||||
|
||||
//parameter := []interface{}{"1", 2}
|
||||
//x, y, mes := Done("test", "testBll", "TestAdd", parameter, false)
|
||||
//for key, item := range data {
|
||||
// t.Log(key, item)
|
||||
//}
|
||||
|
||||
//t.Log("B2")
|
||||
//parameter1 := []interface{}{2, 2}
|
||||
//x, y, mes = Done("test", "testBll", "TestAdd", parameter1, true)
|
||||
//for key, item := range data {
|
||||
// t.Log(key, item)
|
||||
//}
|
||||
//t.Log(x)
|
||||
//t.Log(y)
|
||||
//t.Log(mes)
|
||||
//t.Log("B3")
|
||||
//
|
||||
//t.Log("C")
|
||||
//parameter2 := []interface{}{2}
|
||||
//Done("test", "testBll", "ReMove", parameter2, true)
|
||||
//for key, item := range data {
|
||||
// t.Log(key, item)
|
||||
//}
|
||||
//t.Log("D")
|
||||
//
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//parameter3 := []interface{}{1}
|
||||
//Done("test", "testBll", "See2", parameter3, false)
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//parameter4 := []interface{}{2}
|
||||
//Done("test", "testBll", "See1", parameter4, true)
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//parameter5 := []interface{}{1}
|
||||
//Done("test", "testBll", "See1", parameter5, true)
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//
|
||||
//t.Log("E")
|
||||
//
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//for i := 0; i < 1000; i++ {
|
||||
// Done("test", "testBll", "See1", parameter5, true)
|
||||
//}
|
||||
//t.Log(time.Now().UnixMilli())
|
||||
//t.Log("F")
|
||||
|
||||
t.Error("G")
|
||||
}
|
||||
62
trunk/framework/initMgr/initSuccess.go
Normal file
62
trunk/framework/initMgr/initSuccess.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package initMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// 初始化成功对象
|
||||
type InitSuccess struct {
|
||||
name string
|
||||
registerMap map[string]chan bool
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// 注册需要被通知的对象
|
||||
// name:唯一标识
|
||||
// ch:用于通知的通道
|
||||
func (this *InitSuccess) Register(name string, ch chan bool) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
if _, exists := this.registerMap[name]; exists {
|
||||
panic(fmt.Errorf("InitSuccess.Register-%s-%s已经存在,请检查", this.name, name))
|
||||
}
|
||||
|
||||
this.registerMap[name] = ch
|
||||
|
||||
logUtil.DebugLog(fmt.Sprintf("InitSuccess.Register-%s,当前共有%d个注册", this.name, len(this.registerMap)))
|
||||
}
|
||||
|
||||
// 取消启动成功通知注册
|
||||
// name:唯一标识
|
||||
func (this *InitSuccess) Unregister(name string) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
delete(this.registerMap, name)
|
||||
}
|
||||
|
||||
// 通知所有已注册的对象
|
||||
func (this *InitSuccess) Notify() {
|
||||
this.mutex.RLock()
|
||||
defer this.mutex.RUnlock()
|
||||
|
||||
for name, ch := range this.registerMap {
|
||||
ch <- true
|
||||
msg := fmt.Sprintf("通知:%s-%s初始化成功", this.name, name)
|
||||
debugUtil.Println(msg)
|
||||
logUtil.DebugLog(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建初始化成功对象
|
||||
func NewInitSuccess(name string) *InitSuccess {
|
||||
return &InitSuccess{
|
||||
name: name,
|
||||
registerMap: make(map[string]chan bool),
|
||||
}
|
||||
}
|
||||
93
trunk/framework/ipMgr/ipCheck.go
Normal file
93
trunk/framework/ipMgr/ipCheck.go
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
提供统一的ip验证的逻辑;包括两部分:
|
||||
1、ManageCenter中配置到ServerGroup中的IP;系统内部自动处理,外部无需关注(暂时不用);
|
||||
2、各个应用程序中配置的ip;通过调用Init或InitString方法进行初始化;
|
||||
*/
|
||||
package ipMgr
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
ipMap = make(map[string]struct{}, 32) // 本地ip集合
|
||||
ipCheckFuncList = make([]func(string) bool, 0, 16) // ip检查函数列表
|
||||
mutex sync.RWMutex
|
||||
)
|
||||
|
||||
// 初始化IP列表
|
||||
func Init(ipList []string) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 先清空再初始化
|
||||
ipMap = make(map[string]struct{}, 32)
|
||||
for _, item := range ipList {
|
||||
ipMap[item] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化ip字符串(以分隔符分割的,分隔符为:",", ";", ":", "|", "||")
|
||||
func InitString(ipStr string) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 先清空再初始化
|
||||
ipMap = make(map[string]struct{}, 32)
|
||||
for _, item := range stringUtil.Split(ipStr, nil) {
|
||||
ipMap[item] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func AddString(ipStr string) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 先清空再初始化
|
||||
if ipMap == nil {
|
||||
ipMap = make(map[string]struct{}, 32)
|
||||
}
|
||||
|
||||
for _, item := range stringUtil.Split(ipStr, nil) {
|
||||
ipMap[item] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterIpCheckFunc 注册Ip检查函数
|
||||
func RegisterIpCheckFunc(funcName string, funcItem func(string) bool) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
ipCheckFuncList = append(ipCheckFuncList, funcItem)
|
||||
}
|
||||
|
||||
func isLocalValid(ip string) bool {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
||||
_, exist := ipMap[ip]
|
||||
return exist
|
||||
}
|
||||
|
||||
func isCheckFuncValid(ip string) bool {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
||||
for _, funcItem := range ipCheckFuncList {
|
||||
if funcItem(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断传入的Ip是否有效
|
||||
// ip:ip
|
||||
// 返回值:
|
||||
// 是否有效
|
||||
func IsIpValid(ip string) bool {
|
||||
return isLocalValid(ip) || isCheckFuncValid(ip)
|
||||
}
|
||||
44
trunk/framework/ipMgr/ipCheck_test.go
Normal file
44
trunk/framework/ipMgr/ipCheck_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package ipMgr
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsIpValid(t *testing.T) {
|
||||
ip := "10.255.0.7"
|
||||
if IsIpValid(ip) {
|
||||
t.Errorf("%s应该无效,但是现在却有效", ip)
|
||||
}
|
||||
|
||||
ipList := []string{"10.255.0.7", "10.1.0.21"}
|
||||
Init(ipList)
|
||||
|
||||
if IsIpValid(ip) == false {
|
||||
t.Errorf("%s应该有效,但是现在却无效", ip)
|
||||
}
|
||||
|
||||
ipStr := "10.255.0.7,10.1.0.21;10.255.0.6|10.1.0.30||"
|
||||
InitString(ipStr)
|
||||
if IsIpValid(ip) == false {
|
||||
t.Errorf("%s应该有效,但是现在却无效", ip)
|
||||
}
|
||||
|
||||
ip = "192.168.1.1"
|
||||
RegisterIpCheckFunc("", alwaysFalse)
|
||||
if IsIpValid(ip) {
|
||||
t.Errorf("%s应该无效,但是现在却有效", ip)
|
||||
}
|
||||
|
||||
RegisterIpCheckFunc("", alwaysTrue)
|
||||
if IsIpValid(ip) == false {
|
||||
t.Errorf("%s应该有效,但是现在却无效", ip)
|
||||
}
|
||||
}
|
||||
|
||||
func alwaysTrue(ip string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func alwaysFalse(ip string) bool {
|
||||
return false
|
||||
}
|
||||
93
trunk/framework/ipMgr/ipQuery.go
Normal file
93
trunk/framework/ipMgr/ipQuery.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package ipMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"goutil/securityUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
IP_SERVICE_URL = "http://ipip.7qule.com/query"
|
||||
)
|
||||
|
||||
// 服务器的响应对象
|
||||
type QueryResponse struct {
|
||||
// 响应结果的状态值
|
||||
ResultStatus string
|
||||
|
||||
// 响应结果的数据
|
||||
Data *IPInfo
|
||||
}
|
||||
|
||||
// IP信息对象
|
||||
type IPInfo struct {
|
||||
// 所属大陆块
|
||||
Continent string
|
||||
|
||||
// 国家
|
||||
Country string
|
||||
|
||||
// 省份
|
||||
Region string
|
||||
|
||||
// 城市
|
||||
City string
|
||||
|
||||
// 网络服务提供商
|
||||
Isp string
|
||||
}
|
||||
|
||||
// 查询ip地址的详细信息
|
||||
// appId: 为应用分配的唯一标识
|
||||
// appSecret: 为应用分配的密钥
|
||||
// ip: 待查询的ip地址
|
||||
// isDomestic: 是否为国内的IP
|
||||
// timeout:超时时间(单位:秒)
|
||||
// 返回值:
|
||||
// ipInfoObj: IP地址信息对象
|
||||
// err: 错误对象
|
||||
func Query(appId, appSecret, ip string, isDomestic bool, timeout int) (ipInfoObj *IPInfo, err error) {
|
||||
timeStamp := fmt.Sprintf("%d", time.Now().Unix())
|
||||
rawString := fmt.Sprintf("AppId=%s&IP=%s&Timestamp=%s&AppSecret=%s", appId, ip, timeStamp, appSecret)
|
||||
sign := securityUtil.Md5String(rawString, true)
|
||||
|
||||
postData := make(map[string]string, 5)
|
||||
postData["AppId"] = appId
|
||||
postData["IP"] = ip
|
||||
postData["IsDomestic"] = fmt.Sprintf("%t", isDomestic)
|
||||
postData["Timestamp"] = timeStamp
|
||||
postData["Sign"] = sign
|
||||
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, timeout)
|
||||
|
||||
statusCode, result, err := webUtil.PostMapData(IP_SERVICE_URL, postData, header, transport)
|
||||
//statusCode, result, err := webUtil.PostMapData(IP_SERVICE_URL, postData, header, transport)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if statusCode != 200 {
|
||||
err = fmt.Errorf("StatusCode:%d is wrong.", statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var queryResponseObj *QueryResponse
|
||||
err = json.Unmarshal(result, &queryResponseObj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if queryResponseObj.ResultStatus != "" {
|
||||
err = fmt.Errorf("Query result:%s", queryResponseObj.ResultStatus)
|
||||
return
|
||||
}
|
||||
|
||||
ipInfoObj = queryResponseObj.Data
|
||||
|
||||
return
|
||||
}
|
||||
98
trunk/framework/ipMgr/ipQuery_test.go
Normal file
98
trunk/framework/ipMgr/ipQuery_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package ipMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
IP_SERVICE_URL = "http://ipip.7qule.com/query"
|
||||
|
||||
appId := "unittest"
|
||||
appId_wrong := "wrong"
|
||||
appSecret := "c5746980-5d52-4ba9-834f-13d0066ad1d0"
|
||||
appSecret_wrong := "wrong"
|
||||
ip := "117.139.247.210"
|
||||
ip_wrong := "wrong"
|
||||
isDomestic := true
|
||||
continent := ""
|
||||
country := "中国"
|
||||
region := "四川"
|
||||
city := "成都"
|
||||
timeout := 3
|
||||
|
||||
// Test with wrong AppId
|
||||
ipInfoObj, err := Query(appId_wrong, appSecret, ip, isDomestic, timeout)
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there is no error")
|
||||
return
|
||||
}
|
||||
|
||||
// Test with wrong AppSecret
|
||||
ipInfoObj, err = Query(appId, appSecret_wrong, ip, isDomestic, timeout)
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there is no error")
|
||||
return
|
||||
}
|
||||
|
||||
// Test with wrong IP
|
||||
ipInfoObj, err = Query(appId, appSecret, ip_wrong, isDomestic, timeout)
|
||||
if err == nil {
|
||||
t.Errorf("There should be an error, but now there is no error")
|
||||
return
|
||||
}
|
||||
|
||||
// Test with correct information and domestic ip
|
||||
ipInfoObj, err = Query(appId, appSecret, ip, isDomestic, timeout)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is one:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("ipInfoObj:%v\n", ipInfoObj)
|
||||
|
||||
if ipInfoObj.Continent != continent {
|
||||
t.Errorf("Expected continent %s, but got %s", continent, ipInfoObj.Continent)
|
||||
}
|
||||
|
||||
if ipInfoObj.Country != country {
|
||||
t.Errorf("Expected country %s, but got %s", country, ipInfoObj.Country)
|
||||
}
|
||||
|
||||
if ipInfoObj.Region != region {
|
||||
t.Errorf("Expected region %s, but got %s", region, ipInfoObj.Region)
|
||||
}
|
||||
|
||||
if ipInfoObj.City != city {
|
||||
t.Errorf("Expected city %s, but got %s", city, ipInfoObj.City)
|
||||
}
|
||||
|
||||
// Test with correct information and foreign ip
|
||||
isDomestic = false
|
||||
continent = "亚洲"
|
||||
country = "中国"
|
||||
region = "四川省"
|
||||
city = "成都"
|
||||
|
||||
ipInfoObj, err = Query(appId, appSecret, ip, isDomestic, timeout)
|
||||
if err != nil {
|
||||
t.Errorf("There should be no error, but now there is one:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("ipInfoObj:%v\n", ipInfoObj)
|
||||
|
||||
if ipInfoObj.Continent != continent {
|
||||
t.Errorf("Expected continent %s, but got %s", continent, ipInfoObj.Continent)
|
||||
}
|
||||
|
||||
if ipInfoObj.Country != country {
|
||||
t.Errorf("Expected country %s, but got %s", country, ipInfoObj.Country)
|
||||
}
|
||||
|
||||
if ipInfoObj.Region != region {
|
||||
t.Errorf("Expected region %s, but got %s", region, ipInfoObj.Region)
|
||||
}
|
||||
|
||||
if ipInfoObj.City != city {
|
||||
t.Errorf("Expected city %s, but got %s", city, ipInfoObj.City)
|
||||
}
|
||||
}
|
||||
51
trunk/framework/kafkaMgr/kafkaConfig.go
Normal file
51
trunk/framework/kafkaMgr/kafkaConfig.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package kafkaMgr
|
||||
|
||||
import "strings"
|
||||
|
||||
// Kafka配置对象
|
||||
type KafkaConfig struct {
|
||||
// Brokers的地址
|
||||
Brokers string
|
||||
|
||||
// 主题
|
||||
Topics string
|
||||
|
||||
// 分区
|
||||
Partitions string
|
||||
|
||||
// 分组Id
|
||||
GroupId string
|
||||
|
||||
// 用户名
|
||||
UserName string
|
||||
|
||||
// 密码
|
||||
Passward string
|
||||
|
||||
// 需要的证书文件
|
||||
CertFile string
|
||||
}
|
||||
|
||||
func (this *KafkaConfig) GetBrokerList() []string {
|
||||
if len(this.Brokers) <= 0 {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
return strings.Split(this.Brokers, ",")
|
||||
}
|
||||
|
||||
func (this *KafkaConfig) GetTopicList() []string {
|
||||
if len(this.Topics) <= 0 {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
return strings.Split(this.Topics, ",")
|
||||
}
|
||||
|
||||
func (this *KafkaConfig) GetPartitionList() []string {
|
||||
if len(this.Partitions) <= 0 {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
return strings.Split(this.Partitions, ",")
|
||||
}
|
||||
5
trunk/framework/linuxMgr/doc.go
Normal file
5
trunk/framework/linuxMgr/doc.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package linuxMgr
|
||||
|
||||
// Linux平台的管理器,主要提供在Linux平台上才能运行的一些功能
|
||||
// 如:syscall.Dup2
|
||||
// 使用方式,在游戏中引用此包即可
|
||||
29
trunk/framework/linuxMgr/dup.go
Normal file
29
trunk/framework/linuxMgr/dup.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// +build !windows
|
||||
|
||||
package linuxMgr
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"goutil/fileUtil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
//验证文件夹是否存在
|
||||
fileAbsoluteDirectory := filepath.Join("Log")
|
||||
if !fileUtil.IsDirExists(fileAbsoluteDirectory) {
|
||||
if err := os.MkdirAll(fileAbsoluteDirectory, os.ModePerm|os.ModeTemporary); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 标准输出
|
||||
stdoutFile, _ := os.OpenFile("Log/Stdout.txt", os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
|
||||
syscall.Dup2(int(stdoutFile.Fd()), 1)
|
||||
|
||||
// 标准错误输出
|
||||
stderrFile, _ := os.OpenFile("Log/Stderr.txt", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0644)
|
||||
syscall.Dup2(int(stderrFile.Fd()), 2)
|
||||
}
|
||||
174
trunk/framework/managecenterMgr/area.go
Normal file
174
trunk/framework/managecenterMgr/area.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
areaMap = make(map[int32]*Area, 128)
|
||||
areaHash string
|
||||
)
|
||||
|
||||
// 重新加载大区数据
|
||||
func reloadArea(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新大区列表")
|
||||
|
||||
// 连接服务器,以获取数据
|
||||
url := getManageCenterUrl("/API/AreaList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["HashValue"] = areaHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取大区列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取大区列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取大区列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(areaMap) == 0 {
|
||||
areaHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取大区列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpAreaList := make([]*Area, 0, 128)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取大区列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpAreaList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取大区列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新大区信息结束,大区数量:%d", len(tmpAreaList)))
|
||||
|
||||
tmpAreaMap := make(map[int32]*Area)
|
||||
for _, item := range tmpAreaList {
|
||||
tmpAreaMap[item.AreaId] = item
|
||||
}
|
||||
|
||||
// 赋值给最终的areaMap
|
||||
areaMap = tmpAreaMap
|
||||
areaHash = returnObj.HashValue
|
||||
|
||||
// 通知变更
|
||||
mcDataChangeCallBack(managecenterModel.AreaData, isInit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据区服ID获取所属大区ID
|
||||
func GetAreaIdByServerId(serverId int32) (areaId int32, exist bool) {
|
||||
for _, item := range areaMap {
|
||||
if item.CheckServerIdIsInRange(serverId) {
|
||||
areaId = item.AreaId
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据服务器组id获取大区对象数据
|
||||
func GetAreaDBByGroupId(groupId int32) (areaDB *Area, exist bool) {
|
||||
//如果没有大区数据,返回空
|
||||
exist = false
|
||||
if areaMap == nil || len(areaMap) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range areaMap {
|
||||
if item.CheckServerIdIsInRange(groupId) {
|
||||
areaDB = item
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有大区信息
|
||||
func GetAllAreaDB() []*Area {
|
||||
tempList := make([]*Area, 8)
|
||||
for _, item := range areaMap {
|
||||
tempList = append(tempList, item)
|
||||
}
|
||||
return tempList
|
||||
}
|
||||
|
||||
// 根据大区ID获取大区信息
|
||||
func GetAreaDBbyAreaID(areaId int32) (areaDB *Area, exist bool) {
|
||||
//如果没有大区数据,返回空
|
||||
exist = false
|
||||
if areaMap == nil || len(areaMap) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
if item, ok := areaMap[areaId]; ok {
|
||||
areaDB = item
|
||||
exist = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 根据服务器ID获取大区页签信息
|
||||
func GetAreaLabelDBByGroupId(groupId int32) (areaLabelDB *AreaLabel, exist bool) {
|
||||
areaDB, exist := GetAreaDBByGroupId(groupId)
|
||||
if !exist {
|
||||
return nil, false
|
||||
}
|
||||
if areaDB.AreaLabelList == nil || len(areaDB.AreaLabelList) < 1 {
|
||||
return nil, false
|
||||
|
||||
}
|
||||
//校服务器ID是否在大区页签服务器范围内
|
||||
for _, item := range areaDB.AreaLabelList {
|
||||
if exist := item.CheckServerIdIsInLabelRange(groupId); exist {
|
||||
return item, true
|
||||
}
|
||||
}
|
||||
|
||||
//如果没找到,则返回空
|
||||
return nil, false
|
||||
}
|
||||
7
trunk/framework/managecenterMgr/doc.go
Normal file
7
trunk/framework/managecenterMgr/doc.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package managecenterMgr
|
||||
|
||||
// ManageCenter的管理包,提供管理合作商、服务器、服务器组、游戏资源、白名单等功能
|
||||
|
||||
// 使用方法:
|
||||
// 首先调用Start方法,这样会进行初始化,后续就可以使用提供的其它方法
|
||||
// 内部会定时去ManageCenter刷新最新的数据
|
||||
137
trunk/framework/managecenterMgr/managecenter.go
Normal file
137
trunk/framework/managecenterMgr/managecenter.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"Framework/goroutineMgr"
|
||||
"Framework/initMgr"
|
||||
"Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
mcAPIUrl string
|
||||
mcDataSwitchObj *ManageCenterDataSwitch
|
||||
initSuccessObj = initMgr.NewInitSuccess("managecenterMgr")
|
||||
|
||||
//数据变更通知回调
|
||||
mDataChangeCallBackFunc func(managecenterModel.MCDataType) error
|
||||
)
|
||||
|
||||
// 注册初始化成功的通道
|
||||
// name:模块名称
|
||||
// ch:通道对象
|
||||
func RegisterInitSuccess(name string, ch chan bool) {
|
||||
initSuccessObj.Register(name, ch)
|
||||
}
|
||||
|
||||
// 注册MC数据变更通知回调函数
|
||||
// handler:回调方法
|
||||
func RegisterDataChangeCallBackFunc(handler func(managecenterModel.MCDataType) error) {
|
||||
mDataChangeCallBackFunc = handler
|
||||
}
|
||||
|
||||
// Start ...启动ManageCenter管理器
|
||||
// manageCenterAPIUrl:ManageCenter对外提供的API
|
||||
// manageCenterDataSwitchObj:ManageCenter数据获取开关对象
|
||||
func Start(manageCenterAPIUrl string, manageCenterDataSwitchObj *ManageCenterDataSwitch) {
|
||||
mcAPIUrl = manageCenterAPIUrl
|
||||
mcDataSwitchObj = manageCenterDataSwitchObj
|
||||
|
||||
// 先初始化一次数据
|
||||
if err := reload(true); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 通知初始化成功
|
||||
initSuccessObj.Notify()
|
||||
|
||||
// 定时刷新数据
|
||||
go func() {
|
||||
goroutineName := "managecenterMgr.timelyRefresh"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
// 每5秒刷新一次
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// 刷新服务器组
|
||||
reload(false)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 重新加载/初始化
|
||||
func reload(isInit bool) error {
|
||||
var err error
|
||||
|
||||
// 加载合作商数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.PartnerDataSwitch {
|
||||
if err = reloadPartner(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 加载服务器数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.ServerDataSwitch {
|
||||
if err = reloadServer(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 加载服务器组数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.ServerGroupDataSwitch {
|
||||
if err = reloadServerGroup(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 加载资源数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.ResourceVersionDataSwitch {
|
||||
if err = reloadResourceVersion(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 加载玩家白名单数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.WhiteListDataSwitch {
|
||||
if err = reloadWhiteList(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 加载大区数据
|
||||
if mcDataSwitchObj.AllDataSwitch || mcDataSwitchObj.AreaDataSwitch {
|
||||
if err = reloadArea(isInit); err != nil && isInit {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取可访问的ManageCenter地址
|
||||
// suffix:Url后缀
|
||||
// 返回值:
|
||||
// 可访问的ManageCenter地址
|
||||
func getManageCenterUrl(suffix string) string {
|
||||
return fmt.Sprintf("%s/%s", strings.TrimRight(mcAPIUrl, "/"), strings.TrimLeft(suffix, "/"))
|
||||
}
|
||||
|
||||
// 回调
|
||||
// dataType:数据类型
|
||||
// isInit:是否初始化
|
||||
func mcDataChangeCallBack(dataType managecenterModel.MCDataType, isInit bool) {
|
||||
//如果没注册回调函数,或者是数据初始化,则不回调
|
||||
if mDataChangeCallBackFunc == nil || isInit {
|
||||
return
|
||||
}
|
||||
|
||||
//回调
|
||||
err := mDataChangeCallBackFunc(dataType)
|
||||
|
||||
logUtil.ErrorLog(fmt.Sprintf("通知回调出错,DataType:%d,错误信息为:%s", dataType, err))
|
||||
}
|
||||
25
trunk/framework/managecenterMgr/managecenterDataSwitch.go
Normal file
25
trunk/framework/managecenterMgr/managecenterDataSwitch.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package managecenterMgr
|
||||
|
||||
// ManageCenter数据获取开关(每一类数据一个开关)
|
||||
type ManageCenterDataSwitch struct {
|
||||
// 获取所有数据开关(只要这个开关值为true,则不论各类数据的开关是否打开,都获取数据)
|
||||
AllDataSwitch bool
|
||||
|
||||
// 获取合作商数据开关
|
||||
PartnerDataSwitch bool
|
||||
|
||||
// 获取服务器数据开关
|
||||
ServerDataSwitch bool
|
||||
|
||||
// 获取服务器组数开关
|
||||
ServerGroupDataSwitch bool
|
||||
|
||||
// 获取资源包版本数据开关
|
||||
ResourceVersionDataSwitch bool
|
||||
|
||||
// 获取白名单数据开关
|
||||
WhiteListDataSwitch bool
|
||||
|
||||
// 获取大区数据开关
|
||||
AreaDataSwitch bool
|
||||
}
|
||||
132
trunk/framework/managecenterMgr/managecenter_test.go
Normal file
132
trunk/framework/managecenterMgr/managecenter_test.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
manageCenterDataSwitchObj := &ManageCenterDataSwitch{
|
||||
AllDataSwitch: true,
|
||||
}
|
||||
Start("https://managecenterapi-sd3.7qule.com/", manageCenterDataSwitchObj)
|
||||
|
||||
item, exist := GetAreaLabelDBByGroupId(82)
|
||||
if exist {
|
||||
fmt.Printf("%v", item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPartner(t *testing.T) {
|
||||
partnerList := GetPartnerList()
|
||||
fmt.Printf("PartnerList count:%v\n", len(partnerList))
|
||||
if len(partnerList) == 0 {
|
||||
t.Errorf("There is no partner.")
|
||||
return
|
||||
}
|
||||
|
||||
firstPartner := partnerList[0]
|
||||
_, exist := GetPartner(firstPartner.Id)
|
||||
if !exist {
|
||||
t.Errorf("Partner with Id:%d should exist, but now it doesn't.", firstPartner.Id)
|
||||
return
|
||||
}
|
||||
|
||||
_, exist = GetPartnerByAlias(firstPartner.Alias)
|
||||
if !exist {
|
||||
t.Errorf("Partner with Alias:%s should exist, but now it doesn't.", firstPartner.Alias)
|
||||
return
|
||||
}
|
||||
|
||||
_, exist, err := GetOtherConfigInfo(firstPartner.Id, "LoginHandler")
|
||||
if err != nil {
|
||||
t.Errorf("There should no error for Partner:%d, but now there is one:%v", err, firstPartner.Id)
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
t.Errorf("Partner with Id:%d should have an other config named LoginHandler, but now there isn't.", firstPartner.Id)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
serverGroupList := GetServerGroupList()
|
||||
if len(serverGroupList) == 0 {
|
||||
t.Errorf("There is no ServerGroup.")
|
||||
return
|
||||
}
|
||||
firstServerGroup := serverGroupList[0]
|
||||
|
||||
serverList := GetServerListByGroupId(firstServerGroup.Id)
|
||||
fmt.Printf("There are %d servers of GroupId:%d\n", len(serverList), firstServerGroup.Id)
|
||||
|
||||
firstServer := serverList[0]
|
||||
serverList = GetServerListByPartnerId(firstServer.PartnerId)
|
||||
fmt.Printf("There are %d servers of PartnerId:%d\n", len(serverList), firstServer.PartnerId)
|
||||
|
||||
_, exist := GetServerItem(firstServer.PartnerId, firstServer.Id)
|
||||
if !exist {
|
||||
t.Errorf("There is no server with PartnerId:%d, ServerId:%d.", firstServer.PartnerId, firstServer.Id)
|
||||
return
|
||||
}
|
||||
|
||||
distinctServerIdList := GetDistinctServerIdList()
|
||||
fmt.Printf("There are %d distinct ServerId\n", len(distinctServerIdList))
|
||||
}
|
||||
|
||||
func TestServerGroup(t *testing.T) {
|
||||
serverGroupList := GetServerGroupList()
|
||||
if len(serverGroupList) == 0 {
|
||||
t.Errorf("There is no ServerGroup.")
|
||||
return
|
||||
}
|
||||
|
||||
firstServerGroup := serverGroupList[0]
|
||||
_, exist := GetServerGroupItem(firstServerGroup.Id)
|
||||
if !exist {
|
||||
t.Errorf("The ServerGroup with Id:%d should exist, but now it doesn't.", firstServerGroup.Id)
|
||||
return
|
||||
}
|
||||
|
||||
serverList := GetServerListByGroupId(firstServerGroup.Id)
|
||||
if len(serverList) == 0 {
|
||||
t.Errorf("There is no server of ServerGroupId:%d", firstServerGroup.Id)
|
||||
return
|
||||
}
|
||||
firstServer := serverList[0]
|
||||
_, _, exist = GetServerGroup(firstServer.PartnerId, firstServer.Id)
|
||||
if !exist {
|
||||
t.Errorf("The ServerGroup with PartnerId:%d, ServerId:%d should exist, but now it doesn't.", firstServer.PartnerId, firstServer.Id)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceVersion(t *testing.T) {
|
||||
list := GetResourceVersionList()
|
||||
fmt.Printf("There are %d resource versions.\n", len(list))
|
||||
}
|
||||
|
||||
func TestUserWhiteList(t *testing.T) {
|
||||
fmt.Printf("There are %d whiteLists.\n", len(whiteListMap))
|
||||
if len(whiteListMap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var partnerId int32
|
||||
var userId string
|
||||
for _, v := range whiteListMap {
|
||||
for _, _v := range v {
|
||||
partnerId = _v.PartnerId
|
||||
userId = _v.UserId
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
expected := true
|
||||
got := IsInWhiteList(partnerId, userId)
|
||||
if got != expected {
|
||||
t.Errorf("Expected to get %t, but got %t", expected, got)
|
||||
return
|
||||
}
|
||||
}
|
||||
158
trunk/framework/managecenterMgr/partner.go
Normal file
158
trunk/framework/managecenterMgr/partner.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
partnerMap = make(map[int32]*Partner, 128)
|
||||
partnerHash string
|
||||
)
|
||||
|
||||
// 重新加载合作商
|
||||
func reloadPartner(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新合作商列表")
|
||||
|
||||
// 连接服务器,以获取数据
|
||||
url := getManageCenterUrl("/API/PartnerList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["HashValue"] = partnerHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取合作商列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取合作商列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取合作商列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(partnerMap) == 0 {
|
||||
partnerHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取合作商列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpPartnerList := make([]*Partner, 0, 128)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取合作商列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpPartnerList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取合作商列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新合作商信息结束,合作商数量:%d", len(tmpPartnerList)))
|
||||
|
||||
tmpPartnerMap := make(map[int32]*Partner)
|
||||
for _, item := range tmpPartnerList {
|
||||
tmpPartnerMap[item.Id] = item
|
||||
}
|
||||
|
||||
// 赋值给最终的partnerMap
|
||||
partnerMap = tmpPartnerMap
|
||||
partnerHash = returnObj.HashValue
|
||||
|
||||
//通知变更
|
||||
mcDataChangeCallBack(managecenterModel.PartnerData, isInit)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取合作商对象列表
|
||||
// 返回值:
|
||||
// 合作商对象列表
|
||||
func GetPartnerList() (partnerList []*Partner) {
|
||||
for _, item := range partnerMap {
|
||||
partnerList = append(partnerList, item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商Id获取合作商对象
|
||||
// id:合作商Id
|
||||
// 返回值:
|
||||
// 合作商对象
|
||||
// 是否存在
|
||||
func GetPartner(id int32) (partnerObj *Partner, exist bool) {
|
||||
partnerObj, exist = partnerMap[id]
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商别名获取合作商对象
|
||||
// alias:合作商别名
|
||||
// 返回值:
|
||||
// 合作商对象
|
||||
// 是否存在
|
||||
func GetPartnerByAlias(alias string) (partnerObj *Partner, exist bool) {
|
||||
for _, item := range partnerMap {
|
||||
if item.Alias == alias {
|
||||
partnerObj = item
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取合作商的其它配置信息
|
||||
// id:合作商Id
|
||||
// configKey:其它配置Key
|
||||
// 返回值
|
||||
// 配置内容
|
||||
// 是否存在
|
||||
// 错误对象
|
||||
func GetOtherConfigInfo(id int32, configKey string) (configValue string, exist bool, err error) {
|
||||
partnerObj, exist := GetPartner(id)
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
var otherConfigMap map[string]string
|
||||
otherConfigMap, err = partnerObj.ResolveOtherConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
configValue, exist = otherConfigMap[configKey]
|
||||
return
|
||||
}
|
||||
100
trunk/framework/managecenterMgr/resourceVersion.go
Normal file
100
trunk/framework/managecenterMgr/resourceVersion.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
resourceVersionList = make([]*ResourceVersion, 128)
|
||||
resourceVersionHash string
|
||||
)
|
||||
|
||||
// 重新加载资源列表
|
||||
func reloadResourceVersion(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新资源列表")
|
||||
|
||||
// 连接服务器,以获取数据
|
||||
url := getManageCenterUrl("/API/ResourceVersionList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["HashValue"] = resourceVersionHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取资源列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取资源列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取资源列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(resourceVersionList) == 0 {
|
||||
resourceVersionHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取资源列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpResourceVersionList := make([]*ResourceVersion, 0, 128)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取资源列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpResourceVersionList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取资源列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新资源信息结束,资源数量:%d", len(tmpResourceVersionList)))
|
||||
|
||||
// 赋值给最终的partnerMap
|
||||
resourceVersionList = tmpResourceVersionList
|
||||
resourceVersionHash = returnObj.HashValue
|
||||
|
||||
//通知变更
|
||||
mcDataChangeCallBack(managecenterModel.ResourceVersionData, isInit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取资源包列表
|
||||
// 返回值:
|
||||
// 获取资源包列表
|
||||
func GetResourceVersionList() []*ResourceVersion {
|
||||
return resourceVersionList
|
||||
}
|
||||
175
trunk/framework/managecenterMgr/server.go
Normal file
175
trunk/framework/managecenterMgr/server.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
serverMap = make(map[int32]map[int32]*Server, 128)
|
||||
serverDistinctMap = make(map[int32]*Server, 1024)
|
||||
serverHash string
|
||||
)
|
||||
|
||||
// 重新加载服务器
|
||||
func reloadServer(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新服务器列表")
|
||||
|
||||
url := getManageCenterUrl("/API/ServerList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["GroupType"] = "Mix"
|
||||
postDict["HashValue"] = serverHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(serverMap) == 0 {
|
||||
serverHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取服务器列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpServerList := make([]*Server, 0, 1024)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取服务器列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpServerList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新服务器信息结束,服务器数量:%d", len(tmpServerList)))
|
||||
|
||||
tmpServerMap := make(map[int32]map[int32]*Server, 128)
|
||||
tmpServerDistinctMap := make(map[int32]*Server, 1024)
|
||||
for _, item := range tmpServerList {
|
||||
// 构造tmpServerMap数据
|
||||
if _, ok := tmpServerMap[item.PartnerId]; !ok {
|
||||
tmpServerMap[item.PartnerId] = make(map[int32]*Server, 1024)
|
||||
}
|
||||
tmpServerMap[item.PartnerId][item.Id] = item
|
||||
|
||||
// 构造tmpServerDistinctMap数据
|
||||
tmpServerDistinctMap[item.Id] = item
|
||||
}
|
||||
|
||||
// 赋值给最终的serverMap、serverDistinctMap
|
||||
serverMap = tmpServerMap
|
||||
serverDistinctMap = tmpServerDistinctMap
|
||||
serverHash = returnObj.HashValue
|
||||
|
||||
//通知变更
|
||||
mcDataChangeCallBack(managecenterModel.ServerData, isInit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据服务器组Id获取对应的服务器列表
|
||||
// serverGroupId:服务器组Id
|
||||
// 返回值:
|
||||
// 服务器列表
|
||||
func GetServerListByGroupId(serverGroupId int32) (serverList []*Server) {
|
||||
for _, subServerMap := range serverMap {
|
||||
for _, item := range subServerMap {
|
||||
if item.GroupId == serverGroupId {
|
||||
serverList = append(serverList, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商Id获取对应的服务器列表
|
||||
// partnerId:合作商Id
|
||||
// 返回值:
|
||||
// 服务器列表
|
||||
func GetServerListByPartnerId(partnerId int32) (serverList []*Server) {
|
||||
for _, item := range serverMap[partnerId] {
|
||||
serverList = append(serverList, item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商对象、服务器Id获取服务器对象
|
||||
// partnerObj:合作商对象
|
||||
// serverId:服务器Id
|
||||
// 返回值:
|
||||
// 服务器对象
|
||||
// 是否存在
|
||||
func GetServer(partnerObj *Partner, serverId int32) (serverObj *Server, exist bool) {
|
||||
if subServerMap, exist1 := serverMap[partnerObj.Id]; exist1 {
|
||||
serverObj, exist = subServerMap[serverId]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商Id、服务器Id获取服务器对象
|
||||
// partnerId:合作商Id
|
||||
// serverId:服务器Id
|
||||
// 返回值:
|
||||
// 服务器对象
|
||||
// 是否存在
|
||||
func GetServerItem(partnerId, serverId int32) (serverObj *Server, exist bool) {
|
||||
if subServerMap, exist1 := serverMap[partnerId]; exist1 {
|
||||
serverObj, exist = subServerMap[serverId]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取不重复的服务器Id列表
|
||||
// 返回值:
|
||||
// 不重复的服务器Id列表
|
||||
func GetDistinctServerIdList() (distinctServerIdList []int32) {
|
||||
for _, item := range serverDistinctMap {
|
||||
distinctServerIdList = append(distinctServerIdList, item.Id)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
247
trunk/framework/managecenterMgr/servergroup.go
Normal file
247
trunk/framework/managecenterMgr/servergroup.go
Normal file
@@ -0,0 +1,247 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"Framework/ipMgr"
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
// 服务器组集合
|
||||
serverGroupMap = make(map[int32]*ServerGroup, 512)
|
||||
serverGroupHash string
|
||||
|
||||
// 服务器组变化方法集合 (完整列表,新增列表,删除列表,更新列表)
|
||||
serverGroupChangeFuncMap = make(map[string]func([]*ServerGroup, []*ServerGroup, []*ServerGroup, []*ServerGroup))
|
||||
)
|
||||
|
||||
func init() {
|
||||
ipMgr.RegisterIpCheckFunc("ServerGroupIpCheck", isIpValid)
|
||||
}
|
||||
|
||||
// 重新加载服务器组
|
||||
func reloadServerGroup(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新服务器组信息")
|
||||
|
||||
url := getManageCenterUrl("/API/ServerGroupList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["GroupType"] = "Mix"
|
||||
postDict["HashValue"] = serverGroupHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,反序列化返回值出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(serverGroupMap) == 0 {
|
||||
serverGroupHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取服务器组列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpServerGroupList := make([]*ServerGroup, 0, 512)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取服务器组列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpServerGroupList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新服务器组信息结束,服务器组数量:%d", len(tmpServerGroupList)))
|
||||
|
||||
tmpServerGroupMap := make(map[int32]*ServerGroup, 512)
|
||||
for _, item := range tmpServerGroupList {
|
||||
tmpServerGroupMap[item.Id] = item
|
||||
}
|
||||
|
||||
// 处理服务器组是否变化情况
|
||||
addList, deleteList, updateList := handleServerGroupChange(GetServerGroupMap(), tmpServerGroupMap)
|
||||
triggerServerGroupChangeFunc(tmpServerGroupList, addList, deleteList, updateList)
|
||||
|
||||
// 赋值给最终的ServerGroupMap
|
||||
serverGroupMap = tmpServerGroupMap
|
||||
serverGroupHash = returnObj.HashValue
|
||||
|
||||
//通知变更
|
||||
mcDataChangeCallBack(managecenterModel.ServerGroupData, isInit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理服务器组是否变化情况
|
||||
// originalServerGroupMap: 当前服务器组集合
|
||||
// newServerGroupMap: 新的服务器组集合
|
||||
func handleServerGroupChange(currServerGroupMap, newServerGroupMap map[int32]*ServerGroup) (
|
||||
addList []*ServerGroup, deleteList []*ServerGroup, updateList []*ServerGroup) {
|
||||
|
||||
// 判断是否有新增的数据
|
||||
for k, v := range newServerGroupMap {
|
||||
if _, exist := currServerGroupMap[k]; !exist {
|
||||
addList = append(addList, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有删除的数据
|
||||
for k, v := range currServerGroupMap {
|
||||
if _, exist := newServerGroupMap[k]; !exist {
|
||||
deleteList = append(deleteList, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有更新的数据
|
||||
for k, currItem := range currServerGroupMap {
|
||||
if newItem, exist := newServerGroupMap[k]; exist {
|
||||
if currItem.IsEqual(newItem) == false {
|
||||
updateList = append(updateList, newItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 触发服务器组变化的方法
|
||||
func triggerServerGroupChangeFunc(allList []*ServerGroup, addList []*ServerGroup, deleteList []*ServerGroup, updateList []*ServerGroup) {
|
||||
// 如果有注册服务器组变化的方法
|
||||
if len(serverGroupChangeFuncMap) > 0 {
|
||||
for _, serverGroupChangeFunc := range serverGroupChangeFuncMap {
|
||||
serverGroupChangeFunc(allList, addList, deleteList, updateList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册服务器组变化方法
|
||||
// funcName:方法名称
|
||||
// serverGroupChangeFunc:服务器组变化方法
|
||||
func RegisterServerGroupChangeFunc(funcName string, serverGroupChangeFunc func([]*ServerGroup, []*ServerGroup, []*ServerGroup, []*ServerGroup)) {
|
||||
if _, exists := serverGroupChangeFuncMap[funcName]; exists {
|
||||
panic(fmt.Errorf("RegisterServerGroupChange:%s已经存在,请检查", funcName))
|
||||
}
|
||||
serverGroupChangeFuncMap[funcName] = serverGroupChangeFunc
|
||||
|
||||
logUtil.DebugLog(fmt.Sprintf("注册服务器组变化方法 funcName:%s,当前共有%d个注册", funcName, len(serverGroupChangeFuncMap)))
|
||||
}
|
||||
|
||||
// 获取服务器组集合
|
||||
// 返回值:
|
||||
// 服务器组集合
|
||||
func GetServerGroupMap() (retServerGroupMap map[int32]*ServerGroup) {
|
||||
retServerGroupMap = make(map[int32]*ServerGroup, 128)
|
||||
for k, v := range serverGroupMap {
|
||||
retServerGroupMap[k] = v
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取服务器组列表
|
||||
// 返回值:
|
||||
// 服务器组列表
|
||||
func GetServerGroupList() (serverGroupList []*ServerGroup) {
|
||||
for _, item := range serverGroupMap {
|
||||
serverGroupList = append(serverGroupList, item)
|
||||
}
|
||||
|
||||
sort.Slice(serverGroupList, func(i, j int) bool {
|
||||
return serverGroupList[i].SortByIdAsc(serverGroupList[j])
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取服务器组项
|
||||
// id
|
||||
// 返回值:
|
||||
// 服务器组对象
|
||||
// 是否存在
|
||||
func GetServerGroupItem(id int32) (serverGroupObj *ServerGroup, exist bool) {
|
||||
serverGroupObj, exist = serverGroupMap[id]
|
||||
return
|
||||
}
|
||||
|
||||
// 根据合作商Id、服务器Id获取服务器组对象
|
||||
// partnerId:合作商Id
|
||||
// serverId:服务器Id
|
||||
// 返回值:
|
||||
// 服务器组对象
|
||||
// 服务器对象
|
||||
// 是否存在
|
||||
func GetServerGroup(partnerId, serverId int32) (serverGroupObj *ServerGroup, serverObj *Server, exist bool) {
|
||||
var partnerObj *Partner
|
||||
|
||||
// 获取合作商对象
|
||||
partnerObj, exist = GetPartner(partnerId)
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取服务器对象
|
||||
serverObj, exist = GetServer(partnerObj, serverId)
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取服务器组对象
|
||||
serverGroupObj, exist = GetServerGroupItem(serverObj.GroupId)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断IP是否有效
|
||||
// ip:指定IP地址
|
||||
// 返回值:
|
||||
// IP是否有效
|
||||
func isIpValid(ip string) (exist bool) {
|
||||
for _, v := range serverGroupMap {
|
||||
for _, item := range v.GetIPList() {
|
||||
if ip == item {
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
114
trunk/framework/managecenterMgr/userWhiteList.go
Normal file
114
trunk/framework/managecenterMgr/userWhiteList.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package managecenterMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"Framework/managecenterModel"
|
||||
. "Framework/managecenterModel"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
whiteListMap = make(map[int32]map[string]*WhiteList, 64)
|
||||
whiteListHash string
|
||||
)
|
||||
|
||||
// 重新加载白名单
|
||||
func reloadWhiteList(isInit bool) error {
|
||||
//logUtil.DebugLog("开始刷新白名单列表")
|
||||
|
||||
url := getManageCenterUrl("/API/UserWhiteList.ashx")
|
||||
|
||||
// 定义请求参数
|
||||
postDict := make(map[string]string)
|
||||
postDict["HashValue"] = whiteListHash
|
||||
|
||||
//请求url,请求头
|
||||
header := webUtil.GetFormHeader()
|
||||
transport := webUtil.NewTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport = webUtil.GetTimeoutTransport(transport, 30)
|
||||
|
||||
statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport)
|
||||
//statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,url:%s,错误信息为:%s", url, err))
|
||||
return err
|
||||
}
|
||||
if statusCode != 200 {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,url:%s,错误码为:%d", url, statusCode))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析返回值
|
||||
returnObj := new(ReturnObject)
|
||||
if err = json.Unmarshal(returnBytes, &returnObj); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes)))
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断返回状态是否为成功
|
||||
if returnObj.Code != 0 {
|
||||
// 数据没有变化,所以没有获取到新的数据,不能算错误。
|
||||
if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" {
|
||||
//如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值
|
||||
if len(whiteListMap) == 0 {
|
||||
whiteListHash = ""
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
msg := fmt.Sprintf("获取白名单列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message)
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析Data
|
||||
tmpWhiteList := make([]*WhiteList, 0, 128)
|
||||
if data, ok := returnObj.Data.(string); !ok {
|
||||
msg := "获取白名单列表出错,返回的数据不是string类型"
|
||||
logUtil.ErrorLog(msg)
|
||||
return errors.New(msg)
|
||||
} else {
|
||||
if err = json.Unmarshal([]byte(data), &tmpWhiteList); err != nil {
|
||||
logUtil.ErrorLog(fmt.Sprintf("获取白名单列表出错,反序列化数据出错,错误信息为:%s", err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
//logUtil.DebugLog(fmt.Sprintf("刷新白名单信息结束,白名单数量:%d", len(tmpWhiteList)))
|
||||
|
||||
tmpWhiteListMap := make(map[int32]map[string]*WhiteList, 64)
|
||||
for _, item := range tmpWhiteList {
|
||||
if _, exist := tmpWhiteListMap[item.PartnerId]; !exist {
|
||||
tmpWhiteListMap[item.PartnerId] = make(map[string]*WhiteList, 8)
|
||||
}
|
||||
|
||||
tmpWhiteListMap[item.PartnerId][item.UserId] = item
|
||||
}
|
||||
|
||||
// 赋值给最终的whiteListMap
|
||||
whiteListMap = tmpWhiteListMap
|
||||
whiteListHash = returnObj.HashValue
|
||||
|
||||
//通知变更
|
||||
mcDataChangeCallBack(managecenterModel.UserWhiteListData, isInit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断用户是否在白名单里面
|
||||
// partnerId: 合作商ID
|
||||
// userId: userId
|
||||
func IsInWhiteList(partnerId int32, userId string) bool {
|
||||
subWhiteListMap, exist := whiteListMap[partnerId]
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
|
||||
_, exist = subWhiteListMap[userId]
|
||||
return exist
|
||||
}
|
||||
69
trunk/framework/managecenterModel/area.go
Normal file
69
trunk/framework/managecenterModel/area.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package managecenterModel
|
||||
|
||||
import "goutil/stringUtil"
|
||||
|
||||
// 大区对象
|
||||
type Area struct {
|
||||
// 大区Id
|
||||
AreaId int32 `json:"AreaId"`
|
||||
|
||||
//大区名字
|
||||
AreaName string `json:"AreaName"`
|
||||
|
||||
//客户端显示名字
|
||||
ClientName string `json:"ClientName"`
|
||||
|
||||
//区服范围
|
||||
ServerRange string `json:"ServerRange"`
|
||||
|
||||
//资源包下载地址
|
||||
ResourceURL string `json:"ResourceURL"`
|
||||
|
||||
//推荐服开关:0关闭,1:打开
|
||||
RecommendStitch int32 `json:"RecommendStitch"`
|
||||
|
||||
//推荐最大注册人数
|
||||
MaxRegistration int32 `json:"MaxRegistration"`
|
||||
|
||||
//限制注册的开关
|
||||
RegRestrictionSwitch int32 `json:"RegRestrictionSwitch"`
|
||||
|
||||
//玩家数量大于该数量,自动开服
|
||||
AutoOpenServerPlayers int32 `json:"AutoOpenServerPlayers"`
|
||||
|
||||
//大区维护状态(1:正常;2:维护)
|
||||
AreaMaintainStatus int32 `json:"AreaMaintainStatus"`
|
||||
|
||||
//维护消息
|
||||
AreaMaintainMsg string `json:"AreaMaintainMsg"`
|
||||
|
||||
//大区页签集合
|
||||
AreaLabelList []*AreaLabel `json:"AreaLabelList"`
|
||||
}
|
||||
|
||||
//
|
||||
//检测服务器是否在大区的区间范围
|
||||
func (this *Area) CheckServerIdIsInRange(serverId int32) (isVaild bool) {
|
||||
isVaild = false
|
||||
for _, serverRangeItem := range stringUtil.Split(this.ServerRange, []string{","}) {
|
||||
serverRange, _ := stringUtil.SplitToInt32Slice(serverRangeItem, "-")
|
||||
lower := serverRange[0]
|
||||
upper := serverRange[1]
|
||||
|
||||
//如果范围大小顺序不对,则换位
|
||||
if lower > upper {
|
||||
temp := lower
|
||||
lower = upper
|
||||
upper = temp
|
||||
}
|
||||
|
||||
//如果服务器在该大区的任意区服区间,则返回true
|
||||
if serverId >= lower && serverId <= upper {
|
||||
isVaild = true
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
45
trunk/framework/managecenterModel/areaLabel.go
Normal file
45
trunk/framework/managecenterModel/areaLabel.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package managecenterModel
|
||||
|
||||
import "goutil/stringUtil"
|
||||
|
||||
//大区页签对象
|
||||
type AreaLabel struct {
|
||||
// 大区Id
|
||||
AreaId int32 `json:"AreaID"`
|
||||
//标签ID
|
||||
LabelID int32 `json:"LabelID"`
|
||||
//标签名字
|
||||
LabelName string `json:"LabelName"`
|
||||
//客户端显示名字
|
||||
ClientName string `json:"ClientName"`
|
||||
//标签区间字符串1-100,200-300
|
||||
LabelServerRange string `json:"LabelServerRange"`
|
||||
//渠道列表
|
||||
PartnerIdList []int64 `json:"PartnerIdList"`
|
||||
}
|
||||
|
||||
//检测服务器是否在大区页签的区间范围
|
||||
func (this *AreaLabel) CheckServerIdIsInLabelRange(serverId int32) (isVaild bool) {
|
||||
isVaild = false
|
||||
for _, serverRangeItem := range stringUtil.Split(this.LabelServerRange, []string{","}) {
|
||||
serverRange, _ := stringUtil.SplitToInt32Slice(serverRangeItem, "-")
|
||||
lower := serverRange[0]
|
||||
upper := serverRange[1]
|
||||
|
||||
//如果范围大小顺序不对,则换位
|
||||
if lower > upper {
|
||||
temp := lower
|
||||
lower = upper
|
||||
upper = temp
|
||||
}
|
||||
|
||||
//如果服务器在该大区的任意区服区间,则返回true
|
||||
if serverId >= lower && serverId <= upper {
|
||||
isVaild = true
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
44
trunk/framework/managecenterModel/chargeConfig.go
Normal file
44
trunk/framework/managecenterModel/chargeConfig.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package managecenterModel
|
||||
|
||||
// 充值配置
|
||||
type ChargeConfig struct {
|
||||
// 产品Id
|
||||
ProductId string
|
||||
|
||||
// 充值点数(以元为单位;如果是人民币是整数,但如果是美元,或者其它货币可能为小数)
|
||||
ChargePoint float64
|
||||
|
||||
// 游戏内货币点数(元宝/钻石等,必定是整数)
|
||||
GamePoint int
|
||||
|
||||
// 充值金额与游戏内货币的兑换比率
|
||||
Ratio float64
|
||||
|
||||
// 赠送的游戏内货币点数(必定是整数)
|
||||
GiveGamePoint int
|
||||
|
||||
// 赠送的比率
|
||||
GiveRatio float64
|
||||
|
||||
// 首充时赠送的游戏内货币点数
|
||||
FirstGiveGamePoint int
|
||||
|
||||
// 所需的vip等级
|
||||
VipLv byte
|
||||
|
||||
// 首充时是否显示
|
||||
IfFirstShow byte
|
||||
|
||||
// 第二次(及以后)充值时是否显示
|
||||
IfSecondShow byte
|
||||
|
||||
// 是否为月卡
|
||||
IsMonthCard bool
|
||||
}
|
||||
|
||||
// 按照充值金额进行升序排序
|
||||
// target:另一个充值配置对象
|
||||
// 是否是小于
|
||||
func (this *ChargeConfig) SortByChargePointAsc(target *ChargeConfig) bool {
|
||||
return this.ChargePoint < target.ChargePoint
|
||||
}
|
||||
57
trunk/framework/managecenterModel/dbConnectionConfig.go
Normal file
57
trunk/framework/managecenterModel/dbConnectionConfig.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package managecenterModel
|
||||
|
||||
import (
|
||||
. "goutil/mysqlUtil"
|
||||
. "goutil/redisUtil"
|
||||
)
|
||||
|
||||
// 数据库连接字符串配置
|
||||
type DBConnectionConfig struct {
|
||||
// 模型数据库内网连接字符串
|
||||
GameModelDB string
|
||||
|
||||
// 游戏数据库内网连接字符串
|
||||
GameDB string
|
||||
|
||||
// 日志数据库内网连接字符串
|
||||
LogDB string
|
||||
|
||||
// Redis连接字符串
|
||||
RedisConfig string
|
||||
}
|
||||
|
||||
// 获取游戏模型数据库连接
|
||||
// 返回值:
|
||||
// 数据库连接配置对象
|
||||
// 错误对象
|
||||
func (this *DBConnectionConfig) GetGameModelDBConn() (dbConfig *DBConfig, err error) {
|
||||
dbConfig, err = NewDBConfig2(this.GameModelDB)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取游戏数据库连接
|
||||
// 返回值:
|
||||
// 数据库连接配置对象
|
||||
// 错误对象
|
||||
func (this *DBConnectionConfig) GetGameDBConn() (dbConfig *DBConfig, err error) {
|
||||
dbConfig, err = NewDBConfig2(this.GameDB)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取游戏日志数据库连接
|
||||
// 返回值:
|
||||
// 数据库连接配置对象
|
||||
// 错误对象
|
||||
func (this *DBConnectionConfig) GetLogDBConn() (dbConfig *DBConfig, err error) {
|
||||
dbConfig, err = NewDBConfig2(this.LogDB)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取Redis配置
|
||||
// 返回值:
|
||||
// redis配置对象
|
||||
// 错误对象
|
||||
func (this *DBConnectionConfig) GetRedisConfig() (redisConfig *RedisConfig, err error) {
|
||||
redisConfig, err = NewRedisConfig(this.RedisConfig)
|
||||
return
|
||||
}
|
||||
3
trunk/framework/managecenterModel/doc.go
Normal file
3
trunk/framework/managecenterModel/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package managecenterModel
|
||||
|
||||
// 与ManageCenter共享的模型对象定义
|
||||
10
trunk/framework/managecenterModel/gameVersion.go
Normal file
10
trunk/framework/managecenterModel/gameVersion.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package managecenterModel
|
||||
|
||||
// 游戏版本
|
||||
type GameVersion struct {
|
||||
// Id
|
||||
Id int32 `json:"GameVersionID"`
|
||||
|
||||
// 名称
|
||||
Name string `json:"GameVersionName"`
|
||||
}
|
||||
15
trunk/framework/managecenterModel/maintainType.go
Normal file
15
trunk/framework/managecenterModel/maintainType.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package managecenterModel
|
||||
|
||||
// 服务器状态
|
||||
type MaintainType int32
|
||||
|
||||
const (
|
||||
// 计划维护
|
||||
Con_MaintainType_PlanMaintain MaintainType = 1
|
||||
|
||||
// 开始维护
|
||||
Con_MaintainType_BeginMaintain MaintainType = 2
|
||||
|
||||
// 结束维护
|
||||
Con_MaintainType_EndMaintain MaintainType = 3
|
||||
)
|
||||
26
trunk/framework/managecenterModel/mcDataType.go
Normal file
26
trunk/framework/managecenterModel/mcDataType.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package managecenterModel
|
||||
|
||||
type MCDataType int
|
||||
|
||||
const (
|
||||
// 服务器
|
||||
ServerData MCDataType = 1
|
||||
|
||||
// 服务器组
|
||||
ServerGroupData MCDataType = 2
|
||||
|
||||
// 合作商
|
||||
PartnerData MCDataType = 3
|
||||
|
||||
// 资源
|
||||
ResourceVersionData MCDataType = 4
|
||||
|
||||
// 白名单
|
||||
UserWhiteListData MCDataType = 5
|
||||
|
||||
// 公告
|
||||
GameNoticeData MCDataType = 6
|
||||
|
||||
// 大区
|
||||
AreaData MCDataType = 7
|
||||
)
|
||||
11
trunk/framework/managecenterModel/officialOrTest.go
Normal file
11
trunk/framework/managecenterModel/officialOrTest.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package managecenterModel
|
||||
|
||||
type OfficialOrTest int32
|
||||
|
||||
const (
|
||||
// 正式服
|
||||
Con_Official OfficialOrTest = 1
|
||||
|
||||
// 测试服
|
||||
Con_Test OfficialOrTest = 2
|
||||
)
|
||||
55
trunk/framework/managecenterModel/partner.go
Normal file
55
trunk/framework/managecenterModel/partner.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package managecenterModel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// 合作商
|
||||
type Partner struct {
|
||||
// 合作商Id
|
||||
Id int32 `json:"PartnerID"`
|
||||
|
||||
// 合作商名称
|
||||
Name string `json:"PartnerName"`
|
||||
|
||||
// 合作商别名
|
||||
Alias string `json:"PartnerAlias"`
|
||||
|
||||
// 应用Id
|
||||
AppId string `json:"AppID"`
|
||||
|
||||
// 登陆加密Key
|
||||
LoginKey string `json:"LoginKey"`
|
||||
|
||||
// 充值配置
|
||||
ChargeConfig string `json:"ChargeConfig"`
|
||||
|
||||
// 其它配置
|
||||
OtherConfigInfo string `json:"OtherConfigInfo"`
|
||||
|
||||
// 游戏版本下载Url
|
||||
GameVersionUrl string `json:"GameVersionUrl"`
|
||||
|
||||
// 充值服务器Url
|
||||
ChargeServerUrl string `json:"ChargeServerUrl"`
|
||||
|
||||
// 合作商类型
|
||||
PartnerType int32 `json:"PartnerType"`
|
||||
|
||||
// 权重
|
||||
Weight int32 `json:"Weight"`
|
||||
|
||||
// 资源包所属类型
|
||||
ResourceType int32 `json:"ResourceType"`
|
||||
}
|
||||
|
||||
// 解析其它配置信息
|
||||
func (this *Partner) ResolveOtherConfig() (otherConfigMap map[string]string, err error) {
|
||||
otherConfigMap = make(map[string]string, 8)
|
||||
if this.OtherConfigInfo == "" {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(this.OtherConfigInfo), &otherConfigMap)
|
||||
return
|
||||
}
|
||||
15
trunk/framework/managecenterModel/partnerType.go
Normal file
15
trunk/framework/managecenterModel/partnerType.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package managecenterModel
|
||||
|
||||
// 合作商类型
|
||||
type PartnerType int32
|
||||
|
||||
const (
|
||||
// IOS
|
||||
Con_IOS PartnerType = 0
|
||||
|
||||
// Android
|
||||
Con_Android PartnerType = 1
|
||||
|
||||
// 越狱
|
||||
Con_JailBreak PartnerType = 2
|
||||
)
|
||||
210
trunk/framework/managecenterModel/resourceVersion.go
Normal file
210
trunk/framework/managecenterModel/resourceVersion.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package managecenterModel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"goutil/stringUtil"
|
||||
"goutil/typeUtil"
|
||||
)
|
||||
|
||||
// 游戏版本
|
||||
type ResourceVersion struct {
|
||||
// 资源版本唯一标识
|
||||
Id int32 `json:"ResourceVersionID"`
|
||||
|
||||
// 资源版本名称
|
||||
Name string `json:"ResourceVersionName"`
|
||||
|
||||
// 资源版本的url地址
|
||||
Url string `json:"ResourceVersionUrl"`
|
||||
|
||||
// 资源大小
|
||||
Size int32 `json:"Size"`
|
||||
|
||||
// 资源文件MD5加密的结果
|
||||
MD5 string `json:"MD5"`
|
||||
|
||||
//大区Id
|
||||
AreaID int32 `json:"AreaID"`
|
||||
|
||||
// 资源生效时间
|
||||
StartTime string `json:"StartTime"`
|
||||
StartTimeTick int64 `json:"StartTimeTick"`
|
||||
|
||||
// 资源失效时间
|
||||
EndTime string `json:"EndTime"`
|
||||
EndTimeTick int64 `json:"EndTimeTick"`
|
||||
|
||||
// 添加时间
|
||||
Crdate string `json:"Crdate"`
|
||||
CrdateTick int64 `json:"CrdateTick"`
|
||||
|
||||
// 更新时间
|
||||
UpdateTime string `json:"UpdateTime"`
|
||||
UpdateTimeTick int64 `json:"UpdateTimeTick"`
|
||||
|
||||
// 是否重启客户端
|
||||
IfRestart int32 `json:"IfRestart"`
|
||||
|
||||
// 是否禁用
|
||||
IfDelete int32 `json:"IfDelete"`
|
||||
|
||||
// 是否审核服下载
|
||||
IfAuditServiceDownload int32 `json:"IfAuditServiceDownload"`
|
||||
|
||||
// 资源所属的合作商ID集合
|
||||
PartnerIds string `json:"PartnerIDs"`
|
||||
|
||||
// 资源所属的游戏版本ID集合
|
||||
GameVersionIds string `json:"GameVersionIDs"`
|
||||
}
|
||||
|
||||
// 判断资源是否包含指定合作商
|
||||
// partnerId:合作商Id
|
||||
// 返回值
|
||||
// 是否包含
|
||||
func (this *ResourceVersion) ContainsPartner(partnerId int32) bool {
|
||||
partnerIdList, _ := stringUtil.SplitToInt32Slice(this.PartnerIds, ",")
|
||||
for _, item := range partnerIdList {
|
||||
if item == partnerId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断资源是否包含指定游戏版本
|
||||
// gameVersionId:游戏版本Id
|
||||
// 返回值
|
||||
// 是否包含
|
||||
func (this *ResourceVersion) ContainsGameVersion(gameVersionId int32) bool {
|
||||
gameVersionIdList, _ := stringUtil.SplitToInt32Slice(this.GameVersionIds, ",")
|
||||
for _, item := range gameVersionIdList {
|
||||
if item == gameVersionId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取有效资源包
|
||||
func GetAvailableResource(resourceVersionList []*ResourceVersion, partnerId, gameVersionId int32, resourceVersionName string, offTest OfficialOrTest) (availableResourceVersion map[string]interface{}) {
|
||||
|
||||
if len(resourceVersionList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
//判断资源是否有效
|
||||
_, hashCode, isVaild := IsResourceVersionNameValid(resourceVersionName)
|
||||
if !isVaild {
|
||||
return
|
||||
}
|
||||
|
||||
//根据合作商Id和游戏版本Id和开始时间来过滤
|
||||
var targetResourceVersionList []*ResourceVersion
|
||||
for _, resourceVersion := range resourceVersionList {
|
||||
startime, err := typeUtil.DateTime(resourceVersion.StartTimeTick)
|
||||
if resourceVersion.ContainsPartner(partnerId) && resourceVersion.ContainsGameVersion(gameVersionId) && err == nil && startime.Before(time.Now()) {
|
||||
targetResourceVersionList = append(targetResourceVersionList, resourceVersion)
|
||||
}
|
||||
}
|
||||
|
||||
if len(targetResourceVersionList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
//组装数据
|
||||
|
||||
//按照资源Id进行降序排列
|
||||
sort.Slice(targetResourceVersionList, func(i, j int) bool {
|
||||
return targetResourceVersionList[i].SortByIdDesc(targetResourceVersionList[j])
|
||||
})
|
||||
|
||||
//取出资源号最大的资源,如果与传入的资源名称相等,则表示没有新资源
|
||||
availableResourceVersion = make(map[string]interface{}, 0)
|
||||
newResource := targetResourceVersionList[0]
|
||||
availableResourceVersion["ResourceVersionName"] = newResource.Name
|
||||
availableResourceVersion["Url"] = strings.Replace(newResource.Url, ".zip", "", -1)
|
||||
|
||||
if newResource.Name == resourceVersionName {
|
||||
|
||||
//是否有新资源,如果为fasle,也需要返回project.manifest.temp.zip 用于子包验证
|
||||
availableResourceVersion["IsNewResource"] = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//判断资源号中的HashCode是否相等,如果相等,则表示没有新资源;如果传入的timeTick>最新的timeTick说明服务器没有被刷新,表示没有新资源
|
||||
_, newHashCode, newIsVaild := IsResourceVersionNameValid(newResource.Name)
|
||||
if !newIsVaild {
|
||||
return
|
||||
}
|
||||
|
||||
if compareRes := strings.Compare(hashCode, newHashCode); compareRes == 0 {
|
||||
//是否有新资源,如果为fasle,也需要返回project.manifest.temp.zip 用于子包验证
|
||||
availableResourceVersion["IsNewResource"] = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if offTest == Con_Test && newResource.IfAuditServiceDownload == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
availableResourceVersion["IsNewResource"] = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 按照Id进行升序排序
|
||||
// target:另一个资源对象
|
||||
// 是否是小于
|
||||
func (this *ResourceVersion) SortByIdAsc(target *ResourceVersion) bool {
|
||||
return this.Id < target.Id
|
||||
}
|
||||
|
||||
// 按照Id进行降序排序
|
||||
// target:另一个资源对象
|
||||
// 是否是大于
|
||||
func (this *ResourceVersion) SortByIdDesc(target *ResourceVersion) bool {
|
||||
return this.Id > target.Id
|
||||
}
|
||||
|
||||
//判断资源版本是否有效
|
||||
func IsResourceVersionNameValid(resourceVersionName string) (timeTick int64, hashCode string, isValid bool) {
|
||||
if len(resourceVersionName) == 0 {
|
||||
isValid = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if index := strings.Index(resourceVersionName, "_"); index == -1 {
|
||||
resourceVersionName = fmt.Sprintf("0_%s", resourceVersionName)
|
||||
}
|
||||
|
||||
resourceList := stringUtil.Split(resourceVersionName, []string{"_"})
|
||||
if len(resourceList) != 2 {
|
||||
isValid = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//解析timeTick
|
||||
timeTick, err := strconv.ParseInt(resourceList[0], 10, 64)
|
||||
if err != nil {
|
||||
isValid = false
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
hashCode = resourceList[1]
|
||||
isValid = true
|
||||
|
||||
return
|
||||
}
|
||||
16
trunk/framework/managecenterModel/returnObject.go
Normal file
16
trunk/framework/managecenterModel/returnObject.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package managecenterModel
|
||||
|
||||
// 返回结果对象
|
||||
type ReturnObject struct {
|
||||
// 返回的状态值;0:成功;非0:失败(根据实际情况进行定义)
|
||||
Code int32
|
||||
|
||||
// 返回的失败描述信息
|
||||
Message string
|
||||
|
||||
// 返回的数据
|
||||
Data interface{}
|
||||
|
||||
// 返回的数据hash值
|
||||
HashValue string
|
||||
}
|
||||
22
trunk/framework/managecenterModel/server.go
Normal file
22
trunk/framework/managecenterModel/server.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package managecenterModel
|
||||
|
||||
// 服务器
|
||||
type Server struct {
|
||||
// 服务器Id
|
||||
Id int32 `json:"ServerID"`
|
||||
|
||||
// 服务器名称
|
||||
Name string `json:"ServerName"`
|
||||
|
||||
// 合作商Id
|
||||
PartnerId int32 `json:"PartnerID"`
|
||||
|
||||
// 服务器组Id
|
||||
GroupId int32 `json:"GroupID"`
|
||||
|
||||
// 对应的游戏版本号
|
||||
GameVersionId int32 `json:"GameVersionID"`
|
||||
|
||||
// 需要的最低游戏版本号
|
||||
MinGameVersionId int32 `json:"MinGameVersionID"`
|
||||
}
|
||||
184
trunk/framework/managecenterModel/serverGroup.go
Normal file
184
trunk/framework/managecenterModel/serverGroup.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package managecenterModel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
// 服务器组
|
||||
type ServerGroup struct {
|
||||
// 服务器组Id
|
||||
Id int32 `json:"GroupID"`
|
||||
|
||||
// 服务器组名称
|
||||
Name string `json:"GroupName"`
|
||||
|
||||
// 服务器组Url
|
||||
Url string `json:"GroupUrl"`
|
||||
|
||||
// 聊天服务器Url
|
||||
ChatServerUrl string `json:"ChatServerUrl"`
|
||||
|
||||
// 数据库连接配置
|
||||
DBConnectionConfig string `json:"DBConnectionConfig"`
|
||||
|
||||
// 服务器组状态(1:正常;2:维护)
|
||||
GroupState int32 `json:"GroupState"`
|
||||
|
||||
// 服务器组热度(1:正常;2:新服;3:推荐)
|
||||
GroupHeat int32 `json:"GroupHeat"`
|
||||
|
||||
// 服务器组负载(1:正常;2:火爆)
|
||||
GroupLoad int32 `json:"GroupLoad"`
|
||||
|
||||
// 服务器开服时间对应的Unix时间戳
|
||||
OpenTimeTick int64 `json:OpenTimeTick`
|
||||
|
||||
// 服务器组Ip(外网IP;内网IP;回调GS内网端口)
|
||||
Ip string `json:"GroupIp"`
|
||||
|
||||
// 正式服或测试服;1:正式服;2:测试服
|
||||
OfficialOrTest int32 `json:"OfficialOrTest"`
|
||||
|
||||
// 服务器组类型
|
||||
Type int32 `json:"GroupType"`
|
||||
|
||||
// 服务器组排序
|
||||
Order int32 `json:"GroupOrder"`
|
||||
|
||||
// 服务器组维护开始时间对应的时间戳
|
||||
MaintainBeginTimeTick int64 `json:MaintainBeginTimeTick`
|
||||
|
||||
// 维护持续分钟数
|
||||
MaintainMinutes int32 `json:"MaintainMinutes"`
|
||||
|
||||
// 维护信息
|
||||
MaintainMessage string `json:"MaintainMessage"`
|
||||
|
||||
// 游戏监听地址
|
||||
GameListenAddr string `json:"GameListenAddr"`
|
||||
|
||||
// 回调监听地址
|
||||
CallbackListenAddr string `json:"CallbackListenAddr"`
|
||||
|
||||
// 外网回调地址
|
||||
ExternalCallbackUrl string `json:"ExternalCallbackUrl"`
|
||||
|
||||
// 内网回调地址
|
||||
InternalCallbackUrl string `json:"InternalCallbackUrl"`
|
||||
|
||||
// 是否在主群组(机房)内
|
||||
IsInMainGroup bool `json:"IsInMainGroup"`
|
||||
|
||||
// 监控端口
|
||||
GopsPort string `json:"GopsPort"`
|
||||
}
|
||||
|
||||
// 排序方法(默认按照Id进行升序排序)
|
||||
// target:另一个服务器组对象
|
||||
// 是否是小于
|
||||
func (this *ServerGroup) SortByIdAsc(target *ServerGroup) bool {
|
||||
return this.Id < target.Id
|
||||
}
|
||||
|
||||
// 按照开服时间进行升序排序
|
||||
// target:另一个服务器组对象
|
||||
// 是否是小于
|
||||
func (this *ServerGroup) SortByOpenTimeAsc(target *ServerGroup) bool {
|
||||
return this.OpenTimeTick < target.OpenTimeTick
|
||||
}
|
||||
|
||||
// 获取数据库配置对象
|
||||
// 返回值:
|
||||
// 数据库配置对象
|
||||
// 错误对象
|
||||
func (this *ServerGroup) GetDBConfig() (*DBConnectionConfig, error) {
|
||||
var dbConfig *DBConnectionConfig
|
||||
if err := json.Unmarshal([]byte(this.DBConnectionConfig), &dbConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dbConfig, nil
|
||||
}
|
||||
|
||||
// 获取ip列表
|
||||
// 返回值:
|
||||
// ip列表
|
||||
func (this *ServerGroup) GetIPList() []string {
|
||||
return stringUtil.Split(this.Ip, nil)
|
||||
}
|
||||
|
||||
// 服务器组是否开启
|
||||
// 返回值:
|
||||
// 是否开启
|
||||
func (this *ServerGroup) IsOpen() bool {
|
||||
return this.OpenTimeTick < time.Now().Unix()
|
||||
}
|
||||
|
||||
// 获取游戏服务器的回调地址
|
||||
// suffix:地址后缀
|
||||
// 返回值
|
||||
// 游戏服务器的回调地址
|
||||
func (this *ServerGroup) GetGSCallbackUrl(suffix string) string {
|
||||
// 如果是在主群组(机房)内,则使用内网地址,否则使用外网地址
|
||||
url := ""
|
||||
if this.IsInMainGroup {
|
||||
url = this.InternalCallbackUrl
|
||||
} else {
|
||||
url = this.ExternalCallbackUrl
|
||||
}
|
||||
|
||||
if url != "" {
|
||||
if strings.HasSuffix(url, "/") {
|
||||
return fmt.Sprintf("%s%s", url, suffix)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", url, suffix)
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容旧的ManageCenter版本
|
||||
ipList := this.GetIPList()
|
||||
|
||||
// 外网IP;内网IP;回调GS内网端口;如果数量小于3,则直接使用配置的GroupUrl;否则使用第3个值
|
||||
if len(ipList) < 3 {
|
||||
if strings.HasSuffix(this.Url, "/") {
|
||||
return fmt.Sprintf("%s%s", this.Url, suffix)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", this.Url, suffix)
|
||||
}
|
||||
} else {
|
||||
return fmt.Sprintf("http://%s:%s/%s", ipList[1], ipList[2], suffix)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断服务器组是否相同
|
||||
// target:目标服务器组
|
||||
// 是否相同
|
||||
func (this *ServerGroup) IsEqual(target *ServerGroup) bool {
|
||||
return this.Id == target.Id &&
|
||||
this.Name == target.Name &&
|
||||
this.Url == target.Url &&
|
||||
this.ChatServerUrl == target.ChatServerUrl &&
|
||||
this.DBConnectionConfig == target.DBConnectionConfig &&
|
||||
this.GroupState == target.GroupState &&
|
||||
this.GroupHeat == target.GroupHeat &&
|
||||
this.GroupLoad == target.GroupLoad &&
|
||||
this.OpenTimeTick == target.OpenTimeTick &&
|
||||
this.Ip == target.Ip &&
|
||||
this.OfficialOrTest == target.OfficialOrTest &&
|
||||
this.Type == target.Type &&
|
||||
this.Order == target.Order &&
|
||||
this.MaintainBeginTimeTick == target.MaintainBeginTimeTick &&
|
||||
this.MaintainMinutes == target.MaintainMinutes &&
|
||||
this.MaintainMessage == target.MaintainMessage &&
|
||||
this.GameListenAddr == target.GameListenAddr &&
|
||||
this.CallbackListenAddr == target.CallbackListenAddr &&
|
||||
this.ExternalCallbackUrl == target.ExternalCallbackUrl &&
|
||||
this.InternalCallbackUrl == target.InternalCallbackUrl &&
|
||||
this.IsInMainGroup == target.IsInMainGroup &&
|
||||
this.GopsPort == target.GopsPort
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user