登录代码提交
This commit is contained in:
parent
8c40855c4e
commit
22ac6c1fed
@ -4,7 +4,16 @@
|
||||
<option name="autoReloadType" value="ALL" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="2037df1b-9ccc-4caa-9145-2d6722712612" name="更改" comment="" />
|
||||
<list default="true" id="2037df1b-9ccc-4caa-9145-2d6722712612" name="更改" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/admincenter/config.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/center/admincenter/config.yaml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/common/configsYaml/baseConfig.go" beforeDir="false" afterPath="$PROJECT_DIR$/center/common/configsYaml/baseConfig.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/common/configsYaml/configYaml.go" beforeDir="false" afterPath="$PROJECT_DIR$/center/common/configsYaml/configYaml.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/common/connection/dal.go" beforeDir="false" afterPath="$PROJECT_DIR$/center/common/connection/dal.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/common/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/center/common/go.mod" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/common/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/center/common/go.sum" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/center/paycenter/internal/pay/logic.go" beforeDir="false" afterPath="$PROJECT_DIR$/center/paycenter/internal/pay/logic.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
@ -30,40 +39,47 @@
|
||||
"associatedIndex": 3
|
||||
}</component>
|
||||
<component name="ProjectId" id="2qn73uMaWLMYCjjMpyatMYepw4t" />
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<ConfirmationsSetting value="1" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"DefaultGoTemplateProperty": "Go File",
|
||||
"Docker.admincenter.redis: Compose 部署.executor": "Run",
|
||||
"Docker.center/admincenter/Dockerfile builder.executor": "Run",
|
||||
"Go 构建.go build admincenter.executor": "Debug",
|
||||
"Go 构建.go build logincenter.executor": "Debug",
|
||||
"Go 构建.go build usercenter.executor": "Debug",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.go.formatter.settings.were.checked": "true",
|
||||
"RunOnceActivity.go.migrated.go.modules.settings": "true",
|
||||
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
|
||||
"git-widget-placeholder": "master",
|
||||
"go.import.settings.migrated": "true",
|
||||
"go.sdk.automatically.set": "true",
|
||||
"last_opened_file_path": "D:/workspace/e2023/goProject/trunk",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager"
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"DefaultGoTemplateProperty": "Go File",
|
||||
"Docker.admincenter.redis: Compose 部署.executor": "Run",
|
||||
"Docker.center/admincenter/Dockerfile builder.executor": "Run",
|
||||
"Go 构建.go build admincenter.executor": "Run",
|
||||
"Go 构建.go build logincenter.executor": "Debug",
|
||||
"Go 构建.go build usercenter.executor": "Debug",
|
||||
"Go 测试.dbcenter 中的 Test001.executor": "Run",
|
||||
"Go 测试.dbcenter 中的 Test002.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.go.formatter.settings.were.checked": "true",
|
||||
"RunOnceActivity.go.migrated.go.modules.settings": "true",
|
||||
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
|
||||
"git-widget-placeholder": "master",
|
||||
"go.import.settings.migrated": "true",
|
||||
"go.sdk.automatically.set": "true",
|
||||
"last_opened_file_path": "D:/workspace/e2023/goProject/trunk/game/common",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "org.intellij.sdk.editor.settings.AppSettingsConfigurable"
|
||||
}
|
||||
}</component>
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="D:\workspace\e2023\goProject\trunk\game\common" />
|
||||
<recent name="D:\workspace\e2023\goProject\trunk\game\common\model" />
|
||||
<recent name="D:\workspace\e2023\goProject\trunk\center\logincenter\internal\game" />
|
||||
<recent name="D:\workspace\e2023\goProject\trunk\center\logincenter" />
|
||||
<recent name="D:\workspace\e2023\goProject\trunk\center" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Go 构建.go build usercenter">
|
||||
<component name="RunManager" selected="Go 测试.dbcenter 中的 Test002">
|
||||
<configuration name="go build admincenter" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="trunk" />
|
||||
<working_directory value="$PROJECT_DIR$/center/admincenter" />
|
||||
@ -73,13 +89,26 @@
|
||||
<filePath value="$PROJECT_DIR$/center/admincenter/main.go" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="go build usercenter" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true">
|
||||
<configuration name="dbcenter 中的 Test001" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="trunk" />
|
||||
<working_directory value="$PROJECT_DIR$/center/usercenter" />
|
||||
<working_directory value="$PROJECT_DIR$/center/dbcenter" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="logincenter" />
|
||||
<package value="dbcenter" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$/center/logincenter/main.go" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<pattern value="^\QTest001\E$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="dbcenter 中的 Test002" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="trunk" />
|
||||
<working_directory value="$PROJECT_DIR$/center/dbcenter" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="dbcenter" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<pattern value="^\QTest002\E$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="docker-deploy" factoryName="docker-compose.yml" temporary="true">
|
||||
@ -119,10 +148,11 @@
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Go 构建.go build usercenter" />
|
||||
<item itemvalue="Go 测试.dbcenter 中的 Test002" />
|
||||
<item itemvalue="Go 测试.dbcenter 中的 Test001" />
|
||||
<item itemvalue="Go 构建.go build admincenter" />
|
||||
<item itemvalue="Docker.admincenter.redis: Compose 部署" />
|
||||
<item itemvalue="Docker.center/admincenter/Dockerfile builder" />
|
||||
<item itemvalue="Docker.admincenter.redis: Compose 部署" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
|
||||
BIN
trunk/center/admincenter/adminServer
Normal file
BIN
trunk/center/admincenter/adminServer
Normal file
Binary file not shown.
@ -9,6 +9,12 @@ root:
|
||||
# Elasticsearch 地址
|
||||
es_urls: "http://10.252.0.70:18099"
|
||||
|
||||
# RabbitMQ 配置
|
||||
rabbitmq_config: "amqp://guest:guest@localhost:5672/"
|
||||
|
||||
# mq队列名称
|
||||
mq_queue_name: "admin_center"
|
||||
|
||||
# 数据库配置
|
||||
db_config:
|
||||
admin_db:
|
||||
@ -29,7 +35,7 @@ root:
|
||||
max_idle_conns: 0
|
||||
|
||||
# 数据库连接字符串
|
||||
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/pay?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
|
||||
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
|
||||
|
||||
redis_config:
|
||||
# 数据库连接字符串
|
||||
|
||||
@ -36,6 +36,12 @@ var (
|
||||
EsUrls string
|
||||
|
||||
BaseDay int
|
||||
|
||||
// Rabbitmq 配置
|
||||
Rabbitmq string
|
||||
|
||||
// RabbitMQName mq队列名称
|
||||
RabbitMQName string
|
||||
)
|
||||
|
||||
// initBaseConfig
|
||||
@ -69,6 +75,11 @@ func initBaseConfig() {
|
||||
EsUrls = root.EsUrls
|
||||
|
||||
BaseDay = root.BaseDay
|
||||
|
||||
// rabbitmq配置
|
||||
Rabbitmq = root.RabbitMQAddress
|
||||
|
||||
RabbitMQName = root.RabbitMQName
|
||||
}
|
||||
|
||||
// GetDebug
|
||||
@ -77,14 +88,14 @@ func initBaseConfig() {
|
||||
// return:
|
||||
// @bool:
|
||||
func GetDebug() bool {
|
||||
return ConfigYaml.Root.Debug
|
||||
return DEBUG
|
||||
}
|
||||
|
||||
// GetWebServerAddress 返回Web服务器的地址。
|
||||
// 该函数通过访问ConfigYaml中的配置信息,获取并返回Web服务器的地址。
|
||||
// 主要用于需要与Web服务器建立连接的场景。
|
||||
func GetWebServerAddress() string {
|
||||
return ConfigYaml.Root.WebServerAddress
|
||||
return WebServerAddress
|
||||
}
|
||||
|
||||
// GetEsUrls 返回配置文件中 Elasticsearch 的 URL 地址。
|
||||
@ -93,5 +104,13 @@ func GetWebServerAddress() string {
|
||||
// 并将其作为字符串返回。这提供了一种简单的方法来获取 Elasticsearch 数据库的连接信息,
|
||||
// 而无需直接访问配置文件。
|
||||
func GetEsUrls() string {
|
||||
return ConfigYaml.Root.EsUrls
|
||||
return EsUrls
|
||||
}
|
||||
|
||||
func GetRabbitMQAddress() string {
|
||||
return Rabbitmq
|
||||
}
|
||||
|
||||
func GetRabbitMQName() string {
|
||||
return RabbitMQName
|
||||
}
|
||||
|
||||
@ -43,6 +43,12 @@ type Root struct {
|
||||
// ES 地址
|
||||
EsUrls string `yaml:"es_urls"`
|
||||
|
||||
// rabbitMQ 地址
|
||||
RabbitMQAddress string `yaml:"rabbitmq_address"`
|
||||
|
||||
// mq队列名称
|
||||
RabbitMQName string `yaml:"mq_queue_name"`
|
||||
|
||||
// 数据库配置
|
||||
DbConfig DBConfig `yaml:"db_config"`
|
||||
|
||||
|
||||
@ -92,12 +92,12 @@ func initMysql(dbConfig *mysqlUtil.DBConfig) *gorm.DB {
|
||||
if dbConfig == nil || dbConfig.ConnectionString == "" {
|
||||
return nil
|
||||
}
|
||||
logUtilPlus.WarnLog("开始连接mysql:%s", dbConfig.ConnectionString)
|
||||
dbObj, err := gorm.Open(mysql.Open(dbConfig.ConnectionString), &gorm.Config{})
|
||||
logUtilPlus.DebugLog("开始连接mysql:%s", dbConfig.ConnectionString)
|
||||
dbObj, err := gorm.Open(mysql.Open(dbConfig.ConnectionString), &gorm.Config{PrepareStmt: true})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("初始化数据库:%s失败,错误信息为:%s", dbConfig.ConnectionString, err))
|
||||
}
|
||||
logUtilPlus.WarnLog("连接mysql:%s成功", dbConfig.ConnectionString)
|
||||
logUtilPlus.DebugLog("连接mysql:%s成功", dbConfig.ConnectionString)
|
||||
|
||||
return dbObj
|
||||
}
|
||||
@ -126,7 +126,7 @@ func initRedis(redisConfig *redisUtil.RedisConfig) *goredis.Client {
|
||||
panic(fmt.Errorf("ping->redis:%s失败,DB:%s,错误信息为:%s", redisConfig.ConnectionString, redisConfig.Database, err))
|
||||
}
|
||||
|
||||
logUtilPlus.WarnLog("ping->redis:%s成功,信息为:%s", redisConfig.ConnectionString, ping)
|
||||
logUtilPlus.DebugLog("ping->redis:%s成功,信息为:%s", redisConfig.ConnectionString, ping)
|
||||
return client
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ replace (
|
||||
require (
|
||||
framework v0.0.0-20230425160006-b2d0b0a0b0b0
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/streadway/amqp v1.1.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
goutil v0.0.0-20230425160006-b2d0b0a0b0b0
|
||||
@ -24,6 +26,8 @@ require (
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/gomodule/redigo v1.8.9 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/jinzhu/gorm v1.9.12 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
|
||||
@ -1,109 +1,47 @@
|
||||
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/go.mod h1:mdtqvCSg8JOxk8PmpTNGyo6wzd4BMm4QXSfDnTXmgkE=
|
||||
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/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
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/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
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/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/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/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
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/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||
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/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
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/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/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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
@ -111,115 +49,40 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
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/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
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/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
|
||||
github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
|
||||
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/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
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/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 h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM=
|
||||
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/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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
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/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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
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=
|
||||
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
@ -227,5 +90,3 @@ gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkD
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
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=
|
||||
|
||||
54
trunk/center/common/rebbitMQ/config.go
Normal file
54
trunk/center/common/rebbitMQ/config.go
Normal file
@ -0,0 +1,54 @@
|
||||
package rebbitMQ
|
||||
|
||||
import (
|
||||
configYaml "common/configsYaml"
|
||||
"github.com/streadway/amqp"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var RabbitMQConn *amqp.Connection
|
||||
var RabbitMQChannel *amqp.Channel
|
||||
|
||||
// 初始化rabbitMQ
|
||||
func init() {
|
||||
|
||||
rabbitMQAddress := configYaml.GetRabbitMQAddress()
|
||||
|
||||
//是否有mq配置
|
||||
if rabbitMQAddress == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 连接到 RabbitMQ 服务器
|
||||
var err error
|
||||
RabbitMQConn, err = amqp.Dial(rabbitMQAddress)
|
||||
if err != nil {
|
||||
|
||||
//抛出一个异常
|
||||
logUtil.FatalLog("Failed to connect to RabbitMQ: %s,err:%s", rabbitMQAddress, err.Error())
|
||||
}
|
||||
|
||||
// 打开一个通道
|
||||
RabbitMQChannel, err = RabbitMQConn.Channel()
|
||||
if err != nil {
|
||||
|
||||
//抛出一个异常
|
||||
logUtil.FatalLog("Failed to open a channel,err:%s", err.Error())
|
||||
}
|
||||
|
||||
//队列名称
|
||||
queueName := configYaml.GetRabbitMQName()
|
||||
|
||||
// 声明一个队列
|
||||
_, err = RabbitMQChannel.QueueDeclare(
|
||||
queueName, // 队列名称
|
||||
true, // 是否持久化
|
||||
false, // 是否在使用后删除
|
||||
false, // 是否排他
|
||||
false, // 是否阻塞
|
||||
nil, // 其他参数
|
||||
)
|
||||
if err != nil {
|
||||
logUtil.FatalLog("Failed to declare a queue,queueName:%s,err:%s", queueName, err.Error())
|
||||
}
|
||||
}
|
||||
25
trunk/center/common/rebbitMQ/sendData.go
Normal file
25
trunk/center/common/rebbitMQ/sendData.go
Normal file
@ -0,0 +1,25 @@
|
||||
package rebbitMQ
|
||||
|
||||
import (
|
||||
configYaml "common/configsYaml"
|
||||
"github.com/streadway/amqp"
|
||||
"goutil/logUtilPlus"
|
||||
)
|
||||
|
||||
// 发送单挑mq消息
|
||||
func sendMqData(data string) {
|
||||
|
||||
// 发布消息到队列
|
||||
err := RabbitMQChannel.Publish(
|
||||
"", // 交换机名称
|
||||
configYaml.GetRabbitMQName(), // 路由键
|
||||
false, // 是否强制
|
||||
false, // 是否立即
|
||||
amqp.Publishing{
|
||||
ContentType: "text/plain",
|
||||
Body: []byte(data),
|
||||
})
|
||||
if err != nil {
|
||||
logUtilPlus.ErrorLog("Failed to publish a message,err:%s", err.Error())
|
||||
}
|
||||
}
|
||||
104
trunk/center/dbcenter/01_test.go
Normal file
104
trunk/center/dbcenter/01_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
amqp "github.com/streadway/amqp"
|
||||
)
|
||||
|
||||
// failOnError 检查错误并记录致命错误
|
||||
func failOnError(err error, msg string) {
|
||||
if err != nil {
|
||||
log.Fatalf("%s: %s", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试函数
|
||||
func Test001(t *testing.T) {
|
||||
// 连接到 RabbitMQ 服务器
|
||||
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
|
||||
failOnError(err, "连接到 RabbitMQ 失败")
|
||||
defer conn.Close()
|
||||
|
||||
// 打开一个通道
|
||||
ch, err := conn.Channel()
|
||||
failOnError(err, "打开通道失败")
|
||||
defer ch.Close()
|
||||
|
||||
// 声明一个队列
|
||||
q, err := ch.QueueDeclare(
|
||||
"hello", // 队列名称
|
||||
true, // 是否持久化
|
||||
false, // 是否在使用后删除
|
||||
false, // 是否排他
|
||||
false, // 是否阻塞
|
||||
nil, // 其他参数
|
||||
)
|
||||
failOnError(err, "声明队列失败")
|
||||
|
||||
// 注册一个消费者
|
||||
msgs, err := ch.Consume(
|
||||
q.Name, // 队列名称
|
||||
"", // 消费者名称
|
||||
true, // 是否自动确认
|
||||
false, // 是否排他
|
||||
false, // 是否本地
|
||||
false, // 是否阻塞
|
||||
nil, // 其他参数
|
||||
)
|
||||
failOnError(err, "注册消费者失败")
|
||||
|
||||
// 创建一个无缓冲的通道,用于阻塞主 goroutine
|
||||
forever := make(chan bool)
|
||||
|
||||
// 启动一个 goroutine 来处理消息
|
||||
go func() {
|
||||
for d := range msgs {
|
||||
log.Printf("收到消息: %s", d.Body)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Printf(" [*] 等待消息。按 CTRL+C 退出")
|
||||
<-forever
|
||||
}
|
||||
|
||||
func Test002(t *testing.T) {
|
||||
// 连接到 RabbitMQ 服务器
|
||||
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
|
||||
failOnError(err, "连接到 RabbitMQ 失败")
|
||||
defer conn.Close()
|
||||
|
||||
// 打开一个通道
|
||||
ch, err := conn.Channel()
|
||||
failOnError(err, "打开通道失败")
|
||||
defer ch.Close()
|
||||
|
||||
// 声明一个队列
|
||||
q, err := ch.QueueDeclare(
|
||||
"hello", // 队列名称
|
||||
true, // 是否持久化
|
||||
false, // 是否在使用后删除
|
||||
false, // 是否排他
|
||||
false, // 是否阻塞
|
||||
nil, // 其他参数
|
||||
)
|
||||
failOnError(err, "声明队列失败")
|
||||
|
||||
// 定义要发送的消息内容
|
||||
body := "Hello World!1111"
|
||||
|
||||
// 发布消息到队列
|
||||
err = ch.Publish(
|
||||
"", // 交换机名称
|
||||
q.Name, // 路由键
|
||||
false, // 是否强制
|
||||
false, // 是否立即
|
||||
amqp.Publishing{
|
||||
ContentType: "text/plain",
|
||||
Body: []byte(body),
|
||||
})
|
||||
failOnError(err, "发布消息失败")
|
||||
|
||||
log.Printf(" [x] 发送 %s", body)
|
||||
}
|
||||
5
trunk/center/dbcenter/go.mod
Normal file
5
trunk/center/dbcenter/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module dbcenter
|
||||
|
||||
go 1.22.10
|
||||
|
||||
require github.com/streadway/amqp v1.1.0 // indirect
|
||||
2
trunk/center/dbcenter/go.sum
Normal file
2
trunk/center/dbcenter/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM=
|
||||
github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg=
|
||||
5
trunk/center/dbcenter/main.go
Normal file
5
trunk/center/dbcenter/main.go
Normal file
@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
||||
@ -47,8 +47,8 @@ func GetUserByID(orderID int64) (*Order, error) {
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// AddUserCache 添加用户缓存
|
||||
func AddUserCache(order *Order) {
|
||||
// AddOrderCache 添加用户缓存
|
||||
func AddOrderCache(order *Order) {
|
||||
rwmu.Lock()
|
||||
defer rwmu.Unlock()
|
||||
orderMap[order.OrderID] = order
|
||||
@ -65,5 +65,8 @@ func AddOrder(order *Order) (int64, error) {
|
||||
logUtilPlus.ErrorLog("添加支付订单失败 错误信息:", result.Error.Error())
|
||||
}
|
||||
|
||||
//添加缓存
|
||||
AddOrderCache(order)
|
||||
|
||||
return order.OrderID, nil
|
||||
}
|
||||
|
||||
109
trunk/game/common/clientMgr/clientMgr.go
Normal file
109
trunk/game/common/clientMgr/clientMgr.go
Normal file
@ -0,0 +1,109 @@
|
||||
package clientMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"goutil/debugUtil"
|
||||
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
clientMap = make(map[int32]IClient, 1024)
|
||||
mutex sync.RWMutex
|
||||
)
|
||||
|
||||
func RegisterClient(clientObj IClient) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
clientMap[clientObj.GetId()] = clientObj
|
||||
}
|
||||
|
||||
func UnregisterClient(clientObj IClient) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
delete(clientMap, clientObj.GetId())
|
||||
}
|
||||
|
||||
func GetClient(id int32) (clientObj IClient, exists bool) {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
||||
clientObj, exists = clientMap[id]
|
||||
return
|
||||
}
|
||||
|
||||
func getClientCount() int {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
||||
return len(clientMap)
|
||||
}
|
||||
|
||||
func getExpiredClientList() (expiredList []IClient) {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
|
||||
for _, item := range clientMap {
|
||||
if item.Expired() {
|
||||
expiredList = append(expiredList, item)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 绑定连接到玩家
|
||||
func BindClientAndPlayer(clientObj IClient, playerObj *Player) {
|
||||
// 发送在另一台设备登陆的信息
|
||||
sendLoginAnotherDeviceMsg := func(clientObj IClient) {
|
||||
responseObj := NewServerResponseObject()
|
||||
responseObj.SetMethodName("Login")
|
||||
responseObj.SetResultStatus(LoginOnAnotherDevice)
|
||||
|
||||
mes, _ := json.Marshal(responseObj)
|
||||
|
||||
if debugUtil.IsDebug() {
|
||||
logUtil.WarnLog("BindClientAndPlayer11BindClientAndPlayer:%v", string(mes))
|
||||
}
|
||||
|
||||
// 先发送消息,然后再断开连接
|
||||
clientObj.SendMessage(responseObj)
|
||||
clientObj.SendMessage(NewDisconnectServerResponseObject())
|
||||
}
|
||||
|
||||
// 立即更新活跃时间,避免在将要清除时,玩家又登陆的极端情况
|
||||
clientObj.Active()
|
||||
clientObj.ClearSendData()
|
||||
|
||||
// 判断是否重复登陆
|
||||
if playerObj.ClientId > 0 {
|
||||
if oldClientObj, exist := GetClient(playerObj.ClientId); exist {
|
||||
// 如果不是同一个客户端,则先给客户端发送在其他设备登陆信息,然后断开连接
|
||||
if clientObj != oldClientObj {
|
||||
sendLoginAnotherDeviceMsg(oldClientObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新客户端对象的玩家Id、以及玩家对象对应的客户端Id
|
||||
clientObj.PlayerLogin(playerObj.Id)
|
||||
playerObj.ClientLogin(clientObj.GetId())
|
||||
}
|
||||
|
||||
// Disconnect 清理断开的连接数据
|
||||
// / 连接对象
|
||||
func Disconnect(clientObj IClient) {
|
||||
if clientObj.GetPlayerId() != 0 {
|
||||
playerObj, exist, err := getPlayerHandler(clientObj.GetPlayerId(), false)
|
||||
if err == nil && exist && clientObj.GetId() == playerObj.ClientId {
|
||||
playerObj.ClientLogout()
|
||||
}
|
||||
}
|
||||
|
||||
clientObj.Close()
|
||||
UnregisterClient(clientObj)
|
||||
}
|
||||
41
trunk/game/common/clientMgr/expire.go
Normal file
41
trunk/game/common/clientMgr/expire.go
Normal file
@ -0,0 +1,41 @@
|
||||
package clientMgr
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"framework/goroutineMgr"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 清理过期的客户端
|
||||
go clearExpiredClient()
|
||||
}
|
||||
|
||||
// 清理过期的客户端
|
||||
func clearExpiredClient() {
|
||||
// 处理goroutine数量
|
||||
goroutineName := "clientMgr.clearExpiredClient"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
for {
|
||||
// 休眠指定的时间(单位:秒)(放在此处是因为程序刚启动时并没有过期的客户端,所以先不用占用资源;并且此时LogPath尚未设置,如果直接执行后面的代码会出现panic异常)
|
||||
time.Sleep(5 * time.Minute)
|
||||
|
||||
// 获取过期的客户端列表
|
||||
expiredClientList := getExpiredClientList()
|
||||
expiredClientCount := len(expiredClientList)
|
||||
beforeClientCount := getClientCount()
|
||||
|
||||
// 客户端断开
|
||||
if expiredClientCount > 0 {
|
||||
for _, item := range expiredClientList {
|
||||
Disconnect(item)
|
||||
}
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
logUtil.DebugLog("清理前的客户端数量为:%d,本次清理不活跃的客户端数量为:%d", beforeClientCount, expiredClientCount)
|
||||
}
|
||||
}
|
||||
86
trunk/game/common/clientMgr/handleRequest.go
Normal file
86
trunk/game/common/clientMgr/handleRequest.go
Normal file
@ -0,0 +1,86 @@
|
||||
package clientMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
. "common/model"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// HandleRequest 处理客户端请求
|
||||
// clientObj:对应的客户端对象
|
||||
// request:请求内容字节数组(json格式)
|
||||
// 返回值:无
|
||||
func HandleRequest(clientObj IClient, request []byte) {
|
||||
responseObj := NewServerResponseObject()
|
||||
|
||||
defer func() {
|
||||
// 如果是客户端数据错误,则将客户端请求数据记录下来
|
||||
if responseObj.ResultStatus == ClientDataError {
|
||||
logUtil.ErrorLog("client:%s\n请求的数据为:%s, 返回的结果为客户端数据错误", clientObj, string(request))
|
||||
}
|
||||
|
||||
// 调用发送消息接口
|
||||
clientObj.SendMessage(responseObj)
|
||||
|
||||
// 记录DEBUG日志
|
||||
if debugUtil.IsDebug() {
|
||||
result, _ := json.Marshal(responseObj)
|
||||
logUtil.DebugLog("client:%s\nRequest:%s\nResponse:%s", clientObj, string(request), string(result))
|
||||
}
|
||||
}()
|
||||
|
||||
// 解析请求字符串
|
||||
requestObj := new(ServerRequestObject)
|
||||
if err := json.Unmarshal(request, requestObj); err != nil {
|
||||
logUtil.ErrorLog("反序列化出错,字符串:%s,错误信息为:%s", string(request), err)
|
||||
responseObj.SetResultStatus(ClientDataError)
|
||||
return
|
||||
}
|
||||
|
||||
// 为参数赋值
|
||||
responseObj.SetMethodName(requestObj.MethodName)
|
||||
|
||||
// 对参数要特殊处理:将Client、Player特殊处理
|
||||
parameters := make([]interface{}, 0)
|
||||
if requestObj.MethodName == "Login" {
|
||||
parameters = append(parameters, interface{}(clientObj))
|
||||
parameters = append(parameters, requestObj.Parameters...)
|
||||
} else {
|
||||
// 判断玩家是否已经登陆
|
||||
if clientObj.GetPlayerId() == 0 {
|
||||
responseObj.SetResultStatus(NoLogin)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断是否能找到玩家
|
||||
var playerObj *Player
|
||||
var exists bool
|
||||
var err error
|
||||
if getPlayerHandler == nil {
|
||||
panic("getPlayerHandler is nil, please set first")
|
||||
}
|
||||
playerObj, exists, err = getPlayerHandler(clientObj.GetPlayerId(), false)
|
||||
if err != nil {
|
||||
responseObj.SetResultStatus(DataError)
|
||||
return
|
||||
}
|
||||
|
||||
if !exists {
|
||||
responseObj.SetResultStatus(NoLogin)
|
||||
return
|
||||
}
|
||||
|
||||
parameters = append(parameters, interface{}(clientObj))
|
||||
parameters = append(parameters, interface{}(playerObj))
|
||||
parameters = append(parameters, requestObj.Parameters...)
|
||||
}
|
||||
|
||||
// 为参数赋值
|
||||
requestObj.ModuleName = "Chat"
|
||||
requestObj.Parameters = parameters
|
||||
|
||||
// 调用方法
|
||||
responseObj = callFunction(requestObj)
|
||||
}
|
||||
33
trunk/game/common/clientMgr/interface.go
Normal file
33
trunk/game/common/clientMgr/interface.go
Normal file
@ -0,0 +1,33 @@
|
||||
package clientMgr
|
||||
|
||||
import . "common/model"
|
||||
|
||||
// IClient 客户端连接接口
|
||||
type IClient interface {
|
||||
// GetId 获取客户端对象的唯一标识
|
||||
GetId() int32
|
||||
|
||||
// 获取玩家Id
|
||||
GetPlayerId() int64
|
||||
|
||||
// 玩家登录
|
||||
PlayerLogin(int64)
|
||||
|
||||
// 发送数据
|
||||
SendMessage(*ServerResponseObject)
|
||||
|
||||
// 清空待发送数据
|
||||
ClearSendData()
|
||||
|
||||
// 客户端活跃
|
||||
Active()
|
||||
|
||||
// 获取远程地址(IP_Port)
|
||||
GetRemoteAddr() string
|
||||
|
||||
// 客户端连接超时
|
||||
Expired() bool
|
||||
|
||||
// 客户端连接对象断开
|
||||
Close()
|
||||
}
|
||||
25
trunk/game/common/clientMgr/reflect_method.go
Normal file
25
trunk/game/common/clientMgr/reflect_method.go
Normal file
@ -0,0 +1,25 @@
|
||||
package clientMgr
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 反射的方法和输入、输出参数类型组合类型
|
||||
type methodAndInOutTypes struct {
|
||||
// 反射出来的对应方法对象
|
||||
Method reflect.Value
|
||||
|
||||
// 反射出来的方法的输入参数的类型集合
|
||||
InTypes []reflect.Type
|
||||
|
||||
// 反射出来的方法的输出参数的类型集合
|
||||
OutTypes []reflect.Type
|
||||
}
|
||||
|
||||
func newmethodAndInOutTypes(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *methodAndInOutTypes {
|
||||
return &methodAndInOutTypes{
|
||||
Method: _method,
|
||||
InTypes: _inTypes,
|
||||
OutTypes: _outTypes,
|
||||
}
|
||||
}
|
||||
356
trunk/game/common/clientMgr/reflect_mgr.go
Normal file
356
trunk/game/common/clientMgr/reflect_mgr.go
Normal file
@ -0,0 +1,356 @@
|
||||
package clientMgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
. "common/model"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
const (
|
||||
// 供客户端访问的模块的后缀
|
||||
con_ModuleSuffix = "Module"
|
||||
|
||||
// 定义用于分隔模块名称和方法名称的分隔符
|
||||
con_DelimeterOfObjAndMethod = "_"
|
||||
)
|
||||
|
||||
var (
|
||||
// 定义存放所有方法映射的变量
|
||||
methodMap = make(map[string]*methodAndInOutTypes)
|
||||
)
|
||||
|
||||
// 获取结构体类型的名称
|
||||
// structType:结构体类型
|
||||
// 返回值:
|
||||
// 结构体类型的名称
|
||||
func getStructName(structType reflect.Type) string {
|
||||
reflectTypeStr := structType.String()
|
||||
reflectTypeArr := strings.Split(reflectTypeStr, ".")
|
||||
|
||||
return reflectTypeArr[len(reflectTypeArr)-1]
|
||||
}
|
||||
|
||||
// 获取完整的模块名称
|
||||
// moduleName:模块名称
|
||||
// 返回值:
|
||||
// 完整的模块名称
|
||||
func getFullModuleName(moduleName string) string {
|
||||
return moduleName + con_ModuleSuffix
|
||||
}
|
||||
|
||||
// 获取完整的方法名称
|
||||
// structName:结构体名称
|
||||
// methodName:方法名称
|
||||
// 返回值:
|
||||
// 完整的方法名称
|
||||
func getFullMethodName(structName, methodName string) string {
|
||||
return structName + con_DelimeterOfObjAndMethod + methodName
|
||||
}
|
||||
|
||||
// 解析方法的输入输出参数
|
||||
// method:方法对应的反射值
|
||||
// 返回值:
|
||||
// 输入参数类型集合
|
||||
// 输出参数类型集合
|
||||
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
|
||||
}
|
||||
|
||||
// 将需要对客户端提供方法的对象进行注册
|
||||
// structObject:对象
|
||||
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
|
||||
outType := outTypes[0]
|
||||
if _, ok := outType.FieldByName("Code"); !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := outType.FieldByName("Message"); !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := outType.FieldByName("Data"); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 添加到列表中
|
||||
methodMap[getFullMethodName(structName, methodName)] = newmethodAndInOutTypes(method, inTypes, outTypes)
|
||||
|
||||
debugUtil.Println(fmt.Sprintf("%s_%s注册成功,当前共%d个方法", structName, methodName, len(methodMap)))
|
||||
}
|
||||
}
|
||||
|
||||
// 调用方法
|
||||
// requestObj:请求对象
|
||||
func callFunction(requestObj *ServerRequestObject) *ServerResponseObject {
|
||||
responseObj := NewServerResponseObject()
|
||||
var methodAndInOutTypes *methodAndInOutTypes
|
||||
var exists bool
|
||||
|
||||
// 根据传入的ModuleName和MethodName找到对应的方法对象
|
||||
key := getFullMethodName(getFullModuleName(requestObj.ModuleName), requestObj.MethodName)
|
||||
if methodAndInOutTypes, exists = methodMap[key]; !exists {
|
||||
logUtil.ErrorLog("找不到指定的方法:%v,%s", methodMap, key)
|
||||
return responseObj.SetResultStatus(NoTargetMethod)
|
||||
}
|
||||
|
||||
// 判断参数数量是否相同
|
||||
inTypesLength := len(methodAndInOutTypes.InTypes)
|
||||
paramLength := len(requestObj.Parameters)
|
||||
if paramLength != inTypesLength {
|
||||
logUtil.ErrorLog("传入的参数数量不符,本地方法%s的参数数量:%d,传入的参数数量为:%d", key, inTypesLength, paramLength)
|
||||
return responseObj.SetResultStatus(ParamNotMatch)
|
||||
}
|
||||
|
||||
// 构造参数
|
||||
in := make([]reflect.Value, inTypesLength)
|
||||
for i := 0; i < inTypesLength; i++ {
|
||||
inTypeItem := methodAndInOutTypes.InTypes[i]
|
||||
paramItem := requestObj.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.Interface:
|
||||
if param_client, ok := paramItem.(IClient); ok {
|
||||
in[i] = reflect.ValueOf(param_client)
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if param_player, ok := paramItem.(*Player); ok {
|
||||
in[i] = reflect.ValueOf(param_player)
|
||||
}
|
||||
case reflect.Bool:
|
||||
if param_bool, ok := paramItem.(bool); ok {
|
||||
in[i] = reflect.ValueOf(param_bool)
|
||||
}
|
||||
case reflect.Int:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(int(param_float64))
|
||||
}
|
||||
case reflect.Int8:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(int8(param_float64))
|
||||
}
|
||||
case reflect.Int16:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(int16(param_float64))
|
||||
}
|
||||
case reflect.Int32:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(int32(param_float64))
|
||||
}
|
||||
case reflect.Int64:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(int64(param_float64))
|
||||
}
|
||||
case reflect.Uint:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(uint(param_float64))
|
||||
}
|
||||
case reflect.Uint8:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(uint8(param_float64))
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(uint16(param_float64))
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(uint32(param_float64))
|
||||
}
|
||||
case reflect.Uint64:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(uint64(param_float64))
|
||||
}
|
||||
case reflect.Float32:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(float32(param_float64))
|
||||
}
|
||||
case reflect.Float64:
|
||||
if param_float64, ok := paramItem.(float64); ok {
|
||||
in[i] = reflect.ValueOf(param_float64)
|
||||
}
|
||||
case reflect.String:
|
||||
if param_string, ok := paramItem.(string); ok {
|
||||
in[i] = reflect.ValueOf(param_string)
|
||||
}
|
||||
case reflect.Slice:
|
||||
// 如果是Slice类型,则需要对其中的项再次进行类型判断及类型转换
|
||||
if param_interface, ok := paramItem.([]interface{}); ok {
|
||||
switch inTypeItem.String() {
|
||||
case "[]bool":
|
||||
params_inner := make([]bool, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_bool, ok := param_interface[i].(bool); ok {
|
||||
params_inner[i] = param_bool
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]int":
|
||||
params_inner := make([]int, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = int(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]int8":
|
||||
params_inner := make([]int8, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = int8(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]int16":
|
||||
params_inner := make([]int16, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = int16(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]int32":
|
||||
params_inner := make([]int32, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = int32(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]int64":
|
||||
params_inner := make([]int64, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = int64(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]uint":
|
||||
params_inner := make([]uint, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = uint(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
// case "[]uint8": 特殊处理
|
||||
case "[]uint16":
|
||||
params_inner := make([]uint16, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = uint16(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]uint32":
|
||||
params_inner := make([]uint32, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = uint32(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]uint64":
|
||||
params_inner := make([]uint64, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = uint64(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]float32":
|
||||
params_inner := make([]float32, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = float32(param_float64)
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]float64":
|
||||
params_inner := make([]float64, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_float64, ok := param_interface[i].(float64); ok {
|
||||
params_inner[i] = param_float64
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
case "[]string":
|
||||
params_inner := make([]string, len(param_interface))
|
||||
for i := 0; i < len(param_interface); i++ {
|
||||
if param_string, ok := param_interface[i].(string); ok {
|
||||
params_inner[i] = param_string
|
||||
}
|
||||
}
|
||||
in[i] = reflect.ValueOf(params_inner)
|
||||
}
|
||||
} else if inTypeItem.String() == "[]uint8" { // 由于[]uint8在传输过程中会被转化成字符串,所以单独处理;
|
||||
if param_string, ok := paramItem.(string); ok {
|
||||
param_uint8 := ([]uint8)(param_string)
|
||||
in[i] = reflect.ValueOf(param_uint8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否有无效的参数(传入的参数类型和方法定义的类型不匹配导致没有赋值)
|
||||
for _, item := range in {
|
||||
if reflect.Value.IsValid(item) == false {
|
||||
logUtil.ErrorLog("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObj.Parameters)
|
||||
return responseObj.SetResultStatus(ParamInValid)
|
||||
}
|
||||
}
|
||||
|
||||
// 传入参数,调用方法
|
||||
out := methodAndInOutTypes.Method.Call(in)
|
||||
|
||||
// 由于只有一个返回值,所以取out[0]
|
||||
if retResponseObj, ok := (out[0]).Interface().(ServerResponseObject); ok {
|
||||
responseObj.SetMethodName(requestObj.MethodName)
|
||||
responseObj.SetResultStatus(retResponseObj.ResultStatus)
|
||||
responseObj.SetData(retResponseObj.Data)
|
||||
} else {
|
||||
logUtil.ErrorLog("(&out[0]).Interface()转换类型失败")
|
||||
}
|
||||
|
||||
return responseObj
|
||||
}
|
||||
101
trunk/game/common/config/baseConfig.go
Normal file
101
trunk/game/common/config/baseConfig.go
Normal file
@ -0,0 +1,101 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"goutil/configUtil"
|
||||
"goutil/debugUtil"
|
||||
)
|
||||
|
||||
// 基础配置对象
|
||||
type BaseConfig struct {
|
||||
// ChatCenter监听地址
|
||||
ChatCenterAddress string
|
||||
|
||||
// ManageCenter的API的域名地址
|
||||
ManageCenterDomain string
|
||||
|
||||
// 通信协议tcp/websocket
|
||||
Protocol string
|
||||
|
||||
// 内网地址
|
||||
PrivateIP string
|
||||
|
||||
// 公网地址
|
||||
PublicIP string
|
||||
|
||||
// 为ChatServer提价服务的端口
|
||||
ChatServerPort string
|
||||
|
||||
// 为GameServer提供服务的端口
|
||||
GameServerPort string
|
||||
|
||||
// 为GameServer提供服务的Web端口
|
||||
GameServerWebPort string
|
||||
|
||||
// 是否压缩返回给客户端的数据
|
||||
IfCompressData bool
|
||||
|
||||
// GoPs监控程序监听地址
|
||||
GopsAddr string
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPrivateChatServerAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PrivateIP, this.ChatServerPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPrivateGameServerAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PrivateIP, this.GameServerPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPrivateGameServerWebAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PrivateIP, this.GameServerWebPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPrivateGopsAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PrivateIP, this.GopsAddr)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPublicChatServerAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PublicIP, this.ChatServerPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPublicGameServerAddress() string {
|
||||
return fmt.Sprintf("%s:%s", this.PublicIP, this.GameServerPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) GetPublicGameServerWebAddress() string {
|
||||
return fmt.Sprintf("http://%s:%s/API/player/login", this.PublicIP, this.GameServerWebPort)
|
||||
}
|
||||
|
||||
func (this *BaseConfig) String() string {
|
||||
bytes, _ := json.Marshal(this)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
var (
|
||||
baseConfig *BaseConfig
|
||||
)
|
||||
|
||||
func initBaseConfig(config *configUtil.XmlConfig) error {
|
||||
tempConfig := new(BaseConfig)
|
||||
err := config.Unmarshal("root/BaseConfig", tempConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseConfig = tempConfig
|
||||
debugUtil.Printf("baseConfig:%v\n", baseConfig)
|
||||
|
||||
if baseConfig.Protocol != "tcp" && baseConfig.Protocol != "websocket" {
|
||||
panic("Protocol Error, it should be either tcp or websocket")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBaseConfig 获取服务器基础配置
|
||||
func GetBaseConfig() *BaseConfig {
|
||||
return baseConfig
|
||||
}
|
||||
56
trunk/game/common/config/config.go
Normal file
56
trunk/game/common/config/config.go
Normal file
@ -0,0 +1,56 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"goutil/configUtil"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
configManager = configMgr.NewConfigManager()
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 优先加基础配置
|
||||
configManager.RegisterInitFunc(initBaseConfig)
|
||||
configManager.RegisterInitFunc(initDBConfig)
|
||||
configManager.RegisterInitFunc(initMonitorConfig)
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 设置日志文件的存储目录
|
||||
logUtil.SetLogPath("LOG")
|
||||
|
||||
if err := reload(); err != nil {
|
||||
panic(fmt.Errorf("初始化配置文件失败,错误信息为:%s", err))
|
||||
}
|
||||
|
||||
// 注册重新加载的方法
|
||||
reloadMgr.RegisterReloadFunc("config.reload", reload)
|
||||
}
|
||||
|
||||
func reload() error {
|
||||
// 读取配置文件内容
|
||||
configObj := configUtil.NewXmlConfig()
|
||||
err := configObj.LoadFromFile("config.xml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
debug, err := configObj.Bool("root/DEBUG", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置debugUtil的状态
|
||||
debugUtil.SetDebug(debug)
|
||||
|
||||
// 调用所有已经注册的配置初始化方法
|
||||
if err := configManager.Init(configObj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
29
trunk/game/common/config/dbConfig.go
Normal file
29
trunk/game/common/config/dbConfig.go
Normal file
@ -0,0 +1,29 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"goutil/configUtil"
|
||||
"goutil/debugUtil"
|
||||
"goutil/mysqlUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
dbConfig *mysqlUtil.DBConfig
|
||||
)
|
||||
|
||||
func initDBConfig(config *configUtil.XmlConfig) error {
|
||||
tempConfig := new(mysqlUtil.DBConfig)
|
||||
err := config.Unmarshal("root/DBConnection", tempConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbConfig = tempConfig
|
||||
debugUtil.Printf("dbConfig:%v\n", dbConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDBConfig 获取mysql数据库配置
|
||||
func GetDBConfig() *mysqlUtil.DBConfig {
|
||||
return dbConfig
|
||||
}
|
||||
27
trunk/game/common/config/monitorConfig.go
Normal file
27
trunk/game/common/config/monitorConfig.go
Normal file
@ -0,0 +1,27 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"goutil/configUtil"
|
||||
"goutil/debugUtil"
|
||||
)
|
||||
|
||||
var (
|
||||
monitorConfig *monitorMgr.MonitorConfig
|
||||
)
|
||||
|
||||
func initMonitorConfig(config *configUtil.XmlConfig) error {
|
||||
tempConfig := new(monitorMgr.MonitorConfig)
|
||||
err := config.Unmarshal("root/MonitorConfig", tempConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
monitorConfig = tempConfig
|
||||
debugUtil.Printf("monitorConfig:%v\n", monitorConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMonitorConfig 获监测配置
|
||||
func GetMonitorConfig() *monitorMgr.MonitorConfig {
|
||||
return monitorConfig
|
||||
}
|
||||
13
trunk/game/common/go.mod
Normal file
13
trunk/game/common/go.mod
Normal file
@ -0,0 +1,13 @@
|
||||
module common
|
||||
|
||||
go 1.22.10
|
||||
|
||||
replace (
|
||||
framework => ../../framework
|
||||
goutil => ../../goutil
|
||||
)
|
||||
|
||||
require (
|
||||
framework v0.0.0-20230425160006-b2d0b0a0b0b0
|
||||
goutil v0.0.0-20230425160006-b2d0b0a0b0b0
|
||||
)
|
||||
6
trunk/game/common/go.sum
Normal file
6
trunk/game/common/go.sum
Normal file
@ -0,0 +1,6 @@
|
||||
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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
63
trunk/game/common/model/resultStatus.go
Normal file
63
trunk/game/common/model/resultStatus.go
Normal file
@ -0,0 +1,63 @@
|
||||
package model
|
||||
|
||||
// 返回结果状态
|
||||
type ResultStatus struct {
|
||||
// 状态值(成功是0,非成功以负数来表示)
|
||||
Code int
|
||||
|
||||
// 状态信息
|
||||
Message string
|
||||
}
|
||||
|
||||
func newResultStatus(code int, message string) *ResultStatus {
|
||||
return &ResultStatus{
|
||||
Code: code,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// 定义所有的响应结果的状态枚举值
|
||||
var (
|
||||
Success = newResultStatus(0, "成功")
|
||||
DataError = newResultStatus(-1, "数据错误")
|
||||
DBError = newResultStatus(-2, "数据库错误")
|
||||
MethodNotDefined = newResultStatus(-3, "方法未定义")
|
||||
ParamIsEmpty = newResultStatus(-4, "参数为空")
|
||||
ParamNotMatch = newResultStatus(-5, "参数不匹配")
|
||||
ParamTypeError = newResultStatus(-6, "参数类型错误")
|
||||
OnlySupportPOST = newResultStatus(-7, "只支持POST")
|
||||
APINotDefined = newResultStatus(-8, "API未定义")
|
||||
APIParamError = newResultStatus(-9, "API参数错误")
|
||||
InvalidIP = newResultStatus(-10, "IP无效")
|
||||
PlayerNotExists = newResultStatus(-11, "玩家不存在")
|
||||
NoAvailableServer = newResultStatus(-12, "没有可用的服务器")
|
||||
ClientDataError = newResultStatus(-13, "客户端数据错误")
|
||||
TokenInvalid = newResultStatus(-14, "令牌无效")
|
||||
ChannelNotDefined = newResultStatus(-15, "聊天频道未定义")
|
||||
NoTargetMethod = newResultStatus(-16, "找不到目标方法")
|
||||
ParamInValid = newResultStatus(-17, "参数无效")
|
||||
NoLogin = newResultStatus(-18, "尚未登陆")
|
||||
NotInUnion = newResultStatus(-19, "不在公会中")
|
||||
NotInShimen = newResultStatus(-20, "不在师门中")
|
||||
NotFoundTarget = newResultStatus(-21, "未找到目标玩家")
|
||||
PlayerNotExist = newResultStatus(-22, "玩家不存在")
|
||||
ServerGroupNotExist = newResultStatus(-23, "服务器组不存在")
|
||||
NotInTeam = newResultStatus(-24, "不在队伍中")
|
||||
LoginOnAnotherDevice = newResultStatus(-25, "在另一台设备上登录")
|
||||
CantSendMessageToSelf = newResultStatus(-26, "不能给自己发消息")
|
||||
ResourceNotEnough = newResultStatus(-27, "资源不足")
|
||||
NetworkError = newResultStatus(-28, "网络错误")
|
||||
ContainForbiddenWord = newResultStatus(-29, "含有屏蔽词语")
|
||||
SendMessageTooFast = newResultStatus(-30, "发送消息太快")
|
||||
LvIsNotEnough = newResultStatus(-31, "等级不足,系统未开放")
|
||||
RepeatTooMuch = newResultStatus(-32, "重复次数太多")
|
||||
CantCrossServerTalk = newResultStatus(-33, "不能跨服私聊")
|
||||
InSilent = newResultStatus(-34, "您的账号已被禁言,请联系客服反馈。")
|
||||
NotInCountry = newResultStatus(-35, "不在国家中")
|
||||
CantSendMessageToGM = newResultStatus(-36, "当前GM对话已结束,如有疑问请联系客服QQ咨询")
|
||||
DisconnectStatus = newResultStatus(-37, "DisconnectStatus")
|
||||
LanguageToTextError = newResultStatus(-38, "语音转换失败!")
|
||||
VoiceCloudNotDefined = newResultStatus(-15, "语音识别云商不存在")
|
||||
ContainForbiddenWordForQCGreen = newResultStatus(-39, "内容含有屏蔽词语")
|
||||
ContainForbiddenWordForZSYDun = newResultStatus(-59, "内容中含有屏蔽词语")
|
||||
)
|
||||
29
trunk/game/common/model/serverRequestObject.go
Normal file
29
trunk/game/common/model/serverRequestObject.go
Normal file
@ -0,0 +1,29 @@
|
||||
package model
|
||||
|
||||
// 请求对象
|
||||
type ServerRequestObject struct {
|
||||
// 请求的唯一标识,是需要通过截取请求数据前4位得到并进行手动赋值的(暂时未使用)
|
||||
RequestId int64
|
||||
|
||||
// 请求的模块名称
|
||||
ModuleName string
|
||||
|
||||
// 请求的方法名称
|
||||
MethodName string
|
||||
|
||||
// 请求的参数数组
|
||||
Parameters []interface{}
|
||||
|
||||
// 客户端发送请求的时间
|
||||
SendTime int64
|
||||
|
||||
ReachTime int64
|
||||
|
||||
InQueueTime int64
|
||||
|
||||
HandleStartTime int64
|
||||
|
||||
HandleEndTime int64
|
||||
|
||||
ReturnTime int64
|
||||
}
|
||||
89
trunk/game/common/model/serverResponseData.go
Normal file
89
trunk/game/common/model/serverResponseData.go
Normal file
@ -0,0 +1,89 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 服务器响应对象
|
||||
type ServerResponseData struct {
|
||||
// Id
|
||||
Id int
|
||||
|
||||
// 聊天频道
|
||||
Channel string
|
||||
|
||||
// 聊天消息
|
||||
Message string
|
||||
|
||||
// 语音信息
|
||||
Voice string
|
||||
|
||||
// 语音文字
|
||||
VoiceText string
|
||||
|
||||
// 发送人
|
||||
FromPlayer string
|
||||
FromPlayerId string
|
||||
|
||||
// 接收人
|
||||
ToPlayer string `json:"ToPlayer,omitempty"`
|
||||
ToPlayerId string `json:"ToPlayerId,omitempty"`
|
||||
|
||||
// 创建的时间戳
|
||||
TimeStamp int64
|
||||
|
||||
//是否是离线消息
|
||||
IfOffline bool
|
||||
|
||||
//是否已读消息
|
||||
IfRead bool
|
||||
}
|
||||
|
||||
// 创建新的服务器响应对象
|
||||
func NewServerResponseData(id int, channel, message, voice, voiceText string, from, to *Player, ifOffline, ifRead int32) *ServerResponseData {
|
||||
var fromPlayer, toPlayer string
|
||||
var fromPlayerId, toPlayerId int64
|
||||
if from != nil {
|
||||
fromPlayerId = from.Id
|
||||
fromPlayer = from.String()
|
||||
}
|
||||
|
||||
if to != nil {
|
||||
toPlayerId = to.Id
|
||||
toPlayer = to.String()
|
||||
}
|
||||
|
||||
return &ServerResponseData{
|
||||
Id: id,
|
||||
Channel: channel,
|
||||
Message: message,
|
||||
Voice: voice,
|
||||
VoiceText: voiceText,
|
||||
FromPlayer: fromPlayer,
|
||||
FromPlayerId: strconv.FormatInt(fromPlayerId, 10),
|
||||
ToPlayer: toPlayer,
|
||||
ToPlayerId: strconv.FormatInt(toPlayerId, 10),
|
||||
TimeStamp: time.Now().Unix(),
|
||||
IfOffline: ifOffline == 1,
|
||||
IfRead: ifRead == 1,
|
||||
}
|
||||
}
|
||||
|
||||
// 从其它类型转化为服务器响应对象
|
||||
func ConvertToServerResponseData(id int, channel, message, voice, voiceText, fromPlayer string, fromPlayerId int64, toPlayer string, toPlayerId int64, timeStamp int64, ifOffline, ifRead bool) *ServerResponseData {
|
||||
return &ServerResponseData{
|
||||
Id: id,
|
||||
Channel: channel,
|
||||
Message: message,
|
||||
Voice: voice,
|
||||
VoiceText: voiceText,
|
||||
FromPlayer: fromPlayer,
|
||||
FromPlayerId: strconv.FormatInt(fromPlayerId, 10),
|
||||
ToPlayer: toPlayer,
|
||||
ToPlayerId: strconv.FormatInt(toPlayerId, 10),
|
||||
TimeStamp: timeStamp,
|
||||
IfOffline: ifOffline,
|
||||
IfRead: ifRead,
|
||||
}
|
||||
}
|
||||
80
trunk/game/common/model/serverResponseObject.go
Normal file
80
trunk/game/common/model/serverResponseObject.go
Normal file
@ -0,0 +1,80 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"encoding/json"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
// ChatServer的响应对象
|
||||
type ServerResponseObject struct {
|
||||
// 响应结果的状态值
|
||||
*ResultStatus
|
||||
|
||||
// 响应结果的数据
|
||||
Data interface{} `json:"Data,omitempty"`
|
||||
|
||||
// 响应结果对应的请求的方法名称
|
||||
MethodName string
|
||||
|
||||
// 压缩后的字节
|
||||
DataByte []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *ServerResponseObject) SetResultStatus(rs *ResultStatus) *ServerResponseObject {
|
||||
this.ResultStatus = rs
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ServerResponseObject) SetData(data interface{}) *ServerResponseObject {
|
||||
this.Data = data
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ServerResponseObject) SetMethodName(methodName string) *ServerResponseObject {
|
||||
this.MethodName = methodName
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ServerResponseObject) IsDisconnect() bool {
|
||||
return this.ResultStatus.Code == DisconnectStatus.Code
|
||||
}
|
||||
|
||||
// Compress
|
||||
//
|
||||
// @Description: 压缩数据
|
||||
// parameter:
|
||||
// receiver this
|
||||
// ifCompress
|
||||
// return:
|
||||
func (this *ServerResponseObject) Compress(ifCompress bool) {
|
||||
// 序列化发送的数据
|
||||
contentObj, _ := json.Marshal(this)
|
||||
|
||||
// 进行zlib压缩
|
||||
if ifCompress {
|
||||
contentObj, _ = zlibUtil.Compress(contentObj, zlib.DefaultCompression)
|
||||
}
|
||||
|
||||
//赋值
|
||||
this.DataByte = contentObj
|
||||
}
|
||||
|
||||
func NewServerResponseObject() *ServerResponseObject {
|
||||
return &ServerResponseObject{
|
||||
ResultStatus: Success,
|
||||
Data: nil,
|
||||
MethodName: "",
|
||||
}
|
||||
}
|
||||
|
||||
func NewDisconnectServerResponseObject() *ServerResponseObject {
|
||||
return &ServerResponseObject{
|
||||
ResultStatus: DisconnectStatus,
|
||||
Data: nil,
|
||||
MethodName: "",
|
||||
}
|
||||
}
|
||||
176
trunk/game/common/server_http/context.go
Normal file
176
trunk/game/common/server_http/context.go
Normal file
@ -0,0 +1,176 @@
|
||||
package server_http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"framework/ipMgr"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
. "common/model"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
// 请求上下文对象
|
||||
type Context struct {
|
||||
// 请求对象
|
||||
*http.Request
|
||||
|
||||
// 应答写对象
|
||||
http.ResponseWriter
|
||||
|
||||
// 请求数据
|
||||
requestBytes []byte
|
||||
|
||||
// 数据是否已经解析数据
|
||||
ifDataParsed bool
|
||||
|
||||
// Form的数据是否已经解析
|
||||
ifFormParsed bool
|
||||
}
|
||||
|
||||
// 检查IP是否合法
|
||||
func (this *Context) checkIP() *ResultStatus {
|
||||
if debugUtil.IsDebug() == false && ipMgr.IsIpValid(webUtil.GetRequestIP(this.Request)) == false {
|
||||
return InvalidIP
|
||||
}
|
||||
|
||||
return Success
|
||||
}
|
||||
|
||||
func (this *Context) GetFormValue(key string) (value string, exists bool) {
|
||||
defer func() {
|
||||
this.ifFormParsed = true
|
||||
}()
|
||||
|
||||
if !this.ifFormParsed {
|
||||
this.Request.ParseForm()
|
||||
}
|
||||
|
||||
values := this.Form[key]
|
||||
if values != nil && len(values) > 0 {
|
||||
value = values[0]
|
||||
exists = true
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 转换内容
|
||||
func (this *Context) parseContent() error {
|
||||
defer func() {
|
||||
this.Body.Close()
|
||||
this.ifDataParsed = true
|
||||
}()
|
||||
|
||||
data, err := ioutil.ReadAll(this.Body)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog("url:%s,读取数据出错,错误信息为:%s", this.RequestURI, err)
|
||||
return err
|
||||
}
|
||||
|
||||
this.requestBytes = data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取请求字节数据
|
||||
// 返回值:
|
||||
// []byte:请求字节数组
|
||||
// error:错误信息
|
||||
func (this *Context) GetRequestBytes(isCompressed bool) (result []byte, exists bool, err error) {
|
||||
if this.ifDataParsed == false {
|
||||
this.parseContent()
|
||||
}
|
||||
|
||||
data := this.requestBytes
|
||||
if data == nil || len(data) <= 0 {
|
||||
return
|
||||
} else {
|
||||
exists = true
|
||||
}
|
||||
|
||||
if isCompressed {
|
||||
result, err = zlibUtil.Decompress(data)
|
||||
if err != nil {
|
||||
logUtil.ErrorLog("解压缩请求数据失败:%s", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
result = data
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 获取请求字符串数据
|
||||
// 返回值:
|
||||
// 请求字符串数据
|
||||
func (this *Context) GetRequestString(isCompressed bool) (result string, exists bool, err error) {
|
||||
var data []byte
|
||||
data, exists, err = this.GetRequestBytes(isCompressed)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
result = string(data)
|
||||
exists = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Unmarshal 反序列化
|
||||
// moduleName:模块名称
|
||||
// obj:反序列化结果数据
|
||||
// isCompressed:数据是否已经被压缩
|
||||
// 返回值:
|
||||
// 错误对象
|
||||
func (this *Context) Unmarshal(moduleName string, obj interface{}, isCompressed bool) (exists bool, err error) {
|
||||
var data []byte
|
||||
data, exists, err = this.GetRequestBytes(isCompressed)
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
// 反序列化
|
||||
if err = json.Unmarshal(data, &obj); err != nil {
|
||||
logUtil.ErrorLog("Module:%s, 反序列化%s出错,错误信息为:%s", moduleName, string(data), err)
|
||||
return
|
||||
}
|
||||
|
||||
debugUtil.Printf("接收到GM登录数据data:%v", string(data))
|
||||
return
|
||||
}
|
||||
|
||||
// 输出字符串
|
||||
func (this *Context) WriteString(result string) {
|
||||
this.ResponseWriter.Write([]byte(result))
|
||||
}
|
||||
|
||||
// 输出json数据
|
||||
func (this *Context) WriteJson(result interface{}) {
|
||||
if bytes, err := json.Marshal(result); err == nil {
|
||||
this.ResponseWriter.Write(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到其它页面
|
||||
func (this *Context) RedirectTo(url string) {
|
||||
this.ResponseWriter.Header().Set("Location", url)
|
||||
this.ResponseWriter.WriteHeader(301)
|
||||
}
|
||||
|
||||
// 新建API上下文对象
|
||||
// request:请求对象
|
||||
// responseWriter:应答写对象
|
||||
// 返回值:
|
||||
// *Context:上下文
|
||||
func newContext(request *http.Request, responseWriter http.ResponseWriter) *Context {
|
||||
return &Context{
|
||||
Request: request,
|
||||
ResponseWriter: responseWriter,
|
||||
}
|
||||
}
|
||||
37
trunk/game/common/server_http/handlerMgr.go
Normal file
37
trunk/game/common/server_http/handlerMgr.go
Normal file
@ -0,0 +1,37 @@
|
||||
package server_http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "common/model"
|
||||
)
|
||||
|
||||
type Handler func(*Context) *ServerResponseObject
|
||||
|
||||
var (
|
||||
// 处理函数集合
|
||||
handlerMap map[string]Handler
|
||||
)
|
||||
|
||||
func init() {
|
||||
handlerMap = make(map[string]Handler, 8)
|
||||
}
|
||||
|
||||
// RegisterHandler 详细的注册一个WebAPI处理函数
|
||||
// pattern:路由地址
|
||||
// handler:处理函数
|
||||
// paramInfo:参数列表
|
||||
func RegisterHandler(pattern string, handler Handler) {
|
||||
if _, exist := handlerMap[pattern]; exist {
|
||||
panic(fmt.Errorf("存在重复的webapi注册:%s", pattern))
|
||||
}
|
||||
|
||||
// 添加处理对象
|
||||
handlerMap[pattern] = handler
|
||||
}
|
||||
|
||||
// 获取处理函数
|
||||
func getHandler(pattern string) (handler Handler, exists bool) {
|
||||
handler, exists = handlerMap[pattern]
|
||||
return
|
||||
}
|
||||
71
trunk/game/common/server_http/server.go
Normal file
71
trunk/game/common/server_http/server.go
Normal file
@ -0,0 +1,71 @@
|
||||
package server_http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
. "common/model"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
"goutil/webUtil"
|
||||
)
|
||||
|
||||
// http服务对象
|
||||
type httpServer struct{}
|
||||
|
||||
// http应答处理
|
||||
// response:应答对象
|
||||
// request:请求对象
|
||||
func (this *httpServer) ServeHTTP(response http.ResponseWriter, request *http.Request) {
|
||||
context := newContext(request, response)
|
||||
responseObj := NewServerResponseObject()
|
||||
|
||||
defer func() {
|
||||
if data := recover(); data != nil {
|
||||
logUtil.LogUnknownError(data)
|
||||
return
|
||||
}
|
||||
|
||||
// 特殊路径进行特别处理
|
||||
if request.URL.Path == "/" || request.URL.Path == "/favicon.ico" {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取输入参数的字符串形式
|
||||
parameter := ""
|
||||
if len(request.Form) > 0 {
|
||||
parameter_byte, _ := json.Marshal(request.Form)
|
||||
parameter = string(parameter_byte)
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
if debugUtil.IsDebug() || responseObj.ResultStatus != Success {
|
||||
result, _ := json.Marshal(responseObj)
|
||||
logUtil.DebugLog("%s-->IP:%s;Request:%v;Response:%s;", request.URL.Path, webUtil.GetRequestIP(request), parameter, string(result))
|
||||
}
|
||||
}()
|
||||
|
||||
// 特殊路径进行特别处理
|
||||
if request.URL.Path == "/" || request.URL.Path == "/favicon.ico" {
|
||||
context.WriteString("ok")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证IP
|
||||
if rs := context.checkIP(); rs != Success {
|
||||
context.WriteJson(responseObj.SetResultStatus(rs))
|
||||
return
|
||||
}
|
||||
|
||||
var handler Handler
|
||||
var exists bool
|
||||
if handler, exists = getHandler(request.URL.Path); !exists {
|
||||
logUtil.ErrorLog("访问的页面不存在,RequestAddr: %s request.URL.Path: %s", request.RemoteAddr, request.URL.Path)
|
||||
http.Error(response, "访问的页面不存在", 404)
|
||||
return
|
||||
}
|
||||
|
||||
// 调用处理方法,并返回结果
|
||||
responseObj = handler(context)
|
||||
context.WriteJson(responseObj)
|
||||
}
|
||||
44
trunk/game/common/server_http/start.go
Normal file
44
trunk/game/common/server_http/start.go
Normal file
@ -0,0 +1,44 @@
|
||||
package server_http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 启动Web服务器
|
||||
// wg:WaitGroup对象
|
||||
// address:服务器地址
|
||||
func Start(wg *sync.WaitGroup, address string) {
|
||||
defer func() {
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
//// 开启服务
|
||||
//serverInstance := http.Server{
|
||||
// Addr: address,
|
||||
// Handler: new(httpServer),
|
||||
//}
|
||||
|
||||
//// 开启监听
|
||||
//msg := fmt.Sprintf("server_http begins to listen on: %s...", address)
|
||||
//fmt.Println(msg)
|
||||
//logUtil.InfoLog(msg)
|
||||
|
||||
// 启动Web服务器监听
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/", &httpServer{})
|
||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
if err := http.ListenAndServe(address, mux); err != nil {
|
||||
panic(fmt.Sprintf("server_http ListenAndServe Error:%v", err))
|
||||
}
|
||||
//if err := serverInstance.ListenAndServe(); err != nil {
|
||||
// panic(fmt.Sprintf("server_http ListenAndServe Error:%v", err))
|
||||
//}
|
||||
}
|
||||
347
trunk/game/common/server_tcp/client.go
Normal file
347
trunk/game/common/server_tcp/client.go
Normal file
@ -0,0 +1,347 @@
|
||||
package server_tcp
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"common/clientMgr"
|
||||
"common/config"
|
||||
. "common/model"
|
||||
"framework/goroutineMgr"
|
||||
"goutil/intAndBytesUtil"
|
||||
"goutil/logUtil"
|
||||
"goutil/timeUtil"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
const (
|
||||
// 包头的长度
|
||||
con_HEADER_LENGTH = 4
|
||||
|
||||
// 客户端失效的秒数
|
||||
con_CLIENT_EXPIRE_SECONDS int64 = 300
|
||||
)
|
||||
|
||||
var (
|
||||
// 全局客户端的id,从1开始进行自增
|
||||
globalClientId int32 = 0
|
||||
|
||||
// 字节的大小端顺序
|
||||
byterOrder = binary.LittleEndian
|
||||
)
|
||||
|
||||
// 定义客户端对象,以实现对客户端连接的封装
|
||||
type Client struct {
|
||||
// 唯一标识
|
||||
id int32
|
||||
|
||||
// 客户端连接对象
|
||||
conn net.Conn
|
||||
|
||||
// 接收到的消息内容
|
||||
receiveData []byte
|
||||
|
||||
// 待发送的数据
|
||||
sendData []*ServerResponseObject
|
||||
|
||||
// 连接是否关闭(通过此字段来协调receiveData和sendData方法)
|
||||
closed bool
|
||||
|
||||
// 锁对象(用于控制对sendDatap的并发访问;receiveData不需要,因为是同步访问)
|
||||
mutex sync.Mutex
|
||||
|
||||
// 玩家Id
|
||||
playerId int64
|
||||
|
||||
// 上次活跃时间
|
||||
activeTime int64
|
||||
}
|
||||
|
||||
// 获取唯一标识
|
||||
func (this *Client) GetId() int32 {
|
||||
return this.id
|
||||
}
|
||||
|
||||
// 获取玩家Id
|
||||
// 返回值:
|
||||
// 玩家Id
|
||||
func (this *Client) GetPlayerId() int64 {
|
||||
return this.playerId
|
||||
}
|
||||
|
||||
// 玩家登陆
|
||||
// playerId:玩家Id
|
||||
// 返回值:无
|
||||
func (this *Client) PlayerLogin(playerId int64) {
|
||||
this.playerId = playerId
|
||||
}
|
||||
|
||||
// 获取远程地址(IP_Port)
|
||||
func (this *Client) GetRemoteAddr() string {
|
||||
items := strings.Split(this.conn.RemoteAddr().String(), ":")
|
||||
|
||||
return fmt.Sprintf("%s_%s", items[0], items[1])
|
||||
}
|
||||
|
||||
// 获取远程地址(IP)
|
||||
func (this *Client) getRemoteShortAddr() string {
|
||||
items := strings.Split(this.conn.RemoteAddr().String(), ":")
|
||||
|
||||
return items[0]
|
||||
}
|
||||
|
||||
// 获取待发送的数据
|
||||
// 返回值:
|
||||
// 待发送数据项
|
||||
// 是否含有有效数据
|
||||
func (this *Client) getSendData() (responseObj *ServerResponseObject, exists bool) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
// 如果没有数据则直接返回
|
||||
if len(this.sendData) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 取出第一条数据,并为返回值赋值
|
||||
responseObj = this.sendData[0]
|
||||
exists = true
|
||||
|
||||
// 删除已经取出的数据
|
||||
this.sendData = this.sendData[1:]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 发送数据
|
||||
// sendDataItemObj:待发送数据项
|
||||
// 返回值:无
|
||||
func (this *Client) SendMessage(responseObj *ServerResponseObject) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.sendData = append(this.sendData, responseObj)
|
||||
}
|
||||
|
||||
// 清空待发送数据
|
||||
func (this *Client) ClearSendData() {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.sendData = make([]*ServerResponseObject, 0, 16)
|
||||
}
|
||||
|
||||
// 发送字节数组消息
|
||||
// responseObj:返回值对象
|
||||
func (this *Client) sendResponseObject(responseObj *ServerResponseObject) error {
|
||||
beforeTime := time.Now().Unix()
|
||||
|
||||
// 序列化发送的数据
|
||||
content, _ := json.Marshal(responseObj)
|
||||
|
||||
// 进行zlib压缩
|
||||
if config.GetBaseConfig().IfCompressData {
|
||||
content, _ = zlibUtil.Compress(content, zlib.DefaultCompression)
|
||||
}
|
||||
|
||||
// 获得数据内容的长度
|
||||
contentLength := len(content)
|
||||
|
||||
// 将长度转化为字节数组
|
||||
header := intAndBytesUtil.Int32ToBytes(int32(contentLength), byterOrder)
|
||||
|
||||
// 将头部与内容组合在一起
|
||||
message := append(header, content...)
|
||||
|
||||
// 发送消息
|
||||
if err := this.sendMessage(message); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果发送的时间超过3秒,则记录下来
|
||||
if time.Now().Unix()-beforeTime > 3 {
|
||||
logUtil.WarnLog("消息Size:%d, UseTime:%d", contentLength, time.Now().Unix()-beforeTime)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Client) sendMessage(message []byte) error {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
if _, err := this.conn.Write(message); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 客户端活跃
|
||||
// 返回值:无
|
||||
func (this *Client) Active() {
|
||||
atomic.StoreInt64(&this.activeTime, time.Now().Unix())
|
||||
}
|
||||
|
||||
// 判断客户端是否超时(超过300秒不活跃算作超时)
|
||||
// 返回值:是否超时
|
||||
func (this *Client) Expired() bool {
|
||||
return time.Now().Unix() > this.activeTime+con_CLIENT_EXPIRE_SECONDS
|
||||
}
|
||||
|
||||
// 客户端连接对象断开
|
||||
// 返回值:无
|
||||
func (this *Client) Close() {
|
||||
this.conn.Close()
|
||||
this.closed = true
|
||||
this.playerId = 0
|
||||
}
|
||||
|
||||
// 格式化
|
||||
func (this *Client) String() string {
|
||||
return fmt.Sprintf("{Id:%d, RemoteAddr:%s, activeTime:%s, playerId:%s}", this.id, this.GetRemoteAddr(), timeUtil.Format(time.Unix(this.activeTime, 0), "yyyy-MM-dd HH:mm:ss"), this.playerId)
|
||||
}
|
||||
|
||||
// -----------------------------实现IConnection接口方法end-------------------------
|
||||
|
||||
// 客户端启动函数
|
||||
func (this *Client) start() {
|
||||
go this.handleReceiveData()
|
||||
go this.handleSendData()
|
||||
}
|
||||
|
||||
// 获取有效的消息
|
||||
// 返回值:
|
||||
// 消息内容
|
||||
// 是否含有有效数据
|
||||
func (this *Client) getReceiveData() (message []byte, exists bool) {
|
||||
// 判断是否包含头部信息
|
||||
if len(this.receiveData) < con_HEADER_LENGTH {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取头部信息
|
||||
header := this.receiveData[:con_HEADER_LENGTH]
|
||||
|
||||
// 将头部数据转换为内部的长度
|
||||
contentLength := intAndBytesUtil.BytesToInt32(header, byterOrder)
|
||||
|
||||
// 约定len(message) == 0,为心跳请求
|
||||
if contentLength == 0 {
|
||||
// 将对应的数据截断,以得到新的内容,并返回心跳内容
|
||||
this.receiveData = this.receiveData[con_HEADER_LENGTH:]
|
||||
if err := this.sendMessage([]byte{}); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 判断长度是否满足
|
||||
if len(this.receiveData) < con_HEADER_LENGTH+int(contentLength) {
|
||||
return
|
||||
}
|
||||
|
||||
// 提取消息内容
|
||||
message = this.receiveData[con_HEADER_LENGTH : con_HEADER_LENGTH+contentLength]
|
||||
exists = true
|
||||
|
||||
// 将对应的数据截断,以得到新的数据
|
||||
this.receiveData = this.receiveData[con_HEADER_LENGTH+contentLength:]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 处理客户端收到的数据
|
||||
func (this *Client) handleReceiveData() {
|
||||
// 处理goroutine数量
|
||||
goroutineName := "server_tcp.handleReceiveData"
|
||||
goroutineMgr.MonitorZero(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
defer clientMgr.Disconnect(this)
|
||||
|
||||
// 无限循环,不断地读取数据,解析数据,处理数据
|
||||
for {
|
||||
if this.closed {
|
||||
break
|
||||
}
|
||||
|
||||
// 先读取数据,每次读取1024个字节
|
||||
readBytes := make([]byte, 2048*2)
|
||||
|
||||
// Read方法会阻塞,所以不用考虑异步的方式
|
||||
n, err := this.conn.Read(readBytes)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// 将读取到的数据追加到已获得的数据的末尾,并更新activeTime
|
||||
this.receiveData = append(this.receiveData, readBytes[:n]...)
|
||||
this.Active()
|
||||
|
||||
// 处理数据
|
||||
for {
|
||||
message, exists := this.getReceiveData()
|
||||
if !exists {
|
||||
break
|
||||
}
|
||||
|
||||
clientMgr.HandleRequest(this, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理需要客户端发送的数据
|
||||
func (this *Client) handleSendData() {
|
||||
// 处理goroutine数量
|
||||
goroutineName := "server_tcp.handleSendData"
|
||||
goroutineMgr.MonitorZero(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
defer clientMgr.Disconnect(this)
|
||||
|
||||
for {
|
||||
if this.closed {
|
||||
break
|
||||
}
|
||||
|
||||
// 如果发送出现错误,表示连接已经断开,则退出方法;
|
||||
if sendDataItemObj, exists := this.getSendData(); exists {
|
||||
// 判断是否为断开客户端连接的数据
|
||||
if sendDataItemObj.IsDisconnect() {
|
||||
break
|
||||
}
|
||||
|
||||
if err := this.sendResponseObject(sendDataItemObj); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新建客户端对象
|
||||
// conn:连接对象
|
||||
// 返回值:客户端对象的指针
|
||||
func newClient(conn net.Conn) *Client {
|
||||
// 获得自增的id值
|
||||
getIncrementId := func() int32 {
|
||||
atomic.AddInt32(&globalClientId, 1)
|
||||
return globalClientId
|
||||
}
|
||||
|
||||
return &Client{
|
||||
id: getIncrementId(),
|
||||
conn: conn,
|
||||
receiveData: make([]byte, 0, 2048*2),
|
||||
sendData: make([]*ServerResponseObject, 0, 16),
|
||||
activeTime: time.Now().Unix(),
|
||||
playerId: 0,
|
||||
}
|
||||
}
|
||||
55
trunk/game/common/server_tcp/start.go
Normal file
55
trunk/game/common/server_tcp/start.go
Normal file
@ -0,0 +1,55 @@
|
||||
package server_tcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"framework/goroutineMgr"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"goutil/debugUtil"
|
||||
|
||||
"common/clientMgr"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
// Start 启动服务器
|
||||
func Start(wg *sync.WaitGroup, address string) {
|
||||
defer func() {
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
// 处理goroutine数量
|
||||
goroutineName := "server_tcp.Start"
|
||||
goroutineMgr.Monitor(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
|
||||
msg := fmt.Sprintf("server_tcp begins to listen on:%s...", address)
|
||||
fmt.Println(msg)
|
||||
logUtil.InfoLog(msg)
|
||||
|
||||
// 监听指定的端口
|
||||
listener, err := net.Listen("tcp", address)
|
||||
|
||||
//debug模式下打印日志
|
||||
if debugUtil.IsDebug() {
|
||||
logUtil.DebugLog(fmt.Sprintf("收到客户的连接请求,ip:%v", listener.Addr()))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("server_tcp listen Error: %s", err))
|
||||
}
|
||||
|
||||
for {
|
||||
// 阻塞直至新连接到来
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
logUtil.ErrorLog("server_tcp accept error: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 创建客户端对象
|
||||
clientObj := newClient(conn)
|
||||
clientObj.start()
|
||||
clientMgr.RegisterClient(clientObj)
|
||||
}
|
||||
}
|
||||
302
trunk/game/common/server_webSocket/client.go
Normal file
302
trunk/game/common/server_webSocket/client.go
Normal file
@ -0,0 +1,302 @@
|
||||
package server_webSocket
|
||||
|
||||
import (
|
||||
"common/clientMgr"
|
||||
"common/config"
|
||||
"common/model"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"framework/goroutineMgr"
|
||||
"github.com/gorilla/websocket"
|
||||
"goutil/logUtil"
|
||||
"goutil/timeUtil"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// 消息每次读取的上限值
|
||||
con_MaxMessageSize = 2048 * 2
|
||||
|
||||
// 客户端失效的秒数
|
||||
con_CLIENT_EXPIRE_SECONDS = 20
|
||||
)
|
||||
|
||||
var (
|
||||
// 全局客户端的id,从1开始进行自增
|
||||
globalClientId int32 = 0
|
||||
|
||||
// 字节的大小端顺序
|
||||
byterOrder = binary.LittleEndian
|
||||
)
|
||||
|
||||
// Client 实现IConnection接口的所有方法
|
||||
// 定义客户端对象,以实现对客户端连接的封装
|
||||
type Client struct {
|
||||
// 唯一标识
|
||||
id int32
|
||||
|
||||
// The websocket connection.
|
||||
conn *websocket.Conn
|
||||
|
||||
// 接收到的消息内容
|
||||
receiveData []byte
|
||||
|
||||
// 待发送的数据
|
||||
sendData []*model.ServerResponseObject
|
||||
|
||||
// 连接是否关闭(通过此字段来协调receiveData和sendData方法)
|
||||
closed bool
|
||||
|
||||
// 锁对象(用于控制对sendDatap的并发访问;receiveData不需要,因为是同步访问)
|
||||
mutex sync.Mutex
|
||||
|
||||
// 玩家Id
|
||||
playerId int64
|
||||
|
||||
// 上次活跃时间
|
||||
activeTime int64
|
||||
}
|
||||
|
||||
// 获取唯一标识
|
||||
func (this *Client) GetId() int32 {
|
||||
return this.id
|
||||
}
|
||||
|
||||
// 获取玩家Id
|
||||
// 返回值:
|
||||
// 玩家Id
|
||||
func (this *Client) GetPlayerId() int64 {
|
||||
return this.playerId
|
||||
}
|
||||
|
||||
// 玩家登陆
|
||||
// playerId:玩家Id
|
||||
// 返回值:无
|
||||
func (this *Client) PlayerLogin(playerId int64) {
|
||||
this.playerId = playerId
|
||||
}
|
||||
|
||||
// 获取远程地址(IP_Port)
|
||||
func (this *Client) GetRemoteAddr() string {
|
||||
items := strings.Split(this.conn.RemoteAddr().String(), ":")
|
||||
|
||||
return fmt.Sprintf("%s_%s", items[0], items[1])
|
||||
}
|
||||
|
||||
// 获取远程地址(IP)
|
||||
func (this *Client) getRemoteShortAddr() string {
|
||||
items := strings.Split(this.conn.RemoteAddr().String(), ":")
|
||||
|
||||
return items[0]
|
||||
}
|
||||
|
||||
// 获取待发送的数据
|
||||
// 返回值:
|
||||
// 待发送数据项
|
||||
// 是否含有有效数据
|
||||
func (this *Client) getSendData() (responseObj *model.ServerResponseObject, exists bool) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
// 如果没有数据则直接返回
|
||||
if len(this.sendData) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 取出第一条数据,并为返回值赋值
|
||||
responseObj = this.sendData[0]
|
||||
exists = true
|
||||
|
||||
// 删除已经取出的数据
|
||||
this.sendData = this.sendData[1:]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 发送数据
|
||||
// sendDataItemObj:待发送数据项
|
||||
// 返回值:无
|
||||
func (this *Client) SendMessage(responseObj *model.ServerResponseObject) {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.sendData = append(this.sendData, responseObj)
|
||||
}
|
||||
|
||||
// 清空待发送数据
|
||||
func (this *Client) ClearSendData() {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
this.sendData = make([]*model.ServerResponseObject, 0, 16)
|
||||
}
|
||||
|
||||
// 向客户端发送消息
|
||||
// responseObj:返回值对象
|
||||
func (this *Client) sendResponseObject(responseObj *model.ServerResponseObject) error {
|
||||
beforeTime := time.Now().Unix()
|
||||
|
||||
//// 序列化发送的数据
|
||||
//content, _ := json.Marshal(responseObj)
|
||||
//
|
||||
////debug模式下打印日志
|
||||
//if debugUtil.IsDebug() {
|
||||
//
|
||||
// //记录日志,方便查询
|
||||
// logUtil.WarnLog("向客户端发送消息%v", string(content))
|
||||
//}
|
||||
//
|
||||
//// 进行zlib压缩
|
||||
//if config.GetBaseConfig().IfCompressData {
|
||||
// content, _ = zlibUtil.Compress(content, zlib.DefaultCompression)
|
||||
//}
|
||||
|
||||
//检查是否需要压缩
|
||||
if len(responseObj.DataByte) <= 0 {
|
||||
responseObj.Compress(config.GetBaseConfig().IfCompressData)
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
if err := this.sendMessage(responseObj.DataByte); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果发送的时间超过3秒,则记录下来
|
||||
if time.Now().Unix()-beforeTime > 3 {
|
||||
logUtil.WarnLog("消息Size:%d, UseTime:%d", len(responseObj.DataByte), time.Now().Unix()-beforeTime)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Client) sendMessage(message []byte) error {
|
||||
this.mutex.Lock()
|
||||
defer this.mutex.Unlock()
|
||||
|
||||
if err := this.conn.WriteMessage(websocket.BinaryMessage, message); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 客户端活跃
|
||||
// 返回值:无
|
||||
func (this *Client) Active() {
|
||||
atomic.StoreInt64(&this.activeTime, time.Now().Unix())
|
||||
}
|
||||
|
||||
// 判断客户端是否超时(超过300秒不活跃算作超时)
|
||||
// 返回值:是否超时
|
||||
func (this *Client) Expired() bool {
|
||||
return time.Now().Unix() > this.activeTime+con_CLIENT_EXPIRE_SECONDS
|
||||
}
|
||||
|
||||
// 客户端连接对象断开
|
||||
// 返回值:无
|
||||
func (this *Client) Close() {
|
||||
this.conn.Close()
|
||||
this.closed = true
|
||||
this.playerId = 0
|
||||
}
|
||||
|
||||
// 格式化
|
||||
func (this *Client) String() string {
|
||||
return fmt.Sprintf("{Id:%d, RemoteAddr:%s, activeTime:%s, playerId:%s}", this.id, this.GetRemoteAddr(), timeUtil.Format(time.Unix(this.activeTime, 0), "yyyy-MM-dd HH:mm:ss"), this.playerId)
|
||||
}
|
||||
|
||||
// -----------------------------实现IConnection接口方法end-------------------------
|
||||
|
||||
// 客户端启动函数
|
||||
func (this *Client) start() {
|
||||
go this.handleReceiveData()
|
||||
go this.handleSendData()
|
||||
}
|
||||
|
||||
// 处理从连接收到的数据
|
||||
func (this *Client) handleReceiveData() {
|
||||
// 处理goroutine数量
|
||||
goroutineName := "server_webSocket.handleSendData"
|
||||
goroutineMgr.MonitorZero(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
defer clientMgr.Disconnect(this)
|
||||
|
||||
// 无限循环,不断地读取数据,解析数据,处理数据
|
||||
for {
|
||||
if this.closed {
|
||||
break
|
||||
}
|
||||
_, message, err := this.conn.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// 更新activeTime
|
||||
this.Active()
|
||||
|
||||
// 约定len(message) == 0,为心跳请求
|
||||
if len(message) == 0 {
|
||||
if err := this.sendMessage([]byte{}); err != nil {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
clientMgr.HandleRequest(this, message)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理向客户端发送的数据
|
||||
func (this *Client) handleSendData() {
|
||||
// 处理goroutine数量
|
||||
goroutineName := "server_webSocket.handleSendData"
|
||||
goroutineMgr.MonitorZero(goroutineName)
|
||||
defer goroutineMgr.ReleaseMonitor(goroutineName)
|
||||
defer clientMgr.Disconnect(this)
|
||||
|
||||
for {
|
||||
if this.closed {
|
||||
break
|
||||
}
|
||||
|
||||
// 如果发送出现错误,表示连接已经断开,则退出方法;
|
||||
if sendDataItemObj, exists := this.getSendData(); exists {
|
||||
|
||||
// 判断是否为断开客户端连接的数据
|
||||
if sendDataItemObj.IsDisconnect() {
|
||||
break
|
||||
}
|
||||
|
||||
if err := this.sendResponseObject(sendDataItemObj); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新建客户端对象
|
||||
// conn:连接对象
|
||||
// 返回值:客户端对象的指针
|
||||
func newClient(conn *websocket.Conn) *Client {
|
||||
conn.SetReadLimit(con_MaxMessageSize)
|
||||
|
||||
// 获得自增的id值
|
||||
getIncrementId := func() int32 {
|
||||
atomic.AddInt32(&globalClientId, 1)
|
||||
return globalClientId
|
||||
}
|
||||
|
||||
return &Client{
|
||||
id: getIncrementId(),
|
||||
conn: conn,
|
||||
receiveData: make([]byte, 0, 1024),
|
||||
sendData: make([]*model.ServerResponseObject, 0, 16),
|
||||
activeTime: time.Now().Unix(),
|
||||
playerId: 0,
|
||||
}
|
||||
}
|
||||
63
trunk/game/common/server_webSocket/start.go
Normal file
63
trunk/game/common/server_webSocket/start.go
Normal file
@ -0,0 +1,63 @@
|
||||
package server_webSocket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"common/clientMgr"
|
||||
"github.com/gorilla/websocket"
|
||||
"goutil/debugUtil"
|
||||
"goutil/logUtil"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
func handleConn(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
|
||||
//是否debug模式
|
||||
if debugUtil.IsDebug() {
|
||||
logUtil.DebugLog(fmt.Sprintf("收到客户的websockte连接,ip%v", conn.RemoteAddr()))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logUtil.ErrorLog("websocket.handleConn获取连接出错,err:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建客户端对象
|
||||
clientObj := newClient(conn)
|
||||
clientObj.start()
|
||||
clientMgr.RegisterClient(clientObj)
|
||||
|
||||
debugUtil.Printf("收到连接请求:remoteAdd:%s\n", conn.RemoteAddr())
|
||||
}
|
||||
|
||||
// Start 启动服务器
|
||||
func Start(wg *sync.WaitGroup, address string, isUseTSL bool) {
|
||||
defer wg.Done()
|
||||
|
||||
msg := fmt.Sprintf("server_websocket begins to listen on:%s...", address)
|
||||
fmt.Println(msg)
|
||||
logUtil.InfoLog(msg)
|
||||
|
||||
http.HandleFunc("/", handleConn)
|
||||
if isUseTSL {
|
||||
err := http.ListenAndServeTLS(address, "tlsFile/7qule.com.pem", "tlsFile/7qule.com.key", nil)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("server_websocket.ListenAndServeTLS, err:%v", err))
|
||||
}
|
||||
} else {
|
||||
err := http.ListenAndServe(address, nil)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("server_websocket.ListenAndServe, err:%v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user