diff --git a/trunk/.idea/workspace.xml b/trunk/.idea/workspace.xml
index f8b2a94..468d5a6 100644
--- a/trunk/.idea/workspace.xml
+++ b/trunk/.idea/workspace.xml
@@ -4,7 +4,16 @@
-
+
+
+
+
+
+
+
+
+
+
@@ -30,40 +39,47 @@
"associatedIndex": 3
}
+
+
+
- {
- "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"
+
+}]]>
+
+
-
+
@@ -73,13 +89,26 @@
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -119,10 +148,11 @@
-
+
+
-
+
diff --git a/trunk/center/admincenter/adminServer b/trunk/center/admincenter/adminServer
new file mode 100644
index 0000000..f47f512
Binary files /dev/null and b/trunk/center/admincenter/adminServer differ
diff --git a/trunk/center/admincenter/config.yaml b/trunk/center/admincenter/config.yaml
index 4c079f0..1f8a4bf 100644
--- a/trunk/center/admincenter/config.yaml
+++ b/trunk/center/admincenter/config.yaml
@@ -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:
# 数据库连接字符串
diff --git a/trunk/center/common/configsYaml/baseConfig.go b/trunk/center/common/configsYaml/baseConfig.go
index 5406694..eedee43 100644
--- a/trunk/center/common/configsYaml/baseConfig.go
+++ b/trunk/center/common/configsYaml/baseConfig.go
@@ -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
}
diff --git a/trunk/center/common/configsYaml/configYaml.go b/trunk/center/common/configsYaml/configYaml.go
index 92f9c08..0d3d548 100644
--- a/trunk/center/common/configsYaml/configYaml.go
+++ b/trunk/center/common/configsYaml/configYaml.go
@@ -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"`
diff --git a/trunk/center/common/connection/dal.go b/trunk/center/common/connection/dal.go
index e356fe5..82cdef5 100644
--- a/trunk/center/common/connection/dal.go
+++ b/trunk/center/common/connection/dal.go
@@ -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
}
diff --git a/trunk/center/common/go.mod b/trunk/center/common/go.mod
index 871d1fd..e70fe32 100644
--- a/trunk/center/common/go.mod
+++ b/trunk/center/common/go.mod
@@ -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
diff --git a/trunk/center/common/go.sum b/trunk/center/common/go.sum
index eb50995..62ebb4b 100644
--- a/trunk/center/common/go.sum
+++ b/trunk/center/common/go.sum
@@ -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=
diff --git a/trunk/center/common/rebbitMQ/config.go b/trunk/center/common/rebbitMQ/config.go
new file mode 100644
index 0000000..b3d4ed0
--- /dev/null
+++ b/trunk/center/common/rebbitMQ/config.go
@@ -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())
+ }
+}
diff --git a/trunk/center/common/rebbitMQ/sendData.go b/trunk/center/common/rebbitMQ/sendData.go
new file mode 100644
index 0000000..1618ed7
--- /dev/null
+++ b/trunk/center/common/rebbitMQ/sendData.go
@@ -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())
+ }
+}
diff --git a/trunk/center/dbcenter/01_test.go b/trunk/center/dbcenter/01_test.go
new file mode 100644
index 0000000..1e6ee57
--- /dev/null
+++ b/trunk/center/dbcenter/01_test.go
@@ -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)
+}
diff --git a/trunk/center/dbcenter/go.mod b/trunk/center/dbcenter/go.mod
new file mode 100644
index 0000000..1038662
--- /dev/null
+++ b/trunk/center/dbcenter/go.mod
@@ -0,0 +1,5 @@
+module dbcenter
+
+go 1.22.10
+
+require github.com/streadway/amqp v1.1.0 // indirect
diff --git a/trunk/center/dbcenter/go.sum b/trunk/center/dbcenter/go.sum
new file mode 100644
index 0000000..322c16d
--- /dev/null
+++ b/trunk/center/dbcenter/go.sum
@@ -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=
diff --git a/trunk/center/dbcenter/main.go b/trunk/center/dbcenter/main.go
new file mode 100644
index 0000000..7905807
--- /dev/null
+++ b/trunk/center/dbcenter/main.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+
+}
diff --git a/trunk/center/paycenter/internal/pay/logic.go b/trunk/center/paycenter/internal/pay/logic.go
index 9840a47..b4a8431 100644
--- a/trunk/center/paycenter/internal/pay/logic.go
+++ b/trunk/center/paycenter/internal/pay/logic.go
@@ -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
}
diff --git a/trunk/game/common/clientMgr/clientMgr.go b/trunk/game/common/clientMgr/clientMgr.go
new file mode 100644
index 0000000..036bf68
--- /dev/null
+++ b/trunk/game/common/clientMgr/clientMgr.go
@@ -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)
+}
diff --git a/trunk/game/common/clientMgr/expire.go b/trunk/game/common/clientMgr/expire.go
new file mode 100644
index 0000000..d1794fc
--- /dev/null
+++ b/trunk/game/common/clientMgr/expire.go
@@ -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)
+ }
+}
diff --git a/trunk/game/common/clientMgr/handleRequest.go b/trunk/game/common/clientMgr/handleRequest.go
new file mode 100644
index 0000000..52303c8
--- /dev/null
+++ b/trunk/game/common/clientMgr/handleRequest.go
@@ -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)
+}
diff --git a/trunk/game/common/clientMgr/interface.go b/trunk/game/common/clientMgr/interface.go
new file mode 100644
index 0000000..289bf04
--- /dev/null
+++ b/trunk/game/common/clientMgr/interface.go
@@ -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()
+}
diff --git a/trunk/game/common/clientMgr/reflect_method.go b/trunk/game/common/clientMgr/reflect_method.go
new file mode 100644
index 0000000..5962081
--- /dev/null
+++ b/trunk/game/common/clientMgr/reflect_method.go
@@ -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,
+ }
+}
diff --git a/trunk/game/common/clientMgr/reflect_mgr.go b/trunk/game/common/clientMgr/reflect_mgr.go
new file mode 100644
index 0000000..e98a112
--- /dev/null
+++ b/trunk/game/common/clientMgr/reflect_mgr.go
@@ -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
+}
diff --git a/trunk/game/common/config/baseConfig.go b/trunk/game/common/config/baseConfig.go
new file mode 100644
index 0000000..3eadf2d
--- /dev/null
+++ b/trunk/game/common/config/baseConfig.go
@@ -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
+}
diff --git a/trunk/game/common/config/config.go b/trunk/game/common/config/config.go
new file mode 100644
index 0000000..5b37b5f
--- /dev/null
+++ b/trunk/game/common/config/config.go
@@ -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
+}
diff --git a/trunk/game/common/config/dbConfig.go b/trunk/game/common/config/dbConfig.go
new file mode 100644
index 0000000..880ac09
--- /dev/null
+++ b/trunk/game/common/config/dbConfig.go
@@ -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
+}
diff --git a/trunk/game/common/config/monitorConfig.go b/trunk/game/common/config/monitorConfig.go
new file mode 100644
index 0000000..b4d1ce1
--- /dev/null
+++ b/trunk/game/common/config/monitorConfig.go
@@ -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
+}
diff --git a/trunk/game/common/go.mod b/trunk/game/common/go.mod
new file mode 100644
index 0000000..a933041
--- /dev/null
+++ b/trunk/game/common/go.mod
@@ -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
+)
\ No newline at end of file
diff --git a/trunk/game/common/go.sum b/trunk/game/common/go.sum
new file mode 100644
index 0000000..ec82fc1
--- /dev/null
+++ b/trunk/game/common/go.sum
@@ -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=
diff --git a/trunk/game/common/model/resultStatus.go b/trunk/game/common/model/resultStatus.go
new file mode 100644
index 0000000..c4b01f5
--- /dev/null
+++ b/trunk/game/common/model/resultStatus.go
@@ -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, "内容中含有屏蔽词语")
+)
diff --git a/trunk/game/common/model/serverRequestObject.go b/trunk/game/common/model/serverRequestObject.go
new file mode 100644
index 0000000..ba95489
--- /dev/null
+++ b/trunk/game/common/model/serverRequestObject.go
@@ -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
+}
diff --git a/trunk/game/common/model/serverResponseData.go b/trunk/game/common/model/serverResponseData.go
new file mode 100644
index 0000000..0dc5218
--- /dev/null
+++ b/trunk/game/common/model/serverResponseData.go
@@ -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,
+ }
+}
diff --git a/trunk/game/common/model/serverResponseObject.go b/trunk/game/common/model/serverResponseObject.go
new file mode 100644
index 0000000..fb9245e
--- /dev/null
+++ b/trunk/game/common/model/serverResponseObject.go
@@ -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: "",
+ }
+}
diff --git a/trunk/game/common/server_http/context.go b/trunk/game/common/server_http/context.go
new file mode 100644
index 0000000..4acdac9
--- /dev/null
+++ b/trunk/game/common/server_http/context.go
@@ -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,
+ }
+}
diff --git a/trunk/game/common/server_http/handlerMgr.go b/trunk/game/common/server_http/handlerMgr.go
new file mode 100644
index 0000000..98a4341
--- /dev/null
+++ b/trunk/game/common/server_http/handlerMgr.go
@@ -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
+}
diff --git a/trunk/game/common/server_http/server.go b/trunk/game/common/server_http/server.go
new file mode 100644
index 0000000..7702687
--- /dev/null
+++ b/trunk/game/common/server_http/server.go
@@ -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)
+}
diff --git a/trunk/game/common/server_http/start.go b/trunk/game/common/server_http/start.go
new file mode 100644
index 0000000..9ca57ab
--- /dev/null
+++ b/trunk/game/common/server_http/start.go
@@ -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))
+ //}
+}
diff --git a/trunk/game/common/server_tcp/client.go b/trunk/game/common/server_tcp/client.go
new file mode 100644
index 0000000..26ff187
--- /dev/null
+++ b/trunk/game/common/server_tcp/client.go
@@ -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,
+ }
+}
diff --git a/trunk/game/common/server_tcp/start.go b/trunk/game/common/server_tcp/start.go
new file mode 100644
index 0000000..f9c01e4
--- /dev/null
+++ b/trunk/game/common/server_tcp/start.go
@@ -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)
+ }
+}
diff --git a/trunk/game/common/server_webSocket/client.go b/trunk/game/common/server_webSocket/client.go
new file mode 100644
index 0000000..de3f65d
--- /dev/null
+++ b/trunk/game/common/server_webSocket/client.go
@@ -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,
+ }
+}
diff --git a/trunk/game/common/server_webSocket/start.go b/trunk/game/common/server_webSocket/start.go
new file mode 100644
index 0000000..7c67339
--- /dev/null
+++ b/trunk/game/common/server_webSocket/start.go
@@ -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))
+ }
+ }
+}