初始化项目

This commit is contained in:
皮蛋13361098506 2025-01-06 16:01:02 +08:00
commit 1b77f62820
575 changed files with 69193 additions and 0 deletions

149
trunk/.idea/workspace.xml Normal file
View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="ALL" />
</component>
<component name="ChangeListManager">
<list default="true" id="2037df1b-9ccc-4caa-9145-2d6722712612" name="更改" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Dockerfile" />
<option value="Go File" />
</list>
</option>
</component>
<component name="GOROOT" url="file://$USER_HOME$/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.windows-amd64" />
<component name="HighlightingSettingsPerFile">
<setting file="file://$USER_HOME$/go/pkg/mod/github.com/wechatpay-apiv3/wechatpay-go@v0.2.20/services/payments/jsapi/api_jsapi_request_payment.go" root0="SKIP_INSPECTION" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 3
}</component>
<component name="ProjectId" id="2qn73uMaWLMYCjjMpyatMYepw4t" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<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": "Debug",
"Go 构建.go build logincenter.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",
"go.import.settings.migrated": "true",
"go.sdk.automatically.set": "true",
"last_opened_file_path": "D:/desktop/go_test01",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "go.sdk"
}
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<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 logincenter">
<configuration name="go build admincenter" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
<module name="trunk" />
<working_directory value="$PROJECT_DIR$/center/admincenter" />
<kind value="PACKAGE" />
<package value="admincenter" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/center/admincenter/main.go" />
<method v="2" />
</configuration>
<configuration name="go build logincenter" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
<module name="trunk" />
<working_directory value="$PROJECT_DIR$/center/logincenter" />
<kind value="PACKAGE" />
<package value="logincenter" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/center/logincenter/main.go" />
<method v="2" />
</configuration>
<configuration default="true" type="docker-deploy" factoryName="docker-compose.yml" temporary="true">
<deployment type="docker-compose.yml">
<settings />
</deployment>
<method v="2" />
</configuration>
<configuration default="true" type="docker-deploy" factoryName="dockerfile" temporary="true">
<deployment type="dockerfile">
<settings />
</deployment>
<method v="2" />
</configuration>
<configuration name="admincenter.redis: Compose 部署" type="docker-deploy" factoryName="docker-compose.yml" temporary="true" server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
<option name="services">
<list>
<option value="redis" />
</list>
</option>
<option name="sourceFilePath" value="center/admincenter/docker-compose.yml" />
</settings>
</deployment>
<method v="2" />
</configuration>
<configuration name="center/admincenter/Dockerfile builder" type="docker-deploy" factoryName="dockerfile" temporary="true" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="golang1.20_builder" />
<option name="buildCliOptions" value="--target builder" />
<option name="sourceFilePath" value="center/admincenter/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Go 构建.go build logincenter" />
<item itemvalue="Go 构建.go build admincenter" />
<item itemvalue="Docker.admincenter.redis: Compose 部署" />
<item itemvalue="Docker.center/admincenter/Dockerfile builder" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-gosdk-5df93f7ad4aa-df9ad98b711f-org.jetbrains.plugins.go.sharedIndexes.bundled-GO-242.22855.85" />
<option value="bundled-js-predefined-d6986cc7102b-5c90d61e3bab-JavaScript-GO-242.22855.85" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VgoProject">
<settings-migrated>true</settings-migrated>
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$USER_HOME$/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.windows-amd64/src/context/context.go</url>
<line>68</line>
<option name="timeStamp" value="8" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

8
trunk/center/.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/center.iml" filepath="$PROJECT_DIR$/.idea/center.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,40 @@
# 使用官方的 Go 镜像作为构建环境
FROM golang:1.22.10-alpine AS builder
# 设置工作目录
WORKDIR /app
# 设置 Go 代理
ENV GOPROXY=https://goproxy.cn,direct
# 禁用 CGO
ENV CGO_ENABLED=0
# 复制所有源代码文件
COPY . .
WORKDIR /app/admincenter
# 构建应用程序,并确认生成的文件
RUN go build -o adminserver -ldflags="-s -w"
# 使用官方的 Alpine 镜像作为运行环境
FROM alpine:latest
# 设置作者标签
LABEL authors="tp"
# 设置工作目录
WORKDIR /app
# 从构建阶段复制编译好的可执行文件
COPY --from=builder /app/admincenter/adminserver .
# 复制配置文件
COPY --from=builder /app/admincenter/config.yaml .
# 暴露端口(假设 adminserver 监听 10051 端口)
EXPOSE 10051
# 设置容器启动时运行 adminserver
ENTRYPOINT ["./adminserver"]

View File

@ -0,0 +1,6 @@
2025-01-02 13:41:26---->
开始加载DbConfig
------------------------------------------------------
2025-01-02 13:41:26---->
开始加载LogMgr
------------------------------------------------------

View File

@ -0,0 +1,18 @@
2025-01-02 13:41:26---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-02 13:41:26---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-02 13:41:26---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-02 13:41:26---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-02 13:41:26---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-02 13:41:26---->
Web服务器开始监听:192.168.50.85:10051
------------------------------------------------------

View File

@ -0,0 +1,21 @@
#!/bin/bash
# 设置 Go 环境变量,确保使用 Linux 架构
export GOOS=linux
export GOARCH=amd64
echo "开始编译..."
# 编译 Go 代码
go build -o adminServer
# 检查编译是否成功
if [ $? -eq 0 ]; then
echo "编译成功!"
else
echo "编译失败!"
fi
# 等待用户输入任意键
read -p "编译完成,按任意键继续..."
exit 1

View File

@ -0,0 +1,54 @@
# 配置根节点
root:
# 是否是调试模式
debug: true
# Web服务监听地址和端口
web_server_address: "192.168.50.85:10051"
# Elasticsearch 地址
es_urls: "http://10.252.0.70:18099"
# 数据库配置
db_config:
admin_db:
# 最大处于开启状态的连接数
max_open_conns: 0
# 最大处于空闲状态的连接数
max_idle_conns: 0
# 数据库连接字符串
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
user_db:
# 最大处于开启状态的连接数
max_open_conns: 0
# 最大处于空闲状态的连接数
max_idle_conns: 0
# 数据库连接字符串
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
redis_config:
# 数据库连接字符串
connection_string: "192.168.50.110:6379"
# 密码, 如果要设置用户Id则密码设置为:"UserId:Password"
password: ""
# 数据库序号
database: 5
# 最大活跃连接数
max_active: 500
# 最大空闲的连接数
max_idle: 200
# 连接空闲超时时间,单位:秒
idle_timeout: 300
# 连接超时时间, 单位:秒
dial_connect_timeout: 10

View File

@ -0,0 +1,37 @@
version: '3'
services:
mysql:
image: mysql:8.0
container_name: mysql-admin
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: admin,user
volumes:
- /my/own/datadir:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:7.0
container_name: redis-admin
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: always
command: ["redis-server", "--appendonly", "yes"]
admin-center:
build:
context: .
dockerfile: Dockerfile
container_name: admin-center
ports:
- "10051:10051"
volumes:
- ./app:/app
depends_on:
- mysql
- redis
volumes:
redis_data:

View File

@ -0,0 +1,28 @@
#!/bin/bash
# 导航到 Dockerfile 所在目录
#cd D:\workspace\e2023\goProject\trunk\center\admincenter
# 构建 Docker 镜像
echo "开始构建 Docker 镜像..."
docker build -t adminserver-image .
# 检查构建是否成功
if [ $? -ne 0 ]; then
echo "构建失败!"
exit 1
fi
echo "镜像构建成功!"
# 运行 Docker 容器
echo "开始运行 Docker 容器..."
docker run -d -p 10051:10051 --name adminserver-container adminserver-image
# 检查容器是否成功运行
if [ $? -ne 0 ]; then
echo "容器启动失败!"
exit 1
fi
echo "容器启动成功!"

View File

@ -0,0 +1,38 @@
module admincenter
go 1.22.10
replace (
common => ../common
framework => ../../framework
goutil => ../../goutil
)
require (
common v0.0.0-00010101000000-000000000000
goutil v0.0.0-20230425160006-b2d0b0a0b0b0
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
framework v0.0.0-20230425160006-b2d0b0a0b0b0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-sql-driver/mysql v1.8.1 // 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
github.com/mattn/go-isatty v0.0.17 // indirect
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gorm.io/driver/mysql v1.5.7 // indirect
gorm.io/gorm v1.25.12 // indirect
)

View File

@ -0,0 +1,89 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/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/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/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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
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.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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/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=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/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=
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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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/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-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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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/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.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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
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=

View File

@ -0,0 +1,5 @@
package internal
import (
_ "admincenter/internal/admin"
)

View File

@ -0,0 +1,34 @@
package admin
import (
"common/connection"
)
func init() {
//注册数据库
connection.RegisterDBModel(&Admin{})
}
type Admin struct {
ID int64 `gorm:"column:id;primary_key;comment:管理员id;autoIncrementIncrement" json:"id"`
//账号
Account string `gorm:"column:account;comment:账号" json:"account"`
Name string `gorm:"column:name;comment:管理员名称" json:"name"`
Password string `gorm:"column:password;comment:管理员密码" json:"password"`
//性别
Sex int32 `gorm:"column:sex;comment:性别" json:"sex"`
//生日
Birthday string `gorm:"column:birthday;comment:生日" json:"birthday"`
//手机
Phone int64 `gorm:"column:phone;comment:手机" json:"phone"`
//邮箱
Email string `gorm:"column:email;comment:邮箱" json:"email"`
//微信群【方便发送通知】
WechatGroup string `gorm:"column:wechat_group;comment:微信群" json:"wechat_group"`
//备注
Describe string `gorm:"column:describe;comment:备注" json:"describe"`
}
func (Admin) TableName() string {
return "admin"
}

View File

@ -0,0 +1,198 @@
package admin
import (
"common/remark"
"common/resultStatus"
"common/webServer"
"goutil/intUtil"
"goutil/securityUtil"
"strconv"
"time"
)
func init() {
//注册接口
webServer.RegisterFunction(new(AdminApi))
}
func init() {
moduleName := "AdminApi"
desc := "管理员接口"
author := "tangping"
mendor := ""
date := "2024-12-25"
remark.RegisterModuleRemark(moduleName, desc, author, mendor, date)
}
// AdminApi 管理员接口
type AdminApi struct {
}
// ---------------------------------------- 接口 --------------------------------------------------
func init() {
moduleName := "AdminApi"
methodName := "Add"
methodDesc := "添加管理员用户"
methodAuthor := "tangping"
methodMendor := ""
methodDate := "2024-12-25 15:55:00"
methodInParam := []string{"string 账号,string:管理员名称,string:管理员密码,string:管理员性别,string:管理员生日,int64:管理员手机号,string:管理员邮箱,string:管理员微信群,string:管理员备注"}
methodOutParam := `
{
"Code '类型:int'": "响应结果的状态值",
"Message '类型:string'": "响应结果的状态值所对应的描述信息",
"Data '类型:interface{}'": "响应结果的数据"
{
"id '类型:int'": "管理员id",
}
}`
remark.RegisterMethodRemark(moduleName, methodName, methodDesc, methodAuthor, methodMendor, methodDate, methodInParam, methodOutParam)
}
func (a *AdminApi) Add(account string, name string, password string, sex int32, birthday string, phone int64, email string, wechatGroup string, describe string) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
//校验参数
if account == "" || name == "" || password == "" || sex == 0 || birthday == "" || phone == 0 || email == "" || wechatGroup == "" {
responseObj.SetResultStatus(resultStatus.APIDataError)
return
}
//密码md5加密
password = securityUtil.Md5String(password, true)
//处理数据
adminModel := &Admin{
Account: account,
Name: name,
Password: password,
Sex: sex,
Birthday: birthday,
Phone: phone,
Email: email,
WechatGroup: wechatGroup,
Describe: describe,
}
//添加到数据库
AddAdmin(adminModel)
resultMap := make(map[string]any)
resultMap["id"] = adminModel.ID
responseObj.SetData(resultMap)
return
}
func init() {
moduleName := "AdminApi"
methodName := "Get"
methodDesc := "获取管理员用户"
methodAuthor := "tangping"
methodMendor := ""
methodDate := "2024-12-25 15:55:00"
methodInParam := []string{"int64:管理员id"}
methodOutParam := `
{
"Code '类型:int'": "响应结果的状态值",
"Message '类型:string'": "响应结果的状态值所对应的描述信息",
"Data '类型:interface{}'": "响应结果的数据"
{
"account '类型:string'": "管理员账号",
"name '类型:string'": "管理员名称",
"sex '类型:int32'": "管理员性别",
"birthday '类型:string'": "管理员生日",
"phone '类型:int64'": "管理员手机号",
"email '类型:string'": "管理员邮箱",
"wechatGroup '类型:string'": "管理员微信群",
"describe '类型:string'": "管理员备注",
}
}`
remark.RegisterMethodRemark(moduleName, methodName, methodDesc, methodAuthor, methodMendor, methodDate, methodInParam, methodOutParam)
}
func (a *AdminApi) Get(adminId int64) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
//验证参数
if adminId == 0 {
responseObj.SetResultStatus(resultStatus.APIDataError)
return
}
adminData, err := GetAdminByID(adminId)
if err != nil {
responseObj.SetResultStatus(resultStatus.DataError)
return
}
//adminData映射成map
resultMap := make(map[string]any)
resultMap["account"] = adminData.Account
resultMap["name"] = adminData.Name
resultMap["sex"] = adminData.Sex
resultMap["birthday"] = adminData.Birthday
resultMap["phone"] = adminData.Phone
resultMap["email"] = adminData.Email
resultMap["wechatGroup"] = adminData.WechatGroup
resultMap["describe"] = adminData.Describe
responseObj.SetData(resultMap)
return
}
// 管理员登录
func init() {
moduleName := "AdminApi"
methodName := "Login"
methodDesc := "管理员登录"
methodAuthor := "tangping"
methodMendor := ""
methodDate := "2024-12-26 15:55:00"
methodInParam := []string{"string:账号,string:密码"}
methodOutParam := `
{
"Code '类型:int'": "响应结果的状态值",
"Message '类型:string'": "响应结果的状态值所对应的描述信息",
"Data '类型:interface{}'": "响应结果的数据"
{
"Token '类型:string'": "登录令牌",
}
}`
remark.RegisterMethodRemark(moduleName, methodName, methodDesc, methodAuthor, methodMendor, methodDate, methodInParam, methodOutParam)
}
func (a *AdminApi) Login(account string, password string) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
//验证参数
if account == "" || password == "" {
responseObj.SetResultStatus(resultStatus.APIDataError)
return
}
adminData, err := Login(account, securityUtil.Md5String(password, true))
if err != nil {
responseObj.SetResultStatus(resultStatus.DataError)
return
}
//生成一个随机token
token, err := intUtil.ShuffleIntDigits(time.Now().UnixNano())
if err != nil {
responseObj.SetResultStatus(resultStatus.DataError)
return
}
//添加登录用户
webServer.AddLoginUserToken(token, &webServer.TokenInfo{Id: adminData.ID, Account: account})
//adminData映射成map
resultMap := make(map[string]any)
resultMap["Token"] = strconv.FormatInt(token, 10)
responseObj.SetData(resultMap)
return
}

View File

@ -0,0 +1,43 @@
package admin
import (
"common/connection"
"goutil/logUtilPlus"
)
// AddAdmin 添加管理员
// AddAdmin 添加新的管理员到数据库中。
// 参数 admin: 包含管理员信息的对象。
// 返回值: 插入操作影响的行数和可能发生的错误。
func AddAdmin(admin *Admin) (int64, error) {
//处理一些验证
// 写入到数据库
result := connection.GetAdminDB().Create(&admin) // 通过数据的指针来创建
if result.Error != nil {
logUtilPlus.ErrorLog("添加管理员失败 错误信息:", result.Error.Error())
}
return admin.ID, nil
}
// GetAdminByID 根据管理员ID获取管理员信息
func GetAdminByID(adminID int64) (*Admin, error) {
var admin Admin
result := connection.GetAdminDB().First(&admin, adminID)
if result.Error != nil {
return nil, result.Error
}
return &admin, nil
}
// 管理员登录
func Login(account string, password string) (*Admin, error) {
var admin Admin
result := connection.GetAdminDB().Where("account = ? AND password = ?", account, password).First(&admin)
if result.Error != nil {
return nil, result.Error
}
return &admin, nil
}

View File

@ -0,0 +1,40 @@
package main
import (
"common/connection"
"sync"
_ "admincenter/internal/admin"
_ "common/resultStatus"
"common/webServer"
)
var (
wg sync.WaitGroup
)
func init() {
// 设置WaitGroup需要等待的数量只要有一个服务器出现错误都停止服务器
wg.Add(1)
}
func main() {
//加载配置
loadConfig()
// 启动webserver
go webServer.Start(&wg)
// 阻塞等待以免main线程退出
wg.Wait()
}
// loadConfig 用于加载配置信息。
// 该函数会读取配置文件或环境变量中的设置,并根据这些设置初始化程序所需的配置。
// 目前函数的实现为空,需要根据实际的配置加载逻辑进行填充。
func loadConfig() {
//构建数据库
connection.BuildDB()
}

View File

@ -0,0 +1,20 @@
#!/bin/bash
# 赋予可执行权限
chmod +x adminServer
echo "启动中..."
# 接受命令行传入一个参数
case "$1" in
d)
# 使用 nohup 将进程放到后台运行,并将输出重定向到 nohup.out 文件
nohup ./adminServer > nohup.out 2>&1 &
echo "启动完成"
;;
*)
./adminServer
;;
esac
echo "启动完成"

View File

@ -0,0 +1,16 @@
#!/bin/bash
# 查找 adminServer 的 PID
PID=$(pgrep adminServer)
if [ -z "$PID" ]; then
echo "adminServer 进程未找到"
else
echo "停止中... (PID: $PID)"
kill $PID
if [ $? -eq 0 ]; then
echo "adminServer 进程已终止 (PID: $PID)"
else
echo "无法终止 adminServer 进程 (PID: $PID)"
fi
fi

52
trunk/center/common/cache/cache.go vendored Normal file
View File

@ -0,0 +1,52 @@
package cache
import (
"sync"
)
// Cache 结构体代表缓存
type Cache struct {
data map[string]any
rwmu sync.RWMutex
}
// NewCache 创建并返回一个新的缓存实例
func NewCache() *Cache {
return &Cache{
data: make(map[string]any),
}
}
// Set 方法用于向缓存中设置键值对,写操作会加写锁保证并发安全
func (c *Cache) set(key string, value any) {
c.rwmu.Lock()
defer c.rwmu.Unlock()
c.data[key] = value
}
// Get 方法用于从缓存中根据键获取对应的值,读操作会加读锁允许并发读
func (c *Cache) get(key string) any {
c.rwmu.RLock()
defer c.rwmu.RUnlock()
value := c.data[key]
return value
}
// Delete 方法用于从缓存中删除指定的键值对,写操作会加写锁保证并发安全
func (c *Cache) Delete(key string) {
c.rwmu.Lock()
defer c.rwmu.Unlock()
delete(c.data, key)
}
// GetData 方法用于从缓存中根据键获取对应的值,读操作会加读锁允许并发读
func GetData[V any](c *Cache, key string) (value V, ok bool) {
v := c.get(key)
value, ok = v.(V)
return
}
// SetData 方法用于向缓存中设置键值对,写操作会加写锁保证并发安全
func SetData(c *Cache, key string, value any) {
c.set(key, value)
}

48
trunk/center/common/cache/cacheslice.go vendored Normal file
View File

@ -0,0 +1,48 @@
package cache
import (
"sync"
)
// SliceCache结构体代表基于切片的缓存内部使用切片存储元素并通过读写锁保证并发安全
type SliceCache struct {
data []interface{}
rwmu sync.RWMutex
}
// NewSliceCache创建并返回一个新的基于切片的缓存实例
func NewSliceCache() *SliceCache {
return &SliceCache{
data: make([]interface{}, 0),
}
}
// Add方法用于向切片缓存中添加元素写操作加写锁保证并发安全
func (sc *SliceCache) Add(element interface{}) {
sc.rwmu.Lock()
sc.data = append(sc.data, element)
sc.rwmu.Unlock()
}
// GetAll方法用于获取切片缓存中的所有元素读操作加读锁允许并发读
func (sc *SliceCache) GetAll() []interface{} {
sc.rwmu.RLock()
result := make([]interface{}, len(sc.data))
copy(result, sc.data)
sc.rwmu.RUnlock()
return result
}
// Remove方法用于从切片缓存中删除指定元素写操作加写锁保证并发安全
func (sc *SliceCache) Remove(element interface{}) bool {
sc.rwmu.Lock()
for i, e := range sc.data {
if e == element {
sc.data = append(sc.data[:i], sc.data[i+1:]...)
sc.rwmu.Unlock()
return true
}
}
sc.rwmu.Unlock()
return false
}

Binary file not shown.

View File

@ -0,0 +1,97 @@
/*
配置包提供项目的配置信息
*/
package configYaml
import (
"goutil/debugUtil"
)
var (
// 是否是DEBUG模式
DEBUG bool
// web服务监听端口
WebServerAddress string
// gRpc监听地址和端口(内网地址即可)
GrpcServerAddress string
// 战斗服务器地址
FightServerAddress string
// 战区Id
BigGroupId int
// 页签Id
TagId int
// 是否是中心服务器地址
PlayerServerCenter bool
// 数据中心服务器地址
DataCenterAddress string
// es urls
EsUrls string
BaseDay int
)
// initBaseConfig
// @description: 初始化基础配置数据
// parameter:
// @configObj: 基础配置数据
// return:
// @error: 错误信息
func initBaseConfig() {
root := ConfigYaml.Root
// 为DEBUG模式赋值
DEBUG = root.Debug
// 设置debugUtil的状态
debugUtil.SetDebug(DEBUG)
// 解析rpcConfig配置
WebServerAddress = root.WebServerAddress
// gRpc监听地址和端口(内网地址即可)
GrpcServerAddress = root.GrpcServerAddress
// 解析BigGroupId配置
BigGroupId = root.BigGroupId
// 解析FightServerAddress配置
FightServerAddress = root.FightServerAddress
EsUrls = root.EsUrls
BaseDay = root.BaseDay
}
// GetDebug
// @description: 获取是否是开发环境
// parameter:
// return:
// @bool:
func GetDebug() bool {
return ConfigYaml.Root.Debug
}
// GetWebServerAddress 返回Web服务器的地址。
// 该函数通过访问ConfigYaml中的配置信息获取并返回Web服务器的地址。
// 主要用于需要与Web服务器建立连接的场景。
func GetWebServerAddress() string {
return ConfigYaml.Root.WebServerAddress
}
// GetEsUrls 返回配置文件中 Elasticsearch 的 URL 地址。
//
// 该函数通过访问全局变量 ConfigYaml获取其 Root 字段下的 EsUrls 属性,
// 并将其作为字符串返回。这提供了一种简单的方法来获取 Elasticsearch 数据库的连接信息,
// 而无需直接访问配置文件。
func GetEsUrls() string {
return ConfigYaml.Root.EsUrls
}

View File

@ -0,0 +1,154 @@
package configYaml
var ConfigYaml = Config{}
// Config 定义与 YAML 文件结构匹配的结构体
type Config struct {
Root Root
}
// Root 是整个配置文件的根结构体
type Root struct {
// 是否是调试模式
Debug bool `yaml:"debug"`
// 是否是 CrossServer 中心节点(标记为 true 时,才会进行排行榜处理)
CrossServerCenter bool `yaml:"cross_server_center"`
// ManagerCenter 配置
ManagerCenterConfig ManagerCenterConf `yaml:"manager_center_config"`
// logmgr 配置
LogMgr LogMgr `yaml:"log_mgr"`
// Web 服务监听地址和端口
WebServerAddress string `yaml:"web_server_address"`
// gRPC 监听地址和端口 (内网地址即可)
GrpcServerAddress string `yaml:"grpc_server_address"`
// 战斗服务器地址
FightServerAddress string `yaml:"fight_server_address"`
// 数据中心地址
DataCenterAddress string `yaml:"data_center_address"`
// OrderId 和 BigGroupId仅用于非 PlayerServer
OrderId int `yaml:"order_id"`
BigGroupId int `yaml:"big_group_id"`
// 重启时载入 Redis 数据日期范围
BaseDay int `yaml:"base_day"`
// ES 地址
EsUrls string `yaml:"es_urls"`
// 数据库配置
DbConfig DBConfig `yaml:"db_config"`
// 监控相关配置
MonitorConfig MonitorConf `yaml:"monitor_config"`
// 功能开关配置
FunctionConfig FunctionConf `yaml:"function_config"`
}
// ManagerCenterConf 是 ManagerCenter 的配置结构体
type ManagerCenterConf struct {
// ManagerCenter API 的 URL
ManageCenterAPIUrl string `yaml:"manage_center_api_url"`
// 服务器组类型
GroupType string `yaml:"group_type"`
// 刷新间隔,单位:分钟
RefreshInterval int `yaml:"refresh_interval"`
}
// LogMgr 是日志管理器的配置结构体
type LogMgr struct {
// group boxId
GroupId string `yaml:"group_id"`
// group secret
GroupSecret string `yaml:"group_secret"`
// product boxId
ProductId string `yaml:"product_id"`
}
// DBConfig 包含数据库和 Redis 的配置
type DBConfig struct {
//管理员数据库配置
AdminDB DatabaseConfig `yaml:"admin_db"`
// 用户数据库配置
UserDB DatabaseConfig `yaml:"user_db"`
// 游戏模型数据库配置
GameModel DatabaseConfig `yaml:"game_model"`
// 游戏数据库配置
GameDB DatabaseConfig `yaml:"game_db"`
// 玩家数据库配置
PlayerDB DatabaseConfig `yaml:"player_db"`
// Redis 配置
RedisConfig RedisConfig `yaml:"redis_config"`
}
// DatabaseConfig 是数据库连接的配置结构体
type DatabaseConfig struct {
// 最大处于开启状态的连接数
MaxOpenConns int `yaml:"max_open_conns"`
// 最大处于空闲状态的连接数
MaxIdleConns int `yaml:"max_idle_conns"`
// 数据库连接字符串
ConnectionString string `yaml:"connection_string"`
}
// RedisConfig 是 Redis 连接的配置结构体
type RedisConfig struct {
// Redis 数据库连接字符串
ConnectionString string `yaml:"connection_string"`
// 密码, 如果要设置用户 Id则密码设置为: "UserId:Password"
Password string `yaml:"password"`
// 数据库序号
Database int `yaml:"database"`
// 最大活跃连接数
MaxActive int `yaml:"max_active"`
// 最大空闲的连接数
MaxIdle int `yaml:"max_idle"`
// 连接空闲超时时间,单位:秒
IdleTimeout int `yaml:"idle_timeout"`
// 连接超时时间, 单位:秒
DialConnectTimeout int `yaml:"dial_connect_timeout"`
}
// MonitorConf 是监控配置的结构体
type MonitorConf struct {
// 监控使用的服务器 IP (本机的外网地址)
ServerIP string `yaml:"server_ip"`
// 监控使用的服务器名称
ServerName string `yaml:"server_name"`
// 监控的时间间隔(单位:分钟)
Interval int `yaml:"interval"`
}
// FunctionConf 是功能开关配置的结构体
type FunctionConf struct {
// 游戏代码: qyc, xh, dzz
GameCode string `yaml:"game_code"`
}

View File

@ -0,0 +1,188 @@
package configYaml
import (
"goutil/logUtilPlus"
"goutil/mysqlUtil"
"goutil/redisUtil"
"time"
)
// DbConfig
//
// @description: mysql配置对象
type DbConfig struct {
// 管理员数据库链接字符串
adminConfig *mysqlUtil.DBConfig
// 用户数据库链接字符串
userConfig *mysqlUtil.DBConfig
// 游戏模型数据库链接字符串
gameModelConfig *mysqlUtil.DBConfig
// 游戏数据库链接字符串
gameConfig *mysqlUtil.DBConfig
// 游戏数据库链接字符串
playerConfig *mysqlUtil.DBConfig
// redis配置对象
redisConfig *redisUtil.RedisConfig
}
var (
// 数据库配置对象
dbConfigObj *DbConfig
)
// GetAdminConfig
// @description: 获取admin库配置
// parameter:
//
// @receiver config:config
//
// return:
//
// @*mysqlUtil.DBConfig:admin库配置
func (config *DbConfig) GetAdminConfig() *mysqlUtil.DBConfig {
return config.adminConfig
}
// GetUserConfig
// @description: 获取user库配置
// parameter:
//
// @receiver config:config
//
// return:
//
// @*mysqlUtil.DBConfig:user库配置
func (config *DbConfig) GetUserConfig() *mysqlUtil.DBConfig {
return config.userConfig
}
// GetGameModelConfig
// @description: 获取model库配置
// parameter:
//
// @receiver config:config
//
// return:
//
// @*mysqlUtil.DBConfig:model库配置
func (config *DbConfig) GetGameModelConfig() *mysqlUtil.DBConfig {
return config.gameModelConfig
}
// GetGameConfig
// @description: 获取Game库配置
// parameter:
//
// @receiver config:config
//
// return:
//
// @*mysqlUtil.DBConfig:Game库配置
func (config *DbConfig) GetGameConfig() *mysqlUtil.DBConfig {
return config.gameConfig
}
// GetPlayerConfig
// @description: 获取玩家库配置
// parameter:
//
// @receiver config:config
//
// return:
//
// @*mysqlUtil.DBConfig:玩家库配置
func (config *DbConfig) GetPlayerConfig() *mysqlUtil.DBConfig {
return config.playerConfig
}
// GetRedisConfig
// @description: 获取redis配置对象
// parameter:
//
// @receiver config:config
//
// return:
//
// @*redisUtil.RedisConfig:redis配置
func (config *DbConfig) GetRedisConfig() *redisUtil.RedisConfig {
return config.redisConfig
}
// newMysqlConfig
//
// @description: 创建新的Mysql配置对象
//
// parameter:
//
// @_gameModelConfig:
// @_gameConfig:
// @_playerConfig:
// @_redisConfig:
//
// return:
//
// @*DbConfig:
func newMysqlConfig(_adminConfig *mysqlUtil.DBConfig, _userConfig *mysqlUtil.DBConfig, _gameModelConfig *mysqlUtil.DBConfig,
_gameConfig *mysqlUtil.DBConfig,
_playerConfig *mysqlUtil.DBConfig,
_redisConfig *redisUtil.RedisConfig) *DbConfig {
return &DbConfig{
adminConfig: _adminConfig,
userConfig: _userConfig,
gameModelConfig: _gameModelConfig,
gameConfig: _gameConfig,
redisConfig: _redisConfig,
playerConfig: _playerConfig,
}
}
// initDbConfig
//
// @description: 初始化数据库配置
//
// parameter:
//
// @configObj: 数据库配置
//
// return:
//
// @error: 错误数据
func initDbConfig() error {
logUtilPlus.DebugLog("开始加载DbConfig")
redisConfig := ConfigYaml.Root.DbConfig.RedisConfig
//if redisConfig == nil {
// logUtilPlus.DebugLog("redis配置为空")
// return nil
//}
// 初始化mysql配置对象
dbConfigObj = newMysqlConfig(
mysqlUtil.NewDBConfig(ConfigYaml.Root.DbConfig.AdminDB.ConnectionString, ConfigYaml.Root.DbConfig.AdminDB.MaxOpenConns, ConfigYaml.Root.DbConfig.AdminDB.MaxIdleConns),
mysqlUtil.NewDBConfig(ConfigYaml.Root.DbConfig.UserDB.ConnectionString, ConfigYaml.Root.DbConfig.UserDB.MaxOpenConns, ConfigYaml.Root.DbConfig.UserDB.MaxIdleConns),
mysqlUtil.NewDBConfig(ConfigYaml.Root.DbConfig.GameModel.ConnectionString, ConfigYaml.Root.DbConfig.GameModel.MaxOpenConns, ConfigYaml.Root.DbConfig.GameModel.MaxIdleConns),
mysqlUtil.NewDBConfig(ConfigYaml.Root.DbConfig.GameDB.ConnectionString, ConfigYaml.Root.DbConfig.GameDB.MaxOpenConns, ConfigYaml.Root.DbConfig.GameDB.MaxIdleConns),
mysqlUtil.NewDBConfig(ConfigYaml.Root.DbConfig.PlayerDB.ConnectionString, ConfigYaml.Root.DbConfig.PlayerDB.MaxOpenConns, ConfigYaml.Root.DbConfig.PlayerDB.MaxIdleConns),
redisUtil.NewRedisConfig2(redisConfig.ConnectionString, redisConfig.Password, redisConfig.Database, redisConfig.MaxActive, redisConfig.MaxIdle, time.Duration(redisConfig.IdleTimeout)*time.Second, time.Duration(redisConfig.DialConnectTimeout)*time.Second))
return nil
}
// GetDbConfig
//
// @description: 获取mysql配置
//
// parameter:
// return:
//
// @*DbConfig: mysql配置对象
func GetDbConfig() *DbConfig {
return dbConfigObj
}

View File

@ -0,0 +1,63 @@
package configYaml
// FunctionConfig
//
// @description: 功能开关配置
type FunctionConfig struct {
// 游戏代码
GameCode string
// 仙术副本 清理过期房间信息时间 5 分钟
MagicCopyTeamOutTime int
// 请求青瓷的Url
QCSdk_Url string
// 请求青瓷的GameCode
QCSdk_GameCode string
// 请求青瓷的GameId
QCSdk_GameId string
// 请求青瓷的加密signKey
QCSdk_SignKey string
}
var (
// 功能开关配置对象
functionConfigObj *FunctionConfig
)
// initFunctionConfig
//
// @description: 加载功能开关配置
//
// parameter:
//
// @configObj: 开关配置
//
// return:
//
// @error: 错误信息
func initFunctionConfig() error {
functionConfigObj = &FunctionConfig{}
functionConfig := ConfigYaml.Root.FunctionConfig
functionConfigObj.GameCode = functionConfig.GameCode
return nil
}
// GetFunctionConfigObj
//
// @description: 获取功能开关配置对象
//
// parameter:
// return:
//
// @*FunctionConfig:
func GetFunctionConfigObj() *FunctionConfig {
return functionConfigObj
}

View File

@ -0,0 +1,61 @@
package configYaml
import (
"framework/configMgr"
"gopkg.in/yaml.v3"
"goutil/logUtil"
"goutil/yamlUtil"
"log"
)
var (
// 配置对象
configManager = configMgr.NewConfigManager()
)
// init
//
// @description: init
//
// parameter:
// return:
func init() {
// 设置日志文件的存储目录
logUtil.SetLogPath("LOG")
if err := reloadConfig(); err != nil {
panic(err)
}
//加载配置
initBaseConfig()
initDbConfig()
initFunctionConfig()
initLogMgrConfig()
}
// reloadConfig
//
// @description: reloadConfig
//
// parameter:
// return:
//
// @error: 错误信息
func reloadConfig() error {
yamlFile, err := yamlUtil.LoadFromFile("config.yaml")
if err != nil {
return err
}
// 解析 YAML 文件
err = yaml.Unmarshal(yamlFile, &ConfigYaml)
if err != nil {
log.Fatalf("Error unmarshalling config file: %v", err)
return err
}
return nil
}

View File

@ -0,0 +1,62 @@
package configYaml
import (
"goutil/logUtilPlus"
)
// LogMgrConfig
//
// @description: logMgr配置对象
type LogMgrConfig struct {
// 组id
GroupId string
// 组秘钥
GroupSecret string
// 项目id
ProductId string
}
var (
// logMgr配置对象
logMgrConfigObj *LogMgrConfig
)
// initLogMgrConfig
//
// @description: 初始化LogMgr配置
//
// parameter:
//
// @configObj:
//
// return:
//
// @error: 错误信息
func initLogMgrConfig() error {
logUtilPlus.DebugLog("开始加载LogMgr")
logMgr := ConfigYaml.Root.LogMgr
logMgrConfigObj = &LogMgrConfig{
GroupId: logMgr.GroupId,
GroupSecret: logMgr.GroupSecret,
ProductId: logMgr.ProductId,
}
return nil
}
// GetLogMgrConfig
//
// @description: 获取游戏模型数据库链接字符串
//
// parameter:
// return:
//
// @*LogMgrConfig: 游戏模型数据库链接字符串
func GetLogMgrConfig() *LogMgrConfig {
return logMgrConfigObj
}

View File

@ -0,0 +1,225 @@
package connection
import (
"context"
"fmt"
"framework/sqlAsyncMgr"
goredis "github.com/go-redis/redis/v8"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"goutil/logUtilPlus"
"time"
// _ "github.com/go-sql-driver/mysql"
config "common/configsYaml"
"goutil/mysqlUtil"
"goutil/redisUtil"
)
var (
adminDB *gorm.DB //管理员数据库对象
userDB *gorm.DB //用户数据库对象
gameModelDB *gorm.DB // 游戏模型数据库对象
gameDB *gorm.DB // 游戏数据库
gamePlayerDB *gorm.DB // 玩家库
redisDB *goredis.Client // 游戏redis连接客户端
syncMgr *sqlAsyncMgr.SqlAsyncUtil // 同步管理对象
syncFileSize = 1024 * 1024 // 同步文件大小
fileMaxSaveTime = 24 * 7 // 保留7天的sql文件
)
var excuteSqlFunc func(*gorm.DB, ITable, string) error
var loghandle func(s string, is ...interface{})
var defaultType = SyncSql
type ITable interface {
TableName() string
}
type SqlExecuteType int32
const (
SyncSql SqlExecuteType = iota
ASyncSql
Name = "BaseDal"
)
// init
// @description: init
// parameter:
// return:
func init() {
//管理中心数据库配置
adminDB = initMysql(config.GetDbConfig().GetAdminConfig())
userDB = initMysql(config.GetDbConfig().GetUserConfig())
// 初始化游戏模型数据库
gameModelDBConfig := config.GetDbConfig().GetGameModelConfig()
gameModelDB = initMysql(gameModelDBConfig)
// 初始化crossSever 游戏数据库
gameDBConfig := config.GetDbConfig().GetGameConfig()
gameDB = initMysql(gameDBConfig)
gamePlayerDB = initMysql(config.GetDbConfig().GetPlayerConfig())
// 初始化redis-client
excuteSqlFunc = func(gdb *gorm.DB, table ITable, sql string) error {
db := gdb.Exec(sql)
if db.Error != nil {
loghandle("sql执行错误:%s;错误信息:%v", sql, db.Error.Error())
return db.Error
}
return nil
}
redisDB = initRedis(config.GetDbConfig().GetRedisConfig())
}
// 初始化Mysql
// initMysql
// @description: 初始化Mysql
// parameter:
// @dbConfig: dbConfig
// return:
// @*gorm.DB: DB
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{})
if err != nil {
panic(fmt.Errorf("初始化数据库:%s失败错误信息为%s", dbConfig.ConnectionString, err))
}
logUtilPlus.WarnLog("连接mysql:%s成功", dbConfig.ConnectionString)
return dbObj
}
// initRedis
// @description: 初始化redis客户端
// parameter:
// @redisConfig: redisConfig
// return:
// @*goredis.Client: Client
func initRedis(redisConfig *redisUtil.RedisConfig) *goredis.Client {
client := goredis.NewClient(&goredis.Options{
Addr: redisConfig.ConnectionString,
Password: redisConfig.Password,
DB: redisConfig.Database,
IdleTimeout: redisConfig.IdleTimeout,
DialTimeout: redisConfig.DialConnectTimeout,
})
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
ping, err := client.Ping(ctx).Result()
if err != nil {
panic(fmt.Errorf("ping->redis:%s失败,DB:%s错误信息为%s", redisConfig.ConnectionString, redisConfig.Database, err))
}
logUtilPlus.WarnLog("ping->redis:%s成功信息为%s", redisConfig.ConnectionString, ping)
return client
}
// GetAdminDB
// @description: 获取admin库db实例
// parameter:
// return:
// @*gorm.DB:admin库db实例
func GetAdminDB() *gorm.DB {
return adminDB
}
// GetUserDB
// @description: 获取user库db实例
// parameter:
// return:
// @*gorm.DB:user库db实例
func GetUserDB() *gorm.DB {
return userDB
}
// GetGameDB
// @description: 获取game库db实例
// parameter:
// return:
// @*gorm.DB:game库db实例
func GetGameDB() *gorm.DB {
return gameDB
}
// GetPlayerDB
// @description: 获取玩家库db实例
// parameter:
// return:
// @*gorm.DB:玩家库db实例
func GetPlayerDB() *gorm.DB {
return gamePlayerDB
}
// GetGameModelDB
// @description: 获取model库db实例
// parameter:
// return:
// @*gorm.DB:model库db实例
func GetGameModelDB() *gorm.DB {
return gameModelDB
}
// GetRedisClient
// @description: 获取redisdb实例
// parameter:
// return:
// @*goredis.Client:redisdb实例
func GetRedisClient() *goredis.Client {
return redisDB
}
// GetAll
// @description: 获取model数据
// parameter:
// @dataList:数据列表
// return:
// @error:错误信息
func GetAll(dataList interface{}) error {
mysqlObj := GetGameModelDB()
if mysqlObj = mysqlObj.Find(dataList); mysqlObj.Error != nil {
WriteLog("dal.GetAll", mysqlObj.Error)
return mysqlObj.Error
}
return nil
}
// GetGameModelData
// @description: 获取GameModel数据
// parameter:
// @moduleName:模块名称
// @dataList:数据列表
// return:
// @error:错误信息
func GetGameModelData(moduleName string, dataList interface{}) error {
if result := gameModelDB.Find(dataList); result.Error != nil {
WriteLog(moduleName+"GetGameModelData", result.Error)
return result.Error
}
return nil
}
// WriteLog
// @description: 记录错误日志
// parameter:
// @command:命令
// @err:错误信息
// return:
func WriteLog(command string, err error) {
logUtilPlus.ErrorLog(fmt.Sprintf("Scan失败错误信息%scommand:%s", err, command))
}

View File

@ -0,0 +1,31 @@
package connection
import (
"testing"
"time"
)
type testDal struct{}
func (t testDal) TableName() string {
return "test"
}
var TestDal = testDal{}
type User struct {
ID uint `gorm:"primary_key"`
Name string `gorm:"column:name"`
Age int `gorm:"column:age"`
Birthday time.Time `gorm:"column:birthday"`
}
func TestExecute(t *testing.T) {
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := adminDB.Create(&user) // 通过数据的指针来创建
_ = user.ID // 返回插入数据的主键
_ = result.Error // 返回 error
_ = result.RowsAffected // 返回插入记录的条数
}

View File

@ -0,0 +1,41 @@
package connection
import "gorm.io/gorm"
var (
// 存放实体结构
dbModelMap = make([]interface{}, 0)
//当前管理数据库
modelDB *gorm.DB
)
// RegisterDBModel 注册数据库模型到全局变量dbModelMap中。
// 这个函数接受一个interface{}类型的参数dbModel表示数据库模型。
// 函数的目的是将传入的数据库模型添加到全局变量dbModelMap中
// 以便在其他地方可以访问和使用这些数据库模型。
func RegisterDBModel(dbModel interface{}) {
// 将dbModel的地址添加到dbModelMap中。
// 这里使用地址是因为数据库模型可能比较大,通过引用存储可以提高效率。
dbModelMap = append(dbModelMap, &dbModel)
}
// 设置modelDB 类型
func SetModelDB(db *gorm.DB) {
modelDB = db
}
// BuildDB 用于遍历dbModelMap中的所有数据库模型并检查每个模型对应的表是否存在于数据库中。
// 如果表不存在,则自动迁移(创建)该表。这样可以确保数据库模式与程序中的模型保持同步。
func BuildDB() {
// 遍历dbModelMap中的每个元素
for _, dbModel := range dbModelMap {
// 检查数据库中是否存在与dbModel对应的表
tableExists := modelDB.Migrator().HasTable(dbModel)
if !tableExists {
// 如果表不存在,则进行自动迁移
modelDB.AutoMigrate(dbModel)
}
}
}

View File

@ -0,0 +1,35 @@
module common
go 1.22.10
toolchain go1.23.4
replace (
framework => ../../framework
goutil => ../../goutil
)
require (
framework v0.0.0-20230425160006-b2d0b0a0b0b0
github.com/go-redis/redis/v8 v8.11.5
gorm.io/driver/mysql v1.5.7
gorm.io/gorm v1.25.12
goutil v0.0.0-20230425160006-b2d0b0a0b0b0
)
require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 // indirect
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/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

231
trunk/center/common/go.sum Normal file
View File

@ -0,0 +1,231 @@
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/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/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/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/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/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/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/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=
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/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/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/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=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
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=

View File

@ -0,0 +1,191 @@
package httpServer
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"goutil/logUtilPlus"
"goutil/typeUtil"
"goutil/zlibUtil"
)
// ApiContext
// @description: Api请求上下文对象
type ApiContext struct {
// 请求对象
request *http.Request
// 应答写对象
responseWriter http.ResponseWriter
// 请求数据
requestBytes []byte
// 字典形式的请求数据
requestDataByMap typeUtil.MapData
}
// GetRequest
// @description: 获取请求对象
// parameter:
// @receiver this: this
// return:
// @*http.Request: 请求对象
func (this *ApiContext) GetRequest() *http.Request {
return this.request
}
// GetResponseWriter
// @description: 获取应答写对象
// parameter:
// @receiver this: this
// return:
// @http.ResponseWriter: 应答写对象
func (this *ApiContext) GetResponseWriter() http.ResponseWriter {
return this.responseWriter
}
// GetRequestBytes
// @description: 获取请求字节数据
// parameter:
// @receiver this: this
// return:
// @[]byte: 请求字节数组
func (this *ApiContext) GetRequestBytes() []byte {
return this.requestBytes
}
// readContent
// @description: 读取内容
// parameter:
// @receiver this: this 请求对象
// @isZlib: 是否数据压缩
// return:
// @content: 二进制格式的内容
// @err: 错误对象
func (this *ApiContext) readContent(isZlib bool) (content []byte, err error) {
var buffer []byte
defer this.request.Body.Close()
if buffer, err = ioutil.ReadAll(this.request.Body); err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,读取数据出错,错误信息为:%s", this.request.RequestURI, err))
return
}
// 不压缩,则直接返回
if isZlib == false {
this.requestBytes = buffer
return buffer, err
}
// 解压数据
if content, err = zlibUtil.Decompress(buffer); err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,解压缩数据出错,错误信息为:%s", this.request.RequestURI, err))
return
}
this.requestBytes = content
return
}
// Unmarshal
// @description: 反序列化
// parameter:
// @receiver this: this
// @obj: 反序列化结果数据
// return:
// @error: 反序列化错误数据
func (this *ApiContext) Unmarshal(obj interface{}) error {
contentData := this.GetRequestBytes()
// 反序列化
if errMsg := json.Unmarshal(contentData, &obj); errMsg != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("反序列化%s出错错误信息为%s", string(contentData), errMsg.Error()))
return errMsg
}
return nil
}
// RequestDataByMap
// @description: 获取请求的map格式数据
// parameter:
// @receiver this: this
// return:
// @typeUtil.MapData: map数据
// @error: 错误信息
func (this *ApiContext) RequestDataByMap() (typeUtil.MapData, error) {
if this.requestDataByMap != nil {
return this.requestDataByMap, nil
}
var data typeUtil.MapData
if err := this.Unmarshal(&data); err != nil {
return nil, err
}
this.requestDataByMap = data
return this.requestDataByMap, nil
}
// RequestDataBySlice
// @description: 获取请求的slice格式数据
// parameter:
// @receiver this: this
// return:
// @[]interface{}: 返回的数组数据
func (this *ApiContext) RequestDataBySlice() []interface{} {
result := make([]interface{}, 0, 8)
for _, value := range this.requestDataByMap {
result = append(result, value)
}
return result
}
// RequestDataBySlice2
// @description: 获取请求的slice格式数据
// parameter:
// @receiver this: this
// return:
// @[]interface{}: 返回的数组数据
// @error:
func (this *ApiContext) RequestDataBySlice2() ([]interface{}, error) {
contentData := this.GetRequestBytes()
// 反序列化
result := make([]interface{}, 0, 8)
if errMsg := json.Unmarshal(contentData, &result); errMsg != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("用[]interface{}反序列化%s出错错误信息为%s", string(contentData), errMsg.Error()))
return nil, errMsg
}
return result, nil
}
// NewApiContext
// @description: 新建API上下文对象
// parameter:
// @_request: 请求对象
// @_responseWriter: 应答写对象
// @isZlib: 数据是否压缩
// return:
// @*ApiContext: 上下文
// @error: 错误信息
func NewApiContext(_request *http.Request, _responseWriter http.ResponseWriter, isZlib bool) (*ApiContext, error) {
context := &ApiContext{
request: _request,
responseWriter: _responseWriter,
}
// 读取数据
_, errMsg := context.readContent(isZlib)
if errMsg != nil {
return nil, errMsg
}
return context, nil
}

View File

@ -0,0 +1,87 @@
package httpServer
import (
"common/webServer"
"net/http"
"common/resultStatus"
)
// 处理函数
type HandleFunc func(context *ApiContext) *webServer.ResponseObject
// ApiHandler
// @description: API处理结构
type ApiHandler struct {
// API完整路径名称
apiFullName string
// 方法定义
handleFun HandleFunc
// 方法参数名称集合
funcParamNames []string
}
// ApiFullName
// @description: API完整路径名称
// parameter:
// @receiver this: this
// return:
// @string:
func (this *ApiHandler) ApiFullName() string {
return this.apiFullName
}
// HandleFun
// @description: 方法定义
// parameter:
// @receiver this: this
// return:
// @HandleFunc: 方法
func (this *ApiHandler) HandleFun() HandleFunc {
return this.handleFun
}
// FuncParamNames
// @description: 方法参数名称集合
// parameter:
// @receiver this: this
// return:
// @[]string: 方法参数名称集合
func (this *ApiHandler) FuncParamNames() []string {
return this.funcParamNames
}
// CheckParam
// @description: 检测参数数量
// parameter:
// @receiver this: this
// @r:
// return:
// @resultStatus.ResultStatus: 状态码数据
func (this *ApiHandler) CheckParam(r *http.Request) resultStatus.ResultStatus {
for _, name := range this.funcParamNames {
if r.Form[name] == nil || len(r.Form[name]) == 0 {
return resultStatus.APIParamError
}
}
return resultStatus.Success
}
// newApiHandler
// @description: 创建新的请求方法对象
// parameter:
// @_apiFullName: API完整路径名称
// @_funcDefinition: 方法定义
// @_funcParamNames: 方法参数名称集合
// return:
// @*ApiHandler: 请求方法对象
func newApiHandler(_apiFullName string, _funcDefinition HandleFunc, _funcParamNames ...string) *ApiHandler {
return &ApiHandler{
apiFullName: _apiFullName,
handleFun: _funcDefinition,
funcParamNames: _funcParamNames,
}
}

View File

@ -0,0 +1,56 @@
package httpServer
import (
"fmt"
"net/http"
)
var (
// 处理方法集合
// Key:API名
handlerData = make(map[string]*ApiHandler)
// 文档方法
remarkFunc func(w http.ResponseWriter, r *http.Request)
)
// RegisterRemarkFunc
// @description: 注册文档api方法
// parameter:
// @_remarkFunc: _remarkFunc
// return:
func RegisterRemarkFunc(_remarkFunc func(w http.ResponseWriter, r *http.Request)) {
remarkFunc = _remarkFunc
}
// RegisterHandleFunc
// @description: 注册处理方法
// parameter:
// @apiName: API名称
// @callback: 回调方法
// @paramNames: 参数名称集合
// return:
func RegisterHandleFunc(apiName string, callback HandleFunc, paramNames ...string) {
apiFullName := fmt.Sprintf("/API/%s", apiName)
if _, exist := handlerData[apiFullName]; exist {
panic(fmt.Errorf("重复注册处理函数:%s", apiFullName))
}
handlerData[apiFullName] = newApiHandler(apiFullName, callback, paramNames...)
}
// GetHandleFunc
// @description: 获取请求方法
// parameter:
// @apiFullName: 方法名称
// return:
// @*ApiHandler: 请求方法
// @bool: 是否存在
func GetHandleFunc(apiFullName string) (*ApiHandler, bool) {
if requestFuncObj, exists := handlerData[apiFullName]; exists {
return requestFuncObj, exists
}
return nil, false
}

View File

@ -0,0 +1,400 @@
package httpServer
import (
config "common/configsYaml"
"common/resultStatus"
"common/webServer"
"goutil/logUtilPlus"
"reflect"
"strconv"
"strings"
)
const (
// 供客户端访问的模块的后缀
con_ModuleSuffix = "Module"
// 定义用于分隔模块名称和方法名称的分隔符
con_DelimeterOfObjAndMethod = "_"
)
var (
// 定义存放所有方法映射的变量
methodMap = make(map[string]*methodAndInOutTypes)
// 函数返回值类型
responseType reflect.Type = reflect.TypeOf(new(webServer.ResponseObject))
)
// getStructName
// @description: 获取结构体类型的名称
// parameter:
// @structType: 结构体类型
// return:
// @string: 结构体类型的名称
func getStructName(structType reflect.Type) string {
reflectTypeStr := structType.String()
reflectTypeArr := strings.Split(reflectTypeStr, ".")
return reflectTypeArr[len(reflectTypeArr)-1]
}
// getFullModuleName
// @description: 获取完整的模块名称
// parameter:
// @moduleName: 模块名称
// return:
// @string: 完整的模块名称
func getFullModuleName(moduleName string) string {
return moduleName + con_ModuleSuffix
}
// getFullMethodName
// @description: 获取完整的方法名称
// parameter:
// @structName: 结构体名称
// @methodName: 方法名称
// return:
// @string: 完整的方法名称
func getFullMethodName(structName, methodName string) string {
return structName + con_DelimeterOfObjAndMethod + methodName
}
// resolveMethodInOutParams
// @description: 解析方法的输入输出参数
// parameter:
// @method: 方法对应的反射值
// return:
// @inTypes: 输入参数类型集合
// @outTypes: 输出参数类型集合
func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) {
methodType := method.Type()
for i := 0; i < methodType.NumIn(); i++ {
inTypes = append(inTypes, methodType.In(i))
}
for i := 0; i < methodType.NumOut(); i++ {
outTypes = append(outTypes, methodType.Out(i))
}
return
}
// RegisterFunction
// @description: 将需要对客户端提供方法的对象进行注册
// parameter:
// @structObject: 对象
// return:
func RegisterFunction(structObject interface{}) {
// 获取structObject对应的反射 Type 和 Value
reflectValue := reflect.ValueOf(structObject)
reflectType := reflect.TypeOf(structObject)
// 提取对象类型名称
structName := getStructName(reflectType)
// 获取structObject中返回值为responseObject的方法
for i := 0; i < reflectType.NumMethod(); i++ {
// 获得方法名称
methodName := reflectType.Method(i).Name
// 获得方法及其输入参数的类型列表
method := reflectValue.MethodByName(methodName)
inTypes, outTypes := resolveMethodInOutParams(method)
// 判断输出参数数量是否正确
if len(outTypes) != 1 {
continue
}
// 判断返回值是否为responseObject
if outTypes[0] != responseType {
continue
}
// 添加到列表中
methodMap[getFullMethodName(structName, methodName)] = newmethodAndInOutTypes(method, inTypes, outTypes)
}
}
// CallFunction
// @description: 调用方法
// parameter:
// @requestObj: 客户端对象
// return:
// @responseObj: 请求对象
func CallFunction(requestObj *webServer.RequestObject) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
var methodAndInOutTypes *methodAndInOutTypes
var ok bool
// 根据传入的ModuleName和MethodName找到对应的方法对象
key := getFullMethodName(requestObj.ModuleName, requestObj.MethodName)
if methodAndInOutTypes, ok = methodMap[key]; !ok {
logUtilPlus.ErrorLog("找不到指定的方法:%s", key)
responseObj.SetResultStatus(resultStatus.NotSpecificMethod)
return
}
// 判断参数数量是否相同
inTypesLength := len(methodAndInOutTypes.InTypes)
paramLength := len(requestObj.Parameters)
if paramLength != inTypesLength {
logUtilPlus.ErrorLog("传入的参数数量不符,本地方法%s的参数数量%d传入的参数数量为%d", key, inTypesLength, paramLength)
responseObj.SetResultStatus(resultStatus.ParamNotMatch)
return
}
// 构造参数
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.Bool:
if param_bool, ok := paramItem.(bool); ok {
in[i] = reflect.ValueOf(param_bool)
}
case reflect.Int:
if param_float64, ok := paramItem.(int); 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.(int64); ok {
in[i] = reflect.ValueOf(int64(param_float64))
} else if param_uint64, ok := paramItem.(uint64); ok {
in[i] = reflect.ValueOf(int64(param_uint64))
} else if param_string, ok := paramItem.(string); ok {
i64, err := strconv.ParseInt(param_string, 10, 64)
if err == nil {
in[i] = reflect.ValueOf(i64)
}
}
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.(uint8); ok {
in[i] = reflect.ValueOf(uint8(param_float64))
}
case reflect.Uint16:
if param_float64, ok := paramItem.(uint16); 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), 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), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(int); ok {
params_inner[i] = int(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]int8":
params_inner := make([]int8, len(param_interface), 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), 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), len(param_interface))
for i := 0; i < len(param_interface); i++ {
param_float64, ok := param_interface[i].(int32)
if ok {
params_inner[i] = int32(param_float64)
continue
} else {
param_int16, right := param_interface[i].(uint16)
if right == true {
params_inner[i] = int32(param_int16)
}
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]int64":
params_inner := make([]int64, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(int64); ok {
params_inner[i] = int64(param_float64)
} else if param_uint64, ok := param_interface[i].(uint64); ok {
params_inner[i] = int64(param_uint64)
} else if param_string, ok := param_interface[i].(string); ok {
i64, err := strconv.ParseInt(param_string, 10, 64)
if err == nil {
params_inner[i] = i64
}
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint":
params_inner := make([]uint, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint); ok {
params_inner[i] = uint(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
// case "[]uint8": 特殊处理
case "[]uint16":
params_inner := make([]uint16, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint16); ok {
params_inner[i] = uint16(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint32":
params_inner := make([]uint32, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint32); ok {
params_inner[i] = uint32(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint64":
params_inner := make([]uint64, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint64); ok {
params_inner[i] = uint64(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]float32":
params_inner := make([]float32, len(param_interface), 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), 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), 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 {
logUtilPlus.ErrorLog("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObj.Parameters)
responseObj.SetResultStatus(resultStatus.ParamInValid)
return
}
}
// 传入参数,调用方法
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
logUtilPlus.DebugLog("Begin Call Func:module:%v, method:%v,inParams:%v\n\n", requestObj.ModuleName, requestObj.MethodName, in)
}
}
out := methodAndInOutTypes.Method.Call(in)
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
for i, v := range in {
logUtilPlus.DebugLog("\nparams %v,%v\n", i, v)
}
}
}
// 并输出结果到客户端由于只有一个返回值所以取out[0]
if responseObj, ok = (&out[0]).Interface().(*webServer.ResponseObject); !ok {
logUtilPlus.ErrorLog("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0]))
responseObj.SetResultStatus(resultStatus.ParamInValid)
return
}
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
logUtilPlus.DebugLog("返回数据:code:%v, data:%v, mess:%v\n\n", responseObj.Code, responseObj.Value, responseObj.Message)
}
}
return
}

View File

@ -0,0 +1,34 @@
package httpServer
import (
"reflect"
)
// methodAndInOutTypes
// @description: 反射的方法和输入、输出参数类型组合类型
type methodAndInOutTypes struct {
// 反射出来的对应方法对象
Method reflect.Value
// 反射出来的方法的输入参数的类型集合
InTypes []reflect.Type
// 反射出来的方法的输出参数的类型集合
OutTypes []reflect.Type
}
// newmethodAndInOutTypes
// @description: newmethodAndInOutTypes
// parameter:
// @_method: _method
// @_inTypes: _inTypes
// @_outTypes: _outTypes
// return:
// @*methodAndInOutTypes: methodAndInOutTypes
func newmethodAndInOutTypes(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *methodAndInOutTypes {
return &methodAndInOutTypes{
Method: _method,
InTypes: _inTypes,
OutTypes: _outTypes,
}
}

View File

@ -0,0 +1,27 @@
package httpServer
import (
"common/webServer"
"encoding/json"
"fmt"
"goutil/logUtilPlus"
"net/http"
"strconv"
)
// responseResult
// @description: responseResult
// parameter:
// @w: w
// @responseObj: responseObj
// return:
func responseResult(w http.ResponseWriter, responseObj *webServer.ResponseObject) {
b, err := json.Marshal(responseObj)
if err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("序列化输出结果%v出错", responseObj))
return
}
w.Header().Add("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
}

View File

@ -0,0 +1,80 @@
package httpServer
import (
config "common/configsYaml"
"common/resultStatus"
"common/utils"
"common/webServer"
"encoding/json"
"fmt"
"goutil/logUtilPlus"
"goutil/stringUtil"
"net/http"
"strings"
)
// selfDefineMux
// @description: 定义自定义的Mux对象
type selfDefineMux struct {
}
// ServeHTTP
// @description: ServeHTTP
// parameter:
// @receiver mux: mux
// @w: w
// @r: r
// return:
func (mux *selfDefineMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
responseObj := webServer.GetInitResponseObj()
defer utils.LogReqErrorRecover(r)
// 判断是否是接口文档
if strings.Contains(r.RequestURI, "Remarks") && r.Method == "GET" {
remarkFunc(w, r)
return
}
// 判断是否是POST方法
if r.Method != "POST" {
responseResult(w, responseObj.SetResultStatus(resultStatus.OnlySupportPOST))
return
}
// 因为httpserver——面向外网client故屏蔽了webserver中的ip限制
// 构造contex
context, errMsg := NewApiContext(r, w, false)
if errMsg != nil {
// 输出结果
responseResult(w, responseObj.SetResultStatus(resultStatus.APIDataError))
return
}
// 根据路径选择不同的处理方法
if handlerFunObj, exists := GetHandleFunc(r.RequestURI); exists {
defer func() {
if config.DEBUG {
b, _ := json.Marshal(responseObj)
msg := fmt.Sprintf("API:%v 请求数据:%v;返回数据:%s;",
r.RequestURI, string(context.GetRequestBytes()), string(b))
logUtilPlus.DebugLog(msg)
}
}()
// 输出结果
responseObj := handlerFunObj.HandleFun()(context)
responseResult(w, responseObj)
return
}
// 通过反射选择不同的方法
strs := stringUtil.Split(r.RequestURI, []string{"/"})
params, err := context.RequestDataBySlice2()
if err != nil {
responseResult(w, responseObj.SetResultStatus(resultStatus.APIDataError))
return
}
resquestData := webServer.NewRequestObject(strs[1], strs[2], params)
resp := CallFunction(resquestData)
responseResult(w, resp)
}

View File

@ -0,0 +1,42 @@
package httpServer
import (
"fmt"
"net/http"
"sync"
"goutil/logUtil"
"goutil/logUtilPlus"
// "log"
"net/http/pprof"
config "common/configsYaml"
)
// Start
// @description: 启动服务器
// parameter:
// @wg: WaitGroup对象
// return:
func Start(wg *sync.WaitGroup) {
defer func() {
wg.Done()
}()
// 启动过程中不需要捕获异常
logUtilPlus.PrintAndWriteLog(logUtil.Info, fmt.Sprintf("Web服务器开始监听:%v", config.WebServerAddress))
// 启动Web服务器监听
mux := http.NewServeMux()
mux.Handle("/", &selfDefineMux{})
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)
err := http.ListenAndServe(config.WebServerAddress, mux)
if err != nil {
panic(fmt.Errorf("ListenAndServe失败错误信息为%s", err))
}
}

View File

@ -0,0 +1,58 @@
package remark
// 方法说明对象
type MethodRemark struct {
// 模块名称
ModuleName string
// 方法名称
Name string
// 方法描述
Desc string
// 接口作者
Author string
// 修改者
Mendor string
// 接口设计日期
Date string
// 输入参数
InParam []string
// 输出参数
OutParam string
}
// newMethodRemark
// @description: 创建新的方法说明对象
// parameter:
// @moduleName: 模块名称
// @name: 方法名称
// @desc: 方法描述
// @author: 方法作者
// @mendor: 方法修改者(多个用,分隔)
// @date: 创建日期
// @inParam: 输入参数
// @outParam: 输出参数
// return:
// @*MethodRemark: 新的方法说明对象
func newMethodRemark(moduleName, name, desc, author, mendor, date string, inParam []string, outParam string) *MethodRemark {
if mendor == "" {
mendor = "无"
}
return &MethodRemark{
ModuleName: moduleName,
Name: name,
Desc: desc,
Author: author,
Mendor: mendor,
Date: date,
InParam: inParam,
OutParam: outParam,
}
}

View File

@ -0,0 +1,48 @@
package remark
// ModuleRemark
// @description: 模块说明对象
type ModuleRemark struct {
// 模块名称
Name string
// 模块描述
Desc string
// 接口作者
Author string
// 修改者
Mendor string
// 接口设计日期
Date string
// 方法对象列表
MethodRemarkSlice []*MethodRemark
}
// newModuleRemark
// @description: 创建新的模块说明对象
// parameter:
// @name: 模块名称
// @desc: 模块描述
// @author: 模块作者
// @mendor: 模块修改者(多个用,分隔)
// @date: 创建日期
// return:
// @*ModuleRemark: 新的模块说明对象
func newModuleRemark(name, desc, author, mendor, date string) *ModuleRemark {
if mendor == "" {
mendor = "无"
}
return &ModuleRemark{
Name: name,
Desc: desc,
Author: author,
Mendor: mendor,
Date: date,
MethodRemarkSlice: make([]*MethodRemark, 0, 16),
}
}

View File

@ -0,0 +1,60 @@
package remark
import (
"goutil/logUtilPlus"
)
var (
remarksSlice []*ModuleRemark = make([]*ModuleRemark, 0, 32)
)
// RegisterModuleRemark
//
// @description: 注册模块说明对象
//
// parameter:
//
// @name: 模块名称
// @desc: 模块描述
// @author: 模块作者
// @mendor: 模块修改者(多个用,分隔)
// @date: 创建日期
//
// return:
func RegisterModuleRemark(name, desc, author, mendor, date string) {
remarksSlice = append(remarksSlice, newModuleRemark(name, desc, author, mendor, date))
}
// RegisterMethodRemark
//
// @description: 注册方法说明对象
//
// parameter:
//
// @moduleName: 模块名称
// @name: 方法名称
// @desc: 方法描述
// @author: 方法作者
// @mendor: 方法修改者(多个用,分隔)
// @date: 创建日期
// @inParam: 输入参数
// @outParam: 输出参数
//
// return:
func RegisterMethodRemark(moduleName, name, desc, author, mendor, date string, inParam []string, outParam string) {
var moduleRemark *ModuleRemark
var exists bool
for _, item := range remarksSlice {
if item.Name == moduleName {
moduleRemark = item
exists = true
}
}
if !exists {
logUtilPlus.ErrorLog("ModuleRemark:%s尚未注册", moduleName)
return
}
moduleRemark.MethodRemarkSlice = append(moduleRemark.MethodRemarkSlice, newMethodRemark(moduleName, name, desc, author, mendor, date, inParam, outParam))
}

View File

@ -0,0 +1,56 @@
package remark
import (
"common/httpServer"
"fmt"
"net/http"
"common/webServer"
)
// init
// @description: init
// parameter:
// return:
func init() {
webServer.RegisterRemarkFunc(remarkdCallback)
httpServer.RegisterRemarkFunc(remarkdCallback)
}
// remarkdCallback
// @description: remarkdCallback
// parameter:
// @w: w
// @r: r
// return:
func remarkdCallback(w http.ResponseWriter, r *http.Request) {
for index, moduleItem := range remarksSlice {
// 输出模块信息
fmt.Fprintf(w, fmt.Sprintf("%d、%s【Name:%s Author:%s Mendor:%s Date:%s】\n", index+1, moduleItem.Desc, moduleItem.Name, moduleItem.Author, moduleItem.Mendor, moduleItem.Date))
// 输出方法列表信息
for subIndex, methodItem := range moduleItem.MethodRemarkSlice {
fmt.Fprintf(w, fmt.Sprintf(" %d.%d、%s【Name:%s Author:%s Mendor:%s Date:%s】\n", index+1, subIndex+1, methodItem.Desc, methodItem.Name, methodItem.Author, methodItem.Mendor, methodItem.Date))
fmt.Fprintln(w, " \t输入参数")
if len(methodItem.InParam) > 0 {
for _, param := range methodItem.InParam {
fmt.Fprintln(w, " ", param)
}
} else {
fmt.Fprintln(w, " ", "无")
}
fmt.Fprintln(w, " \t输出参数")
if methodItem.OutParam != "" {
fmt.Fprintln(w, " ", methodItem.OutParam)
} else {
fmt.Fprintln(w, " ", "无")
}
fmt.Fprintln(w)
}
}
return
}

View File

@ -0,0 +1,71 @@
package resultStatus
import (
"fmt"
)
type StatusCode int
// ResultStatus
// @description: 状态码数据
type ResultStatus struct {
// 状态码
code StatusCode
// 消息
message string
}
// Code
// @description: 状态码
// parameter:
// @receiver this: this
// return:
// @StatusCode: 状态码
func (this *ResultStatus) Code() StatusCode {
return this.code
}
// Message
// @description: 错误信息
// parameter:
// @receiver this: this
// return:
// @string:
func (this *ResultStatus) Message() string {
return this.message
}
// NewResultStatus
// @description: 创建新的状态码对象
// parameter:
// @_code: 错误码
// @_message: 提示消息
// return:
// @ResultStatus: 状态码对象
func NewResultStatus(_code StatusCode, _message string) ResultStatus {
return ResultStatus{
code: _code,
message: _message,
}
}
// IsSuccess
// @description: 是否是成功
// parameter:
// @receiver this: this
// return:
// @bool: true:成功 false:失败
func (this *ResultStatus) IsSuccess() bool {
return this.code == Success.Code()
}
// String
// @description: 打印状态码信息
// parameter:
// @receiver this: this
// return:
// @string: 状态码信息
func (this *ResultStatus) String() string {
return fmt.Sprintf("Code:%d,Message:%s", this.code, this.message)
}

View File

@ -0,0 +1,910 @@
package resultStatus
// 系统错误码
var (
// 成功
Success = NewResultStatus(0, "Success")
// 数据库错误
DBError = NewResultStatus(-2, "DBError")
// 方法未定义
MethodNotDefined = NewResultStatus(-3, "MethodNotDefined")
// 参数无效
ParamInValid = NewResultStatus(-4, "ParamInValid")
// 参数不匹配
ParamNotMatch = NewResultStatus(-5, "ParamNotMatch")
// 功能未开启
ModuleNotOpen = NewResultStatus(-6, "ModuleNotOpen")
// 只支持Post
OnlySupportPOST = NewResultStatus(-7, "OnlySupportPOST")
// API未定义
APINotDefined = NewResultStatus(-8, "APINotDefined")
// API数据错误
APIDataError = NewResultStatus(-9, "APIDataError")
// API参数错误
APIParamError = NewResultStatus(-10, "APIParamError")
// IP被禁用
IPForbid = NewResultStatus(-11, "IPForbid")
// 没有有效的服务器
NoAvailableServer = NewResultStatus(-12, "NoAvailableServer")
// 服务器组不存在
ServerGroupNotExists = NewResultStatus(-13, "ServerGroupNotExists")
// 测试接口只能debug下调用
DebugInterface = NewResultStatus(-14, "DebugInterface")
// 模块不存在
ModuleNotExists = NewResultStatus(-15, "ModuleNotExists")
// 未能找到指定方法
NotSpecificMethod = NewResultStatus(-16, "NotSpecificMethod")
// 非指定区域
NotMatchRegion = NewResultStatus(-17, "NotMatchRegion")
// 发送空数据
SendNullData = NewResultStatus(-18, "SendNullData")
// 序列化失败
MarshalDataError = NewResultStatus(-19, "MarshalDataError")
//未登录
NotLogin = NewResultStatus(-20, "NotLogin")
// 数据错误
DataError = NewResultStatus(-31, "DataError")
// 战区合并维护中,敬请期待
MergeDataRunning = NewResultStatus(-67, "MergeDataRunning")
// 下载器内容未配置
QcDownloadConfigNotExists = NewResultStatus(-68, "QcDownloadConfigNotExists")
// 下载器奖励已领取
QcDownloadHasReward = NewResultStatus(-69, "QcDownloadHasReward")
// 下载器奖励没有奖励可领取
QcDownloadNotReward = NewResultStatus(-70, "QcDownloadNotReward")
// 下载器奖励积分不足
QcDownloadNotScore = NewResultStatus(-71, "QcDownloadNotScore")
)
// 玩家
var (
// 玩家不存在
PlayerNotExist = NewResultStatus(-1110, "PlayerNotExist")
// 没有合适的玩家
NotSuitablePlayer = NewResultStatus(-1155, "NotSuitablePlayer")
// 玩家阵容不存在
PlayerSlotFormationNotExist = NewResultStatus(-1156, "PlayerSlotFormationNotExist")
)
// 仙盟和GS保持同步
var (
// 玩家不在仙盟中
GuildNotIn = NewResultStatus(-9401, "玩家不在仙盟中")
// 仙盟不存在
GuildNotExist = NewResultStatus(-9402, "仙盟不存在")
// 玩家已在仙盟中
GuildHasIn = NewResultStatus(-9403, "玩家已在仙盟中")
// 玩家操作目标和所在仙盟不一致
TargetGuildNotMatch = NewResultStatus(-9404, "玩家操作目标和所在仙盟不一致")
// 仙盟不存在成员
GuildMemberNotExist = NewResultStatus(-9405, "仙盟不存在成员")
// vip等级不足
GuildNeedVip = NewResultStatus(-9406, "vip等级不足")
// 仙盟权限不足
GuildNeedAuth = NewResultStatus(-9407, "仙盟权限不足")
// boss节点今日未开放
GuildBossTodayNotOpen = NewResultStatus(-9411, "boss节点今日未开放")
// 职位人数已满
GuildPostEnough = NewResultStatus(-9415, "职位人数已满")
// boss开启错误
GuildBossOpenError = NewResultStatus(-9416, "boss开启错误")
// boss开启条件不足
GuildBossOpenEnough = NewResultStatus(-9417, "boss开启条件不足")
// 仙盟名称已存在
GuildNameHasExist = NewResultStatus(-9419, "仙盟名称已存在")
// 该职位人数达上限
GuildPostLimit = NewResultStatus(-9420, "该职位人数达上限")
// 世界喊话CD中
GuildShareCd = NewResultStatus(-9423, "世界喊话CD中")
// 弹劾条件不足
GuildImpeachNotEnough = NewResultStatus(-9424, "弹劾条件不足")
// 不是成员或者长老
GuildIsNotMember = NewResultStatus(-9428, "不是成员或者长老")
// boss已开启
GuildBossHasOpen = NewResultStatus(-9429, "boss已开启")
// 盟主不允许退盟
GuildLeaderNotAllowedExit = NewResultStatus(-9430, "盟主不允许退盟")
// 盟主公告锁定
GuildNoticeIsLock = NewResultStatus(-9431, "盟主公告锁定")
// 仙盟次数不足
GuildMiniGameNumNotAllow = NewResultStatus(-9439, "仙盟次数不足")
// 仙盟名称已被占用
GuildNameIsNotValid = NewResultStatus(-9445, "仙盟名称已存在")
// 不是盟主
GuildPlayerNotLeader = NewResultStatus(-9454, "不是盟主")
// 模式切换未到冷却时间
GuildSwitchModeNotCool = NewResultStatus(-9455, "模式切换未到冷却时间")
// 该玩家职位变更还在冷却中
GuildChangePostNotCool = NewResultStatus(-9460, "该玩家职位变更还在冷却中")
// 当前仙盟管理模式不可任命
GuildModeCanNotAppoint = NewResultStatus(-9461, "当前仙盟管理模式不可任命")
// 当前仙盟管理模式不可挑战
GuildModeCanNotFight = NewResultStatus(-9463, "当前仙盟管理模式不可挑战")
// 玩家等级不满足仙盟等级要求
GuildPlayerLvLessThanNeedLv = NewResultStatus(-9465, "玩家等级不满足仙盟等级要求")
// 玩家未申请
GuildPlayerNotApply = NewResultStatus(-9466, "玩家未申请")
// 仙盟信息未变更
GuildInfoNotChange = NewResultStatus(-9483, "仙盟信息未变更")
// 战略编辑次数不足,明日再来
GuildStrategyEditNum = NewResultStatus(-9486, "战略编辑次数不足,明日再来")
// 建筑不存在
GuildBuildNotExist = NewResultStatus(-9489, "建筑不存在")
// 礼包已采购
GuildWelfarePurchased = NewResultStatus(-9490, "该礼包已采购")
// 礼包已采购
GuildWelfareCaptailNotEnough = NewResultStatus(-9491, "采购礼包所需资金不足")
// 礼包已采购
GuildWelfareLvNotEnough = NewResultStatus(-9492, "仙盟等级不足,无法采购")
// 建筑经验超过最大值
GuildBuildExpOverMax = NewResultStatus(-9496, "建筑经验超过最大值")
// 未能设置该类型职位信息
GuildSetPostTypeNot = NewResultStatus(-9497, "未能设置该类型职位信息")
// 仙盟成员已达上限
GuildNumMax = NewResultStatus(-9499, "仙盟成员已达上限")
// 建筑尚未开启
GuildBuildIsLock = NewResultStatus(-109013, "建筑尚未开启")
// 建筑配置未获取
GuildBuildConfigNotExist = NewResultStatus(-109014, "未获取到建筑配置")
// 等级不匹配
GuildWelfareLvNotMatch = NewResultStatus(-109015, "等级不匹配")
// 建筑等级已达到满级
GuildBuildHasMaxLv = NewResultStatus(-109017, "建筑等级已达到满级")
// 采购礼包ID不存在
GuildGiftIdNotExist = NewResultStatus(-109018, "采购礼包ID不存在")
// 盟主令次数不足
GuildLeaderOrderCount = NewResultStatus(-109019, "盟主令次数不足")
// 仙盟每日可踢出人数已达上限
GuildTodayKickOutCountIsMax = NewResultStatus(-109020, "仙盟每日可踢出人数已达上限")
// 已申请该仙盟,请耐心等待审核
GuildHasApply = NewResultStatus(-109499, "已申请该仙盟,请耐心等待审核")
)
// 仙盟试炼
var (
GuildTrainBoxRewardDrawed = NewResultStatus(-109001, "仙盟试炼宝箱已领取")
// 仙盟boss战报不存在
GuildTimeBossReportNotExists = NewResultStatus(-109002, "仙盟boss战报不存在")
// 仙盟试炼节点不存在
GuildTrainNodeNotExists = NewResultStatus(-109003, "仙盟试炼节点不存在")
// 仙盟试炼奖励槽位不存在
GuildTrainBoxSlotNotExists = NewResultStatus(-109004, "仙盟试炼奖励槽位不存在")
// 仙盟试炼目标位置奖励信息已变化
GuildTrainBoxSlotHasRefresh = NewResultStatus(-109005, "仙盟试炼目标位置奖励信息已变化")
// 仙盟限时boss开启积分不足
GuildTimedOpenNotEnougth = NewResultStatus(-109006, "仙盟限时boss开启积分不足")
// 仙盟限时boss开启积分不足
GuildTrainNotKill = NewResultStatus(-109007, "BOSS未镇压无法领奖")
// 试炼章节暂未开启
GuildTrainNodeNotOpen = NewResultStatus(-109010, "试炼章节暂未开启")
// 试炼已经镇压
GuildTrainIsKilled = NewResultStatus(-109011, "BOSS已镇压不可挑战")
)
// 仙盟红包
var (
// 仙盟红包不存在
GuildRedPacketNotExist = NewResultStatus(-9950, "仙盟红包不存在")
// 仙盟玩家红包不存在
GuildPlayerRedPacketNotExist = NewResultStatus(-9959, "仙盟玩家红包不存在")
// 仙盟红包已过期
GuildRedPacketIsExpire = NewResultStatus(-9953, "仙盟红包已过期")
// 仙盟红包没有奖励可以领取
GuildRedPacketNotReward = NewResultStatus(-9960, "仙盟红包没有奖励可以领取")
// 仙盟红包奖励已领取
GuildRedPacketHasRewarded = NewResultStatus(-9954, "仙盟红包奖励已领取")
)
// 组队副本
var (
// 房间不存在
TeamCopyRoomNotExists = NewResultStatus(-9612, "TeamCopyRoomNotExists")
// 成员不存在
TeamCopyMemberNotExists = NewResultStatus(-9613, "TeamCopyMemberNotExists")
// 不是房主
TeamCopyNotIsLeader = NewResultStatus(-9614, "TeamCopyNotIsLeader")
// 战斗失败
TeamCopyFigthFail = NewResultStatus(-9615, "TeamCopyFigthFail")
// 房间玩家未准备
TeamCopyNotAllReady = NewResultStatus(-9616, "TeamCopyNotAllReady")
// 玩家人数不足
TeamCopyNotEnough = NewResultStatus(-9617, "TeamCopyNotEnough")
// 玩家战力不足
TeamCopyFapNotEnough = NewResultStatus(-9618, "TeamCopyFapNotEnough")
// 仍有奖励未领取
TeamCopyHasReward = NewResultStatus(-9619, "TeamCopyHasReward")
// 未被邀请
TeamCopyNotShare = NewResultStatus(-9620, "TeamCopyNotShare")
// 目标节点尚未开启
TeamCopyNodeNotOpen = NewResultStatus(-9622, "TeamCopyNodeNotOpen")
// 人数已满
TeamCopyIsMax = NewResultStatus(-9624, "TeamCopyIsMax")
// 没有权限进入房间
TeamCopyNotAuth = NewResultStatus(-9625, "TeamCopyNotAuth")
// 组队战斗已开始
TeamCopyIsFighting = NewResultStatus(-9626, "TeamCopyIsFighting")
// 邀请已存在
TeamCopyIsExistShare = NewResultStatus(-9627, "TeamCopyIsExistShare")
// 队伍不能为全部助战状态
TeamCopyIsAllHelp = NewResultStatus(-9633, "TeamCopyIsAllHelp")
// 您已被踢出
TeamCopyKickOut = NewResultStatus(-9638, "TeamCopyKickOut")
// 房间已经解散
TeamCopyRoomRemove = NewResultStatus(-9639, "房间已经解散")
// 玩家不在房间中
TeamCopyRoomMemberNotIn = NewResultStatus(-9644, "玩家不在房间中")
// 玩家战力不足
TeamCopyPlayerFapLimit = NewResultStatus(-9647, "玩家战力不足")
// 布阵阵容错误
TeamCopyFormationError = NewResultStatus(-212603, "布阵阵容错误")
// 单人模式不允许加入
TeamCopySingleNotJoin = NewResultStatus(-212604, "单人模式不允许加入")
// 队员未准备
PlayerNotReady = NewResultStatus(-212605, "队员未准备")
)
// 矿战
var (
// 矿战玩家信息不存在
KuangzhanPlayerNotExist = NewResultStatus(-36131, "KuangzhanPlayerNotExist")
// 占领节点错误
KuangzhanOccupyNode = NewResultStatus(-36113, "KuangzhanOccupyNode")
// 矿战节点不存在
NodeConfigNotExist = NewResultStatus(-36132, "NodeConfigNotExist")
// 此洞府正在被攻击
TheOtherPlayerFighting = NewResultStatus(-36114, "TheOtherPlayerFighting")
// 该节点已经被占领
KuangzhanoverOccupyNode = NewResultStatus(-36113, "KuangzhanoverOccupyNode")
// 占领节点玩家无阵容
KuangzhanPlayerNoFormation = NewResultStatus(-36133, "KuangzhanPlayerNoFormation")
// 获取阵容失败
KuangzhanPlayerGetFormationFail = NewResultStatus(-36134, "KuangzhanPlayerGetFormationFail")
// 已占领洞府节点
KuangzhanOverLoad = NewResultStatus(-36115, "KuangzhanOverLoad")
// 今日抢夺次数已经用完
KuangzhanDailyLootOver = NewResultStatus(-36117, "KuangzhanDailyLootOver")
// 此洞府今日已无法被抢夺
KuangzhanDailyRobbedOver = NewResultStatus(-36118, "KuangzhanDailyRobbedOver")
// 洞天抢夺暂未开启
KuangzhanRobbedTimeNotOpen = NewResultStatus(-36119, "KuangzhanRobbedTimeNotOpen")
// 剩余洞天宝石不可抢夺
KuangzhanGemIsOver = NewResultStatus(-36120, "KuangzhanGemIsOver")
// 玩家不匹配
KuangzhanPlayerNotMatching = NewResultStatus(-36122, "KuangzhanPlayerNotMatching")
// 不是被邀请的玩家
KuangzhanInviteFailed = NewResultStatus(-36123, "邀请好友失败")
// 不是被邀请的玩家
KuangzhanNotInvited = NewResultStatus(-36124, "不是被邀请的玩家")
// 协助信息已失效
KuangzhanInviteExpired = NewResultStatus(-36125, "协助信息已失效")
// 已经帮助过该玩家
KuangzhanAlreadyHelped = NewResultStatus(-36135, "已经帮助过该玩家")
// 对方任务已经完成
KuangzhanTaskFinished = NewResultStatus(-36136, "对方任务已经完成")
)
// 蜀山论剑
var (
// 战斗校验出现异常
FightException = NewResultStatus(-1354, "FightException")
// 比武大会玩家信息不存在
HegeMonyPlayerInfoNotExist = NewResultStatus(-9701, "HegeMonyPlayerInfoNotExist")
// 比武大会玩家已有匹配
HegeMonyHasMatch = NewResultStatus(-9702, "HegeMonyHasMatch")
// 比武大会玩家未找到匹配
HegeMonyNotMatch = NewResultStatus(-9703, "HegeMonyNotMatch")
// 比武大会玩家未找到阵容
HegeMonyFormationNotExist = NewResultStatus(-9704, "HegeMonyFormationNotExist")
// 比武大会对手玩家信息不存在
HegeMonyTargetPlayerInfoNotExist = NewResultStatus(-9705, "HegeMonyTargetPlayerInfoNotExist")
// 比武大会玩家未匹配
HegeMonyPlayerNotMatch = NewResultStatus(-9706, "HegeMonyPlayerNotMatch")
// 比武大会赛季不匹配
SeasonNotMatch = NewResultStatus(-9707, "SeasonNotMatch")
// 比武大会战报信息不存在
HegeMonyReportNotExist = NewResultStatus(-9730, "HegeMonyReportNotExist")
// 比武大会战斗未能找到匹配对手
HegeMonyFightNotMatch = NewResultStatus(-9731, "HegeMonyFightNotMatch")
// 比武大会荣耀玩家不存在
HegeMonyHonorPlayerNotExist = NewResultStatus(-9732, "HegeMonyHonorPlayerNotExist")
)
// 战报
var (
// 战报信息不存在
FightReportNotExist = NewResultStatus(-9707, "FightReportNotExist")
// 数据解析错误
JsonDecodeDataError = NewResultStatus(-9708, "JsonDecodeDataError")
)
// 喜信
var (
// 信息Id错误
HappyNewsIdError = NewResultStatus(-40103, "HappyNewsIdError")
// 信息序号错误
HappyNewsOrderIdError = NewResultStatus(-40104, "HappyNewsOrderIdError")
// 喜信获取好友失败
HappyNewsGetFriendsError = NewResultStatus(-40105, "HappyNewsGetFriendsError")
// 没有好友
NoFriend = NewResultStatus(-8565, "NoFriend")
)
// 仙盟远征
var (
// 仙盟远征错误
GuildExpeditionError = NewResultStatus(-29900, "GuildExpeditionError")
// 仙盟远征活动未开启
GuildExpeditionActivityNotOpen = NewResultStatus(-29906, "GuildExpeditionActivityNotOpen")
// 仙盟远征公会未匹配
GuildExpeditionGuildNotMatch = NewResultStatus(-29908, "GuildExpeditionGuildNotMatch")
// 仙盟远征阵容无法解析
GuildExpeditionFormationUnknow = NewResultStatus(-29909, "GuildExpeditionFormationUnknow")
// 仙盟远征房间信息不存在
GuildExpeditionRoomInfoError = NewResultStatus(-29912, "GuildExpeditionRoomInfoError")
// 仙盟远征阶段一挑战次数不足
GuildExpeditionFirstStepTimesIsNotEnough = NewResultStatus(-29913, "GuildExpeditionfirstStepTimesIsNotEnough")
// 仙盟远征阶段一挑战次数不足
GuildExpeditionSecondStepTimesIsNotEnough = NewResultStatus(-29914, "GuildExpeditionSecondStepTimesIsNotEnough")
// 仙盟远征房间已锁定
GuildExpeditionRoomIsLock = NewResultStatus(-29915, "GuildExpeditionRoomIsLock")
// 不是参与远征的仙盟成员
GuildExpeditionIsNotJoinMember = NewResultStatus(-29916, "GuildExpeditionIsNotJoinMember")
// 目标没有防御阵容
GuildExpeditionTargetNoDefenceFormation = NewResultStatus(-29917, "GuildExpeditionTargetNoDefenceFormation")
// 仙盟远征战斗验证失败
GuildExpeditionFightValidFail = NewResultStatus(-29918, "GuildExpeditionFightValidFail")
)
// 义结金兰
var (
// 玩家未结交标记g_yjjl对象
YjjlPlayerNotExist = NewResultStatus(-33501, "YjjlPlayerNotExist")
// 玩家未结义标记g_yjjl_player对象
YjjlPlayerNotExistForPlayer = NewResultStatus(-33588, "YjjlPlayerNotExistForPlayer")
// 玩家未结义,标记玩家对象属于第三者
YjjlPlayerNotMatch = NewResultStatus(-33589, "YjjlPlayerNotMatch")
// 玩家已结交
YjjlPlayerHasExist = NewResultStatus(-33502, "YjjlPlayerHasExist")
// 玩家已设置本特效
QingyiLvSpecialeffectsIsExists = NewResultStatus(-33515, "QingyiLvSpecialeffectsIsExists")
// 亲密付已达月上限
HelpPayIsLimit = NewResultStatus(-33571, "HelpPayIsLimit")
// 玩家当前未培养花卉
FlowerNotExist = NewResultStatus(-33523, "FlowerNotExist")
// 玩家当前花卉经验值已满
FlowerExpIsMax = NewResultStatus(-33524, "FlowerExpIsMax")
// 玩家当前花卉经验值未满
FlowerExpNotEnough = NewResultStatus(-33525, "FlowerExpNotEnough")
// 玩家已培养花卉
FlowerIsExists = NewResultStatus(-33530, "FlowerIsExists")
// 培养的花卉不匹配
FlowerNotMatch = NewResultStatus(-33531, "FlowerNotMatch")
// 花卉可收获,不能重置
FlowerCanGet = NewResultStatus(-33532, "FlowerCanGet")
// 同心榜CP组唯一标识错误
RankGroupIdError = NewResultStatus(-33541, "RankGroupIdError")
// 暂无留言
RankTipNotExists = NewResultStatus(-33542, "RankTipNotExists")
// 结交好友匹配错误
RankCpMatchError = NewResultStatus(-33544, "RankCpMatchError")
// 留言点赞和玩家结义数据不匹配
RankCpMessageZanNotMatch = NewResultStatus(-33545, "RankCpMessageZanNotMatch")
// 该玩家今日已点赞!
PlayerGood = NewResultStatus(-212301, "PlayerGood")
// 义结金兰没有任务数据
YjjlTaskNoData = NewResultStatus(-33547, "YjjlTaskNoData")
// 金兰契奖励节点错误
YjjlRewardNodeError = NewResultStatus(-33568, "YjjlRewardNodeError")
// 亲密等级不足
IntimacyLvNotEnough = NewResultStatus(-33569, "IntimacyLvNotEnough")
// 活动期间获取的亲密度不足
AddIntimacyNotEnough = NewResultStatus(-33583, "活动期间获取的亲密度不足")
// 亲密度奖励已经领取
HasAddIntimacyReward = NewResultStatus(-33584, "亲密度奖励已经领取")
// 亲密等级不足,未解锁
YjjlShowIsLock = NewResultStatus(-33586, "亲密等级不足,未解锁")
// 活动还没结束
TimedActivityNotClose = NewResultStatus(-2006, "活动还没结束")
)
// 蜀山之巅(跨服Pvp冠军赛)
var (
// 赛季未开启
WeekChampionSeasonNotOpen = NewResultStatus(-4000, "WeekChampionSeasonNotOpen")
// 赛季分组数据不存在
WeekChampionNoExistGroupMatch = NewResultStatus(-4007, "WeekChampionNoExistGroupMatch")
// 跨服蜀山之巅竞猜玩家错误
WeekChampionBetPlayerError = NewResultStatus(-4008, "WeekChampionBetPlayerError")
// 战报信息不存在
WeekChampionFightReportNotExist = NewResultStatus(-4009, "WeekChampionFightReportNotExist")
// 战报信息解析错误
WeekChampionFightReportJsonDecodeDataError = NewResultStatus(-4010, "WeekChampionFightReportJsonDecodeDataError")
)
var (
// SocialSquareGiftNotExist 礼物不存在
SocialSquareGiftNotExist = NewResultStatus(-40400, "SocialSquareGiftNotExist")
// SocialSquarePlayerNotExist 社交广场玩家不存在
SocialSquarePlayerNotExist = NewResultStatus(-40401, "SocialSquarePlayerNotExist")
// SocialSquarePhotoNotExist 社交广场玩家不存在
SocialSquarePhotoNotExist = NewResultStatus(-40402, "SocialSquarePhotoNotExist")
)
var (
// 模块错误
VideoModuleError = NewResultStatus(-38183, "VideoModuleError")
// 未检测到该战报
VideoIdError = NewResultStatus(-38184, "VideoIdError")
)
var (
// 金兰宴玩家对象不是举办方
YjjlFeastIsNotHost = NewResultStatus(-44108, "YjjlFeastIsNotHost")
// 宴会还在准备中
YjjlFeastIsPreraring = NewResultStatus(-44111, "YjjlFeastIsPreraring")
// 金兰宴宴会已开始
YjjlFeastRandomIsStart = NewResultStatus(-44112, "YjjlFeastRandomIsStart")
// 金兰宴房间类型错误
YjjlFeastRoomTypeError = NewResultStatus(-44116, "YjjlFeastRoomTypeError")
// 金兰宴房间不存在
YjjlFeastRoomNotExist = NewResultStatus(-44118, "YjjlFeastRoomNotExist")
// 金兰宴玩家不能加入该房间
YjjlFeastPlayerCantEnterThisRoom = NewResultStatus(-44119, "YjjlFeastPlayerCantEnterThisRoom")
// 金兰宴玩家不能同时主办两场及以上的宴会
YjjlFeastHostBuySamePlayer = NewResultStatus(-44120, "YjjlFeastHostBuySamePlayer")
// 金兰宴宾客人数达到上限
YjjlFeastRoomGuestMax = NewResultStatus(-44121, "YjjlFeastRoomGuestMax")
// 金兰宴玩家不在房间
YjjlFeastIsNotInScene = NewResultStatus(-44122, "YjjlFeastIsNotInScene")
// 金兰宴不是来宾
YjjlFeastIsHost = NewResultStatus(-44123, "YjjlFeastIsHost")
// 金兰宴红包不存在
YjjlFeastRedPacketNotExist = NewResultStatus(-44124, "YjjlFeastRedPacketNotExist")
// 金兰宴红包已领取或已领完
YjjlFeastRedPacketHadDraw = NewResultStatus(-44125, "YjjlFeastRedPacketHadDraw")
)
var (
// 全服红包id错误
RedPacketIdError = NewResultStatus(-40501, "RedPacketIdError")
// 全服红包已经领取完
RedPacketHaveOver = NewResultStatus(-40502, "RedPacketHaveOver")
// 全服红包不可领取
RedPacketCanNotDraw = NewResultStatus(-40503, "RedPacketCanNotDraw")
// 已经领取该红包
RedPacketHaveDraw = NewResultStatus(-40504, "RedPacketHaveDraw")
// 红包领取失败
RedPacketDrawError = NewResultStatus(-40505, "RedPacketDrawError")
)
// 跨服昆仑神虚
var (
// 昆仑之墟尚未开启
GlobalCitywarMapNotOpen = NewResultStatus(-45003, "昆仑之墟尚未开启")
// 仙盟未参与
CitywarCsGuildNotParticipate = NewResultStatus(-50000, "CitywarCsGuildNotParticipate")
// 跨服昆仑神虚地图不存在
CitywarCsMapNotExist = NewResultStatus(-50001, "CitywarCsMapNotExist")
// 跨服昆仑神虚城池不存在
CitywarCsLandNotExist = NewResultStatus(-50002, "CitywarCsLandNotExist")
// 跨服昆仑神虚城池未占领
CitywarCsLandNotOccupy = NewResultStatus(-50003, "CitywarCsLandNotOccupy")
// 跨服昆仑神虚城池正在战斗中
CitywarCsLandIsFighting = NewResultStatus(-50004, "CitywarCsLandIsFighting")
// 昆仑之墟节点坐标不匹配
CitywarCsAxisNotRight = NewResultStatus(-50011, "CitywarCsAxisNotRight")
// 昆仑之墟玩家队伍不存在
CitywarCsPlayerTeamNotExist = NewResultStatus(-50012, "CitywarCsPlayerTeamNotExist")
// 昆仑之墟玩家队伍复活中
CitywarCsPlayerTeamReviving = NewResultStatus(-50013, "CitywarCsPlayerTeamReviving")
// 昆仑之墟玩家已派遣
CitywarCsPlayerTeamIsMoving = NewResultStatus(-50014, "CitywarCsPlayerTeamIsMoving")
// 昆仑之墟玩家未派遣
CitywarCsPlayerTeamNoMoving = NewResultStatus(-50015, "CitywarCsPlayerTeamNoMoving")
// 昆仑之墟玩家玩家队伍已经死亡
CitywarCsTeamIdDead = NewResultStatus(-50016, "CitywarCsTeamIdDead")
// 没有奖励可以领取
CitywarCsNotDrawReward = NewResultStatus(-50017, "CitywarCsNotDrawReward")
// 昆仑之墟休战中
CitywarCsNotFightTime = NewResultStatus(-50018, "CitywarCsNotFightTime")
// 昆仑之墟已经结束
CitywarCsIsEnd = NewResultStatus(-50019, "CitywarCsIsEnd")
// 玩家昆仑之墟出征次数不足
CitywarCsFightNumNotEnough = NewResultStatus(-50020, "CitywarCsFightNumNotEnough")
// 昆仑之墟出生地无法操作
CitywarCsLandIsBirth = NewResultStatus(-50021, "CitywarCsLandIsBirth")
// 昆仑之墟队伍已放入仙盟大营中
CitywarCsPlayerTeamInGuildTeam = NewResultStatus(-50022, "CitywarCsPlayerTeamInGuildTeam")
// 昆仑之墟队伍不在仙盟大营中
CitywarCsPlayerTeamNotInGuildTeam = NewResultStatus(-50023, "CitywarCsPlayerTeamNotInGuildTeam")
// 昆仑神墟未选择仙盟大营中队伍
CitywarCsGuildTeamNotExist = NewResultStatus(-50024, "CitywarCsGuildTeamNotExist")
// 昆仑神墟地块正在燃烧
CitywarCsLandIsFire = NewResultStatus(-50025, "CitywarCsLandIsFire")
// 非相邻地不允许攻击
CitywarCsLandNotAdjoinNotAtk = NewResultStatus(-50027, "CitywarCsLandNotAdjoinNotAtk")
)
var (
// 巅峰对决信息不存在
PeakInfoNotExist = NewResultStatus(-40804, "PeakInfoNotExist")
// 该位置不是空位置
PeakRankNotEmpty = NewResultStatus(-40805, "PeakRankNotEmpty")
// 不能挑战低于自己的对手
PeakCantFight = NewResultStatus(-40806, "PeakCantFight")
// 排位已经变化
PeakNeedRefresh = NewResultStatus(-40808, "PeakNeedRefresh")
// 当前排名不可挑战,挑战列表已刷新
PeakNeedRefreshTwo = NewResultStatus(-40814, "PeakNeedRefreshTwo")
// 不可挑战前三
PeakCantFightTopThree = NewResultStatus(-40815, "PeakCantFightTopThree")
)
// 蜀山论剑PvpTournament
var (
// 玩家信息不存在
PvpTournamentInfoNotExist = NewResultStatus(-40901, "PvpTournamentInfoNotExist")
// 玩家未找到阵容
PvpTournamentFormationNotExist = NewResultStatus(-40902, "PvpTournamentFormationNotExist")
// 排位已经变化
PvpTournamentNeedRefresh = NewResultStatus(-40903, "PvpTournamentNeedRefresh")
// 不能挑战太靠前的玩家
PvpTournamentCantFight = NewResultStatus(-40907, "PvpTournamentCantFight")
)
// 幸运彩卡luckyCard
var (
// 幸运彩卡奖励配置不存在
LuckyCardRewardConfigNotExist = NewResultStatus(-42610, "LuckyCardRewardConfigNotExist")
// 幸运彩卡奖励不足
LuckyCardRewardNotEnough = NewResultStatus(-42611, "LuckyCardRewardNotEnough")
// 幸运彩卡青钻奖励不足
LuckyCardRewardQingzuanNotEnough = NewResultStatus(-42612, "LuckyCardRewardQingzuanNotEnough")
// 用户青钻额度不足
LuckyCardQingzuanNotEnough = NewResultStatus(-42613, "LuckyCardQingzuanNotEnough")
// 交换信息不存在
LuckyCardExchangeMessageNotExist = NewResultStatus(-42615, "LuckyCardExchangeMessageNotExist")
)
// 新版金兰宴
var (
// NewFeastHaveAppointment 已经预约过
NewFeastHaveAppointment = NewResultStatus(-41101, "NewFeastHaveAppointment")
// NewFeastAppointmentTimeOut 时间已过
NewFeastAppointmentTimeOut = NewResultStatus(-41102, "NewFeastAppointmentTimeOut")
// NotAppointment 没有预约
NewFeastNotAppointment = NewResultStatus(-41103, "NewFeastNotAppointment")
// NewFeastHaveInvite 已经邀请
NewFeastHaveInvite = NewResultStatus(-41104, "NewFeastHaveInvite")
// NewFeastAppointmentOverdue 宴会已过期
NewFeastAppointmentOverdue = NewResultStatus(-41105, "NewFeastAppointmentOverdue")
// 金兰宴房间不存在
NewFeastRoomNotExist = NewResultStatus(-41106, "NewFeastRoomNotExist")
// 金兰宴玩家不存在
NewFeastPlayerNotInRoom = NewResultStatus(-41107, "NewFeastPlayerNotInRoom")
// 金兰宴对方玩家不存在
NewFeastTargetPlayerPlayerNotInRoom = NewResultStatus(-41108, "NewFeastTargetPlayerPlayerNotInRoom")
// 道具已被抢
NewFeastPropBeRobbed = NewResultStatus(-41109, "NewFeastPropBeRobbed")
// 变身球数量不足
NewFeastBallNotEnough = NewResultStatus(-41110, "NewFeastBallNotEnough")
// 已拥有烟花
NewFeastHaveFirework = NewResultStatus(-41111, "NewFeastHaveFirework")
// 宴会已结束
NewFeastEnd = NewResultStatus(-41112, "NewFeastEnd")
// 已经品菜过了
NewFeastHaveEatFood = NewResultStatus(-41113, "NewFeastHaveEatFood")
// 不在品菜时间内
NewFeastNotEatFoodTime = NewResultStatus(-41114, "NewFeastNotEatFoodTime")
// 房间人气不足
NewFeastRoomPopularNotEnough = NewResultStatus(-41115, "NewFeastRoomPopularNotEnough")
// 密码不正确
NewFeastBoxPasswordError = NewResultStatus(-41116, "NewFeastBoxPasswordError")
// 不是房主
NewFeastNotHsot = NewResultStatus(-41117, "NewFeastNotHsot")
// 已经领取
NewFeastBoxHaveDraw = NewResultStatus(-41118, "NewFeastBoxHaveDraw")
// 房间人数已满
NewFeastRoomPlayerMax = NewResultStatus(-41119, "NewFeastRoomPlayerMax")
// 不能邀请
NewFeastCantInvite = NewResultStatus(-41120, "NewFeastCantInvite")
// 被其他人预约
NewFeastAppointmentByOthers = NewResultStatus(-41121, "NewFeastAppointmentByOthers")
)
// NoWorldBossDamageData 世界boss1.0
var (
NoWorldBossDamageData = NewResultStatus(-41200, "NoWorldBossDamageData")
)
var (
// 拍卖行商品不存在
AuctionGoodsNotExist = NewResultStatus(-41301, "AuctionGoodsNotExist")
// 拍卖行加价失败
AuctionAddPriceErr = NewResultStatus(-41302, "AuctionAddPriceErr")
// 仙盟拍卖暂无商品
AuctionGuildNoGoods = NewResultStatus(-41303, "AuctionGuildNoGoods")
// 仙盟拍卖未结束
AuctionGuildNotEnd = NewResultStatus(-41304, "AuctionGuildNotEnd")
// 分红已经领取
AuctionBonusHaveDraw = NewResultStatus(-41305, "AuctionBonusHaveDraw")
// 暂无分红
AuctionNoBonus = NewResultStatus(-41306, "AuctionNoBonus")
// 不能取消关注
AuctionCantCancelFollow = NewResultStatus(-41307, "AuctionCantCancelFollow")
// 拍卖未开始
AuctionNotStart = NewResultStatus(-41308, "AuctionNotStart")
// 该商品已经售出
AuctionGoodsHaveAuction = NewResultStatus(-41309, "AuctionGoodsHaveAuction")
// 该商品已经流拍
AuctionGoodsHaveNoPrice = NewResultStatus(-41310, "AuctionGoodsHaveNoPrice")
// 玩家金龙不足
AuctionPlayerGoldNotEnough = NewResultStatus(-41311, "AuctionPlayerGoldNotEnough")
//该商品拍卖时间已结束
AuctionGoodsEnd = NewResultStatus(-41312, "AuctionGoodsEnd")
//未参与决战神虚,不可分红
AuctionCantBonus = NewResultStatus(-41313, "AuctionCantBonus")
)
var (
// 交易行商品不存在
TradeProductNotExistInfoNotExist = NewResultStatus(-41500, "TradeProductNotExistInfoNotExist")
// 交易行审核类型不存在
TradeAuditTypeNotExist = NewResultStatus(-41501, "TradeAuditTypeNotExist")
)

View File

@ -0,0 +1,377 @@
package utils
import (
"bytes"
"compress/flate"
"encoding/json"
"fmt"
"goutil/logUtilPlus"
"io/ioutil"
"math/rand"
"net/http"
"runtime/debug"
"strconv"
"strings"
"time"
)
// 定义常量
var MinDateTime = time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local)
var MaxDateTime = time.Date(3000, 1, 1, 0, 0, 0, 0, time.Local)
var GuidEmpty = "00000000-0000-0000-0000-000000000000"
// IsTrue
// @description: 是否为true
// parameter:
// @data: []byte格式的bool信息
// return:
// @bool: 返回布尔值
func IsTrue(data []byte) bool {
if data == nil {
return false
}
if len(data) == 0 {
return false
}
if data[0] == 0 {
return false
} else {
return true
}
}
// ConvertBooleanToBytes
// @description: bool型转换成byte数组
// parameter:
// @status: 状态
// return:
// @[]byte: 返回字节数组
func ConvertBooleanToBytes(status bool) []byte {
if status == false {
return []byte{0}
} else {
return []byte{1}
}
}
// StrSliceJoinToStr
// @description: 将[]string组装成字符串
// parameter:
// @numArray: 源int32数组
// @sep: 分割字符串
// return:
// @string: 组成的字符串
func StrSliceJoinToStr(numArray []string, sep string) string {
str := ""
if numArray == nil || len(numArray) == 0 {
return str
}
for _, n := range numArray {
str += fmt.Sprintf("%s%s", n, sep)
}
str = strings.TrimSuffix(str, sep)
return str
}
// Int32SliceJoinToStr
// @description: 将[]int32转换成字符串
// parameter:
// @source: 资源
// @sep: 分隔符
// return:
// @result: 字符串
func Int32SliceJoinToStr(source []int32, sep string) (result string) {
if source == nil || len(source) == 0 {
return ""
}
for _, s := range source {
result += fmt.Sprintf("%d%s", s, sep)
}
result = strings.TrimRight(result, sep)
return
}
// SplitToStrSlice
// @description: 将字符串切割为[]string
// parameter:
// @s: 输入字符串
// @sep: 分割字符串
// @removeEmpty: 是否去除空字符串
// return:
// @resultSlice: 字符串列表
func SplitToStrSlice(s, sep string, removeEmpty bool) (resultSlice []string) {
if len(s) == 0 {
return make([]string, 0)
}
// 先按照分隔符进行切割
strSlice := strings.Split(s, sep)
for _, value := range strSlice {
if removeEmpty {
// 去除空格
if value = strings.TrimSpace(value); value == "" {
continue
}
}
resultSlice = append(resultSlice, value)
}
return resultSlice
}
// ParseTimeString
// @description: 解析时间字符串
// parameter:
// @timeStr: 时间字符串12:33:12
// return:
// @hour: 小时
// @minute: 分钟
// @second: 秒数
func ParseTimeString(timeStr string) (hour int, minute int, second int) {
timeSlice := strings.Split(timeStr, ":")
if len(timeSlice) != 3 {
return
}
hour, _ = strconv.Atoi(timeSlice[0])
minute, _ = strconv.Atoi(timeSlice[1])
second, _ = strconv.Atoi(timeSlice[2])
return
}
// Rm_duplicate_string
// @description: 去重
// parameter:
// @list: 列表
// return:
// @[]string: 去重后的数据
func Rm_duplicate_string(list []string) []string {
var x []string = []string{}
for _, i := range list {
if len(x) == 0 {
x = append(x, i)
} else {
for k, v := range x {
if i == v {
break
}
if k == len(x)-1 {
x = append(x, i)
}
}
}
}
return x
}
// Rm_duplicate_int32
// @description: 去重
// parameter:
// @list: 列表数据
// return:
// @[]int32: 去重后的结果
func Rm_duplicate_int32(list []int32) []int32 {
var x []int32 = []int32{}
for _, i := range list {
if len(x) == 0 {
x = append(x, i)
} else {
for k, v := range x {
if i == v {
break
}
if k == len(x)-1 {
x = append(x, i)
}
}
}
}
return x
}
// RandomAarrayOfInt32
// @description: int32数组乱序
// parameter:
// @arr: 数组
// return:
func RandomAarrayOfInt32(arr []int32) {
if arr == nil {
return
}
if len(arr) <= 0 {
return
}
rand.Seed(time.Now().UnixNano())
for i := len(arr) - 1; i > 0; i-- {
num := rand.Intn(i + 1)
arr[i], arr[num] = arr[num], arr[i]
}
}
// RandomAarrayOfString
// @description: string数组乱序
// parameter:
// @arr: 数组
// return:
func RandomAarrayOfString(arr []string) {
if arr == nil {
return
}
if len(arr) <= 0 {
return
}
rand.Seed(time.Now().UnixNano())
for i := len(arr) - 1; i > 0; i-- {
num := rand.Intn(i + 1)
arr[i], arr[num] = arr[num], arr[i]
}
}
// LogErrorRecover
// @description: 记录错误
// parameter:
// return:
func LogErrorRecover() {
if err := recover(); err != nil {
tmsg := fmt.Sprintf("err msg:%s stack:%s", err, debug.Stack())
logUtilPlus.ErrorLog(tmsg)
}
}
// LogReqErrorRecover
// @description: 记录错误
// parameter:
// @r:
// return:
func LogReqErrorRecover(r *http.Request) {
if err := recover(); err != nil {
b, err := json.Marshal(r)
reqStr := ""
if err == nil {
reqStr = string(b)
}
tmsg := fmt.Sprintf("RequestInfo:%s .err msg:%s stack:%s", reqStr, err, debug.Stack())
logUtilPlus.ErrorLog(tmsg)
}
}
// StringSliceIsExists
// @description: StringSliceIsExists
// parameter:
// @strList: strList
// @val: val
// return:
// @bool: 是否存在
func StringSliceIsExists(strList []string, val string) bool {
if strList == nil {
return false
}
for _, v := range strList {
if v == val {
return true
}
}
return false
}
// Int64SliceIsExists
// @description: Int64SliceIsExists
// parameter:
// @strList: strList
// @val: val
// return:
// @bool: 是否存在
func Int64SliceIsExists(strList []int64, val int64) bool {
if strList == nil {
return false
}
for _, v := range strList {
if v == val {
return true
}
}
return false
}
// SliceIsExists
// @description: SliceIsExists
// parameter:
// @n: n
// @f: f
// return:
// @bool: 是否存在
func SliceIsExists(n int, f func(int) bool) bool {
for i := 0; i < n; i++ {
if f(i) {
return true
}
}
return false
}
// FlateEncode
// @description: 压缩字符串
// parameter:
// @input: 输入字符列表
// return:
// @result: 结果字符列表
// @err: 错误信息
func FlateEncode(input []byte) (result []byte, err error) {
var buf bytes.Buffer
w, err := flate.NewWriter(&buf, flate.DefaultCompression)
if err != nil {
return nil, err
}
// 无法使用defer close使用无法拿到结果
_, err = w.Write(input)
if err != nil {
return nil, err
}
w.Close()
result = buf.Bytes()
return
}
// FlateDecode
// @description: FlateDecode
// parameter:
// @input: 输入字符列表
// return:
// @result: 结果字符列表
// @err: 错误信息
func FlateDecode(input []byte) (result []byte, err error) {
result, err = ioutil.ReadAll(flate.NewReader(bytes.NewReader(input)))
return
}

View File

@ -0,0 +1,218 @@
package webServer
import (
"encoding/json"
"fmt"
"goutil/jsonUtil"
"goutil/logUtilPlus"
"goutil/typeUtil"
"goutil/zlibUtil"
"io/ioutil"
"net/http"
)
// ApiContext
// @description: Api请求上下文对象
type ApiContext struct {
// 请求对象
request *http.Request
// 应答写对象
responseWriter http.ResponseWriter
// 请求数据
requestBytes []byte
// 字典形式的请求数据
requestDataByMap typeUtil.MapData
//获取头部信息
header *http.Header
}
// GetRequest
// @description: 获取请求对象
// parameter:
// @receiver this: this
// return:
// @*http.Request: 请求对象
func (this *ApiContext) GetRequest() *http.Request {
return this.request
}
// GetResponseWriter
// @description: 获取应答写对象
// parameter:
// @receiver this: this
// return:
// @http.ResponseWriter: 应答写对象
func (this *ApiContext) GetResponseWriter() http.ResponseWriter {
return this.responseWriter
}
// GetRequestBytes
// @description: 获取请求字节数据
// parameter:
// @receiver this: this
// return:
// @[]byte: 请求字节数组
func (this *ApiContext) GetRequestBytes() []byte {
return this.requestBytes
}
// readContent
// @description: 读取内容
// parameter:
// @receiver this: this 请求对象
// @isZlib: 是否数据压缩
// return:
// @content: 二进制格式的内容
// @err: 错误对象
func (this *ApiContext) readContent(isZlib bool) (content []byte, err error) {
var buffer []byte
defer this.request.Body.Close()
if buffer, err = ioutil.ReadAll(this.request.Body); err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,读取数据出错,错误信息为:%s", this.request.RequestURI, err))
return
}
// 不压缩,则直接返回
if isZlib == false {
this.requestBytes = buffer
return buffer, err
}
// 解压数据
if content, err = zlibUtil.Decompress(buffer); err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,解压缩数据出错,错误信息为:%s", this.request.RequestURI, err))
return
}
this.requestBytes = content
return
}
// Unmarshal
// @description: 反序列化
// parameter:
// @receiver this: this
// @obj: 反序列化结果数据
// return:
// @error: 反序列化错误数据
func (this *ApiContext) Unmarshal(obj interface{}) error {
contentData := this.GetRequestBytes()
var errMsg error
// 反序列化
if obj, errMsg = json.Marshal(contentData); errMsg != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("反序列化%s出错错误信息为%s", string(contentData), errMsg.Error()))
return errMsg
}
return nil
}
// RequestDataByMap
// @description: 获取请求的map格式数据
// parameter:
// @receiver this: this
// return:
// @typeUtil.MapData: map数据
// @error: 错误信息
func (this *ApiContext) RequestDataByMap() (typeUtil.MapData, error) {
if this.requestDataByMap != nil {
return this.requestDataByMap, nil
}
var data typeUtil.MapData
if err := this.Unmarshal(&data); err != nil {
return nil, err
}
this.requestDataByMap = data
return this.requestDataByMap, nil
}
// RequestDataBySlice
// @description: 获取请求的slice格式数据
// parameter:
// @receiver this: this
// return:
// @[]interface{}: 返回的数组数据
func (this *ApiContext) RequestDataBySlice() []interface{} {
result := make([]interface{}, 0, 8)
for _, value := range this.requestDataByMap {
result = append(result, value)
}
return result
}
// RequestDataBySlice2
// @description: 获取请求的slice格式数据
// parameter:
// @receiver this: this
// return:
// @[]interface{}: 返回的数组数据
// @error:
func (this *ApiContext) RequestDataBySlice2() (interface{}, error) {
contentData := this.GetRequestBytes()
// 反序列化
var result interface{}
var errMsg error
if result, errMsg = jsonUtil.UnMarshalWithNumberType(string(contentData)); errMsg != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("用[]interface{}反序列化%s出错错误信息为%s", string(contentData), errMsg.Error()))
return nil, errMsg
}
return result, nil
}
// RequestDataBySlice2ByJson
// @description: 获取请求的slice格式数据
// parameter:
// @receiver this: this
// return:
// @[]interface{}: 返回的数组数据
// @error:
func (this *ApiContext) RequestDataBySlice2ByJson() ([]interface{}, error) {
contentData := this.GetRequestBytes()
// 反序列化
result := make([]interface{}, 0, 8)
if errMsg := json.Unmarshal(contentData, &result); errMsg != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("用[]interface{}反序列化%s出错错误信息为%s", string(contentData), errMsg.Error()))
return nil, errMsg
}
return result, nil
}
// NewApiContext
// @description: 新建API上下文对象
// parameter:
// @_request: 请求对象
// @_responseWriter: 应答写对象
// @isZlib: 数据是否压缩
// return:
// @*ApiContext: 上下文
// @error: 错误信息
func NewApiContext(_request *http.Request, _responseWriter http.ResponseWriter, isZlib bool) (*ApiContext, error) {
context := &ApiContext{
request: _request,
header: &_request.Header,
responseWriter: _responseWriter,
}
// 读取数据
_, errMsg := context.readContent(isZlib)
if errMsg != nil {
return nil, errMsg
}
return context, nil
}

View File

@ -0,0 +1,112 @@
package webServer
import (
"net/http"
"common/resultStatus"
)
// 处理函数
type HandleFunc func(context *ApiContext) *ResponseObject
// ApiHandler
//
// @description: API处理结构
type ApiHandler struct {
// API完整路径名称
apiFullName string
// 方法定义
handleFun HandleFunc
// 方法参数名称集合
funcParamNames []string
}
// ApiFullName
//
// @description: API完整路径名称
//
// parameter:
//
// @receiver this: this
//
// return:
//
// @string:
func (this *ApiHandler) ApiFullName() string {
return this.apiFullName
}
// HandleFun
//
// @description: 方法定义
//
// parameter:
//
// @receiver this: this
//
// return:
//
// @HandleFunc: 方法
func (this *ApiHandler) HandleFun() HandleFunc {
return this.handleFun
}
// FuncParamNames
//
// @description: 方法参数名称集合
//
// parameter:
//
// @receiver this: this
//
// return:
//
// @[]string: 方法参数名称集合
func (this *ApiHandler) FuncParamNames() []string {
return this.funcParamNames
}
// CheckParam
//
// @description: 检测参数数量
//
// parameter:
//
// @receiver this: this
// @r:
//
// return:
//
// @resultStatus.ResultStatus: 状态码数据
func (this *ApiHandler) CheckParam(r *http.Request) resultStatus.ResultStatus {
for _, name := range this.funcParamNames {
if r.Form[name] == nil || len(r.Form[name]) == 0 {
return resultStatus.APIParamError
}
}
return resultStatus.Success
}
// newApiHandler
//
// @description: 创建新的请求方法对象
//
// parameter:
//
// @_apiFullName: API完整路径名称
// @_funcDefinition: 方法定义
// @_funcParamNames: 方法参数名称集合
//
// return:
//
// @*ApiHandler: 请求方法对象
func newApiHandler(_apiFullName string, _funcDefinition HandleFunc, _funcParamNames ...string) *ApiHandler {
return &ApiHandler{
apiFullName: _apiFullName,
handleFun: _funcDefinition,
funcParamNames: _funcParamNames,
}
}

View File

@ -0,0 +1,56 @@
package webServer
import (
"fmt"
"net/http"
)
var (
// 处理方法集合
// Key:API名
handlerData = make(map[string]*ApiHandler)
// 文档方法
remarkFunc func(w http.ResponseWriter, r *http.Request)
)
// RegisterRemarkFunc
// @description: 注册文档api方法
// parameter:
// @_remarkFunc: _remarkFunc
// return:
func RegisterRemarkFunc(_remarkFunc func(w http.ResponseWriter, r *http.Request)) {
remarkFunc = _remarkFunc
}
// RegisterHandleFunc
// @description: 注册处理方法
// parameter:
// @apiName: API名称
// @callback: 回调方法
// @paramNames: 参数名称集合
// return:
func RegisterHandleFunc(apiName string, callback HandleFunc, paramNames ...string) {
apiFullName := fmt.Sprintf("/API/%s", apiName)
if _, exist := handlerData[apiFullName]; exist {
panic(fmt.Errorf("重复注册处理函数:%s", apiFullName))
}
handlerData[apiFullName] = newApiHandler(apiFullName, callback, paramNames...)
}
// GetHandleFunc
// @description: 获取请求方法
// parameter:
// @apiFullName: 方法名称
// return:
// @*ApiHandler: 请求方法
// @bool: 是否存在
func GetHandleFunc(apiFullName string) (*ApiHandler, bool) {
if requestFuncObj, exists := handlerData[apiFullName]; exists {
return requestFuncObj, exists
}
return nil, false
}

View File

@ -0,0 +1,431 @@
package webServer
import (
config "common/configsYaml"
"common/resultStatus"
"goutil/logUtilPlus"
"reflect"
"strconv"
"strings"
)
const (
// 供客户端访问的模块的后缀
con_ModuleSuffix = "Module"
// 定义用于分隔模块名称和方法名称的分隔符
con_DelimeterOfObjAndMethod = "_"
)
var (
// 定义存放所有方法映射的变量
methodMap = make(map[string]*methodAndInOutTypes)
// 函数返回值类型
responseType reflect.Type = reflect.TypeOf(new(ResponseObject))
)
// getStructName
//
// @description: 获取结构体类型的名称
//
// parameter:
//
// @structType: 结构体类型
//
// return:
//
// @string: 结构体类型的名称
func getStructName(structType reflect.Type) string {
reflectTypeStr := structType.String()
reflectTypeArr := strings.Split(reflectTypeStr, ".")
return reflectTypeArr[len(reflectTypeArr)-1]
}
// getFullModuleName
//
// @description: 获取完整的模块名称
//
// parameter:
//
// @moduleName: 模块名称
//
// return:
//
// @string: 完整的模块名称
func getFullModuleName(moduleName string) string {
return moduleName + con_ModuleSuffix
}
// getFullMethodName
//
// @description: 获取完整的方法名称
//
// parameter:
//
// @structName: 结构体名称
// @methodName: 方法名称
//
// return:
//
// @string: 完整的方法名称
func getFullMethodName(structName, methodName string) string {
return structName + con_DelimeterOfObjAndMethod + methodName
}
// resolveMethodInOutParams
//
// @description: 解析方法的输入输出参数
//
// parameter:
//
// @method: 方法对应的反射值
//
// return:
//
// @inTypes: 输入参数类型集合
// @outTypes: 输出参数类型集合
func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) {
methodType := method.Type()
for i := 0; i < methodType.NumIn(); i++ {
inTypes = append(inTypes, methodType.In(i))
}
for i := 0; i < methodType.NumOut(); i++ {
outTypes = append(outTypes, methodType.Out(i))
}
return
}
// RegisterFunction
//
// @description: 将需要对客户端提供方法的对象进行注册
//
// parameter:
//
// @structObject: 对象
//
// return:
func RegisterFunction(structObject interface{}) {
// 获取structObject对应的反射 Type 和 Value
reflectValue := reflect.ValueOf(structObject)
reflectType := reflect.TypeOf(structObject)
// 提取对象类型名称
structName := getStructName(reflectType)
// 获取structObject中返回值为responseObject的方法
for i := 0; i < reflectType.NumMethod(); i++ {
// 获得方法名称
methodName := reflectType.Method(i).Name
// 获得方法及其输入参数的类型列表
method := reflectValue.MethodByName(methodName)
inTypes, outTypes := resolveMethodInOutParams(method)
// 判断输出参数数量是否正确
if len(outTypes) != 1 {
continue
}
// 判断返回值是否为responseObject
if outTypes[0] != responseType {
continue
}
// 添加到列表中
methodMap[getFullMethodName(structName, methodName)] = newmethodAndInOutTypes(method, inTypes, outTypes)
}
}
// CallFunction
//
// @description: 调用方法
//
// parameter:
//
// @requestObj: 客户端对象
//
// return:
//
// @responseObj: 请求对象
func CallFunction(requestObj *RequestObject) (responseObj *ResponseObject) {
responseObj = GetInitResponseObj()
var methodAndInOutTypes *methodAndInOutTypes
var ok bool
// 根据传入的ModuleName和MethodName找到对应的方法对象
key := getFullMethodName(requestObj.ModuleName, requestObj.MethodName)
if methodAndInOutTypes, ok = methodMap[key]; !ok {
logUtilPlus.ErrorLog("找不到指定的方法:%s", key)
responseObj.SetResultStatus(resultStatus.NotSpecificMethod)
return
}
// 判断参数数量是否相同
inTypesLength := len(methodAndInOutTypes.InTypes)
paramLength := len(requestObj.Parameters)
if paramLength != inTypesLength {
logUtilPlus.ErrorLog("传入的参数数量不符,本地方法%s的参数数量%d传入的参数数量为%d", key, inTypesLength, paramLength)
responseObj.SetResultStatus(resultStatus.ParamNotMatch)
return
}
// 构造参数
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.Bool:
if paramBool, ok := paramItem.(bool); ok {
in[i] = reflect.ValueOf(paramBool)
}
case reflect.Int:
if paramInt, ok := paramItem.(int); ok {
in[i] = reflect.ValueOf(int(paramInt))
}
case reflect.Int8:
if paramInt8, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(int8(paramInt8))
}
case reflect.Int16:
if paramInt16, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(int16(paramInt16))
}
case reflect.Int32:
if paramInt32, ok := paramItem.(int32); ok {
in[i] = reflect.ValueOf(paramInt32)
} else if paramFloat64, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(int32(paramFloat64))
}
case reflect.Int64:
if paramInt64, ok := paramItem.(int64); ok {
in[i] = reflect.ValueOf(paramInt64)
} else if paramUint64, ok := paramItem.(uint64); ok {
in[i] = reflect.ValueOf(int64(paramUint64))
} else if paramString, ok := paramItem.(string); ok {
i64, err := strconv.ParseInt(paramString, 10, 64)
if err == nil {
in[i] = reflect.ValueOf(i64)
}
} else if paramFloat64, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(int64(paramFloat64))
}
case reflect.Uint:
if paramUint, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(uint(paramUint))
}
case reflect.Uint8:
if paramUint8, ok := paramItem.(uint8); ok {
in[i] = reflect.ValueOf(uint8(paramUint8))
}
case reflect.Uint16:
if paramUint16, ok := paramItem.(uint16); ok {
in[i] = reflect.ValueOf(uint16(paramUint16))
}
case reflect.Uint32:
if paramUint32, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(uint32(paramUint32))
}
case reflect.Uint64:
if paramUint64, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(uint64(paramUint64))
}
case reflect.Float32:
if paramFloat32, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(float32(paramFloat32))
}
case reflect.Float64:
if paramFloat64, ok := paramItem.(float64); ok {
in[i] = reflect.ValueOf(paramFloat64)
}
case reflect.String:
if paramString, ok := paramItem.(string); ok {
in[i] = reflect.ValueOf(paramString)
}
case reflect.Slice:
// 如果是Slice类型则需要对其中的项再次进行类型判断及类型转换
if param_interface, ok := paramItem.([]interface{}); ok {
switch inTypeItem.String() {
case "[]bool":
params_inner := make([]bool, len(param_interface), 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), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(int); ok {
params_inner[i] = int(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]int8":
params_inner := make([]int8, len(param_interface), 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), 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), len(param_interface))
for i := 0; i < len(param_interface); i++ {
param_float64, ok := param_interface[i].(int32)
if ok {
params_inner[i] = int32(param_float64)
continue
} else {
param_int16, right := param_interface[i].(uint16)
if right == true {
params_inner[i] = int32(param_int16)
}
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]int64":
params_inner := make([]int64, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(int64); ok {
params_inner[i] = int64(param_float64)
} else if param_uint64, ok := param_interface[i].(uint64); ok {
params_inner[i] = int64(param_uint64)
} else if param_string, ok := param_interface[i].(string); ok {
i64, err := strconv.ParseInt(param_string, 10, 64)
if err == nil {
params_inner[i] = i64
}
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint":
params_inner := make([]uint, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint); ok {
params_inner[i] = uint(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
// case "[]uint8": 特殊处理
case "[]uint16":
params_inner := make([]uint16, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint16); ok {
params_inner[i] = uint16(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint32":
params_inner := make([]uint32, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint32); ok {
params_inner[i] = uint32(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]uint64":
params_inner := make([]uint64, len(param_interface), len(param_interface))
for i := 0; i < len(param_interface); i++ {
if param_float64, ok := param_interface[i].(uint64); ok {
params_inner[i] = uint64(param_float64)
}
}
in[i] = reflect.ValueOf(params_inner)
case "[]float32":
params_inner := make([]float32, len(param_interface), 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), 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), 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 {
logUtilPlus.ErrorLog("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObj.Parameters)
responseObj.SetResultStatus(resultStatus.ParamInValid)
return
}
}
// 传入参数,调用方法
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
logUtilPlus.DebugLog("Begin Call Func:module:%v, method:%v,inParams:%v\n\n", requestObj.ModuleName, requestObj.MethodName, in)
}
}
out := methodAndInOutTypes.Method.Call(in)
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
for i, v := range in {
logUtilPlus.DebugLog("\nparams %v,%v\n", i, v)
}
}
}
// 并输出结果到客户端由于只有一个返回值所以取out[0]
if responseObj, ok = (&out[0]).Interface().(*ResponseObject); !ok {
logUtilPlus.ErrorLog("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0]))
responseObj.SetResultStatus(resultStatus.ParamInValid)
return
}
if config.DEBUG {
if requestObj.MethodName != "GetRefreshData" {
logUtilPlus.DebugLog("返回数据:code:%v, data:%v, mess:%v\n\n", responseObj.Code, responseObj.Value, responseObj.Message)
}
}
return
}

View File

@ -0,0 +1,34 @@
package webServer
import (
"reflect"
)
// methodAndInOutTypes
// @description: 反射的方法和输入、输出参数类型组合类型
type methodAndInOutTypes struct {
// 反射出来的对应方法对象
Method reflect.Value
// 反射出来的方法的输入参数的类型集合
InTypes []reflect.Type
// 反射出来的方法的输出参数的类型集合
OutTypes []reflect.Type
}
// newmethodAndInOutTypes
// @description: newmethodAndInOutTypes
// parameter:
// @_method: _method
// @_inTypes: _inTypes
// @_outTypes: _outTypes
// return:
// @*methodAndInOutTypes: methodAndInOutTypes
func newmethodAndInOutTypes(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *methodAndInOutTypes {
return &methodAndInOutTypes{
Method: _method,
InTypes: _inTypes,
OutTypes: _outTypes,
}
}

View File

@ -0,0 +1,31 @@
package webServer
// RequestObject
// @description: 请求对象
type RequestObject struct {
// 以下属性是由客户端直接传入的,可以直接反序列化直接得到的
// 请求的模块名称
ModuleName string
// 请求的方法名称
MethodName string
// 请求的参数数组
Parameters []interface{}
}
// NewRequestObject
// @description: NewRequestObject
// parameter:
// @_ModuleName: _ModuleName
// @_MethodName: _MethodName
// @_Parameters: _Parameters
// return:
// @*RequestObject: RequestObject
func NewRequestObject(_ModuleName string, _MethodName string, _Parameters []interface{}) *RequestObject {
return &RequestObject{
ModuleName: _ModuleName,
MethodName: _MethodName,
Parameters: _Parameters,
}
}

View File

@ -0,0 +1,83 @@
package webServer
import (
"common/resultStatus"
)
// ResponseObject
// @description: 响应对象
type ResponseObject struct {
// 响应结果的状态值
Code resultStatus.StatusCode
// Status 状态
Status int32
// 响应结果的状态值所对应的描述信息
Message string
// 响应结果的数据
Value interface{}
}
// SetResultStatus
// @description: 设置响应结果的状态值
// parameter:
// @receiver this: this
// @rs: 响应结果的状态值
// return:
// @*ResponseObject: 响应结果对象
func (this *ResponseObject) SetResultStatus(rs resultStatus.ResultStatus) *ResponseObject {
this.Code = rs.Code()
this.Message = rs.Message()
return this
}
// SetData
// @description: 设置响应对象数据
// parameter:
// @receiver this: this
// @data: 响应结果的数据
// return:
// @*ResponseObject: 响应结果对象
func (this *ResponseObject) SetData(data interface{}) *ResponseObject {
this.Value = data
return this
}
// IsSuccess
// @description: 是否是请求成功
// parameter:
// @receiver this:this
// return:
// @bool:是请求成功
func (this *ResponseObject) IsSuccess() bool {
return this.Code == resultStatus.Success.Code()
}
// SetCodeStatus
// @description: 同步code和status状态
// parameter:
// @receiver this:this
// return:
func (this *ResponseObject) SetCodeStatus() {
if this.Code == resultStatus.Success.Code() && resultStatus.StatusCode(this.Status) != resultStatus.Success.Code() {
this.Code = resultStatus.StatusCode(this.Status)
}
return
}
// GetInitResponseObj
// @description: 获取初始的响应对象
// parameter:
// return:
// @*ResponseObject: 响应对象
func GetInitResponseObj() *ResponseObject {
return &ResponseObject{
Code: resultStatus.Success.Code(),
Message: "",
Value: nil,
}
}

View File

@ -0,0 +1,43 @@
package webServer
import (
"encoding/json"
"fmt"
"goutil/logUtilPlus"
"net/http"
"strconv"
)
// responseResult
// @description: responseResult
// parameter:
// @w: w
// @responseObj: responseObj
// return:
func responseResult(w http.ResponseWriter, responseObj *ResponseObject) {
b, err := json.Marshal(responseObj)
if err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("序列化输出结果%v出错", responseObj))
return
}
w.Header().Add("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
}
// responseResultByJson
// @description: responseResult
// parameter:
// @w: w
// @responseObj: responseObj
// return:
func responseResultByJson(w http.ResponseWriter, responseObj *ResponseObject) {
b, err := json.Marshal(responseObj)
if err != nil {
logUtilPlus.ErrorLog(fmt.Sprintf("序列化输出结果%v出错", responseObj))
return
}
w.Header().Add("Content-Length", strconv.Itoa(len(b)))
w.Write(b)
}

View File

@ -0,0 +1,122 @@
package webServer
import (
config "common/configsYaml"
"common/resultStatus"
"common/utils"
"encoding/json"
"fmt"
"framework/ipMgr"
"goutil/logUtilPlus"
"goutil/stringUtil"
"goutil/webUtil"
"net/http"
"strings"
)
// selfDefineMux
//
// @description: 定义自定义的Mux对象
type selfDefineMux struct {
}
// ServeHTTP
//
// @description: ServeHTTP
//
// parameter:
//
// @receiver mux: mux
// @w: w
// @r: r
//
// return:
func (mux *selfDefineMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
responseObj := GetInitResponseObj()
defer utils.LogReqErrorRecover(r)
// 判断是否是接口文档
if strings.Contains(r.RequestURI, "Remarks") && r.Method == "GET" {
remarkFunc(w, r)
return
}
// 判断是否是POST方法
if r.Method != "POST" {
responseResult(w, responseObj.SetResultStatus(resultStatus.OnlySupportPOST))
return
}
// 验证IP是否正确
if config.DEBUG == false && ipMgr.IsIpValid(webUtil.GetRequestIP(r)) == false {
logUtilPlus.ErrorLog(fmt.Sprintf("请求的IP%s无效", webUtil.GetRequestIP(r)))
responseResult(w, responseObj.SetResultStatus(resultStatus.IPForbid))
return
}
// 构造contex
context, errMsg := NewApiContext(r, w, false)
if errMsg != nil {
// 输出结果
responseResult(w, responseObj.SetResultStatus(resultStatus.APIDataError))
return
}
// 根据路径选择不同的处理方法
if handlerFunObj, exists := GetHandleFunc(r.RequestURI); exists {
defer func() {
if config.DEBUG {
b, _ := json.Marshal(responseObj)
msg := fmt.Sprintf("API:%v 请求数据:%v;返回数据:%s;",
r.RequestURI, string(context.GetRequestBytes()), string(b))
logUtilPlus.DebugLog(msg)
}
}()
// 输出结果
responseObj := handlerFunObj.HandleFun()(context)
responseResult(w, responseObj)
return
}
// 通过反射选择不同的方法
strs := stringUtil.Split(r.RequestURI, []string{"/"})
var params []interface{}
var err error
isJson := false
// 参数错误
if len(strs) != 2 {
responseResult(w, responseObj.SetResultStatus(resultStatus.APIDataError))
return
}
//验证是否登录
if strs[0] != "AdminApi" || strs[1] != "Login" {
tokenStr := context.header.Get("token")
// token 转型成 int64
token := stringUtil.StringToInt64(tokenStr)
//是否存在
if !CheckToken(token) {
responseResult(w, responseObj.SetResultStatus(resultStatus.NotLogin))
return
}
}
params, err = context.RequestDataBySlice2ByJson()
if err != nil {
responseResult(w, responseObj.SetResultStatus(resultStatus.APIDataError))
return
}
resquestData := NewRequestObject(strs[0], strs[1], params)
resp := CallFunction(resquestData)
if isJson {
responseResultByJson(w, resp)
} else {
responseResult(w, resp)
}
}

View File

@ -0,0 +1,41 @@
package webServer
import (
"fmt"
"net/http"
"sync"
"goutil/logUtil"
"goutil/logUtilPlus"
"net/http/pprof"
config "common/configsYaml"
)
// Start
// @description: 启动服务器
// parameter:
// @wg: WaitGroup对象
// return:
func Start(wg *sync.WaitGroup) {
defer func() {
wg.Done()
}()
// 启动过程中不需要捕获异常
logUtilPlus.PrintAndWriteLog(logUtil.Warn, fmt.Sprintf("Web服务器开始监听:%v", config.ConfigYaml.Root.WebServerAddress))
// 启动Web服务器监听
mux := http.NewServeMux()
mux.Handle("/", &selfDefineMux{})
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)
err := http.ListenAndServe(config.ConfigYaml.Root.WebServerAddress, mux)
if err != nil {
panic(fmt.Errorf("ListenAndServe失败错误信息为%s", err))
}
}

View File

@ -0,0 +1,92 @@
package webServer
import (
"sync"
"time"
)
var (
//已经登录的用户
loginUserMap = make(map[int64]*TokenInfo)
//锁
lock sync.RWMutex
)
type TokenInfo struct {
//管理员id
Id int64
//管理员账号
Account string
//过期时间
ExpireTime time.Time
}
// AddLoginUserToken 添加登录用户及其令牌信息到缓存中
// 参数:
//
// token: 用户的登录令牌
// tokenInfo: 令牌的详细信息,包括过期时间等
func AddLoginUserToken(token int64, tokenInfo *TokenInfo) {
//添加锁防止并发
lock.Lock()
defer lock.Unlock()
// 默认24小时过期
tokenInfo.ExpireTime = time.Now().Add(time.Hour * 24)
//移除旧的令牌
for tokenKey, tokenInfoValue := range loginUserMap {
if tokenInfo.Id == tokenInfoValue.Id {
delete(loginUserMap, tokenKey)
}
}
// 将令牌与用户信息添加到全局的登录用户映射中
loginUserMap[token] = tokenInfo
}
// CheckToken 检查令牌是否有效
// 参数:
//
// token: 需要检查的令牌字符串
//
// 返回值:
//
// bool: 表示令牌是否有效的布尔值true表示有效false表示无效
func CheckToken(token int64) bool {
//添加锁防止并发
lock.Lock()
defer lock.Unlock()
// 获取当前时间
now := time.Now()
// 获取令牌对应的用户信息
tokenInfo, ok := loginUserMap[token]
if !ok {
// 如果没有找到对应的用户信息,则令牌无效
return false
}
// 获取令牌过期时间
expireTime := tokenInfo.ExpireTime
// 如果令牌过期时间早于当前时间,则令牌无效
if expireTime.Before(now) {
//移除令牌
delete(loginUserMap, token)
return false
}
//如果生效的话,则更新过期时间
tokenInfo.ExpireTime = now.Add(time.Hour * 24)
return true
}

View File

@ -0,0 +1,5 @@
module main.go
go 1.22.10
require github.com/wechatpay-apiv3/wechatpay-go v0.2.20

View File

@ -0,0 +1,20 @@
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/wechatpay-apiv3/wechatpay-go v0.2.20 h1:gS8oFn1bHGnyapR2Zb4aqTV6l4kJWgbtqjCq6k1L9DQ=
github.com/wechatpay-apiv3/wechatpay-go v0.2.20/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=

View File

@ -0,0 +1,73 @@
package main
import (
"context"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
"log"
)
func main() {
var (
mchID string = "190000****" // 商户号
mchCertificateSerialNumber string = "3775B6A45ACD588826D15E583A95F5DD********" // 商户证书序列号
mchAPIv3Key string = "2ab9****************************" // 商户APIv3密钥
)
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
mchPrivateKey, err := utils.LoadPrivateKeyWithPath("/path/to/merchant/apiclient_key.pem")
if err != nil {
log.Fatal("load merchant private key error")
}
ctx := context.Background()
// 使用商户私钥等初始化 client并使它具有自动定时获取微信支付平台证书的能力
opts := []core.ClientOption{
option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
}
client, err := core.NewClient(ctx, opts...)
if err != nil {
log.Fatalf("new wechat pay client err:%s", err)
}
// 以 Native 支付为例
svc := native.NativeApiService{Client: client}
// 发送请求
resp, result, err := svc.Prepay(ctx,
native.PrepayRequest{
Appid: core.String("wxd678efh567hg6787"),
Mchid: core.String("1900009191"),
Description: core.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: core.String("1217752501201407033233368018"),
Attach: core.String("自定义数据说明"),
NotifyUrl: core.String("https://www.weixin.qq.com/wxpay/pay.php"),
Amount: &native.Amount{
Total: core.Int64(100),
},
},
)
// 使用微信扫描 resp.code_url 对应的二维码即可体验Native支付
log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
svc1 := jsapi.JsapiApiService{Client: client}
// 得到prepay_id以及调起支付所需的参数和签名
resp1, result, err := svc1.PrepayWithRequestPayment(ctx,
jsapi.PrepayRequest{
Appid: core.String("wxd678efh567hg6787"),
Mchid: core.String("1900009191"),
Description: core.String("Image形象店-深圳腾大-QQ公仔"),
OutTradeNo: core.String("1217752501201407033233368018"),
Attach: core.String("自定义数据说明"),
NotifyUrl: core.String("https://www.weixin.qq.com/wxpay/pay.php"),
Amount: &jsapi.Amount{
Total: core.Int64(100),
},
Payer: &jsapi.Payer{
Openid: core.String("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"),
},
},
)
// 使用微信扫描 resp.code_url 对应的二维码即可体验Native支付
log.Printf("status=%d resp=%s", result.Response.StatusCode, resp1)
}

View File

@ -0,0 +1,40 @@
# 使用官方的 Go 镜像作为构建环境
FROM golang:1.22.10-alpine AS builder
# 设置工作目录
WORKDIR /app
# 设置 Go 代理
ENV GOPROXY=https://goproxy.cn,direct
# 禁用 CGO
ENV CGO_ENABLED=0
# 复制所有源代码文件
COPY . .
WORKDIR /app/admincenter
# 构建应用程序,并确认生成的文件
RUN go build -o adminserver -ldflags="-s -w"
# 使用官方的 Alpine 镜像作为运行环境
FROM alpine:latest
# 设置作者标签
LABEL authors="tp"
# 设置工作目录
WORKDIR /app
# 从构建阶段复制编译好的可执行文件
COPY --from=builder /app/admincenter/adminserver .
# 复制配置文件
COPY --from=builder /app/admincenter/config.yaml .
# 暴露端口(假设 adminserver 监听 10051 端口)
EXPOSE 10051
# 设置容器启动时运行 adminserver
ENTRYPOINT ["./adminserver"]

Binary file not shown.

View File

@ -0,0 +1,48 @@
2025-01-03 10:17:22---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:17:22---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:21:53---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:21:53---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:26:46---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:26:46---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:27:18---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:27:18---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:27:57---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:27:57---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:28:06---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:28:06---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:30:37---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:30:37---->
开始加载LogMgr
------------------------------------------------------
2025-01-03 10:31:16---->
开始加载DbConfig
------------------------------------------------------
2025-01-03 10:31:16---->
开始加载LogMgr
------------------------------------------------------

View File

@ -0,0 +1,165 @@
2025-01-03 10:17:22---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:17:22---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:17:22---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:17:22---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:17:22---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:17:22---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:17:32---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:21:53---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:21:53---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:21:53---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:21:53---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:21:53---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:21:53---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:22:03---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:26:46---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:26:46---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:26:46---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:26:46---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:26:46---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:26:46---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:26:56---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:27:18---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:27:18---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:27:18---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:27:18---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:27:18---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:27:18---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:27:28---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:27:57---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:27:57---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:27:57---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:27:57---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:27:57---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:27:57---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:28:06---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:28:06---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:28:06---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:28:06---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:28:06---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:28:56---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:30:02---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:30:37---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:30:37---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:30:42---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:30:42---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:31:04---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------
2025-01-03 10:31:04---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:31:04---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:31:16---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:31:16---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:31:19---->
开始连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true
------------------------------------------------------
2025-01-03 10:31:19---->
连接mysql:root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true成功
------------------------------------------------------
2025-01-03 10:31:19---->
ping->redis:192.168.50.110:6379成功信息为PONG
------------------------------------------------------
2025-01-03 10:31:21---->
Web服务器开始监听:192.168.50.85:10052
------------------------------------------------------
2025-01-03 10:31:26---->
monitorNewMgr没有初始化参数,请调用SetParam进行初始化
------------------------------------------------------

View File

@ -0,0 +1,21 @@
#!/bin/bash
# 设置 Go 环境变量,确保使用 Linux 架构
export GOOS=linux
export GOARCH=amd64
echo "开始编译..."
# 编译 Go 代码
go build -o adminServer
# 检查编译是否成功
if [ $? -eq 0 ]; then
echo "编译成功!"
else
echo "编译失败!"
fi
# 等待用户输入任意键
read -p "编译完成,按任意键继续..."
exit 1

View File

@ -0,0 +1,54 @@
# 配置根节点
root:
# 是否是调试模式
debug: true
# Web服务监听地址和端口
web_server_address: "192.168.50.85:10052"
# Elasticsearch 地址
es_urls: "http://10.252.0.70:18099"
# 数据库配置
db_config:
admin_db:
# 最大处于开启状态的连接数
max_open_conns: 0
# 最大处于空闲状态的连接数
max_idle_conns: 0
# 数据库连接字符串
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
user_db:
# 最大处于开启状态的连接数
max_open_conns: 0
# 最大处于空闲状态的连接数
max_idle_conns: 0
# 数据库连接字符串
connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true"
redis_config:
# 数据库连接字符串
connection_string: "192.168.50.110:6379"
# 密码, 如果要设置用户Id则密码设置为:"UserId:Password"
password: ""
# 数据库序号
database: 5
# 最大活跃连接数
max_active: 500
# 最大空闲的连接数
max_idle: 200
# 连接空闲超时时间,单位:秒
idle_timeout: 300
# 连接超时时间, 单位:秒
dial_connect_timeout: 10

View File

@ -0,0 +1,37 @@
version: '3'
services:
mysql:
image: mysql:8.0
container_name: mysql-admin
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: admin,user
volumes:
- /my/own/datadir:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:7.0
container_name: redis-admin
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: always
command: ["redis-server", "--appendonly", "yes"]
admin-center:
build:
context: .
dockerfile: Dockerfile
container_name: admin-center
ports:
- "10051:10051"
volumes:
- ./app:/app
depends_on:
- mysql
- redis
volumes:
redis_data:

View File

@ -0,0 +1,28 @@
#!/bin/bash
# 导航到 Dockerfile 所在目录
#cd D:\workspace\e2023\goProject\trunk\center\admincenter
# 构建 Docker 镜像
echo "开始构建 Docker 镜像..."
docker build -t adminserver-image .
# 检查构建是否成功
if [ $? -ne 0 ]; then
echo "构建失败!"
exit 1
fi
echo "镜像构建成功!"
# 运行 Docker 容器
echo "开始运行 Docker 容器..."
docker run -d -p 10051:10051 --name adminserver-container adminserver-image
# 检查容器是否成功运行
if [ $? -ne 0 ]; then
echo "容器启动失败!"
exit 1
fi
echo "容器启动成功!"

View File

@ -0,0 +1,38 @@
module logincenter
go 1.22.10
replace (
common => ../common
framework => ../../framework
goutil => ../../goutil
)
require (
common v0.0.0-00010101000000-000000000000
goutil v0.0.0-20230425160006-b2d0b0a0b0b0
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
framework v0.0.0-20230425160006-b2d0b0a0b0b0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-sql-driver/mysql v1.8.1 // 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
github.com/mattn/go-isatty v0.0.17 // indirect
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
gorm.io/driver/mysql v1.5.7 // indirect
gorm.io/gorm v1.25.12 // indirect
)

View File

@ -0,0 +1,89 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/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/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/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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
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.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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/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=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/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=
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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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/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-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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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/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.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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
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=

View File

@ -0,0 +1,21 @@
package game
import (
"common/connection"
)
func init() {
//注册数据库
connection.RegisterDBModel(&Game{})
}
type Game struct {
GameID int64 `gorm:"column:game_id;primary_key;comment:用户id;autoIncrementIncrement" json:"gameid"`
//账号
Account string `gorm:"column:account;comment:账号" json:"account"`
}
func (Game) TableName() string {
return "user"
}

View File

@ -0,0 +1,77 @@
package game
import (
"common/cache"
"common/connection"
"goutil/logUtilPlus"
. "logincenter/internal/user"
"sync"
)
// 包名称(功能名称)
var packageName = "game"
// 读写锁
var lock sync.RWMutex
func AddGame(user *User, game *Game) (int64, error) {
//处理一些验证
//判断缓存是否存在
gameMap, _ := cache.GetData[map[int64]*Game](user.Cache, packageName)
if gameMap == nil {
gameMap = make(map[int64]*Game)
}
//添加新的缓存
func() {
lock.Lock()
defer lock.Unlock()
gameMap[game.GameID] = game
}()
//写入缓存
cache.SetData[*Game](user.Cache, packageName, gameMap)
// 写入到数据库
result := connection.GetUserDB().Create(&game) // 通过数据的指针来创建
if result.Error != nil {
logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error())
}
return game.GameID, nil
}
// 获取有些列表
func GetGameList(user *User) (map[int64]*Game, error) {
//处理一些验证
//验证缓存
gameMap, _ := cache.GetData[map[int64]*Game](user.Cache, packageName)
if gameMap != nil {
return gameMap, nil
}
// 获取全部列表
var gameList []*Game
result := connection.GetUserDB().Find(&gameList) // 通过数据的指针来创建
if result.Error != nil {
logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error())
}
for _, game := range gameList {
gameMap[game.GameID] = game
}
//添加缓存
func() {
lock.Lock()
defer lock.Unlock()
cache.SetData(user.Cache, packageName, gameMap)
}()
return gameMap, nil
}

View File

@ -0,0 +1,6 @@
package internal
import (
_ "logincenter/internal/game"
_ "logincenter/internal/user"
)

View File

@ -0,0 +1,139 @@
package user
import (
"common/remark"
"common/resultStatus"
"common/webServer"
"goutil/intUtil"
"goutil/securityUtil"
"strconv"
"time"
)
func init() {
//注册接口
webServer.RegisterFunction(new(UserApi))
}
func init() {
moduleName := "UserApi"
desc := "用户接口"
author := "tangping"
mendor := ""
date := "2024-12-25"
remark.RegisterModuleRemark(moduleName, desc, author, mendor, date)
}
// UserApi 用户接口
type UserApi struct {
}
// ---------------------------------------- 接口 --------------------------------------------------
func init() {
moduleName := "UserApi"
methodName := "Register"
methodDesc := "注册用户"
methodAuthor := "tangping"
methodMendor := ""
methodDate := "2024-12-25 15:55:00"
methodInParam := []string{"string 账号,string:用户名称,string:用户密码,string:用户性别,string:用户生日,int64:用户手机号,string:用户邮箱,string:用户微信群,string:用户备注"}
methodOutParam := `
{
"Code '类型:int'": "响应结果的状态值",
"Message '类型:string'": "响应结果的状态值所对应的描述信息",
"Data '类型:interface{}'": "响应结果的数据"
{
"id '类型:int'": "用户id",
}
}`
remark.RegisterMethodRemark(moduleName, methodName, methodDesc, methodAuthor, methodMendor, methodDate, methodInParam, methodOutParam)
}
func (a *UserApi) Register(account string, name string, password string, sex int32, birthday string, phone int64, email string, wechatGroup string, describe string) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
//校验参数
if account == "" || name == "" || password == "" || sex == 0 || birthday == "" || phone == 0 || email == "" || wechatGroup == "" {
responseObj.SetResultStatus(resultStatus.APIDataError)
return
}
//密码md5加密
password = securityUtil.Md5String(password, true)
//处理数据
UserModel := &User{
Account: account,
Name: name,
Password: password,
Sex: sex,
Birthday: birthday,
Phone: phone,
Email: email,
Describe: describe,
}
//添加到数据库
AddUser(UserModel)
resultMap := make(map[string]any)
resultMap["id"] = UserModel.ID
responseObj.SetData(resultMap)
return
}
// 用户登录
func init() {
moduleName := "UserApi"
methodName := "Login"
methodDesc := "用户登录"
methodAuthor := "tangping"
methodMendor := ""
methodDate := "2024-12-26 15:55:00"
methodInParam := []string{"string:账号,string:密码"}
methodOutParam := `
{
"Code '类型:int'": "响应结果的状态值",
"Message '类型:string'": "响应结果的状态值所对应的描述信息",
"Data '类型:interface{}'": "响应结果的数据"
{
"Token '类型:string'": "登录令牌",
}
}`
remark.RegisterMethodRemark(moduleName, methodName, methodDesc, methodAuthor, methodMendor, methodDate, methodInParam, methodOutParam)
}
func (a *UserApi) Login(account string, password string) (responseObj *webServer.ResponseObject) {
responseObj = webServer.GetInitResponseObj()
//验证参数
if account == "" || password == "" {
responseObj.SetResultStatus(resultStatus.APIDataError)
return
}
userData, err := Login(account, securityUtil.Md5String(password, true))
if err != nil {
responseObj.SetResultStatus(resultStatus.DataError)
return
}
//生成一个随机token
token, err := intUtil.ShuffleIntDigits(time.Now().UnixNano())
if err != nil {
responseObj.SetResultStatus(resultStatus.DataError)
return
}
//添加登录用户
webServer.AddLoginUserToken(token, &webServer.TokenInfo{Id: userData.ID, Account: account})
//UserData映射成map
resultMap := make(map[string]any)
resultMap["Token"] = strconv.FormatInt(token, 10)
responseObj.SetData(resultMap)
return
}

View File

@ -0,0 +1,89 @@
package user
import (
"common/cache"
"common/connection"
"goutil/logUtilPlus"
"sync"
)
// 用户缓存对象
var userMap = make(map[int64]*User)
var rwmu sync.RWMutex
// GetUserByID 根据用户id获取用户信息
func GetUserByID(UserID int64) (*User, error) {
//判断缓存是否存在
var user *User
func() *User {
rwmu.RLock()
defer rwmu.RUnlock()
ok := true
if user, ok = userMap[UserID]; ok {
return user
}
return nil
}()
if user != nil {
return user, nil
}
result := connection.GetUserDB().First(&user, UserID)
if result.Error != nil {
return nil, result.Error
}
//添加缓存
func() {
rwmu.Lock()
defer rwmu.Unlock()
user.Cache = cache.NewCache()
userMap[user.ID] = user
}()
return user, nil
}
// AddUserCache 添加用户缓存
func AddUserCache(user *User) {
rwmu.Lock()
defer rwmu.Unlock()
user.Cache = cache.NewCache()
userMap[user.ID] = user
}
// AddUser 添加用户
// AddUser 添加新的用户到数据库中。
// 参数 User: 包含用户信息的对象。
// 返回值: 插入操作影响的行数和可能发生的错误。
func AddUser(User *User) (int64, error) {
//处理一些验证
//写入缓存
AddUserCache(User)
// 写入到数据库
result := connection.GetUserDB().Create(&User) // 通过数据的指针来创建
if result.Error != nil {
logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error())
}
return User.ID, nil
}
// Login 用户登录
func Login(account string, password string) (*User, error) {
//这里优先验证缓存数据
var User User
result := connection.GetUserDB().Where("account = ? AND password = ?", account, password).First(&User)
if result.Error != nil {
return nil, result.Error
}
return &User, nil
}

View File

@ -0,0 +1,36 @@
package user
import (
"common/cache"
"common/connection"
)
func init() {
//注册数据库
connection.RegisterDBModel(&User{})
}
type User struct {
ID int64 `gorm:"column:id;primary_key;comment:用户id;autoIncrementIncrement" json:"id"`
//账号
Account string `gorm:"column:account;comment:账号" json:"account"`
Name string `gorm:"column:name;comment:用户名称" json:"name"`
Password string `gorm:"column:password;comment:用户密码" json:"password"`
//性别
Sex int32 `gorm:"column:sex;comment:性别" json:"sex"`
//生日
Birthday string `gorm:"column:birthday;comment:生日" json:"birthday"`
//手机
Phone int64 `gorm:"column:phone;comment:手机" json:"phone"`
//邮箱
Email string `gorm:"column:email;comment:邮箱" json:"email"`
//备注
Describe string `gorm:"column:describe;comment:备注" json:"describe"`
//玩家的缓存对象
Cache *cache.Cache `gorm:"-"`
}
func (User) TableName() string {
return "user"
}

View File

@ -0,0 +1,43 @@
package main
import (
"common/connection"
"sync"
_ "common/resultStatus"
"common/webServer"
_ "logincenter/internal/user"
)
var (
wg sync.WaitGroup
)
func init() {
// 设置WaitGroup需要等待的数量只要有一个服务器出现错误都停止服务器
wg.Add(1)
}
func main() {
//加载配置
loadConfig()
// 启动webserver
go webServer.Start(&wg)
// 阻塞等待以免main线程退出
wg.Wait()
}
// loadConfig 用于加载配置信息。
// 该函数会读取配置文件或环境变量中的设置,并根据这些设置初始化程序所需的配置。
// 目前函数的实现为空,需要根据实际的配置加载逻辑进行填充。
func loadConfig() {
//设置数据类型
connection.SetModelDB(connection.GetUserDB())
//构建数据库
connection.BuildDB()
}

View File

@ -0,0 +1,20 @@
#!/bin/bash
# 赋予可执行权限
chmod +x adminServer
echo "启动中..."
# 接受命令行传入一个参数
case "$1" in
d)
# 使用 nohup 将进程放到后台运行,并将输出重定向到 nohup.out 文件
nohup ./adminServer > nohup.out 2>&1 &
echo "启动完成"
;;
*)
./adminServer
;;
esac
echo "启动完成"

View File

@ -0,0 +1,16 @@
#!/bin/bash
# 查找 adminServer 的 PID
PID=$(pgrep adminServer)
if [ -z "$PID" ]; then
echo "adminServer 进程未找到"
else
echo "停止中... (PID: $PID)"
kill $PID
if [ $? -eq 0 ]; then
echo "adminServer 进程已终止 (PID: $PID)"
else
echo "无法终止 adminServer 进程 (PID: $PID)"
fi
fi

8
trunk/framework/.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,5 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" />
</settings>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Framework.iml" filepath="$PROJECT_DIR$/.idea/Framework.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

17
trunk/framework/README Normal file
View File

@ -0,0 +1,17 @@
v1.0版本,支持以下功能:
1、项目中的各种基础功能
2、其中的managecenterMgr兼容旧版本的ManageCenter2019-12-01之前
3、新增日志记录功能LogMgr 2020-03-09
4、新增监控功能MonitorNewMgr 2020-03-09
5、新增短链功能ShortUrlMgr 2020-03-09
v2.0版本,支持以下功能:
1、新的ManageCenter版本(2019-12-01之后)
v2.0.0.1
LogMgr里面Log日志消息先进行base64编码之后再发送到mq因为原消息有特殊符号
直接发送消息会导致消息返送之后在腾讯mq收到消息之后数据会丢失导致验签失败
v2.0.1.1
新增屏蔽字处理forbidWordsMgr
新增gameServerMgr

View File

@ -0,0 +1,9 @@
Stack trace:
Frame Function Args
000FFFFA328 0018006021E (00180252DED, 001802340A6, 000FFFFA328, 000FFFF9220)
000FFFFA328 00180048859 (00000000000, 00000000000, 00000000000, 00000000000)
000FFFFA328 00180048892 (00180252EA9, 000FFFFA1D8, 000FFFFA328, 00000000000)
000FFFFA328 001800AF0D8 (00000000000, 00000000000, 00000000000, 00000000000)
000FFFFA328 001800AF25D (000FFFFA340, 00000000000, 00000000000, 00000000000)
000FFFFA5B0 001800B0673 (000FFFFA340, 00000000000, 00000000000, 00000000000)
End of stack trace

View File

@ -0,0 +1,34 @@
package configMgr
import (
"goutil/configUtil"
)
// 配置管理对象
type ConfigManager struct {
// 初始化方法列表
initFuncList []func(*configUtil.XmlConfig) error
}
// 注册初始化方法
func (this *ConfigManager) RegisterInitFunc(initFunc func(*configUtil.XmlConfig) error) {
this.initFuncList = append(this.initFuncList, initFunc)
}
// 初始化
func (this *ConfigManager) Init(configObj *configUtil.XmlConfig) error {
for _, initFunc := range this.initFuncList {
if err := initFunc(configObj); err != nil {
return err
}
}
return nil
}
// 创建配置管理对象
func NewConfigManager() *ConfigManager {
return &ConfigManager{
initFuncList: make([]func(*configUtil.XmlConfig) error, 0, 8),
}
}

View File

@ -0,0 +1,13 @@
package contextcheckMgr
type ResultModel struct {
Code int `json:"code"`
Msg string `json:"msg"`
Result ResultDetail `json:"result"`
}
type ResultDetail struct {
TaskId string `json:"taskId"`
Action int `json:"action"`
CensorType int `json:"censorType"`
}

View File

@ -0,0 +1,126 @@
package contextcheckMgr
import (
"encoding/json"
"fmt"
"math/rand"
"sort"
"strconv"
"time"
"goutil/logUtil"
"goutil/securityUtil"
"goutil/webUtil"
)
var (
//接口密钥Id
msecretId string = "c98276c73c122eaa65163fe431cbf7d4"
//接口密钥key
msecretKey string = "3d2b39f824fa2f992494e17be500e303"
//业务ID
mbusinessId string = "9559ce74b5c5d24f6b124799a53c7431"
//接口请求地址
mapiurl string = "http://as.dun.163.com/v3/text/check"
//版本号
mversion string = "v3.1"
)
//参数设置
func SetPara(secretId, secretKey, businessId, apiurl, version string) {
msecretId = secretId
msecretKey = secretKey
mbusinessId = businessId
mapiurl = apiurl
mversion = version
}
//content:用户发表内容
//account:玩家账号(用户唯一标识)
//nickname:角色名称
//extStr1:角色区服名称
//extStr2:UserId
//ip:用户IP地址建议抄送辅助机审策略精准调优
//extLon1:区服ID
//返回值 code: 0通过 1嫌疑2不通过
//文本内容检测
func TextCheck(content, account, nickname, extStr1, extStr2, ip string, extLon1 int64) (code int, err error) {
//构造请求参数
postDataDict := make(map[string]string)
postDataDict["secretId"] = msecretId
postDataDict["businessId"] = mbusinessId
postDataDict["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
postDataDict["nonce"] = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(10000000000), 10)
rawString := fmt.Sprintf("%v%v%v", account, postDataDict["timestamp"], content)
postDataDict["dataId"] = securityUtil.Md5String(rawString, false)
postDataDict["content"] = content
postDataDict["version"] = mversion
postDataDict["account"] = account
postDataDict["nickname"] = nickname
postDataDict["extLon1"] = strconv.FormatInt(extLon1, 10)
// postDataDict["extLon2"] = extLon2
postDataDict["extStr1"] = extStr1
postDataDict["extStr2"] = extStr2
postDataDict["ip"] = ip
postDataDict["signature"] = getSignature(postDataDict)
//请求url,请求头
header := webUtil.GetFormHeader()
transport := webUtil.NewTransport()
transport.DisableKeepAlives = true
transport = webUtil.GetTimeoutTransport(transport, 30)
//请求接口
statusCode, result, err := webUtil.PostMapData(mapiurl, postDataDict, header, transport)
//定义错误信息
var logMessage string
//post请求错误
if err != nil {
logMessage = fmt.Sprintf("TextCheck:,错误信息为:%s", err.Error())
logUtil.ErrorLog(logMessage)
return
}
if statusCode != 200 {
logMessage = fmt.Sprintf("TextCheck:%d is wrong", statusCode)
logUtil.ErrorLog(logMessage)
err = fmt.Errorf("TextCheck:%d is wrong", statusCode)
return
}
//反序列化结果
var checkResponseObj *ResultModel
err = json.Unmarshal(result, &checkResponseObj)
if err != nil {
logMessage = fmt.Sprintf("json.Unmarshal(checkResponseObj),err%s", err.Error())
logUtil.ErrorLog(logMessage)
return
}
//判断接口是否调用成功
if checkResponseObj.Code != 200 {
logMessage = fmt.Sprintf("TextCheck接口调用失败,ResultStatus %d", checkResponseObj.Code)
err = fmt.Errorf("TextCheck接口调用失败code%d", checkResponseObj.Code)
return
}
//返回检测结果
code = checkResponseObj.Result.Action
return
}
//生成签名字符串
func getSignature(postDataDict map[string]string) string {
var paramStr string
keys := make([]string, 0, len(postDataDict))
for k := range postDataDict {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
paramStr += key + postDataDict[key]
}
paramStr += msecretKey
return securityUtil.Md5String(paramStr, false)
}

View File

@ -0,0 +1,49 @@
package contextcheckMgr
import (
"fmt"
"testing"
)
func TestCheck(t *testing.T) {
//content, account, nickname, extLon1, extLon2, extStr1, extStr2, ip
var content = "文本检查测试"
var account = "000e6a6e-7cfc-4da7-81a2-ef3a5d24c586"
var nickname = "不仅仅是喜欢"
var extLon1 int64 = 10001
//var extLon2 = "游戏内聊天"
var extStr1 = "10001铁血丹心"
var extStr2 = "5DF67DD225640567D4D0B6FE273262B5"
var ip = "113.116.66.45"
//设置完全正确的参数
code, err := TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
if err != nil {
t.Errorf("There should be no error, but now there is:%v", err)
return
}
fmt.Printf("检测完成,状态码为:%d\n", code)
content = "修炼发轮功"
code, err = TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
if err != nil {
t.Errorf("There should be no error, but now there is:%v", err)
return
}
fmt.Printf("检测完成,状态码为:%d\n", code)
content = ""
code, err = TextCheck(content, account, nickname, extStr1, extStr2, ip, extLon1)
if err != nil {
t.Errorf("There should be no error, but now there is:%v", err)
return
}
fmt.Printf("检测完成,状态码为:%d\n", code)
}

View File

@ -0,0 +1,13 @@
package mysqlSync
/*
提供数据同步到mysql的方法基本逻辑如下
1对外接收数据以追加的方式保存到大文件中数据的格式为header(4bytes)+content
2启动独立的goroutine来从大文件中读取数据并保存到数据库中
3使用syncInfo.txt文件保存当前已经处理的文件的路径以及下一次将要读取的文件的Offset为了降低向syncInfo.txt文件中写入失败
导致需要从头开始同步数据所以采用了在指定数目的范围内以追加形式来写入数据的方式只有达到了指定数量才会将整个文件清空
对于错误的处理方式分为以下两种
1文件错误由于文件系统是本系统的核心所以如果出现文件的读写出错则需要终止整个进程所以需要抛出panic
2数据库错误当数据库不可访问时为了不影响整个外部进程的运行故而不抛出panic而只是通过monitorNewMgr.Report的方式来报告故障
*/

View File

@ -0,0 +1,100 @@
package mysqlSync
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"goutil/fileUtil"
"goutil/logUtil"
)
var (
// 记录错误sql命令的文件名
con_Error_FileName = "errorFile.txt"
)
// 定义处理错误命令的文件对象
type errorFile struct {
// 错误文件
file *os.File
// 文件路径
filePath string
// 同步数据对象的唯一标识,用于进行重复判断
identifier string
}
// 保存命令到错误文件
// command: sql命令
func (this *errorFile) SaveCommand(command string) {
this.open()
defer this.close()
// 覆盖写入
this.file.Seek(0, 0)
// 写入命令
_, err := this.file.WriteString(command)
if err != nil {
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.SaveCommand")
err = fmt.Errorf("%s-Write %s to file failed:%s", prefix, command, err)
logUtil.ErrorLog(err.Error())
panic(err)
}
// 清理残留数据
this.file.Truncate(int64(len(command)))
}
// 读取文件中命令
func (this *errorFile) ReadCommand() string {
this.open()
defer this.close()
this.file.Seek(0, 0)
content, err := ioutil.ReadAll(this.file)
if err != nil {
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.ReadCommand")
err = fmt.Errorf("%s-Read command failed:%s", prefix, err)
logUtil.ErrorLog(err.Error())
panic(err)
}
return string(content)
}
// 打开文件
func (this *errorFile) open() {
// 打开errorFile文件, 如果没有就创建
var err error
this.file, err = os.OpenFile(this.filePath, os.O_CREATE|os.O_RDWR, os.ModePerm|os.ModeTemporary)
if err != nil {
prefix := fmt.Sprintf("%s-%s", this.identifier, "errorFile.newErrorFile.os.OpenFile")
err = fmt.Errorf("%s-Open File failed:%s", prefix, err)
logUtil.ErrorLog(err.Error())
panic(err)
}
}
// 关闭文件
func (this *errorFile) close() {
this.file.Close()
}
// 删除文件
func (this *errorFile) Delete() {
fileUtil.DeleteFile(this.filePath)
}
// 构造错误文件对象
// _dirPath:文件路径
// _identifier:唯一标识
func newErrorFile(_dirPath string, _identifier string) *errorFile {
_filePath := filepath.Join(_dirPath, con_Error_FileName)
return &errorFile{
filePath: _filePath,
identifier: _identifier,
}
}

View File

@ -0,0 +1,88 @@
package logSqlSync
import (
"database/sql"
"fmt"
"time"
"goutil/logUtil"
)
// 错误信息记录表是否已经初始化
var ifSyncErrorInfoTableInited bool = false
// 同步的错误信息处理对象
type syncErrorInfo struct {
// 数据库连接对象
db *sql.DB
}
// 初始化表信息
func (this *syncErrorInfo) init() error {
// 初始化表结构
if ifSyncErrorInfoTableInited == false {
err := this.initTable(this.db)
if err == nil {
ifSyncErrorInfoTableInited = true
}
return err
}
return nil
}
// 把同步信息更新到数据库
// data:待更新的数据
// 返回值:
// error:错误信息
func (this *syncErrorInfo) AddErrorSql(tran *sql.Tx, data string, errMsg string) error {
updateSql := "INSERT INTO `sync_error_info` (`SqlString`,`ExecuteTime`,`RetryCount`,`ErrMessage`) VALUES(?,?,?,?);"
var err error
if tran != nil {
_, err = tran.Exec(updateSql, data, time.Now(), 0, errMsg)
} else {
_, err = this.db.Exec(updateSql, data, time.Now(), 0, errMsg)
}
if err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.AddErrorSql Error:%s", err.Error()))
}
return err
}
// 初始化同步信息表结构
// db:数据库连接对象
func (this *syncErrorInfo) initTable(db *sql.DB) error {
// 创建同步信息表
createTableSql := `CREATE TABLE IF NOT EXISTS sync_error_info (
Id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增Id',
SqlString varchar(1024) NOT NULL COMMENT '执行的sql',
ExecuteTime datetime NOT NULL COMMENT '最近一次执行时间',
RetryCount int NOT NULL COMMENT '重试次数',
ErrMessage text NULL COMMENT '执行错误的信息',
PRIMARY KEY (Id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='未执行成功的sql数据';`
if _, err := db.Exec(createTableSql); err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.initTable Error:%s", err.Error()))
return err
}
return nil
}
// 创建同步信息对象
// _db:数据库连接对象
// 返回值:
// 同步信息对象
func newSyncErrorInfoObject(_db *sql.DB) (result *syncErrorInfo, err error) {
result = &syncErrorInfo{
db: _db,
}
err = result.init()
return result, err
}

View File

@ -0,0 +1,204 @@
package logSqlSync
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"time"
"Framework/dataSyncMgr/mysqlSync/sqlSync"
"goutil/logUtil"
)
// 同步对象定义
type SyncObject struct {
// 服务器组Id
serverGroupId int32
// 同步数据的存储路径
dirPath string
// 同步数据对象的唯一标识,用于进行重复判断
identifier string
// 数据库对象
dbObj *sql.DB
// 同步信息对象
syncingInfoObj *syncingInfo
// 错误处理对象
errorHandleObj *syncErrorInfo
// 同步对象
syncObj *sqlSync.SyncObject
}
// 初始化
// baseObj:基础同步对象
func (this *SyncObject) Init(baseObj *sqlSync.SyncObject) {
this.syncObj = baseObj
// 初始化同步信息对象
syncingInfoObj, err := newSyncingInfoObject(this.serverGroupId, this.dbObj)
if err != nil {
panic(err)
}
//// 初始化错误处理对象
errorHandleObj, err := newSyncErrorInfoObject(this.dbObj)
if err != nil {
panic(err)
}
this.syncingInfoObj = syncingInfoObj
this.errorHandleObj = errorHandleObj
// 初始化当前处理的文件
fileList := sqlSync.GetDataFileList(this.dirPath)
filePath, _ := this.syncingInfoObj.GetSyncingInfo()
if len(filePath) < 0 && len(fileList) > 0 {
this.syncingInfoObj.Update(fileList[0], 0, nil)
}
}
// 获取正在同步的信息
// filePath:文件路径
// offset:文件偏移量
func (this *SyncObject) GetSyncingInfo() (filePath string, offset int64) {
return this.syncingInfoObj.GetSyncingInfo()
}
// 更新
// filePath:文件路径
// offset:文件偏移量
// tran:事务对象
// 返回值:
// error:错误对象
func (this *SyncObject) Update(filePath string, offset int64, tx *sql.Tx) error {
return this.syncingInfoObj.Update(filePath, offset, tx)
}
// 同步一条sql语句
// command:待执行的命令
// filePath:保存路径
// offset:文件偏移量
// 返回值:
// error:错误信息
func (this *SyncObject) SyncOneSql(command string, filePath string, offset int64) {
var err error
for {
err = sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) {
// 保存sql到数据库
err = this.syncToMysql(command, tran)
if err != nil {
return
}
// 保存进度信息到数据库
err = this.syncingInfoObj.Update(filePath, offset, tran)
if err != nil {
return
}
isCommit = true
return
})
// 如果是连接出错,则仍然循环执行
if err != nil {
if sqlSync.CheckIfConnectionError(err.Error()) {
time.Sleep(5 * time.Second)
continue
}
}
// 如果不是数据库连接出错,则算是执行完成
break
}
// 如果存在错误,则循环尝试执行
if err != nil {
this.recordSqlError(command, filePath, offset, err.Error())
}
return
}
// 同步数据到mysql中
// command:sql语句
// tx:事务处理对象
// 返回值:
// error:错误信息
func (this *SyncObject) syncToMysql(command string, tx *sql.Tx) error {
_, err := tx.Exec(command)
if err != nil {
logUtil.ErrorLog(fmt.Sprintf("mysqlSync/logSqlSync/syncObject.syncToMysql error:%s", err.Error()))
return err
}
return nil
}
// 错误处理
// cmd:待执行的命令
// filePath:保存路径
// offset:文件偏移量
// errMsg:错误信息
func (this *SyncObject) recordSqlError(command string, filePath string, offset int64, errMsg string) {
errMsg = sqlSync.GetSimpleErrorMessage(errMsg)
for {
err := sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) {
// 保存sql到数据库
err = this.errorHandleObj.AddErrorSql(tran, command, errMsg)
if err != nil {
return
}
// 保存进度信息到数据库
err = this.syncingInfoObj.Update(filePath, offset, tran)
if err != nil {
return
}
isCommit = true
return
})
if err == nil {
return
}
time.Sleep(5 * time.Second)
}
}
// 创新新的mysql同步对象
// dirPath:存放数据的目录
// identifier:当前数据的唯一标识(可以使用数据库表名)
// dbObj:数据库对象
// syncingInfoObj:同步信息记录对象
// errorHandleObj:错误处理对象
// 返回值:
// mysql同步对象
func NewSyncObject(serverGroupId int32, dirPath, identifier string, dbObj *sql.DB) *SyncObject {
dirPath = filepath.Join(dirPath, identifier)
// 创建更新目录
err := os.MkdirAll(dirPath, os.ModePerm|os.ModeTemporary)
if err != nil {
err = fmt.Errorf("%s-%s-make dir failed:%s", identifier, "SyncObject.newSyncObject.os.MkdirAll", err)
logUtil.ErrorLog(err.Error())
panic(err)
}
// 构造同步信息对象
result := &SyncObject{
serverGroupId: serverGroupId,
dirPath: dirPath,
identifier: identifier,
dbObj: dbObj,
}
return result
}

View File

@ -0,0 +1,186 @@
package logSqlSync
import (
"database/sql"
"fmt"
"time"
"goutil/logUtil"
)
// 同步信息表是否已经被初始化
var ifSyncingTableInited bool = false
// 同步信息项,保存已经处理过的文件的信息
type syncingModel struct {
// 服务器组Id
ServerGroupId int32
// 待处理文件的绝对路径
FilePath string
// 待处理文件的偏移量
FileOffset int64
// 更新时间
UpdateTime time.Time
}
// 同步信息对象
type syncingInfo struct {
// 服务器组Id
ServerGroupId int32
// 同步信息项
item *syncingModel
// 数据库连接对象
db *sql.DB
}
// 获取同步信息
// filePath:正在同步的文件
// fileOffset:同步到的位置
func (this *syncingInfo) GetSyncingInfo() (filePath string, fileOffset int64) {
return this.item.FilePath, this.item.FileOffset
}
// 更新正在同步的位置和文件信息
// filePath:文件路径
// offset:当前同步到的位置
// tran:事务对象可以为nil
// 返回值:
// error:处理的错误信息
func (this *syncingInfo) Update(filePath string, offset int64, tran *sql.Tx) error {
this.item.FilePath = filePath
this.item.FileOffset = offset
this.item.UpdateTime = time.Now()
// 更新到数据库
return this.update(this.item, tran)
}
// 初始化同步信息
// 返回值:
// error:错误信息
func (this *syncingInfo) init() error {
// 数据表初始化
if ifSyncingTableInited == false {
if err := this.initSyncingInfoTable(this.db); err == nil {
ifSyncingTableInited = true
} else {
return err
}
}
// 获取此表的同步信息
data, exist, err := this.get()
if err != nil {
return err
}
// 2. 如果同步信息不存在,则初始化一条到此表
if exist == false {
data = &syncingModel{
ServerGroupId: this.ServerGroupId,
FilePath: "",
FileOffset: 0,
UpdateTime: time.Now(),
}
}
this.item = data
return nil
}
// 初始化同步信息表结构
// db:数据库连接对象
func (this *syncingInfo) initSyncingInfoTable(db *sql.DB) error {
// 创建同步信息表
createTableSql := `CREATE TABLE IF NOT EXISTS syncing_info (
ServerGroupId int NOT NULL COMMENT '服务器组Id',
FilePath varchar(500) NOT NULL COMMENT '正在同步的文件路径',
FileOffset bigint(20) NOT NULL COMMENT '偏移量',
UpdateTime datetime NOT NULL COMMENT '最后一次更新时间',
PRIMARY KEY (ServerGroupId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在同步的文件信息';`
if _, err := db.Exec(createTableSql); err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.initSyncingInfoTable Error:%s", err.Error()))
return err
}
return nil
}
// 从数据库获取数据
// 返回值:
// data:获取到的数据
// exist:是否存在此数据
// err:错误信息
func (this *syncingInfo) get() (data *syncingModel, exist bool, err error) {
//// 从数据库查询
querySql := fmt.Sprintf("SELECT FilePath,FileOffset,UpdateTime FROM syncing_info WHERE ServerGroupId ='%v'", this.ServerGroupId)
var rows *sql.Rows
rows, err = this.db.Query(querySql)
if err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
return
}
defer rows.Close()
if rows.Next() == false {
exist = false
return
}
exist = true
// 读取数据
data = &syncingModel{
ServerGroupId: this.ServerGroupId,
}
err = rows.Scan(&data.FilePath, &data.FileOffset, &data.UpdateTime)
if err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
return
}
return
}
// 把同步信息更新到数据库
// data:待更新的数据
// tran:事务处理对象
// 返回值:
// error:错误信息
func (this *syncingInfo) update(data *syncingModel, tran *sql.Tx) error {
updateSql := "REPLACE INTO `syncing_info` SET `ServerGroupId` = ?, `FilePath` = ?,`FileOffset` = ?, `UpdateTime` = ?;"
var err error
if tran != nil {
_, err = tran.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
} else {
_, err = this.db.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
}
if err != nil {
logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.update ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
}
return err
}
// 创建同步信息对象
// _dirPath:目录的路径
// _identifier:当前数据的唯一标识(可以使用数据库表名)
// _db:数据库连接对象
// 返回值:
// 同步信息对象
func newSyncingInfoObject(serverGroupId int32, _db *sql.DB) (result *syncingInfo, err error) {
result = &syncingInfo{
ServerGroupId: serverGroupId,
db: _db,
}
err = result.init()
return result, err
}

View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"Framework/dataSyncMgr/mysqlSync"
"goutil/logUtil"
)
var _ = mysql.DeregisterLocalFile
var (
connectionString = "root:moqikaka3309@tcp(10.1.0.10:3309)/develop_liujun?charset=utf8&parseTime=true&loc=Local&timeout=60s"
maxOpenConns = 10
maxIdleConns = 10
syncFileSize = 1024 * 1024
)
var (
// 数据库对象
dbObj *gorm.DB
// 同步管理对象
syncMgr *mysqlSync.SyncMgr
)
func init() {
// 初始化数据库连接
dbObj = initMysql()
// 构造同步管理对象
syncMgr = mysqlSync.NewLogSyncMgr(1, "Sync", syncFileSize, dbObj.DB())
}
// 初始化Mysql
func initMysql() *gorm.DB {
dbObj, err := gorm.Open("mysql", connectionString)
if err != nil {
panic(fmt.Errorf("初始化数据库:%s失败错误信息为%s", connectionString, err))
}
logUtil.DebugLog(fmt.Sprintf("连接mysql:%s成功", connectionString))
if maxOpenConns > 0 && maxIdleConns > 0 {
dbObj.DB().SetMaxOpenConns(maxOpenConns)
dbObj.DB().SetMaxIdleConns(maxIdleConns)
}
return dbObj
}
// 注册同步对象
func registerSyncObj(identifier string) {
syncMgr.RegisterSyncObj(identifier)
}
// 保存sql数据
func save(identifier string, command string) {
syncMgr.Save(identifier, command)
}

Some files were not shown because too many files have changed in this diff Show More