├── config └── local │ ├── log.json │ ├── mongo.json │ ├── redis.json │ ├── service.json │ └── mysql.json ├── GoGameServer.png ├── servives ├── public │ ├── errCodes │ │ └── errCode.go │ ├── redisKeys │ │ └── redisKey.go │ ├── mongoInstances │ │ └── mongoInstance.go │ ├── redisInstances │ │ └── redisInstance.go │ ├── mysqlInstances │ │ └── mysqlInstance.go │ ├── gameProto │ │ ├── gameProtoMsgId.go │ │ ├── gameProto.go │ │ ├── gameProto.proto │ │ └── gameProto.pb.go │ ├── redisCaches │ │ └── user.go │ ├── common.go │ ├── token.go │ ├── mongoModels │ │ └── user.go │ └── mysqlModels │ │ └── user.go ├── chat │ ├── model │ │ └── chatUser.go │ ├── main.go │ ├── cache │ │ └── online.go │ └── module │ │ └── chat.go ├── login │ ├── model │ │ └── onlineUser.go │ ├── main.go │ ├── cache │ │ └── online.go │ └── module │ │ └── login.go ├── log │ └── main.go ├── api │ ├── main.go │ └── controllers │ │ ├── connector.go │ │ └── default.go ├── connector │ ├── module │ │ └── server.go │ ├── main.go │ ├── messages │ │ ├── frontMessage.go │ │ └── frontMessageHandle.go │ └── cache │ │ └── serverCache.go ├── game │ ├── main.go │ └── module │ │ └── user.go └── test │ ├── main.go │ └── main_ws.go ├── core ├── consts │ ├── errCode.go │ ├── serviceType.go │ └── service.go ├── libs │ ├── sessions │ │ ├── session.go │ │ ├── backSessionService.go │ │ ├── frontSessionService.go │ │ ├── backSession.go │ │ └── frontSession.go │ ├── hash │ │ ├── md5.go │ │ └── murmurHash.go │ ├── grpc │ │ ├── ipc │ │ │ ├── ipc.proto │ │ │ ├── client.go │ │ │ ├── server.go │ │ │ ├── ipc_grpc.pb.go │ │ │ └── ipc.pb.go │ │ ├── server.go │ │ └── client.go │ ├── array │ │ └── array.go │ ├── system │ │ └── system.go │ ├── random │ │ └── random.go │ ├── common │ │ └── common.go │ ├── rpc │ │ ├── server.go │ │ └── client.go │ ├── export.go │ ├── jwt │ │ └── jwt.go │ ├── stack │ │ └── stack.go │ ├── guid │ │ └── guid.go │ ├── socket │ │ ├── frontCodec.go │ │ └── socket.go │ ├── websocket │ │ ├── frontCodec.go │ │ └── websocket.go │ ├── mysql │ │ └── client.go │ ├── redis │ │ └── client.go │ ├── consul │ │ ├── server.go │ │ ├── kv.go │ │ └── client.go │ ├── request │ │ └── request.go │ ├── timer │ │ └── timer.go │ ├── mongo │ │ └── client.go │ ├── protos │ │ └── protos.go │ ├── dict │ │ └── dict.go │ └── logger │ │ └── logger.go ├── messages │ ├── frontMessage.go │ ├── ipcServerMessageHandle.go │ ├── ipcClientMessage.go │ └── ipcServerMessage.go ├── service │ ├── service_pprof.go │ ├── service_mongo.go │ ├── service_redis.go │ ├── service_socket.go │ ├── service_mysql.go │ ├── service_websocket.go │ ├── service_http.go │ ├── service_handle.go │ ├── service_rpc.go │ ├── service_ipc.go │ └── service.go ├── global.go └── config │ ├── class.go │ └── config.go ├── readme ├── .gitignore ├── test.sh ├── stop.sh ├── proto.sh ├── README.md ├── run.sh ├── dbs └── user.sql └── go.mod /config/local/log.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug": true, 3 | "both": true, 4 | "file": true 5 | } -------------------------------------------------------------------------------- /GoGameServer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yicaoyimuys/GoGameServer/HEAD/GoGameServer.png -------------------------------------------------------------------------------- /servives/public/errCodes/errCode.go: -------------------------------------------------------------------------------- 1 | package errCodes 2 | 3 | const ( 4 | PARAM_ERROR = 1 //参数错误 5 | ) 6 | -------------------------------------------------------------------------------- /core/consts/errCode.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | ErrCode_SystemError = 9999 //系统错误,服务器未启动 5 | ) 6 | -------------------------------------------------------------------------------- /readme: -------------------------------------------------------------------------------- 1 | 消息划分 2 | 3 | 1-999: 系统消息 4 | 1000-1999: connector消息 5 | 2000-2999: login消息 6 | 3000-3999: game消息 7 | 4000-4999: chat消息 -------------------------------------------------------------------------------- /servives/public/redisKeys/redisKey.go: -------------------------------------------------------------------------------- 1 | package redisKeys 2 | 3 | const ( 4 | ServerInfo = "server.info" 5 | DbUser = "db.user." 6 | ) 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | bin/ 3 | /logs/ 4 | pkg/ 5 | release/ 6 | consul_run.sh 7 | mongod_run.sh 8 | redis_run.sh 9 | .DS_Store 10 | dump.rdb 11 | 12 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sh stop.sh servives/test/main 4 | sh stop.sh servives/test/main_ws 5 | go run servives/test/main.go -e local 6 | # go run servives/test/main_ws.go -e local -------------------------------------------------------------------------------- /config/local/mongo.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "host": "localhost", 4 | "port": "27017", 5 | "user": "", 6 | "password": "", 7 | "db": "test_global_1" 8 | } 9 | } -------------------------------------------------------------------------------- /servives/chat/model/chatUser.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 4 | 5 | type ChatUser struct { 6 | Session *sessions.BackSession 7 | UserID uint64 8 | UserName string 9 | } 10 | -------------------------------------------------------------------------------- /servives/login/model/onlineUser.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 4 | 5 | type OnlineUser struct { 6 | Session *sessions.BackSession 7 | UserID uint64 8 | Account string 9 | } 10 | -------------------------------------------------------------------------------- /core/consts/serviceType.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | ServiceType_Socket = "socket" 5 | ServiceType_WebSocket = "webSocket" 6 | ServiceType_Http = "http" 7 | ServiceType_Rpc = "rpc" 8 | ServiceType_Ipc = "ipc" 9 | ) 10 | -------------------------------------------------------------------------------- /core/libs/sessions/session.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | type closeCallback struct { 8 | Handler interface{} 9 | Key interface{} 10 | Func func() 11 | Next *closeCallback 12 | } 13 | 14 | var ErrClosed = errors.New("session closed") 15 | -------------------------------------------------------------------------------- /core/consts/service.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | Service_Connector = "connector" 5 | Service_Login = "login" 6 | Service_Game = "game" 7 | Service_Log = "log" 8 | Service_Chat = "chat" 9 | Service_Api = "api" 10 | Service_Test = "test" 11 | ) 12 | -------------------------------------------------------------------------------- /servives/public/mongoInstances/mongoInstance.go: -------------------------------------------------------------------------------- 1 | package mongoInstances 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/mongo" 6 | ) 7 | 8 | func Global() *mongo.Client { 9 | return core.Service.GetMongoClient("global") 10 | } 11 | -------------------------------------------------------------------------------- /core/messages/frontMessage.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 6 | ) 7 | 8 | func FontReceive(session *sessions.FrontSession, msgBody []byte) { 9 | WARN("FontReceive自己实现一下吧,实现分发逻辑") 10 | } 11 | -------------------------------------------------------------------------------- /core/libs/hash/md5.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | ) 7 | 8 | //Md5加密 9 | func Md5(str string) string { 10 | md5Ctx := md5.New() 11 | md5Ctx.Write([]byte(str)) 12 | cipherStr := md5Ctx.Sum(nil) 13 | md5Str := hex.EncodeToString(cipherStr) 14 | return md5Str 15 | } 16 | -------------------------------------------------------------------------------- /config/local/redis.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "prefix": "local", 4 | "host": "127.0.0.1", 5 | "port": "6379", 6 | "auth_pass": "", 7 | "db": 1 8 | }, 9 | "user": { 10 | "prefix": "local", 11 | "host": "127.0.0.1", 12 | "port": "6379", 13 | "auth_pass": "", 14 | "db": 2 15 | } 16 | } -------------------------------------------------------------------------------- /stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | function func(){ 3 | ps -ef | grep $1 | grep -v grep | awk '{print $2}' | xargs kill -9 4 | } 5 | 6 | if [ $# -eq 0 ] 7 | then 8 | func servives/connector/main 9 | func servives/game/main 10 | func servives/login/main 11 | func servives/chat/main 12 | func servives/log/main 13 | func servives/api/main 14 | func exe/main 15 | else 16 | func $1 17 | fi -------------------------------------------------------------------------------- /core/libs/grpc/ipc/ipc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = ".;ipc"; 4 | 5 | message Req{ 6 | string serviceIdentify = 1; 7 | uint64 userSessionId = 2; 8 | bytes data = 3; 9 | } 10 | 11 | message Res{ 12 | repeated uint64 userSessionIds = 1; 13 | bytes data = 2; 14 | } 15 | 16 | service Ipc{ 17 | rpc Transfer(stream Req) returns (stream Res) {} 18 | } -------------------------------------------------------------------------------- /servives/public/redisInstances/redisInstance.go: -------------------------------------------------------------------------------- 1 | package redisInstances 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/redis" 6 | ) 7 | 8 | func Global() *redis.Client { 9 | return core.Service.GetRedisClient("global") 10 | } 11 | 12 | func User() *redis.Client { 13 | return core.Service.GetRedisClient("user") 14 | } 15 | -------------------------------------------------------------------------------- /proto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # go get -u google.golang.org/protobuf/cmd/protoc-gen-go 4 | # go install google.golang.org/protobuf/cmd/protoc-gen-go 5 | # go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc 6 | # go install google.golang.org/grpc/cmd/protoc-gen-go-grpc 7 | 8 | DIR=$(pwd) 9 | cd $DIR/servives/public/gameProto && protoc --go_out=. gameProto.proto 10 | cd $DIR/core/libs/grpc/ipc && protoc --go_out=. --go-grpc_out=. ipc.proto -------------------------------------------------------------------------------- /servives/log/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/service" 7 | ) 8 | 9 | func main() { 10 | //初始化Service 11 | newService := service.NewService(consts.Service_Log) 12 | newService.StartRpcServer() 13 | 14 | //模块初始化 15 | initModule() 16 | 17 | //保持进程 18 | Run() 19 | } 20 | 21 | func initModule() { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /servives/public/mysqlInstances/mysqlInstance.go: -------------------------------------------------------------------------------- 1 | package mysqlInstances 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/mysql" 6 | ) 7 | 8 | func Global() *mysql.Client { 9 | return core.Service.GetMysqlClient("global") 10 | } 11 | 12 | func User() *mysql.Client { 13 | return core.Service.GetMysqlClient("user") 14 | } 15 | 16 | func Log() *mysql.Client { 17 | return core.Service.GetMysqlClient("log") 18 | } 19 | -------------------------------------------------------------------------------- /servives/public/gameProto/gameProtoMsgId.go: -------------------------------------------------------------------------------- 1 | package gameProto 2 | 3 | const ( 4 | ID_error_notice_s2c = 500 5 | 6 | ID_client_ping_c2s = 1001 7 | 8 | ID_user_login_c2s = 2001 9 | ID_user_login_s2c = 2002 10 | ID_user_otherLogin_notice_s2c = 2004 11 | 12 | ID_user_getInfo_c2s = 3001 13 | ID_user_getInfo_s2c = 3002 14 | 15 | ID_user_joinChat_c2s = 4001 16 | ID_user_joinChat_s2c = 4002 17 | ID_user_chat_c2s = 4003 18 | ID_user_chat_notice_s2c = 4004 19 | ) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GoGameServer 2 | =============== 3 | 4 | 使用go搭建的一个游戏服务器项目 5 | 1:consul作为服务注册/发现中心,便于服务的动态扩容 6 | 2:与客户端的通信协议使用protobuf 7 | 3:服务之间支持基于TCP的ipc,rpc通信 8 | 4:缓存使用redis 9 | 5:数据库支持mysql、mongodb 10 | 11 | 12 | 结构图 13 | =============== 14 | 15 | 16 | ![image](GoGameServer.png) 17 | 18 | 19 | 启动说明 20 | =============== 21 | 22 | 启动consul 23 | 启动mysql(config/local/mysql.json) 24 | 启动redis(config/local/redis.json) 25 | 执行sh run.sh启动服务器 26 | 执行sh stop.sh停止服务器 27 | 执行sh test.sh启动测试服务器 28 | 执行sh proto.sh生成proto文件 -------------------------------------------------------------------------------- /core/service/service_pprof.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "net/http" 5 | _ "net/http/pprof" 6 | 7 | "github.com/spf13/cast" 8 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | func (this *Service) StartPProf(port int) { 14 | port = port + this.id 15 | go func() { 16 | defer stack.TryError() 17 | http.ListenAndServe(":"+cast.ToString(port), nil) 18 | }() 19 | INFO("PProf Start", zap.Int("Port", port)) 20 | } 21 | -------------------------------------------------------------------------------- /core/libs/array/array.go: -------------------------------------------------------------------------------- 1 | package array 2 | 3 | import "reflect" 4 | 5 | func IndexOf(array interface{}, value interface{}) int { 6 | arrType := reflect.TypeOf(array).Kind() 7 | if arrType != reflect.Slice && arrType != reflect.Array { 8 | return -1 9 | } 10 | 11 | arr := reflect.ValueOf(array) 12 | for i := 0; i < arr.Len(); i++ { 13 | if arr.Index(i).Interface() == value { 14 | return i 15 | } 16 | } 17 | return -1 18 | } 19 | 20 | func InArray(array interface{}, value interface{}) bool { 21 | return IndexOf(array, value) != -1 22 | } 23 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sh stop.sh 4 | 5 | sleep 1 6 | go run servives/api/main.go -e local -s 1 & 7 | 8 | sleep 1 9 | go run servives/log/main.go -e local -s 1 & 10 | 11 | sleep 1 12 | go run servives/game/main.go -e local -s 1 & 13 | sleep 1 14 | go run servives/game/main.go -e local -s 2 & 15 | 16 | sleep 1 17 | go run servives/login/main.go -e local -s 1 & 18 | 19 | sleep 1 20 | go run servives/chat/main.go -e local -s 1 & 21 | 22 | sleep 1 23 | go run servives/connector/main.go -e local -s 1 & 24 | sleep 1 25 | go run servives/connector/main.go -e local -s 2 -------------------------------------------------------------------------------- /config/local/service.json: -------------------------------------------------------------------------------- 1 | { 2 | "connector": { 3 | "tslCrt": "/usr/local/nginx/cert/xxx.crt", 4 | "tslKey": "/usr/local/nginx/cert/xxx.key", 5 | "services":{ 6 | "1": { "clientPort": "19881", "useSSL": false }, 7 | "2": { "clientPort": "19882", "useSSL": false } 8 | } 9 | }, 10 | "api": { 11 | "tslCrt": "/usr/local/nginx/cert/xxx.crt", 12 | "tslKey": "/usr/local/nginx/cert/xxx.key", 13 | "services":{ 14 | "1": { "clientPort": "18881", "useSSL": false }, 15 | "2": { "clientPort": "18882", "useSSL": false } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /config/local/mysql.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "host": "localhost", 4 | "port": "3306", 5 | "user": "root", 6 | "password": "123456", 7 | "db": "test_global_1", 8 | "charset": "utf8" 9 | }, 10 | "user": { 11 | "host": "localhost", 12 | "port": "3306", 13 | "user": "root", 14 | "password": "123456", 15 | "db": "test_user_1", 16 | "charset": "utf8" 17 | }, 18 | "log": { 19 | "host": "localhost", 20 | "port": "3306", 21 | "user": "root", 22 | "password": "123456", 23 | "db": "test_log_1", 24 | "charset": "utf8" 25 | } 26 | } -------------------------------------------------------------------------------- /core/messages/ipcServerMessageHandle.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 5 | 6 | "google.golang.org/protobuf/proto" 7 | ) 8 | 9 | type ipcServerMsgHandle func(clientSession *sessions.BackSession, msgData proto.Message) 10 | 11 | var ( 12 | backHandles = make(map[uint16]ipcServerMsgHandle) 13 | ) 14 | 15 | func RegisterIpcServerHandle(msgId uint16, handle ipcServerMsgHandle) { 16 | backHandles[msgId] = handle 17 | } 18 | 19 | func GetIpcServerHandle(msgId uint16) ipcServerMsgHandle { 20 | handle, ok := backHandles[msgId] 21 | if ok { 22 | return handle 23 | } else { 24 | return nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/libs/system/system.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/jessevdk/go-flags" 7 | ) 8 | 9 | var ( 10 | Root string 11 | Args struct { 12 | Env string `short:"e" long:"env" description:"环境" default:"local"` 13 | ServiceId int `short:"s" long:"serviceId" description:"服务ID" default:"1"` 14 | } 15 | ) 16 | 17 | func init() { 18 | initRootPath() 19 | initArgs() 20 | } 21 | 22 | func initRootPath() { 23 | Root, _ = os.Getwd() 24 | } 25 | 26 | func initArgs() error { 27 | _, err := flags.Parse(&Args) 28 | return err 29 | } 30 | 31 | // Run 保持进程 32 | func Run() { 33 | temp := make(chan int32, 10) 34 | for { 35 | select { 36 | case <-temp: 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /servives/api/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/service" 7 | "github.com/yicaoyimuys/GoGameServer/servives/api/controllers" 8 | ) 9 | 10 | func main() { 11 | //初始化Service 12 | newService := service.NewService(consts.Service_Api) 13 | newService.StartRedis() 14 | newService.StartMongo() 15 | newService.StartHttpServer() 16 | newService.RegisterHttpRouter("/", &controllers.DefaultController{}) 17 | newService.RegisterHttpRouter("/GetConnector", &controllers.ConnectorController{}) 18 | 19 | //模块初始化 20 | initModule() 21 | 22 | //保持进程 23 | Run() 24 | } 25 | 26 | func initModule() { 27 | } 28 | -------------------------------------------------------------------------------- /core/libs/grpc/server.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 8 | 9 | "google.golang.org/grpc" 10 | ) 11 | 12 | func InitServer(registerPbServiceFunc func(*grpc.Server)) (string, error) { 13 | //创建监听 14 | listen, err := net.Listen("tcp", ":") 15 | if err != nil { 16 | return "", err 17 | } 18 | 19 | go func() { 20 | defer stack.TryError() 21 | defer listen.Close() 22 | 23 | //创建grpcServer 24 | grpcServer := grpc.NewServer() 25 | 26 | //注册服务 27 | registerPbServiceFunc(grpcServer) 28 | 29 | //服务开启 30 | grpcServer.Serve(listen) 31 | }() 32 | 33 | //返回端口 34 | serverPort := strconv.Itoa(listen.Addr().(*net.TCPAddr).Port) 35 | return serverPort, nil 36 | } 37 | -------------------------------------------------------------------------------- /core/libs/random/random.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | var r = rand.New(rand.NewSource(time.Now().UnixNano())) 10 | 11 | func RandomInt31n(n int32) int32 { 12 | return r.Int31n(n) 13 | } 14 | 15 | // 随机int [0,n) 16 | func RandIntn(n int) int { 17 | return r.Intn(n) 18 | } 19 | 20 | // 随机int [min,max) 21 | func RandIntRange(min int, max int) int { 22 | if min >= max { 23 | return max 24 | } 25 | return r.Intn(max-min) + min 26 | } 27 | 28 | // 随机float64 [0.0,1.0) 29 | func RandFloat64() float64 { 30 | return r.Float64() 31 | } 32 | 33 | // 随机数组中一个元素 34 | func RandArray(arr []interface{}) interface{} { 35 | var index = math.Floor(r.Float64() * float64(len(arr))) 36 | return arr[int(index)] 37 | } 38 | -------------------------------------------------------------------------------- /core/libs/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "net" 5 | "time" 6 | ) 7 | 8 | //获取当前毫秒时间戳 9 | func UnixMillisecond() int64 { 10 | return time.Now().UnixNano() / 1e6 11 | } 12 | 13 | //获取本机Ip 14 | func GetLocalIp() string { 15 | ipAddr := "localhost" 16 | addrSlice, err := net.InterfaceAddrs() 17 | if err == nil { 18 | for _, addr := range addrSlice { 19 | if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 20 | if nil != ipnet.IP.To4() { 21 | ipAddr = ipnet.IP.String() 22 | break 23 | } 24 | } 25 | } 26 | } 27 | return ipAddr 28 | } 29 | 30 | //三元表达式 31 | func If(condition bool, trueVal, falseVal interface{}) interface{} { 32 | if condition { 33 | return trueVal 34 | } 35 | return falseVal 36 | } 37 | -------------------------------------------------------------------------------- /core/service/service_mongo.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/mongo" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func (this *Service) StartMongo() { 11 | this.mongoClients = make(map[string]*mongo.Client) 12 | 13 | mongoConfigs := config.GetMongoConfig() 14 | for aliasName, mongoConfig := range mongoConfigs { 15 | client, err := mongo.NewClient(mongoConfig) 16 | CheckError(err) 17 | 18 | if client != nil { 19 | this.mongoClients[aliasName] = client 20 | INFO("Mongo连接成功", zap.String("AliasName", aliasName)) 21 | } 22 | } 23 | } 24 | 25 | func (this *Service) GetMongoClient(dbAliasName string) *mongo.Client { 26 | client, _ := this.mongoClients[dbAliasName] 27 | return client 28 | } 29 | -------------------------------------------------------------------------------- /core/global.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/mongo" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/mysql" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/redis" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/rpc" 9 | ) 10 | 11 | type IService interface { 12 | Env() string 13 | Name() string 14 | ID() int 15 | Identify() string 16 | GetIpcClient(serviceName string) *ipc.Client 17 | GetRpcClient(serviceName string) *rpc.Client 18 | GetRedisClient(redisAliasName string) *redis.Client 19 | GetMysqlClient(dbAliasName string) *mysql.Client 20 | GetMongoClient(dbAliasName string) *mongo.Client 21 | GetIpcServer() *ipc.Server 22 | Ip() string 23 | Port(serviceType string) string 24 | } 25 | 26 | var ( 27 | Service IService 28 | ) 29 | -------------------------------------------------------------------------------- /core/service/service_redis.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/redis" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func (this *Service) StartRedis() { 11 | this.redisClients = make(map[string]*redis.Client) 12 | 13 | redisConfigs := config.GetRedisConfig() 14 | for aliasName, redisConfig := range redisConfigs { 15 | client, err := redis.NewClient(redisConfig) 16 | CheckError(err) 17 | 18 | if client != nil { 19 | this.redisClients[aliasName] = client 20 | INFO("Redis连接成功", zap.String("AliasName", aliasName)) 21 | } 22 | } 23 | } 24 | 25 | func (this *Service) GetRedisClient(redisAliasName string) *redis.Client { 26 | client, _ := this.redisClients[redisAliasName] 27 | return client 28 | } 29 | -------------------------------------------------------------------------------- /servives/connector/module/server.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/consts" 6 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 9 | "github.com/yicaoyimuys/GoGameServer/servives/connector/cache" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | func StartServerTimer() { 14 | initServerLogTimer() 15 | } 16 | 17 | func initServerLogTimer() { 18 | //每隔20秒记录一次 19 | timer.DoTimer(20*1000, func() { 20 | onlineUsersNum := sessions.FrontSessionLen() 21 | ip := core.Service.Ip() 22 | port := core.Service.Port(consts.ServiceType_Socket) 23 | cache.SetServerInfo(ip, port, onlineUsersNum) 24 | INFO("当前在线用户数量", zap.Int("OnlineUsersNum", onlineUsersNum)) 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /core/libs/rpc/server.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "net" 5 | "net/rpc" 6 | "net/rpc/jsonrpc" 7 | "strconv" 8 | 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 10 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | func InitServer() (string, error) { 15 | listen, err := net.Listen("tcp", ":") 16 | if err != nil { 17 | return "", err 18 | } 19 | 20 | go func() { 21 | defer stack.TryError() 22 | defer listen.Close() 23 | 24 | for { 25 | conn, err := listen.Accept() 26 | if err != nil { 27 | logger.Error("Listen.Accept()", zap.Error(err)) 28 | } 29 | go jsonrpc.ServeConn(conn) 30 | } 31 | }() 32 | 33 | serverPort := strconv.Itoa(listen.Addr().(*net.TCPAddr).Port) 34 | return serverPort, nil 35 | } 36 | 37 | func RegisterModule(name string, rcvr interface{}) error { 38 | err := rpc.RegisterName(name, rcvr) 39 | return err 40 | } 41 | -------------------------------------------------------------------------------- /servives/public/gameProto/gameProto.go: -------------------------------------------------------------------------------- 1 | package gameProto 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 5 | ) 6 | 7 | // 初始化消息ID和消息类型的对应关系 8 | func init() { 9 | //system 10 | protos.SetMsg(ID_error_notice_s2c, ErrorNoticeS2C{}) 11 | 12 | //connector 13 | protos.SetMsg(ID_client_ping_c2s, ClientPingC2S{}) 14 | 15 | //login 16 | protos.SetMsg(ID_user_login_c2s, UserLoginC2S{}) 17 | protos.SetMsg(ID_user_login_s2c, UserLoginS2C{}) 18 | protos.SetMsg(ID_user_otherLogin_notice_s2c, UserOtherLoginNoticeS2C{}) 19 | 20 | //game 21 | protos.SetMsg(ID_user_getInfo_c2s, UserGetInfoC2S{}) 22 | protos.SetMsg(ID_user_getInfo_s2c, UserGetInfoS2C{}) 23 | 24 | //chat 25 | protos.SetMsg(ID_user_joinChat_c2s, UserJoinChatC2S{}) 26 | protos.SetMsg(ID_user_joinChat_s2c, UserJoinChatS2C{}) 27 | protos.SetMsg(ID_user_chat_c2s, UserChatC2S{}) 28 | protos.SetMsg(ID_user_chat_notice_s2c, UserChatNoticeS2C{}) 29 | } 30 | -------------------------------------------------------------------------------- /core/service/service_socket.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | "github.com/yicaoyimuys/GoGameServer/core/consts" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/socket" 8 | ) 9 | 10 | func (this *Service) StartSocket(handle sessions.FrontSessionReceiveMsgHandle) { 11 | //Socket配置 12 | serviceConfig := config.GetService("connector") 13 | serviceNodeConfig := serviceConfig.ServiceNodes[this.id] 14 | port := serviceNodeConfig.ClientPort 15 | 16 | //创建Socket Server 17 | server := socket.NewServer(port, this.id) 18 | server.SetSessionCreateHandle(this.frontSessionCreateHandle) 19 | server.SetSessionReceiveMsgHandle(handle) 20 | server.Start() 21 | server.StartPing() 22 | 23 | //服务注册 24 | this.registerService(consts.ServiceType_Socket, port) 25 | 26 | //service中保存socketServer 27 | this.socketServer = server 28 | } 29 | -------------------------------------------------------------------------------- /servives/public/redisCaches/user.go: -------------------------------------------------------------------------------- 1 | package redisCaches 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/servives/public/mysqlModels" 8 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisInstances" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisKeys" 10 | 11 | "github.com/spf13/cast" 12 | ) 13 | 14 | // 设置DBUser缓存 15 | func SetUser(dbUser *mysqlModels.User) error { 16 | userKey := redisKeys.DbUser + cast.ToString(dbUser.Id) 17 | userData, _ := json.Marshal(dbUser) 18 | return redisInstances.User().Set(userKey, userData, time.Hour*24).Err() 19 | } 20 | 21 | // 获取DBUser缓存 22 | func GetUser(userId uint64) *mysqlModels.User { 23 | key := redisKeys.DbUser + cast.ToString(userId) 24 | val, err := redisInstances.User().Get(key).Result() 25 | if err != nil { 26 | return nil 27 | } 28 | 29 | var dbUser mysqlModels.User 30 | err = json.Unmarshal([]byte(val), &dbUser) 31 | return &dbUser 32 | } 33 | -------------------------------------------------------------------------------- /core/messages/ipcClientMessage.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func IpcClientReceive(stream ipc.Ipc_TransferClient, msg *ipc.Res) { 12 | if msg.UserSessionIds == nil { 13 | //发送给所有人 14 | sessions.FetchFrontSession(func(clientSession *sessions.FrontSession) { 15 | clientSession.Send(msg.Data) 16 | }) 17 | } else { 18 | //发送给多个人 19 | for _, userSessionId := range msg.UserSessionIds { 20 | clientSession := sessions.GetFrontSession(userSessionId) 21 | if clientSession != nil { 22 | clientSession.Send(msg.Data) 23 | } else { 24 | msgId := protos.UnmarshalProtoId(msg.Data) 25 | WARN("FrontSession No Exists", zap.Uint16("MsgId", msgId)) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/service/service_mysql.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/mysql" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func (this *Service) StartMysql() { 11 | this.mysqlClients = make(map[string]*mysql.Client) 12 | 13 | mysqlConfigs := config.GetMysqlConfig() 14 | index := 0 15 | for key, mysqlConfig := range mysqlConfigs { 16 | dbAliasName := key 17 | if index == 0 { 18 | dbAliasName = "default" 19 | } 20 | index++ 21 | 22 | client, err := mysql.NewClient(dbAliasName, mysqlConfig) 23 | CheckError(err) 24 | 25 | if client != nil { 26 | this.mysqlClients[key] = client 27 | INFO("Mysql连接成功", zap.String("AliasName", key)) 28 | } 29 | } 30 | } 31 | 32 | func (this *Service) GetMysqlClient(dbAliasName string) *mysql.Client { 33 | client, _ := this.mysqlClients[dbAliasName] 34 | return client 35 | } 36 | -------------------------------------------------------------------------------- /servives/login/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/messages" 7 | "github.com/yicaoyimuys/GoGameServer/core/service" 8 | "github.com/yicaoyimuys/GoGameServer/servives/login/module" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 10 | ) 11 | 12 | func main() { 13 | //初始化Service 14 | newService := service.NewService(consts.Service_Login) 15 | newService.StartIpcServer() 16 | newService.StartRpcServer() 17 | newService.StartRpcClient([]string{consts.Service_Log}) 18 | newService.StartRedis() 19 | newService.StartMysql() 20 | 21 | //消息初始化 22 | initMessage() 23 | 24 | //模块初始化 25 | initModule() 26 | 27 | //保持进程 28 | Run() 29 | } 30 | 31 | func initMessage() { 32 | messages.RegisterIpcServerHandle(gameProto.ID_user_login_c2s, module.Login) 33 | } 34 | 35 | func initModule() { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /servives/game/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/messages" 7 | "github.com/yicaoyimuys/GoGameServer/core/service" 8 | "github.com/yicaoyimuys/GoGameServer/servives/game/module" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 10 | ) 11 | 12 | func main() { 13 | //初始化Service 14 | newService := service.NewService(consts.Service_Game) 15 | newService.StartIpcServer() 16 | newService.StartRpcServer() 17 | newService.StartRpcClient([]string{consts.Service_Log}) 18 | newService.StartRedis() 19 | newService.StartMysql() 20 | 21 | //消息初始化 22 | initMessage() 23 | 24 | //模块初始化 25 | initModule() 26 | 27 | //保持进程 28 | Run() 29 | } 30 | 31 | func initMessage() { 32 | messages.RegisterIpcServerHandle(gameProto.ID_user_getInfo_c2s, module.GetInfo) 33 | } 34 | 35 | func initModule() { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/libs/export.go: -------------------------------------------------------------------------------- 1 | package libs 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/common" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/system" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func init() { 12 | } 13 | 14 | func ERR(msg string, fields ...zap.Field) { 15 | logger.Error(msg, fields...) 16 | } 17 | 18 | func WARN(msg string, fields ...zap.Field) { 19 | logger.Warn(msg, fields...) 20 | } 21 | 22 | func INFO(msg string, fields ...zap.Field) { 23 | logger.Info(msg, fields...) 24 | } 25 | 26 | func DEBUG(msg string, fields ...zap.Field) { 27 | logger.Debug(msg, fields...) 28 | } 29 | 30 | func Run() { 31 | system.Run() 32 | } 33 | 34 | func If(condition bool, trueVal, falseVal interface{}) interface{} { 35 | return common.If(condition, trueVal, falseVal) 36 | } 37 | 38 | func CheckError(err error) { 39 | stack.CheckError(err) 40 | } 41 | -------------------------------------------------------------------------------- /servives/connector/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/service" 7 | "github.com/yicaoyimuys/GoGameServer/servives/connector/messages" 8 | "github.com/yicaoyimuys/GoGameServer/servives/connector/module" 9 | ) 10 | 11 | func main() { 12 | //初始化Service 13 | newService := service.NewService(consts.Service_Connector) 14 | newService.StartRedis() 15 | // newService.StartWebSocket(messages.FontReceive) 16 | newService.StartSocket(messages.FontReceive) 17 | newService.StartIpcClient([]string{consts.Service_Game, consts.Service_Login, consts.Service_Chat}) 18 | newService.StartRpcClient([]string{consts.Service_Game, consts.Service_Login, consts.Service_Chat, consts.Service_Log}) 19 | newService.StartPProf(6000) 20 | 21 | //模块初始化 22 | initModule() 23 | 24 | //保持进程 25 | Run() 26 | } 27 | 28 | func initModule() { 29 | module.StartServerTimer() 30 | } 31 | -------------------------------------------------------------------------------- /servives/chat/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/messages" 7 | "github.com/yicaoyimuys/GoGameServer/core/service" 8 | "github.com/yicaoyimuys/GoGameServer/servives/chat/module" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 10 | ) 11 | 12 | func main() { 13 | //初始化Service 14 | newService := service.NewService(consts.Service_Chat) 15 | newService.StartIpcServer() 16 | newService.StartRpcServer() 17 | newService.StartRpcClient([]string{consts.Service_Log}) 18 | newService.StartRedis() 19 | 20 | //消息初始化 21 | initMessage() 22 | 23 | //模块初始化 24 | initModule() 25 | 26 | //保持进程 27 | Run() 28 | } 29 | 30 | func initMessage() { 31 | messages.RegisterIpcServerHandle(gameProto.ID_user_joinChat_c2s, module.JoinChat) 32 | messages.RegisterIpcServerHandle(gameProto.ID_user_chat_c2s, module.Chat) 33 | } 34 | 35 | func initModule() { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/libs/jwt/jwt.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 5 | "go.uber.org/zap" 6 | 7 | "github.com/dgrijalva/jwt-go" 8 | ) 9 | 10 | type Jwt struct { 11 | secretKey []byte 12 | } 13 | 14 | func NewJwt(secret string) *Jwt { 15 | return &Jwt{ 16 | secretKey: []byte(secret), 17 | } 18 | } 19 | 20 | func (this *Jwt) Sign(claims jwt.MapClaims) string { 21 | token := jwt.New(jwt.SigningMethodHS256) 22 | token.Claims = claims 23 | 24 | tokenString, err := token.SignedString(this.secretKey) 25 | if err != nil { 26 | logger.Error("jwt.Sign", zap.Error(err)) 27 | return "" 28 | } 29 | return tokenString 30 | } 31 | 32 | func (this *Jwt) Parse(tokenString string) jwt.MapClaims { 33 | token, err := jwt.Parse(tokenString, func(*jwt.Token) (interface{}, error) { 34 | return this.secretKey, nil 35 | }) 36 | 37 | if !token.Valid { 38 | logger.Error("jwt.Parse token not valid") 39 | return nil 40 | } 41 | 42 | if err != nil { 43 | logger.Error("jwt.Parse", zap.Error(err)) 44 | return nil 45 | } 46 | return token.Claims.(jwt.MapClaims) 47 | } 48 | -------------------------------------------------------------------------------- /servives/api/controllers/connector.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 7 | 8 | "github.com/astaxie/beego" 9 | ) 10 | 11 | type ConnectorController struct { 12 | beego.Controller 13 | } 14 | 15 | func init() { 16 | 17 | } 18 | 19 | func packageServiceName(serviceType string, serviceName string) string { 20 | return "<" + serviceType + ">" + serviceName 21 | } 22 | 23 | func (this *ConnectorController) Get() { 24 | consulClient, err := consul.NewClient() 25 | CheckError(err) 26 | 27 | serviceName := "" 28 | 29 | typeStr := this.GetString("type") 30 | if typeStr == "Socket" { 31 | serviceName = packageServiceName(consts.ServiceType_Socket, consts.Service_Connector) 32 | } else if typeStr == "WebSocket" { 33 | serviceName = packageServiceName(consts.ServiceType_WebSocket, consts.Service_Connector) 34 | } 35 | 36 | services := consulClient.GetServices(serviceName) 37 | 38 | this.Data["json"] = services 39 | this.ServeJSON() 40 | } 41 | -------------------------------------------------------------------------------- /core/service/service_websocket.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | "github.com/yicaoyimuys/GoGameServer/core/consts" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/websocket" 8 | ) 9 | 10 | func (this *Service) StartWebSocket(handle sessions.FrontSessionReceiveMsgHandle) { 11 | //WebSocket配置 12 | serviceConfig := config.GetService("connector") 13 | serviceNodeConfig := serviceConfig.ServiceNodes[this.id] 14 | port := serviceNodeConfig.ClientPort 15 | useSSL := serviceNodeConfig.UseSSL 16 | 17 | //创建WebSocket Server 18 | server := websocket.NewServer(port, this.id) 19 | if useSSL { 20 | tslCrt := serviceConfig.TslCrt 21 | tslKey := serviceConfig.TslKey 22 | server.SetTLS(tslCrt, tslKey) 23 | } 24 | server.SetSessionCreateHandle(this.frontSessionCreateHandle) 25 | server.SetSessionReceiveMsgHandle(handle) 26 | server.Start() 27 | server.StartPing() 28 | 29 | //服务注册 30 | this.registerService(consts.ServiceType_WebSocket, port) 31 | 32 | //service中保存websocketServer 33 | this.websocketServer = server 34 | } 35 | -------------------------------------------------------------------------------- /servives/public/common.go: -------------------------------------------------------------------------------- 1 | package public 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 8 | 9 | "google.golang.org/protobuf/proto" 10 | ) 11 | 12 | func SendErrorMsgToClient(session *sessions.BackSession, errorCode int32) { 13 | sendMsg := &gameProto.ErrorNoticeS2C{ 14 | ErrorCode: protos.Int32(errorCode), 15 | } 16 | SendMsgToClient(session, sendMsg) 17 | } 18 | 19 | func SendMsgToClient(session *sessions.BackSession, sendMsg proto.Message) { 20 | if session == nil || sendMsg == nil { 21 | return 22 | } 23 | session.Send(protos.MarshalProtoMsg(sendMsg)) 24 | } 25 | 26 | func SendMsgToClientList(userSessionIds []uint64, sendMsg proto.Message) { 27 | data := protos.MarshalProtoMsg(sendMsg) 28 | core.Service.GetIpcServer().SendToAllClient(userSessionIds, data) 29 | } 30 | 31 | func SendMsgToAllClient(sendMsg proto.Message) { 32 | data := protos.MarshalProtoMsg(sendMsg) 33 | core.Service.GetIpcServer().SendToAllClient(nil, data) 34 | } 35 | -------------------------------------------------------------------------------- /servives/public/token.go: -------------------------------------------------------------------------------- 1 | package public 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/common" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/dict" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/jwt" 7 | ) 8 | 9 | const ( 10 | sessionSignKey = "qwert&mnbvc" 11 | checkTimeOpen = false 12 | userOffineCheckTime int64 = 10 * 60 * 1000 13 | ) 14 | 15 | var ( 16 | myJwt *jwt.Jwt 17 | ) 18 | 19 | func init() { 20 | myJwt = jwt.NewJwt(sessionSignKey) 21 | } 22 | 23 | func CreateToken(userId uint64) string { 24 | claims := make(map[string]interface{}) 25 | claims["userId"] = userId 26 | claims["time"] = common.UnixMillisecond() 27 | token := myJwt.Sign(claims) 28 | return token 29 | } 30 | 31 | func GetUserIdByToken(token string) uint64 { 32 | claims := myJwt.Parse(token) 33 | if claims == nil { 34 | return 0 35 | } 36 | 37 | //用户Id 38 | userId := dict.GetUint64(claims, "userId") 39 | 40 | //检测是否过期 41 | if checkTimeOpen { 42 | time := dict.GetInt64(claims, "time") 43 | nowTime := common.UnixMillisecond() 44 | if nowTime-time >= userOffineCheckTime { 45 | return 0 46 | } 47 | } 48 | 49 | return userId 50 | } 51 | -------------------------------------------------------------------------------- /core/service/service_http.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | "github.com/spf13/cast" 6 | "github.com/yicaoyimuys/GoGameServer/core/config" 7 | "github.com/yicaoyimuys/GoGameServer/core/consts" 8 | ) 9 | 10 | func (this *Service) StartHttpServer() { 11 | //Api服务配置 12 | serviceConfig := config.GetService("api") 13 | serviceNodeConfig := serviceConfig.ServiceNodes[this.id] 14 | port := serviceNodeConfig.ClientPort 15 | useSSL := serviceNodeConfig.UseSSL 16 | 17 | //Http服务配置 18 | if useSSL { 19 | tslCrt := serviceConfig.TslCrt 20 | tslKey := serviceConfig.TslKey 21 | 22 | beego.BConfig.Listen.EnableHTTPS = true 23 | beego.BConfig.Listen.HTTPSCertFile = tslCrt 24 | beego.BConfig.Listen.HTTPSKeyFile = tslKey 25 | beego.BConfig.Listen.HTTPSPort = cast.ToInt(port) 26 | } else { 27 | beego.BConfig.Listen.HTTPPort = cast.ToInt(port) 28 | } 29 | beego.BConfig.RunMode = beego.PROD 30 | 31 | //启动http服务 32 | go beego.Run() 33 | 34 | //服务注册 35 | this.registerService(consts.ServiceType_Http, port) 36 | } 37 | 38 | func (this *Service) RegisterHttpRouter(rootPath string, controller beego.ControllerInterface) { 39 | beego.Router(rootPath, controller) 40 | } 41 | -------------------------------------------------------------------------------- /core/config/class.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type LogConfig struct { 4 | Debug bool `json:"debug"` 5 | Both bool `json:"both"` 6 | File bool `json:"file"` 7 | } 8 | 9 | type MongoConfig struct { 10 | Host string `json:"host"` 11 | Port string `json:"port"` 12 | User string `json:"user"` 13 | Password string `json:"password"` 14 | Db string `json:"db"` 15 | } 16 | 17 | type MysqlConfig struct { 18 | Host string `json:"host"` 19 | Port string `json:"port"` 20 | User string `json:"user"` 21 | Password string `json:"password"` 22 | Db string `json:"db"` 23 | Charset string `json:"charset"` 24 | } 25 | 26 | type RedisConfig struct { 27 | Prefix string `json:"prefix"` 28 | Host string `json:"host"` 29 | Port string `json:"port"` 30 | AuthPass string `json:"auth_pass"` 31 | Db int `json:"db"` 32 | } 33 | 34 | type ServiceConfig struct { 35 | TslCrt string `json:"tslCrt"` 36 | TslKey string `json:"tslKey"` 37 | ServiceNodes map[int]ServiceNodeConfig `json:"services"` 38 | } 39 | 40 | type ServiceNodeConfig struct { 41 | ClientPort string `json:"clientPort"` 42 | UseSSL bool `json:"useSSL"` 43 | } 44 | -------------------------------------------------------------------------------- /servives/chat/cache/online.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "github.com/yicaoyimuys/GoGameServer/servives/chat/model" 8 | ) 9 | 10 | var ( 11 | onlineUsers = make(map[uint64]*model.ChatUser) 12 | onlineUsersNum int32 = 0 13 | onlineUsersMutex sync.RWMutex 14 | ) 15 | 16 | func AddUser(userID uint64, userName string, session *sessions.BackSession) { 17 | onlineUsersMutex.Lock() 18 | defer onlineUsersMutex.Unlock() 19 | 20 | user := &model.ChatUser{ 21 | Session: session, 22 | UserID: userID, 23 | UserName: userName, 24 | } 25 | 26 | if _, ok := onlineUsers[userID]; !ok { 27 | onlineUsersNum++ 28 | } 29 | onlineUsers[userID] = user 30 | } 31 | 32 | func RemoveUser(userID uint64) { 33 | onlineUsersMutex.Lock() 34 | defer onlineUsersMutex.Unlock() 35 | 36 | if _, ok := onlineUsers[userID]; ok { 37 | onlineUsersNum-- 38 | delete(onlineUsers, userID) 39 | } 40 | } 41 | 42 | func GetUser(userID uint64) *model.ChatUser { 43 | onlineUsersMutex.Lock() 44 | defer onlineUsersMutex.Unlock() 45 | 46 | user, _ := onlineUsers[userID] 47 | return user 48 | } 49 | 50 | func GetOnlineUsersNum() int32 { 51 | return onlineUsersNum 52 | } 53 | -------------------------------------------------------------------------------- /servives/api/controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/guid" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/random" 6 | "github.com/yicaoyimuys/GoGameServer/servives/public/mongoModels" 7 | 8 | "github.com/astaxie/beego" 9 | "github.com/spf13/cast" 10 | ) 11 | 12 | type DefaultController struct { 13 | beego.Controller 14 | } 15 | 16 | var ( 17 | g *guid.Guid 18 | ) 19 | 20 | func init() { 21 | g = guid.NewGuid(1) 22 | } 23 | 24 | func (this *DefaultController) Get() { 25 | id := g.NewID() 26 | account := this.GetString("name") 27 | if len(account) == 0 { 28 | account = "ys_" + cast.ToString(id) 29 | } 30 | money := int32(random.RandIntRange(1000, 9999)) 31 | 32 | dbUser := mongoModels.AddUser(id, account, money) 33 | if dbUser == nil { 34 | this.Ctx.WriteString("mongo insert fail") 35 | } else { 36 | money = int32(random.RandIntRange(100, 999)) 37 | if !mongoModels.UpdateUserMoney(id, money) { 38 | this.Ctx.WriteString("mongo update fail") 39 | } else { 40 | dbUser = mongoModels.GetUser(id) 41 | if dbUser == nil { 42 | this.Ctx.WriteString("mongo select fail") 43 | } else { 44 | this.Data["json"] = dbUser 45 | this.ServeJSON() 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/libs/stack/stack.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "runtime" 5 | "strconv" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | // PrintPanicStack 输出错误堆栈信息 12 | func PrintPanicStack() { 13 | for i := 0; i < 10; i++ { 14 | funcName, file, line, ok := runtime.Caller(i) 15 | if ok { 16 | funcName := runtime.FuncForPC(funcName).Name() 17 | logger.Error("错误堆栈", zap.String("Caller", "frame"+strconv.Itoa(i)+": [func:"+funcName+", file:"+file+", line:"+strconv.Itoa(line)+"]")) 18 | } 19 | } 20 | } 21 | 22 | // GetCallStack 获取调用堆栈 23 | func GetCallStack() []string { 24 | result := make([]string, 10) 25 | for i := 0; i < 10; i++ { 26 | pc, file, line, ok := runtime.Caller(i) 27 | if ok { 28 | funcName := runtime.FuncForPC(pc).Name() 29 | result[i] = "frame" + strconv.Itoa(i) + ": [func:" + funcName + ", file:" + file + ", line:" + strconv.Itoa(line) + "]" 30 | } 31 | } 32 | return result 33 | } 34 | 35 | // TryError 捕获异常 36 | func TryError() { 37 | if x := recover(); x != nil { 38 | logger.Error("Error", zap.Any("Recover", x)) 39 | PrintPanicStack() 40 | } 41 | } 42 | 43 | // CheckError 检查Error 44 | func CheckError(err error) { 45 | if err != nil { 46 | logger.Error("Fatal error: %v", zap.Error(err)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /servives/game/module/user.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 6 | "github.com/yicaoyimuys/GoGameServer/servives/public" 7 | "github.com/yicaoyimuys/GoGameServer/servives/public/errCodes" 8 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisCaches" 10 | 11 | "google.golang.org/protobuf/proto" 12 | ) 13 | 14 | // 获取用户信息 15 | func GetInfo(clientSession *sessions.BackSession, msgData proto.Message) { 16 | data := msgData.(*gameProto.UserGetInfoC2S) 17 | token := data.GetToken() 18 | userId := public.GetUserIdByToken(token) 19 | if userId == 0 { 20 | public.SendErrorMsgToClient(clientSession, errCodes.PARAM_ERROR) 21 | return 22 | } 23 | 24 | //获取缓存中用户数据 25 | dbUser := redisCaches.GetUser(userId) 26 | if dbUser == nil { 27 | public.SendErrorMsgToClient(clientSession, errCodes.PARAM_ERROR) 28 | return 29 | } 30 | 31 | //返回客户端消息 32 | sendMsg := &gameProto.UserGetInfoS2C{ 33 | Data: &gameProto.UserInfo{ 34 | Id: protos.Uint64(dbUser.Id), 35 | Name: protos.String(dbUser.Account), 36 | Money: protos.Int32(dbUser.Money), 37 | }, 38 | } 39 | public.SendMsgToClient(clientSession, sendMsg) 40 | } 41 | -------------------------------------------------------------------------------- /core/libs/guid/guid.go: -------------------------------------------------------------------------------- 1 | package guid 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 8 | ) 9 | 10 | type Guid struct { 11 | serverId uint16 12 | sequence int32 13 | mx sync.RWMutex 14 | lastTimestamp int64 15 | } 16 | 17 | func (this *Guid) NewID() uint64 { 18 | this.mx.Lock() 19 | defer this.mx.Unlock() 20 | 21 | if this.serverId > 4095 { 22 | logger.Error("server_id超出最大值") 23 | return 0 24 | } 25 | 26 | timestamp := time.Now().Unix() 27 | if timestamp < this.lastTimestamp { 28 | logger.Error("请调整服务器时间!") 29 | return 0 30 | } 31 | 32 | if timestamp == this.lastTimestamp { 33 | // 当前毫秒内,则+1 34 | this.sequence += 1 35 | if this.sequence > 4095 { 36 | // 当前毫秒内计数满了,则等待下一秒 37 | this.sequence = 0 38 | for { 39 | timestamp = time.Now().Unix() 40 | if timestamp > this.lastTimestamp { 41 | break 42 | } 43 | } 44 | } 45 | } else { 46 | this.sequence = 0 47 | } 48 | this.lastTimestamp = timestamp 49 | 50 | //40(毫秒) + 12(serverID) + 12(重复累加) 51 | return uint64(timestamp<<40) | (uint64(this.serverId) << 12) | uint64(this.sequence) 52 | } 53 | 54 | func NewGuid(server_id uint16) *Guid { 55 | return &Guid{ 56 | serverId: server_id, 57 | sequence: 0, 58 | lastTimestamp: -1, 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/libs/sessions/backSessionService.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/spf13/cast" 7 | ) 8 | 9 | var ( 10 | backSessions = make(map[string]*BackSession) 11 | backSessionMutex sync.Mutex 12 | ) 13 | 14 | func SetBackSession(session *BackSession) { 15 | backSessionMutex.Lock() 16 | defer backSessionMutex.Unlock() 17 | 18 | if oldSession, ok := backSessions[session.id]; ok { 19 | oldSession.RemoveCloseCallback(nil, "RemoveBackSession") 20 | oldSession.Close() 21 | } 22 | 23 | backSessions[session.id] = session 24 | session.AddCloseCallback(nil, "RemoveBackSession", func() { 25 | RemoveBackSession(session.id) 26 | }) 27 | } 28 | 29 | func GetBackSession(key string) *BackSession { 30 | backSessionMutex.Lock() 31 | defer backSessionMutex.Unlock() 32 | 33 | session, _ := backSessions[key] 34 | return session 35 | } 36 | 37 | func RemoveBackSession(key string) { 38 | backSessionMutex.Lock() 39 | defer backSessionMutex.Unlock() 40 | 41 | delete(backSessions, key) 42 | } 43 | 44 | func BackSessionLen() int { 45 | backSessionMutex.Lock() 46 | defer backSessionMutex.Unlock() 47 | 48 | return len(backSessions) 49 | } 50 | 51 | func CreateBackSessionId(serviceIdentify string, userSessionId uint64) string { 52 | return serviceIdentify + "_" + cast.ToString(userSessionId) 53 | } 54 | -------------------------------------------------------------------------------- /core/libs/socket/frontCodec.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "net" 7 | 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 9 | ) 10 | 11 | func NewFrontCodec(rw net.Conn) sessions.Codec { 12 | codec := &frontCodec{ 13 | rw: rw, 14 | headBuf: make([]byte, 2), 15 | } 16 | return codec 17 | } 18 | 19 | type frontCodec struct { 20 | rw net.Conn 21 | headBuf []byte 22 | bodyBuf []byte 23 | } 24 | 25 | func (this *frontCodec) Receive() ([]byte, error) { 26 | //消息长度 27 | if _, err := io.ReadFull(this.rw, this.headBuf); err != nil { 28 | return nil, err 29 | } 30 | msgLen := binary.BigEndian.Uint16(this.headBuf) 31 | 32 | //消息内容 33 | if uint16(cap(this.bodyBuf)) < msgLen { 34 | this.bodyBuf = make([]byte, msgLen, msgLen+128) 35 | } 36 | msgBody := this.bodyBuf[:msgLen] 37 | if _, err := io.ReadFull(this.rw, msgBody); err != nil { 38 | return nil, err 39 | } 40 | 41 | return msgBody, nil 42 | } 43 | 44 | func (this *frontCodec) Send(msg []byte) error { 45 | msgLen := uint16(len(msg)) 46 | sendMsg := make([]byte, msgLen+2) 47 | binary.BigEndian.PutUint16(sendMsg[:2], msgLen) 48 | copy(sendMsg[2:], msg) 49 | 50 | _, err := this.rw.Write(sendMsg) 51 | return err 52 | } 53 | 54 | func (this *frontCodec) Close() error { 55 | return this.rw.Close() 56 | } 57 | -------------------------------------------------------------------------------- /core/libs/websocket/frontCodec.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 8 | 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | func NewFrontCodec(rw *websocket.Conn) sessions.Codec { 13 | codec := &frontCodec{ 14 | rw: rw, 15 | } 16 | return codec 17 | } 18 | 19 | type frontCodec struct { 20 | rw *websocket.Conn 21 | } 22 | 23 | func (this *frontCodec) Receive() ([]byte, error) { 24 | _, data, err := this.rw.ReadMessage() 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | if len(data) < 2 { 30 | logger.Error("消息长度不够") 31 | return nil, err 32 | } 33 | 34 | //消息长度 35 | msgLen := binary.BigEndian.Uint16(data[:2]) 36 | //消息内容 37 | msgBody := data[2:] 38 | //长度检测 39 | if len(msgBody) != int(msgLen) { 40 | logger.Error("消息长度不够") 41 | return nil, err 42 | } 43 | 44 | return msgBody, nil 45 | } 46 | 47 | func (this *frontCodec) Send(msg []byte) error { 48 | msgLen := uint16(len(msg)) 49 | sendMsg := make([]byte, msgLen+2) 50 | binary.BigEndian.PutUint16(sendMsg[:2], msgLen) 51 | copy(sendMsg[2:], msg) 52 | 53 | return this.rw.WriteMessage(websocket.BinaryMessage, sendMsg) 54 | } 55 | 56 | func (this *frontCodec) Close() error { 57 | return this.rw.Close() 58 | } 59 | -------------------------------------------------------------------------------- /core/messages/ipcServerMessage.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func IpcServerReceive(stream *ipc.Stream, msg *ipc.Req) { 12 | msgBody := msg.Data 13 | 14 | //获取Session 15 | id := sessions.CreateBackSessionId(msg.ServiceIdentify, msg.UserSessionId) 16 | session := sessions.GetBackSession(id) 17 | if session == nil { 18 | session = sessions.NewBackSession(id, msg.UserSessionId, stream) 19 | session.SetMsgHandle(dealMessage) 20 | sessions.SetBackSession(session) 21 | } 22 | session.Receive(msgBody) 23 | } 24 | 25 | func dealMessage(session *sessions.BackSession, msgBody []byte) { 26 | //消息解析 27 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 28 | if protoMsg == protos.NullProtoMsg { 29 | msgId := protos.UnmarshalProtoId(msgBody) 30 | ERR("收到错误消息ID", zap.Uint16("MsgId", msgId)) 31 | session.Close() 32 | return 33 | } 34 | 35 | //消息处理 36 | msgId := protoMsg.ID 37 | msgData := protoMsg.Body 38 | handle := GetIpcServerHandle(msgId) 39 | if handle == nil { 40 | ERR("收到未处理的消息ID", zap.Uint16("MsgId", msgId)) 41 | return 42 | } 43 | handle(session, msgData) 44 | } 45 | -------------------------------------------------------------------------------- /servives/public/gameProto/gameProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | option go_package = ".;gameProto"; 4 | 5 | //错误消息(500) 6 | message error_notice_s2c{ 7 | required int32 errorCode = 1; 8 | } 9 | 10 | 11 | 12 | //客户端ping(1001) 13 | message client_ping_c2s{ 14 | 15 | } 16 | 17 | 18 | //用户登录C2S(2001) 19 | message user_login_c2s { 20 | required string account = 1; 21 | } 22 | 23 | //用户登录S2C(2002) 24 | message user_login_s2c { 25 | required string token = 1; 26 | } 27 | 28 | //其他客户端登录S2C(2004) 29 | message user_otherLogin_notice_s2c{ 30 | 31 | } 32 | 33 | 34 | 35 | 36 | //用户数据 37 | message userInfo { 38 | required uint64 id = 1; 39 | required string name = 2; 40 | required int32 money = 3; 41 | } 42 | 43 | //获取用户信息C2S(3001) 44 | message user_getInfo_c2s { 45 | required string token = 1; 46 | } 47 | 48 | //获取用户信息S2C(3002) 49 | message user_getInfo_s2c { 50 | required userInfo data = 1; 51 | } 52 | 53 | 54 | 55 | 56 | //用户加入聊天C2S(4001) 57 | message user_joinChat_c2s { 58 | required string token = 1; 59 | } 60 | 61 | //用户加入聊天S2C(4002) 62 | message user_joinChat_s2c { 63 | } 64 | 65 | //用户聊天消息C2S(4003) 66 | message user_chat_c2s { 67 | required string msg = 1; 68 | } 69 | 70 | //用户聊天消息S2C(4004) 71 | message user_chat_notice_s2c { 72 | required uint64 userId = 1; 73 | required string userName = 2; 74 | required string msg = 3; 75 | } -------------------------------------------------------------------------------- /core/libs/mysql/client.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/config" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 6 | "go.uber.org/zap" 7 | 8 | "github.com/astaxie/beego/orm" 9 | _ "github.com/go-sql-driver/mysql" 10 | ) 11 | 12 | func init() { 13 | err := orm.RegisterDriver("mysql", orm.DRMySQL) 14 | if err != nil { 15 | logger.Error("Mysql_注册失败", zap.Error(err)) 16 | return 17 | } 18 | } 19 | 20 | type Client struct { 21 | orm.Ormer 22 | } 23 | 24 | func NewClient(dbAliasName string, mysqlConfig config.MysqlConfig) (*Client, error) { 25 | dbHost := mysqlConfig.Host 26 | dbPort := mysqlConfig.Port 27 | dbUser := mysqlConfig.User 28 | dbPassword := mysqlConfig.Password 29 | dbName := mysqlConfig.Db 30 | dbCharset := mysqlConfig.Charset 31 | 32 | //数据库连接 33 | dataSource := dbUser + ":" + dbPassword + "@tcp(" + dbHost + ":" + dbPort + ")/" + dbName + "?charset=" + dbCharset 34 | err := orm.RegisterDataBase(dbAliasName, "mysql", dataSource) 35 | if err != nil { 36 | return nil, err 37 | } 38 | 39 | //连接池设置 40 | orm.SetMaxIdleConns(dbAliasName, 30) 41 | orm.SetMaxOpenConns(dbAliasName, 30) 42 | 43 | //创建Orm对象 44 | o := orm.NewOrm() 45 | err = o.Using(dbAliasName) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | //返回数据 51 | client := &Client{o} 52 | return client, nil 53 | } 54 | -------------------------------------------------------------------------------- /dbs/user.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.0.10.10 3 | -- http://www.phpmyadmin.net 4 | -- 5 | -- Host: 127.0.0.1 6 | -- Generation Time: Oct 09, 2018 at 07:25 AM 7 | -- Server version: 5.7.21 8 | -- PHP Version: 5.6.30 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | 19 | -- 20 | -- Database: `test_user_1` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- Table structure for table `user` 27 | -- 28 | 29 | CREATE TABLE IF NOT EXISTS `user` ( 30 | `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', 31 | `account` varchar(50) NOT NULL COMMENT 'Name', 32 | `money` int(11) NOT NULL, 33 | `create_time` int(11) NOT NULL COMMENT '注册时间', 34 | `last_login_time` int(11) NOT NULL COMMENT '最后登录时间', 35 | PRIMARY KEY (`id`), 36 | UNIQUE KEY `name` (`account`) 37 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8465 ; 38 | 39 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 40 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 41 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 42 | -------------------------------------------------------------------------------- /servives/public/mongoModels/user.go: -------------------------------------------------------------------------------- 1 | package mongoModels 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/servives/public/mongoInstances" 7 | 8 | "gopkg.in/mgo.v2/bson" 9 | ) 10 | 11 | type User struct { 12 | Id uint64 `bson:"_id" json:"id"` 13 | Account string `bson:"account" json:"account"` 14 | Money int32 `bson:"money" json:"money"` 15 | CreateTime int64 `bson:"create_time" json:"create_time"` 16 | } 17 | 18 | var collection string 19 | 20 | func init() { 21 | collection = "users" 22 | } 23 | 24 | func AddUser(id uint64, account string, money int32) *User { 25 | create_time := time.Now().Unix() 26 | 27 | user := User{ 28 | Id: id, 29 | Account: account, 30 | Money: money, 31 | CreateTime: create_time, 32 | } 33 | 34 | // insert 35 | err := mongoInstances.Global().Insert(collection, user) 36 | if err != nil { 37 | return nil 38 | } 39 | return &user 40 | } 41 | 42 | func GetUser(id uint64) *User { 43 | var user User 44 | err := mongoInstances.Global().FindOne(collection, bson.M{"_id": id}, nil, &user) 45 | if err != nil { 46 | return nil 47 | } 48 | return &user 49 | } 50 | 51 | func UpdateUserMoney(id uint64, money int32) bool { 52 | err := mongoInstances.Global().Update(collection, bson.M{"_id": id}, bson.M{"$set": bson.M{"money": money}}) 53 | if err != nil { 54 | return false 55 | } 56 | return true 57 | } 58 | -------------------------------------------------------------------------------- /core/libs/hash/murmurHash.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | import "unsafe" 4 | 5 | const ( 6 | c1_32 uint32 = 0xcc9e2d51 7 | c2_32 uint32 = 0x1b873593 8 | ) 9 | 10 | // GetHash returns a murmur32 hash for the data slice. 11 | func GetHash(data []byte) uint32 { 12 | // Seed is set to 37, same as C# version of emitter 13 | var h1 uint32 = 37 14 | 15 | nblocks := len(data) / 4 16 | var p uintptr 17 | if len(data) > 0 { 18 | p = uintptr(unsafe.Pointer(&data[0])) 19 | } 20 | 21 | p1 := p + uintptr(4*nblocks) 22 | for ; p < p1; p += 4 { 23 | k1 := *(*uint32)(unsafe.Pointer(p)) 24 | 25 | k1 *= c1_32 26 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 27 | k1 *= c2_32 28 | 29 | h1 ^= k1 30 | h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 31 | h1 = h1*5 + 0xe6546b64 32 | } 33 | 34 | tail := data[nblocks*4:] 35 | 36 | var k1 uint32 37 | switch len(tail) & 3 { 38 | case 3: 39 | k1 ^= uint32(tail[2]) << 16 40 | fallthrough 41 | case 2: 42 | k1 ^= uint32(tail[1]) << 8 43 | fallthrough 44 | case 1: 45 | k1 ^= uint32(tail[0]) 46 | k1 *= c1_32 47 | k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 48 | k1 *= c2_32 49 | h1 ^= k1 50 | } 51 | 52 | h1 ^= uint32(len(data)) 53 | 54 | h1 ^= h1 >> 16 55 | h1 *= 0x85ebca6b 56 | h1 ^= h1 >> 13 57 | h1 *= 0xc2b2ae35 58 | h1 ^= h1 >> 16 59 | 60 | return (h1 << 24) | (((h1 >> 8) << 16) & 0xFF0000) | (((h1 >> 16) << 8) & 0xFF00) | (h1 >> 24) 61 | } 62 | -------------------------------------------------------------------------------- /core/service/service_handle.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 7 | ) 8 | 9 | type ClientOffline struct { 10 | } 11 | 12 | type ClientOfflineReq struct { 13 | ServiceIdentify string 14 | UserSessionId uint64 15 | } 16 | 17 | type ClientOfflineRes struct { 18 | } 19 | 20 | func (this *ClientOffline) Do(args *ClientOfflineReq, reply *ClientOfflineRes) error { 21 | id := sessions.CreateBackSessionId(args.ServiceIdentify, args.UserSessionId) 22 | session := sessions.GetBackSession(id) 23 | if session != nil { 24 | session.Close() 25 | } 26 | return nil 27 | } 28 | 29 | func (this *Service) frontSessionCreateHandle(session *sessions.FrontSession) { 30 | session.AddCloseCallback(nil, "FrontSessionOffline", func() { 31 | this.frontSessionOfflineHandle(session) 32 | }) 33 | } 34 | 35 | func (this *Service) frontSessionOfflineHandle(session *sessions.FrontSession) { 36 | method := "ClientOffline.Do" 37 | args := &ClientOfflineReq{ 38 | ServiceIdentify: core.Service.Identify(), 39 | UserSessionId: session.ID(), 40 | } 41 | reply := &ClientOfflineRes{} 42 | 43 | //通知后端服务器 44 | for _, v := range this.rpcClients { 45 | var client = v 46 | go func() { 47 | defer stack.TryError() 48 | 49 | client.CallAll(method, args, reply) 50 | }() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /servives/connector/messages/frontMessage.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "go.uber.org/zap" 8 | ) 9 | 10 | func FontReceive(session *sessions.FrontSession, msgBody []byte) { 11 | //消息ID 12 | msgId := protos.UnmarshalProtoId(msgBody) 13 | //DEBUG("FrontMessage收到消息ID:", msgId) 14 | 15 | //消息处理 16 | if isSystemMsg(msgId) { 17 | //系统消息 18 | ERR("ERR???", zap.Uint16("MsgId", msgId)) 19 | } else if isConnectorMsg(msgId) { 20 | //连接服务器消息 21 | dealConnectorMsg(session, msgBody) 22 | } else if isLoginMsg(msgId) { 23 | //登录服务器消息 24 | dealLoginMsg(session, msgBody) 25 | } else if isGameMsg(msgId) { 26 | //游戏服务器消息 27 | dealGameMsg(session, msgBody) 28 | } else if isChatMsg(msgId) { 29 | //聊天服务器消息 30 | dealChatMsg(session, msgBody) 31 | } else { 32 | ERR("WHAT???", zap.Uint16("MsgId", msgId)) 33 | } 34 | } 35 | 36 | func isSystemMsg(msgId uint16) bool { 37 | return msgId >= 1 && msgId <= 999 38 | } 39 | 40 | func isConnectorMsg(msgId uint16) bool { 41 | return msgId >= 1000 && msgId <= 1999 42 | } 43 | 44 | func isLoginMsg(msgId uint16) bool { 45 | return msgId >= 2000 && msgId <= 2999 46 | } 47 | 48 | func isGameMsg(msgId uint16) bool { 49 | return msgId >= 3000 && msgId <= 3999 50 | } 51 | 52 | func isChatMsg(msgId uint16) bool { 53 | return msgId >= 4000 && msgId <= 4999 54 | } 55 | -------------------------------------------------------------------------------- /servives/connector/cache/serverCache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisInstances" 7 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisKeys" 8 | ) 9 | 10 | func SetServerInfo(domainName string, serverPort string, onlineUsersNum int) { 11 | oldServerInfo := GetServerInfo(domainName, serverPort) 12 | 13 | //读取最高在线 14 | var oldMaxOnlineUsersNum = 0 15 | if oldServerInfo != nil { 16 | if num, exists := oldServerInfo["maxOnlineUsersNum"]; exists { 17 | oldMaxOnlineUsersNum = num 18 | } 19 | } 20 | 21 | redisKey := redisKeys.ServerInfo 22 | serverKey := domainName + ":" + serverPort 23 | 24 | serverInfo := make(map[string]int) 25 | serverInfo["onlineUsersNum"] = onlineUsersNum 26 | if onlineUsersNum > oldMaxOnlineUsersNum { 27 | serverInfo["maxOnlineUsersNum"] = onlineUsersNum 28 | } else { 29 | serverInfo["maxOnlineUsersNum"] = oldMaxOnlineUsersNum 30 | } 31 | 32 | byteData, _ := json.Marshal(serverInfo) 33 | redisInstances.Global().HSet(redisKey, serverKey, string(byteData)) 34 | } 35 | 36 | func GetServerInfo(domainName string, serverPort string) map[string]int { 37 | redisKey := redisKeys.ServerInfo 38 | serverKey := domainName + ":" + serverPort 39 | val, err := redisInstances.Global().HGet(redisKey, serverKey).Result() 40 | if err != nil { 41 | return nil 42 | } 43 | 44 | var serverInfo map[string]int 45 | _ = json.Unmarshal([]byte(val), &serverInfo) 46 | return serverInfo 47 | } 48 | -------------------------------------------------------------------------------- /servives/public/mysqlModels/user.go: -------------------------------------------------------------------------------- 1 | package mysqlModels 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/servives/public/mysqlInstances" 7 | 8 | "github.com/astaxie/beego/orm" 9 | ) 10 | 11 | type User struct { 12 | Id uint64 13 | Account string 14 | Money int32 15 | CreateTime int64 16 | LastLoginTime int64 17 | } 18 | 19 | func init() { 20 | orm.RegisterModel(new(User)) 21 | } 22 | 23 | func AddUser(account string, money int32) *User { 24 | create_time := time.Now().Unix() 25 | 26 | user := User{ 27 | Account: account, 28 | Money: money, 29 | CreateTime: create_time, 30 | LastLoginTime: create_time, 31 | } 32 | 33 | // insert 34 | _, err := mysqlInstances.User().Insert(&user) 35 | if err != nil { 36 | return nil 37 | } 38 | return &user 39 | } 40 | 41 | func GetUser(account string) *User { 42 | user := User{Account: account} 43 | err := mysqlInstances.User().Read(&user, "Account") 44 | if err != nil { 45 | return nil 46 | } 47 | return &user 48 | } 49 | 50 | func UpdateUser(dbUser *User) bool { 51 | _, err := mysqlInstances.User().Update(dbUser) 52 | if err != nil { 53 | return false 54 | } 55 | return true 56 | } 57 | 58 | func UpdateUserLoginTime(userId uint64, loginTime int64) bool { 59 | dbUser := User{ 60 | Id: userId, 61 | LastLoginTime: loginTime, 62 | } 63 | _, err := mysqlInstances.User().Update(&dbUser, "LastLoginTime") 64 | if err != nil { 65 | return false 66 | } 67 | return true 68 | } 69 | -------------------------------------------------------------------------------- /core/service/service_rpc.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/rpc" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func (this *Service) StartRpcClient(serviceNames []string) { 12 | this.rpcClients = make(map[string]*rpc.Client) 13 | 14 | //初始化consul客户端 15 | consulClient, err := consul.NewClient() 16 | CheckError(err) 17 | 18 | //初始化Rpc客户端 19 | for _, serviceName := range serviceNames { 20 | serviceName = packageServiceName(consts.ServiceType_Rpc, serviceName) 21 | this.rpcClients[serviceName] = rpc.NewClient(consulClient, serviceName) 22 | INFO("Rpc Client Start", zap.String("ServiceName", serviceName)) 23 | } 24 | } 25 | 26 | func (this *Service) StartRpcServer() { 27 | //开启rpcServer 28 | port, err := rpc.InitServer() 29 | CheckError(err) 30 | INFO("Rpc Server Start", zap.String("Port", port)) 31 | 32 | //注册客户端下线回调 33 | err = rpc.RegisterModule("ClientOffline", &ClientOffline{}) 34 | CheckError(err) 35 | 36 | //服务注册 37 | this.registerService(consts.ServiceType_Rpc, port) 38 | } 39 | 40 | func (this *Service) RegisterRpcModule(rpcName string, rpcModule interface{}) { 41 | //rpc模块注册 42 | err := rpc.RegisterModule(rpcName, rpcModule) 43 | CheckError(err) 44 | } 45 | 46 | func (this *Service) GetRpcClient(serviceName string) *rpc.Client { 47 | serviceName = packageServiceName(consts.ServiceType_Rpc, serviceName) 48 | client, _ := this.rpcClients[serviceName] 49 | return client 50 | } 51 | -------------------------------------------------------------------------------- /core/libs/redis/client.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/config" 7 | 8 | "github.com/go-redis/redis" 9 | ) 10 | 11 | type Client struct { 12 | redisClient *redis.Client 13 | prefix string 14 | } 15 | 16 | func NewClient(redisConfig config.RedisConfig) (*Client, error) { 17 | prefix := redisConfig.Prefix 18 | host := redisConfig.Host 19 | port := redisConfig.Port 20 | pass := redisConfig.AuthPass 21 | db := redisConfig.Db 22 | 23 | client := redis.NewClient(&redis.Options{ 24 | Addr: host + ":" + port, 25 | Password: pass, 26 | DB: db, 27 | }) 28 | 29 | _, err := client.Ping().Result() 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | return &Client{ 35 | redisClient: client, 36 | prefix: prefix, 37 | }, nil 38 | } 39 | 40 | func (this *Client) GetKey(key string) string { 41 | return this.prefix + "." + key 42 | } 43 | 44 | func (this *Client) Set(key string, value interface{}, expiration time.Duration) *redis.StatusCmd { 45 | key = this.GetKey(key) 46 | return this.redisClient.Set(key, value, expiration) 47 | } 48 | 49 | func (this *Client) Get(key string) *redis.StringCmd { 50 | key = this.GetKey(key) 51 | return this.redisClient.Get(key) 52 | } 53 | 54 | func (this *Client) HSet(key, field string, value interface{}) *redis.BoolCmd { 55 | key = this.GetKey(key) 56 | return this.redisClient.HSet(key, field, value) 57 | } 58 | 59 | func (this *Client) HGet(key, field string) *redis.StringCmd { 60 | key = this.GetKey(key) 61 | return this.redisClient.HGet(key, field) 62 | } 63 | 64 | func (this *Client) HGetAll(key string) *redis.StringStringMapCmd { 65 | key = this.GetKey(key) 66 | return this.redisClient.HGetAll(key) 67 | } 68 | -------------------------------------------------------------------------------- /core/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "sync" 7 | 8 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/system" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | var ( 14 | env string 15 | serviceConfig map[string]ServiceConfig 16 | redisConfig map[string]RedisConfig 17 | logConfig LogConfig 18 | mysqlConfig map[string]MysqlConfig 19 | mongoConfig map[string]MongoConfig 20 | lock sync.Mutex 21 | ) 22 | 23 | func Init(_env string) { 24 | env = _env 25 | load() 26 | } 27 | 28 | func load() { 29 | lock.Lock() 30 | loadConfig(&serviceConfig, "service.json") 31 | loadConfig(&redisConfig, "redis.json") 32 | loadConfig(&mysqlConfig, "mysql.json") 33 | loadConfig(&mongoConfig, "mongo.json") 34 | loadConfig(&logConfig, "log.json") 35 | lock.Unlock() 36 | } 37 | 38 | func getConfigPath(configFile string) string { 39 | return system.Root + "/config/" + env + "/" + configFile 40 | } 41 | 42 | func loadConfig(data interface{}, configName string) { 43 | configPath := getConfigPath(configName) 44 | fileData, err := os.ReadFile(configPath) 45 | if err != nil { 46 | ERR("Config读取失败", zap.String("ConfigPath", configPath), zap.Error(err)) 47 | return 48 | } 49 | json.Unmarshal(fileData, data) 50 | } 51 | 52 | func GetService(serviceName string) ServiceConfig { 53 | return serviceConfig[serviceName] 54 | } 55 | 56 | func GetRedisConfig() map[string]RedisConfig { 57 | return redisConfig 58 | } 59 | 60 | func GetMysqlConfig() map[string]MysqlConfig { 61 | return mysqlConfig 62 | } 63 | 64 | func GetLogConfig() LogConfig { 65 | return logConfig 66 | } 67 | 68 | func GetMongoConfig() map[string]MongoConfig { 69 | return mongoConfig 70 | } 71 | -------------------------------------------------------------------------------- /core/libs/consul/server.go: -------------------------------------------------------------------------------- 1 | package consul 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "strconv" 7 | 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 9 | "go.uber.org/zap" 10 | 11 | "github.com/hashicorp/consul/api" 12 | "github.com/spf13/cast" 13 | ) 14 | 15 | func NewServive(serviceAddress string, serviceName string, serviceId int, servicePort string) error { 16 | client, err := api.NewClient(api.DefaultConfig()) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | //服务器配置 22 | address := serviceAddress 23 | port, _ := strconv.Atoi(servicePort) 24 | id := address + ":" + servicePort + "-" + serviceName + "-" + cast.ToString(serviceId) 25 | name := serviceName 26 | 27 | //健康检查配置 28 | checkPath := address + ":" + servicePort 29 | 30 | //服务注册 31 | service := &api.AgentServiceRegistration{ 32 | ID: id, 33 | Name: name, 34 | Address: address, 35 | Port: port, 36 | Tags: []string{name}, 37 | Check: &api.AgentServiceCheck{ 38 | TCP: checkPath, 39 | Timeout: "1s", 40 | Interval: "3s", 41 | DeregisterCriticalServiceAfter: "10s", //check失败后10秒删除本服务 42 | }, 43 | } 44 | err = client.Agent().ServiceRegister(service) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | //关闭处理 50 | go WaitToUnRegistService(client, id) 51 | 52 | return nil 53 | } 54 | 55 | func WaitToUnRegistService(client *api.Client, serviceId string) { 56 | //监听系统退出信号 57 | quit := make(chan os.Signal, 1) 58 | signal.Notify(quit, os.Interrupt, os.Kill) 59 | <-quit 60 | 61 | //取消监听 62 | signal.Stop(quit) 63 | close(quit) 64 | 65 | //从服务中移除 66 | err := client.Agent().ServiceDeregister(serviceId) 67 | if err != nil { 68 | logger.Error("ConsulError", zap.Error(err)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/libs/consul/kv.go: -------------------------------------------------------------------------------- 1 | package consul 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/hashicorp/consul/api" 8 | //"github.com/yicaoyimuys/GoGameServer/core/libs/logger" 9 | ) 10 | 11 | var ( 12 | kv *api.KV 13 | useCache bool 14 | caches map[string]cacheValue 15 | cachesMutex sync.Mutex 16 | ) 17 | 18 | type cacheValue struct { 19 | value string 20 | time int64 21 | } 22 | 23 | func InitKV(cache bool) error { 24 | if kv != nil { 25 | return nil 26 | } 27 | 28 | useCache = cache 29 | if useCache { 30 | caches = make(map[string]cacheValue) 31 | } 32 | 33 | client, err := api.NewClient(api.DefaultConfig()) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | kv = client.KV() 39 | return nil 40 | } 41 | 42 | func kv_getCache(key string) string { 43 | cachesMutex.Lock() 44 | defer cachesMutex.Unlock() 45 | 46 | if v, ok := caches[key]; ok { 47 | now := time.Now().Unix() 48 | //缓存10秒 49 | if now-v.time < 10 { 50 | return v.value 51 | } 52 | } 53 | return "" 54 | } 55 | 56 | func kv_setCache(key string, value string) { 57 | cachesMutex.Lock() 58 | defer cachesMutex.Unlock() 59 | 60 | caches[key] = cacheValue{value, time.Now().Unix()} 61 | } 62 | 63 | func KV_Get(key string) string { 64 | var value = "" 65 | if useCache { 66 | value = kv_getCache(key) 67 | } 68 | 69 | if len(value) == 0 { 70 | pair, _, err := kv.Get(key, nil) 71 | if err == nil && pair != nil { 72 | value = string(pair.Value) 73 | kv_setCache(key, value) 74 | } else { 75 | //logger.Debug("KV_Get", err, key+"不存在") 76 | } 77 | } 78 | return value 79 | } 80 | 81 | func KV_Set(key string, value string) error { 82 | pair := &api.KVPair{ 83 | Key: key, 84 | Value: []byte(value), 85 | } 86 | _, err := kv.Put(pair, nil) 87 | return err 88 | } 89 | -------------------------------------------------------------------------------- /core/libs/request/request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "crypto/tls" 5 | "io" 6 | "net/http" 7 | "strings" 8 | "time" 9 | 10 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | func init() { 15 | //设置http默认超时时间 16 | http.DefaultClient.Timeout = 3 * time.Second 17 | //不检测TLS证书 18 | http.DefaultClient.Transport = &http.Transport{ 19 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 20 | } 21 | } 22 | 23 | // HttpGet 24 | func HttpGet(url string, retryNum int) (string, uint32) { 25 | resp, err := http.Get(url) 26 | if err != nil { 27 | if retryNum > 0 { 28 | logger.Error("HttpGet 重试", zap.String("Url", url), zap.Error(err)) 29 | return HttpGet(url, retryNum-1) 30 | } else { 31 | logger.Error("HttpGet", zap.String("Url", url), zap.Error(err)) 32 | return "error", 1001 33 | } 34 | } 35 | 36 | defer resp.Body.Close() 37 | body, err := io.ReadAll(resp.Body) 38 | if err != nil { 39 | logger.Error("HttpGet", zap.String("Url", url), zap.Error(err)) 40 | return "error", 1002 41 | } 42 | 43 | return string(body), 0 44 | } 45 | 46 | // HttpPost 47 | func HttpPost(url string, retryNum int) (string, uint32) { 48 | arr := strings.Split(url, "?") 49 | resp, err := http.Post(arr[0], "application/x-www-form-urlencoded", strings.NewReader(arr[1])) 50 | if err != nil { 51 | if retryNum > 0 { 52 | logger.Error("HttpPost 重试", zap.String("Url", url), zap.Error(err)) 53 | return HttpPost(url, retryNum-1) 54 | } else { 55 | logger.Error("HttpPost", zap.String("Url", url), zap.Error(err)) 56 | return "error", 1001 57 | } 58 | } 59 | 60 | defer resp.Body.Close() 61 | body, err := io.ReadAll(resp.Body) 62 | if err != nil { 63 | logger.Error("HttpPost", zap.String("Url", url), zap.Error(err)) 64 | return "error", 1002 65 | } 66 | 67 | return string(body), 0 68 | } 69 | -------------------------------------------------------------------------------- /core/service/service_ipc.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/yicaoyimuys/GoGameServer/core/consts" 5 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 10 | "github.com/yicaoyimuys/GoGameServer/core/messages" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | func (this *Service) StartIpcClient(serviceNames []string) { 15 | this.ipcClients = make(map[string]*ipc.Client) 16 | 17 | //初始化consul客户端 18 | consulClient, err := consul.NewClient() 19 | CheckError(err) 20 | 21 | //初始化Ipc客户端 22 | for _, serviceName := range serviceNames { 23 | serviceName = packageServiceName(consts.ServiceType_Ipc, serviceName) 24 | this.ipcClients[serviceName] = ipc.NewClient(consulClient, serviceName, messages.IpcClientReceive) 25 | INFO("Ipc Client Start", zap.String("ServiceName", serviceName)) 26 | } 27 | } 28 | 29 | func (this *Service) StartIpcServer() { 30 | //开启ipcServer 31 | ipcServer, port, err := ipc.InitServer(messages.IpcServerReceive) 32 | CheckError(err) 33 | INFO("Ipc Server Start", zap.String("Port", port)) 34 | 35 | //service中记录ipcServer 36 | this.ipcServer = ipcServer 37 | 38 | //服务注册 39 | this.registerService(consts.ServiceType_Ipc, port) 40 | 41 | //Log 42 | timer.DoTimer(20*1000, func() { 43 | INFO("当前BackSession数量", zap.Int("BackSessionLen", sessions.BackSessionLen())) 44 | }) 45 | } 46 | 47 | func (this *Service) GetIpcClient(serviceName string) *ipc.Client { 48 | serviceName = packageServiceName(consts.ServiceType_Ipc, serviceName) 49 | client, _ := this.ipcClients[serviceName] 50 | return client 51 | } 52 | 53 | func (this *Service) GetIpcServer() *ipc.Server { 54 | return this.ipcServer 55 | } 56 | -------------------------------------------------------------------------------- /core/libs/sessions/frontSessionService.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 8 | ) 9 | 10 | var ( 11 | frontSessions = make(map[uint64]*FrontSession) 12 | frontSessionMutex sync.Mutex 13 | ) 14 | 15 | func AddFrontSession(session *FrontSession) { 16 | frontSessionMutex.Lock() 17 | defer frontSessionMutex.Unlock() 18 | 19 | frontSessions[session.ID()] = session 20 | session.AddCloseCallback(nil, "sessionService.RemoveSession", func() { 21 | RemoveFrontSession(session.ID()) 22 | }) 23 | } 24 | 25 | func RemoveFrontSession(key uint64) { 26 | frontSessionMutex.Lock() 27 | defer frontSessionMutex.Unlock() 28 | 29 | delete(frontSessions, key) 30 | } 31 | 32 | func GetFrontSession(key uint64) *FrontSession { 33 | frontSessionMutex.Lock() 34 | defer frontSessionMutex.Unlock() 35 | 36 | session, _ := frontSessions[key] 37 | return session 38 | } 39 | 40 | func FrontSessionLen() int { 41 | frontSessionMutex.Lock() 42 | defer frontSessionMutex.Unlock() 43 | 44 | return len(frontSessions) 45 | } 46 | 47 | func FetchFrontSession(callback func(*FrontSession)) { 48 | frontSessionMutex.Lock() 49 | defer frontSessionMutex.Unlock() 50 | 51 | for _, session := range frontSessions { 52 | callback(session) 53 | } 54 | } 55 | 56 | func FrontSessionOpenPing(overTimeSec int64) { 57 | //2秒钟检测一次 58 | timer.DoTimer(2*1000, func() { 59 | frontSessionMutex.Lock() 60 | nowTime := time.Now().Unix() 61 | closeSessions := []*FrontSession{} 62 | for _, session := range frontSessions { 63 | //超过15秒 64 | cha := nowTime - session.PingTime() 65 | if cha >= overTimeSec { 66 | closeSessions = append(closeSessions, session) 67 | } 68 | } 69 | frontSessionMutex.Unlock() 70 | 71 | //关闭Session 72 | for _, session := range closeSessions { 73 | session.Close() 74 | } 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /core/libs/timer/timer.go: -------------------------------------------------------------------------------- 1 | package timer 2 | 3 | import ( 4 | "sync/atomic" 5 | "time" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 8 | ) 9 | 10 | type TimerEvent struct { 11 | callBack func() // 回调函数 12 | delay uint32 // 执行间隔 13 | repeatCount uint32 // 执行次数 14 | ticker *time.Ticker //定时器 15 | closeFlag int32 //关闭标识 16 | closeChan chan int //关闭使用 17 | } 18 | 19 | // 是否已关闭 20 | func (this *TimerEvent) IsClosed() bool { 21 | return atomic.LoadInt32(&this.closeFlag) == 1 22 | } 23 | 24 | // 关闭 25 | func (this *TimerEvent) Close() { 26 | if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 27 | if this.ticker != nil { 28 | this.ticker.Stop() 29 | } 30 | close(this.closeChan) 31 | } 32 | } 33 | 34 | // 无限次数执行 35 | func DoTimer(delay uint32, callback func()) *TimerEvent { 36 | return Do(delay, 0, callback) 37 | } 38 | 39 | // 延时处理 40 | func SetTimeOut(delay uint32, callback func()) *TimerEvent { 41 | return Do(delay, 1, callback) 42 | } 43 | 44 | // 移除一个定时器 45 | func Remove(event *TimerEvent) { 46 | if event == nil { 47 | return 48 | } 49 | event.Close() 50 | } 51 | 52 | // 时间间隔,执行次数,回调函数 53 | func Do(delay uint32, repeatCount uint32, callback func()) *TimerEvent { 54 | //最小单位1ms 55 | if delay < 1 { 56 | callback() 57 | return nil 58 | } 59 | 60 | //创建事件对象 61 | event := &TimerEvent{ 62 | callBack: callback, 63 | delay: delay, 64 | repeatCount: repeatCount, 65 | closeChan: make(chan int), 66 | } 67 | 68 | //开启timer 69 | go startTicker(event) 70 | 71 | //返回 72 | return event 73 | } 74 | 75 | func startTicker(event *TimerEvent) { 76 | defer stack.TryError() 77 | event.ticker = time.NewTicker(time.Duration(event.delay) * time.Millisecond) 78 | for { 79 | select { 80 | case <-event.ticker.C: 81 | event.callBack() 82 | if event.repeatCount > 0 { 83 | event.repeatCount -= 1 84 | if event.repeatCount == 0 { 85 | Remove(event) 86 | } 87 | } 88 | case <-event.closeChan: 89 | return 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /servives/chat/module/chat.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 5 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | "github.com/yicaoyimuys/GoGameServer/servives/chat/cache" 8 | "github.com/yicaoyimuys/GoGameServer/servives/public" 9 | "github.com/yicaoyimuys/GoGameServer/servives/public/errCodes" 10 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 11 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisCaches" 12 | "go.uber.org/zap" 13 | 14 | "google.golang.org/protobuf/proto" 15 | ) 16 | 17 | // 获取用户信息 18 | func JoinChat(clientSession *sessions.BackSession, msgData proto.Message) { 19 | data := msgData.(*gameProto.UserJoinChatC2S) 20 | token := data.GetToken() 21 | userId := public.GetUserIdByToken(token) 22 | if userId == 0 { 23 | public.SendErrorMsgToClient(clientSession, errCodes.PARAM_ERROR) 24 | return 25 | } 26 | 27 | //获取redis缓存中用户数据 28 | dbUser := redisCaches.GetUser(userId) 29 | if dbUser == nil { 30 | public.SendErrorMsgToClient(clientSession, errCodes.PARAM_ERROR) 31 | return 32 | } 33 | 34 | //保存到内存中 35 | clientSession.SetUserId(dbUser.Id) 36 | cache.AddUser(dbUser.Id, dbUser.Account, clientSession) 37 | 38 | //用户下线处理 39 | clientSession.AddCloseCallback(nil, "user.joinChatSuccess", func() { 40 | cache.RemoveUser(dbUser.Id) 41 | DEBUG("用户下线", zap.Int32("OnlineUsersNum", cache.GetOnlineUsersNum())) 42 | }) 43 | DEBUG("用户上线", zap.Int32("OnlineUsersNum", cache.GetOnlineUsersNum())) 44 | 45 | //返回客户端 46 | sendMsg := &gameProto.UserJoinChatS2C{} 47 | public.SendMsgToClient(clientSession, sendMsg) 48 | } 49 | 50 | func Chat(clientSession *sessions.BackSession, msgData proto.Message) { 51 | data := msgData.(*gameProto.UserChatC2S) 52 | chatUser := cache.GetUser(clientSession.UserID()) 53 | if chatUser == nil { 54 | public.SendErrorMsgToClient(clientSession, errCodes.PARAM_ERROR) 55 | return 56 | } 57 | 58 | //发送给所有人 59 | sendMsg := &gameProto.UserChatNoticeS2C{ 60 | UserId: protos.Uint64(chatUser.UserID), 61 | UserName: protos.String(chatUser.UserName), 62 | Msg: protos.String(data.GetMsg()), 63 | } 64 | public.SendMsgToAllClient(sendMsg) 65 | } 66 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/yicaoyimuys/GoGameServer 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/astaxie/beego v1.12.3 7 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 8 | github.com/go-redis/redis v6.15.9+incompatible 9 | github.com/go-sql-driver/mysql v1.5.0 10 | github.com/gorilla/websocket v1.4.2 11 | github.com/hashicorp/consul/api v1.8.1 12 | github.com/jessevdk/go-flags v1.4.0 13 | github.com/spf13/cast v1.5.0 14 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 15 | google.golang.org/grpc v1.36.0 16 | google.golang.org/protobuf v1.28.1 17 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 18 | ) 19 | 20 | require ( 21 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect 22 | github.com/beorn7/perks v1.0.1 // indirect 23 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 24 | github.com/fatih/color v1.9.0 // indirect 25 | github.com/golang/protobuf v1.5.0 // indirect 26 | github.com/hashicorp/go-cleanhttp v0.5.1 // indirect 27 | github.com/hashicorp/go-hclog v0.12.0 // indirect 28 | github.com/hashicorp/go-immutable-radix v1.0.0 // indirect 29 | github.com/hashicorp/go-rootcerts v1.0.2 // indirect 30 | github.com/hashicorp/golang-lru v0.5.4 // indirect 31 | github.com/hashicorp/serf v0.9.5 // indirect 32 | github.com/mattn/go-colorable v0.1.6 // indirect 33 | github.com/mattn/go-isatty v0.0.12 // indirect 34 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 35 | github.com/mitchellh/go-homedir v1.1.0 // indirect 36 | github.com/mitchellh/mapstructure v1.1.2 // indirect 37 | github.com/natefinch/lumberjack v2.0.0+incompatible // indirect 38 | github.com/pkg/errors v0.9.1 // indirect 39 | github.com/prometheus/client_golang v1.7.0 // indirect 40 | github.com/prometheus/client_model v0.2.0 // indirect 41 | github.com/prometheus/common v0.10.0 // indirect 42 | github.com/prometheus/procfs v0.1.3 // indirect 43 | github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect 44 | go.uber.org/multierr v1.10.0 // indirect 45 | go.uber.org/zap v1.26.0 // indirect 46 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect 47 | golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect 48 | golang.org/x/text v0.3.3 // indirect 49 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect 50 | gopkg.in/yaml.v2 v2.2.8 // indirect 51 | ) 52 | -------------------------------------------------------------------------------- /core/libs/mongo/client.go: -------------------------------------------------------------------------------- 1 | package mongo 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/config" 7 | 8 | "gopkg.in/mgo.v2" 9 | ) 10 | 11 | type Client struct { 12 | session *mgo.Session 13 | db string 14 | } 15 | 16 | func NewClient(mongoConfig config.MongoConfig) (*Client, error) { 17 | addr := mongoConfig.Host + ":" + mongoConfig.Port 18 | user := mongoConfig.User 19 | pwd := mongoConfig.Password 20 | db := mongoConfig.Db 21 | 22 | dialInfo := &mgo.DialInfo{ 23 | Addrs: []string{addr}, 24 | Username: user, 25 | Password: pwd, 26 | Timeout: 5 * time.Second, 27 | } 28 | 29 | session, err := mgo.DialWithInfo(dialInfo) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | //返回数据 35 | client := &Client{ 36 | session: session, 37 | db: db, 38 | } 39 | return client, nil 40 | } 41 | 42 | func (this *Client) connect(collection string) (*mgo.Session, *mgo.Collection) { 43 | s := this.session.Copy() 44 | c := s.DB(this.db).C(collection) 45 | return s, c 46 | } 47 | 48 | func (this *Client) Insert(collection string, docs ...interface{}) error { 49 | ms, c := this.connect(collection) 50 | defer ms.Close() 51 | return c.Insert(docs...) 52 | } 53 | 54 | func (this *Client) FindOne(collection string, query, selector, result interface{}) error { 55 | ms, c := this.connect(collection) 56 | defer ms.Close() 57 | return c.Find(query).Select(selector).One(result) 58 | } 59 | 60 | func (this *Client) FindAll(collection string, query, selector, result interface{}) error { 61 | ms, c := this.connect(collection) 62 | defer ms.Close() 63 | return c.Find(query).Select(selector).All(result) 64 | } 65 | 66 | func (this *Client) Update(collection string, query, update interface{}) error { 67 | ms, c := this.connect(collection) 68 | defer ms.Close() 69 | return c.Update(query, update) 70 | } 71 | 72 | func (this *Client) UpdateAll(collection string, query, update interface{}) error { 73 | ms, c := this.connect(collection) 74 | defer ms.Close() 75 | _, err := c.UpdateAll(query, update) 76 | return err 77 | } 78 | 79 | func (this *Client) Remove(collection string, query interface{}) error { 80 | ms, c := this.connect(collection) 81 | defer ms.Close() 82 | return c.Remove(query) 83 | } 84 | 85 | func (this *Client) RemoveAll(collection string, query interface{}) error { 86 | ms, c := this.connect(collection) 87 | defer ms.Close() 88 | _, err := c.RemoveAll(query) 89 | return err 90 | } 91 | -------------------------------------------------------------------------------- /core/libs/socket/socket.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/guid" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | const ( 14 | ServerNetworkType = "tcp4" 15 | ) 16 | 17 | type Server struct { 18 | port string 19 | guid *guid.Guid 20 | 21 | sessionCreateHandle sessions.FrontSessionCreateHandle 22 | sessionReceiveMsgHandle sessions.FrontSessionReceiveMsgHandle 23 | } 24 | 25 | func NewServer(port string, serviceId int) *Server { 26 | server := &Server{ 27 | port: port, 28 | guid: guid.NewGuid(uint16(serviceId)), 29 | } 30 | return server 31 | } 32 | 33 | func (this *Server) SetSessionCreateHandle(handle sessions.FrontSessionCreateHandle) { 34 | this.sessionCreateHandle = handle 35 | } 36 | 37 | func (this *Server) SetSessionReceiveMsgHandle(handle sessions.FrontSessionReceiveMsgHandle) { 38 | this.sessionReceiveMsgHandle = handle 39 | } 40 | 41 | func (this *Server) Start() { 42 | logger.Info("Front Start Socket", zap.String("Port", this.port)) 43 | 44 | go func() { 45 | defer stack.TryError() 46 | 47 | var err error 48 | addr, err := net.ResolveTCPAddr(ServerNetworkType, "0.0.0.0:"+this.port) 49 | stack.CheckError(err) 50 | 51 | listener, err := net.ListenTCP(ServerNetworkType, addr) 52 | stack.CheckError(err) 53 | 54 | defer listener.Close() 55 | logger.Info("Socket Waiting Client Connect...") 56 | for { 57 | conn, err := listener.Accept() 58 | stack.CheckError(err) 59 | 60 | go this.handleConnect(conn) 61 | } 62 | }() 63 | } 64 | 65 | func (this *Server) StartPing() { 66 | overTime := 15 67 | sessions.FrontSessionOpenPing(int64(overTime)) 68 | logger.Info("Session超时时间设置", zap.Int("OverTime", overTime)) 69 | } 70 | 71 | func (this *Server) handleConnect(conn net.Conn) { 72 | //捕获异常 73 | defer stack.TryError() 74 | 75 | //Session创建 76 | sessionId := this.guid.NewID() 77 | sessionCodec := NewFrontCodec(conn) 78 | session := sessions.NewFontSession(sessionId, sessionCodec) 79 | this.addFontSession(session) 80 | } 81 | 82 | func (this *Server) addFontSession(session *sessions.FrontSession) { 83 | sessions.AddFrontSession(session) 84 | if this.sessionCreateHandle != nil { 85 | this.sessionCreateHandle(session) 86 | } 87 | if this.sessionReceiveMsgHandle != nil { 88 | session.SetMsgHandle(this.sessionReceiveMsgHandle) 89 | } 90 | 91 | defer session.Close() 92 | for { 93 | msg, err := session.Receive() 94 | if err != nil || msg == nil { 95 | break 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /servives/login/cache/online.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 7 | . "github.com/yicaoyimuys/GoGameServer/servives/login/model" 8 | ) 9 | 10 | var ( 11 | onlineUsers = make(map[string]*OnlineUser) 12 | onlineUserIds = make(map[uint64]string) 13 | onlineUserSessions = make(map[string]string) 14 | onlineUsersNum int32 = 0 15 | onlineUsersMutex sync.RWMutex 16 | ) 17 | 18 | // 添加在线用户缓存 19 | func AddOnlineUser(userID uint64, account string, session *sessions.BackSession) bool { 20 | onlineUsersMutex.Lock() 21 | defer onlineUsersMutex.Unlock() 22 | 23 | //同一账号只能对应一个Session 24 | //同一SessionID只能登陆一个账号 25 | _, exists1 := onlineUsers[account] 26 | _, exists2 := onlineUserSessions[session.ID()] 27 | if !exists1 && !exists2 { 28 | model := &OnlineUser{ 29 | Session: session, 30 | UserID: userID, 31 | Account: account, 32 | } 33 | onlineUsers[account] = model 34 | onlineUserIds[userID] = account 35 | onlineUserSessions[session.ID()] = account 36 | onlineUsersNum += 1 37 | return true 38 | } else { 39 | return false 40 | } 41 | } 42 | 43 | // 获取用户数据根据Account 44 | func GetOnlineUserByAccount(account string) *OnlineUser { 45 | onlineUsersMutex.Lock() 46 | defer onlineUsersMutex.Unlock() 47 | 48 | if user, exists1 := onlineUsers[account]; exists1 { 49 | return user 50 | } 51 | return nil 52 | } 53 | 54 | // 获取用户数据根据UserID 55 | func GetOnlineUserByUserID(userID uint64) *OnlineUser { 56 | onlineUsersMutex.Lock() 57 | defer onlineUsersMutex.Unlock() 58 | 59 | if account, exists := onlineUserIds[userID]; exists { 60 | if user, exists1 := onlineUsers[account]; exists1 { 61 | return user 62 | } 63 | } 64 | return nil 65 | } 66 | 67 | // 获取用户数据根据SessionID 68 | func GetOnlineUserBySession(sessionID string) *OnlineUser { 69 | onlineUsersMutex.Lock() 70 | defer onlineUsersMutex.Unlock() 71 | 72 | if account, exists := onlineUserSessions[sessionID]; exists { 73 | if user, exists1 := onlineUsers[account]; exists1 { 74 | return user 75 | } 76 | } 77 | return nil 78 | } 79 | 80 | // 移除一个在线用户 81 | func RemoveOnlineUser(sessionID string) { 82 | onlineUsersMutex.Lock() 83 | defer onlineUsersMutex.Unlock() 84 | 85 | if account, exists := onlineUserSessions[sessionID]; exists { 86 | if onlineUser, exists1 := onlineUsers[account]; exists1 { 87 | delete(onlineUsers, onlineUser.Account) 88 | delete(onlineUserIds, onlineUser.UserID) 89 | delete(onlineUserSessions, onlineUser.Session.ID()) 90 | onlineUsersNum -= 1 91 | } 92 | } 93 | } 94 | 95 | // 获取在线用户数量 96 | func GetOnlineUsersNum() int32 { 97 | return onlineUsersNum 98 | } 99 | -------------------------------------------------------------------------------- /servives/login/module/login.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "time" 5 | 6 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/random" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 10 | "github.com/yicaoyimuys/GoGameServer/servives/login/cache" 11 | "github.com/yicaoyimuys/GoGameServer/servives/public" 12 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 13 | "github.com/yicaoyimuys/GoGameServer/servives/public/mysqlModels" 14 | "github.com/yicaoyimuys/GoGameServer/servives/public/redisCaches" 15 | "go.uber.org/zap" 16 | 17 | "google.golang.org/protobuf/proto" 18 | ) 19 | 20 | // 登录 21 | func Login(clientSession *sessions.BackSession, msgData proto.Message) { 22 | data := msgData.(*gameProto.UserLoginC2S) 23 | account := data.GetAccount() 24 | 25 | onlineUser := cache.GetOnlineUserByAccount(account) 26 | if onlineUser != nil { 27 | oldClientSession := onlineUser.Session 28 | if oldClientSession.ID() != clientSession.ID() { 29 | //当前在线,但是连接不同,其他客户端连接,需通知当前客户端下线 30 | sendOtherLogin(oldClientSession) 31 | //替换Session 32 | cache.RemoveOnlineUser(oldClientSession.ID()) 33 | //登录成功后处理 34 | loginSuccess(clientSession, onlineUser.Account, onlineUser.UserID) 35 | } 36 | } else { 37 | //进行DB登录 38 | dbUser := login(account) 39 | //登录成功后处理 40 | loginSuccess(clientSession, dbUser.Account, dbUser.Id) 41 | } 42 | } 43 | 44 | func login(account string) *mysqlModels.User { 45 | //db中获取用户数据 46 | dbUser := mysqlModels.GetUser(account) 47 | if dbUser == nil { 48 | //注册新用户 49 | addMoney := random.RandomInt31n(999) 50 | dbUser = mysqlModels.AddUser(account, addMoney) 51 | } else { 52 | //更新用户最后登录时间 53 | dbUser.LastLoginTime = time.Now().Unix() 54 | mysqlModels.UpdateUserLoginTime(dbUser.Id, dbUser.LastLoginTime) 55 | } 56 | //加入redis缓存 57 | redisCaches.SetUser(dbUser) 58 | return dbUser 59 | } 60 | 61 | // 登录成功后处理 62 | func loginSuccess(clientSession *sessions.BackSession, account string, userID uint64) { 63 | //缓存用户在线数据 64 | cache.AddOnlineUser(userID, account, clientSession) 65 | clientSession.AddCloseCallback(nil, "user.loginSuccess", func() { 66 | cache.RemoveOnlineUser(clientSession.ID()) 67 | DEBUG("用户下线", zap.Int32("OnlineUsersNum", cache.GetOnlineUsersNum())) 68 | }) 69 | DEBUG("用户上线", zap.Int32("OnlineUsersNum", cache.GetOnlineUsersNum())) 70 | 71 | //返回客户端数据 72 | token := public.CreateToken(userID) 73 | sendMsg := &gameProto.UserLoginS2C{ 74 | Token: protos.String(token), 75 | } 76 | public.SendMsgToClient(clientSession, sendMsg) 77 | } 78 | 79 | func sendOtherLogin(clientSession *sessions.BackSession) { 80 | sendMsg := &gameProto.UserOtherLoginNoticeS2C{} 81 | public.SendMsgToClient(clientSession, sendMsg) 82 | } 83 | -------------------------------------------------------------------------------- /core/libs/protos/protos.go: -------------------------------------------------------------------------------- 1 | package protos 2 | 3 | import ( 4 | "encoding/binary" 5 | "reflect" 6 | 7 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 8 | "go.uber.org/zap" 9 | 10 | "google.golang.org/protobuf/proto" 11 | ) 12 | 13 | type ProtoMsg struct { 14 | ID uint16 15 | Body proto.Message 16 | } 17 | 18 | var ( 19 | NullProtoMsg = ProtoMsg{0, nil} 20 | MsgObjectMap = make(map[uint16]reflect.Type) 21 | MsgIDMap = make(map[reflect.Type]uint16) 22 | ) 23 | 24 | // 设置消息类型和消息ID的对应关系 25 | func SetMsg(msgId uint16, data interface{}) { 26 | msgType := reflect.TypeOf(data) 27 | 28 | MsgObjectMap[msgId] = msgType 29 | MsgIDMap[reflect.TypeOf(reflect.New(msgType).Interface())] = msgId 30 | } 31 | 32 | // 根据消息ID获取消息实体 33 | func GetMsgObject(msgId uint16) proto.Message { 34 | if msgType, exists := MsgObjectMap[msgId]; exists { 35 | return reflect.New(msgType).Interface().(proto.Message) 36 | } else { 37 | ERR("No MsgId", zap.Uint16("MsgId", msgId)) 38 | } 39 | return nil 40 | } 41 | 42 | // 根据一条消息获取消息ID 43 | func GetMsgId(msg interface{}) uint16 { 44 | msgType := reflect.TypeOf(msg) 45 | if msgId, exists := MsgIDMap[msgType]; exists { 46 | return msgId 47 | } else { 48 | ERR("No MsgType", zap.Any("MsgType", msgType)) 49 | } 50 | return 0 51 | } 52 | 53 | // 序列化 54 | func MarshalProtoMsg(args proto.Message) []byte { 55 | msgId := GetMsgId(args) 56 | msgBody, _ := proto.Marshal(args) 57 | 58 | result := make([]byte, 2+len(msgBody)) 59 | binary.BigEndian.PutUint16(result[:2], msgId) 60 | copy(result[2:], msgBody) 61 | 62 | return result 63 | } 64 | 65 | func UnmarshalProtoId(msg []byte) uint16 { 66 | return binary.BigEndian.Uint16(msg[:2]) 67 | } 68 | 69 | // 反序列化 70 | func UnmarshalProtoMsg(msg []byte) ProtoMsg { 71 | if len(msg) < 2 { 72 | return NullProtoMsg 73 | } 74 | 75 | msgId := UnmarshalProtoId(msg) 76 | msgBody := GetMsgObject(msgId) 77 | if msgBody == nil { 78 | return NullProtoMsg 79 | } 80 | 81 | err := proto.Unmarshal(msg[2:], msgBody) 82 | if err != nil { 83 | return NullProtoMsg 84 | } 85 | 86 | return ProtoMsg{ 87 | ID: msgId, 88 | Body: msgBody, 89 | } 90 | } 91 | 92 | func String(param string) *string { 93 | return proto.String(param) 94 | } 95 | 96 | func Bool(param bool) *bool { 97 | return proto.Bool(param) 98 | } 99 | 100 | func Float64(param float64) *float64 { 101 | return proto.Float64(param) 102 | } 103 | 104 | func Float32(param float32) *float32 { 105 | return proto.Float32(param) 106 | } 107 | 108 | func Int64(param int64) *int64 { 109 | return proto.Int64(param) 110 | } 111 | 112 | func Uint64(param uint64) *uint64 { 113 | return proto.Uint64(param) 114 | } 115 | 116 | func Int32(param int32) *int32 { 117 | return proto.Int32(param) 118 | } 119 | 120 | func Uint32(param uint32) *uint32 { 121 | return proto.Uint32(param) 122 | } 123 | -------------------------------------------------------------------------------- /core/libs/consul/client.go: -------------------------------------------------------------------------------- 1 | package consul 2 | 3 | import ( 4 | "sort" 5 | "strings" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/array" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 9 | 10 | "github.com/hashicorp/consul/api" 11 | "github.com/spf13/cast" 12 | ) 13 | 14 | type Client struct { 15 | consulClient *api.Client 16 | } 17 | 18 | type ServiceInfo struct { 19 | ID string 20 | Name string 21 | Address string 22 | Port string 23 | SortKey string 24 | } 25 | 26 | func NewClient() (*Client, error) { 27 | //开启consulKV 28 | err := InitKV(true) 29 | stack.CheckError(err) 30 | 31 | //开启consul客户端 32 | client, err := api.NewClient(api.DefaultConfig()) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | consulClient := &Client{ 38 | consulClient: client, 39 | } 40 | return consulClient, nil 41 | } 42 | 43 | //func (this *Client) GetServices(service string) []string { 44 | // services, _ := this.consulClient.Agent().Services() 45 | // results := []string{} 46 | // if services != nil { 47 | // for _, value := range services { 48 | // if value.Service != service { 49 | // continue 50 | // } 51 | // addr := value.Address + ":" + cast.ToString(value.Port) 52 | // results = append(results, addr) 53 | // } 54 | // } 55 | // return results 56 | //} 57 | 58 | func getFilterServices() []string { 59 | filterServicesStr := KV_Get("FilterServices") 60 | arr := strings.Split(filterServicesStr, ";") 61 | var result = []string{} 62 | for _, service := range arr { 63 | if len(service) == 0 { 64 | continue 65 | } 66 | result = append(result, strings.TrimSpace(service)) 67 | } 68 | return result 69 | } 70 | 71 | func (this *Client) GetServices(service string) []string { 72 | services, _, _ := this.consulClient.Health().Service(service, "", true, &api.QueryOptions{}) 73 | filterServices := getFilterServices() 74 | serviceDatas := []ServiceInfo{} 75 | if services != nil { 76 | for _, entry := range services { 77 | if array.InArray(filterServices, entry.Service.Address) { 78 | continue 79 | } 80 | 81 | arr := strings.Split(entry.Service.ID, "-") 82 | serviveId := arr[2] 83 | data := ServiceInfo{ 84 | ID: entry.Service.ID, 85 | Name: entry.Service.Service, 86 | Address: entry.Service.Address, 87 | Port: cast.ToString(entry.Service.Port), 88 | SortKey: entry.Service.Address + "-" + serviveId, 89 | } 90 | serviceDatas = append(serviceDatas, data) 91 | } 92 | } 93 | 94 | //排序(从小到大) 95 | sort.Slice(serviceDatas, func(i, j int) bool { 96 | return serviceDatas[i].SortKey < serviceDatas[j].SortKey 97 | }) 98 | 99 | //组装返回数据 100 | results := []string{} 101 | for i := 0; i < len(serviceDatas); i++ { 102 | data := serviceDatas[i] 103 | addr := data.Address + ":" + data.Port 104 | results = append(results, addr) 105 | } 106 | return results 107 | } 108 | 109 | func (this *Client) DeregisterService(serviceID string) { 110 | this.consulClient.Agent().ServiceDeregister(serviceID) 111 | } 112 | -------------------------------------------------------------------------------- /core/libs/websocket/websocket.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core/libs/guid" 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 10 | "go.uber.org/zap" 11 | 12 | "github.com/gorilla/websocket" 13 | ) 14 | 15 | var upgrader = websocket.Upgrader{ 16 | ReadBufferSize: 1024, 17 | WriteBufferSize: 1024, 18 | CheckOrigin: func(r *http.Request) bool { 19 | return true 20 | }, 21 | } 22 | 23 | type Server struct { 24 | port string 25 | guid *guid.Guid 26 | 27 | useSSL bool 28 | tslCrt string 29 | tslKey string 30 | 31 | sessionCreateHandle sessions.FrontSessionCreateHandle 32 | sessionReceiveMsgHandle sessions.FrontSessionReceiveMsgHandle 33 | } 34 | 35 | func NewServer(port string, serviceId int) *Server { 36 | server := &Server{ 37 | port: port, 38 | guid: guid.NewGuid(uint16(serviceId)), 39 | useSSL: false, 40 | } 41 | return server 42 | } 43 | 44 | func (this *Server) SetTLS(tslCrt string, tslKey string) { 45 | this.useSSL = true 46 | this.tslCrt = tslCrt 47 | this.tslKey = tslKey 48 | } 49 | 50 | func (this *Server) SetSessionCreateHandle(handle sessions.FrontSessionCreateHandle) { 51 | this.sessionCreateHandle = handle 52 | } 53 | 54 | func (this *Server) SetSessionReceiveMsgHandle(handle sessions.FrontSessionReceiveMsgHandle) { 55 | this.sessionReceiveMsgHandle = handle 56 | } 57 | 58 | func (this *Server) Start() { 59 | logger.Info("Front Start WebSocket", zap.String("Port", this.port)) 60 | 61 | go func() { 62 | http.HandleFunc("/", this.wsHandler) 63 | var err error 64 | if this.useSSL { 65 | err = http.ListenAndServeTLS("0.0.0.0:"+this.port, this.tslCrt, this.tslKey, nil) 66 | } else { 67 | err = http.ListenAndServe("0.0.0.0:"+this.port, nil) 68 | } 69 | stack.CheckError(err) 70 | }() 71 | } 72 | 73 | func (this *Server) StartPing() { 74 | overTime := 15 75 | sessions.FrontSessionOpenPing(int64(overTime)) 76 | logger.Info("Session超时时间设置", zap.Int("OverTime", overTime)) 77 | } 78 | 79 | func (this *Server) wsHandler(w http.ResponseWriter, r *http.Request) { 80 | conn, err := upgrader.Upgrade(w, r, nil) 81 | if err != nil { 82 | return 83 | } 84 | 85 | //捕获异常 86 | defer stack.TryError() 87 | 88 | //Session创建 89 | sessionId := this.guid.NewID() 90 | sessionCodec := NewFrontCodec(conn) 91 | session := sessions.NewFontSession(sessionId, sessionCodec) 92 | this.addFontSession(session) 93 | } 94 | 95 | func (this *Server) addFontSession(session *sessions.FrontSession) { 96 | sessions.AddFrontSession(session) 97 | if this.sessionCreateHandle != nil { 98 | this.sessionCreateHandle(session) 99 | } 100 | if this.sessionReceiveMsgHandle != nil { 101 | session.SetMsgHandle(this.sessionReceiveMsgHandle) 102 | } 103 | 104 | defer session.Close() 105 | for { 106 | msg, err := session.Receive() 107 | if err != nil || msg == nil { 108 | break 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /core/libs/grpc/ipc/client.go: -------------------------------------------------------------------------------- 1 | package ipc 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 8 | myGprc "github.com/yicaoyimuys/GoGameServer/core/libs/grpc" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 10 | 11 | "google.golang.org/grpc" 12 | ) 13 | 14 | type ClientRecvHandle func(stream Ipc_TransferClient, msg *Res) 15 | 16 | type Client struct { 17 | grpcClient *myGprc.Client 18 | recvHandle ClientRecvHandle 19 | serverStreams map[string]Ipc_TransferClient 20 | serverStreamMutex sync.Mutex 21 | } 22 | 23 | func NewClient(consulClient *consul.Client, serviceName string, handle ClientRecvHandle) *Client { 24 | grpcClient := myGprc.NewClient(consulClient, serviceName, func(conn *grpc.ClientConn) interface{} { 25 | return NewIpcClient(conn) 26 | }) 27 | 28 | client := &Client{ 29 | grpcClient: grpcClient, 30 | recvHandle: handle, 31 | serverStreams: make(map[string]Ipc_TransferClient), 32 | } 33 | return client 34 | } 35 | 36 | func (this *Client) dealRecvHandle(stream Ipc_TransferClient, msg *Res) { 37 | defer stack.TryError() 38 | 39 | this.recvHandle(stream, msg) 40 | } 41 | 42 | func (this *Client) loop(service string, stream Ipc_TransferClient) { 43 | defer stack.TryError() 44 | defer this.removeStream(service) 45 | 46 | for { 47 | in, err := stream.Recv() 48 | if err != nil { 49 | return 50 | } 51 | go this.dealRecvHandle(stream, in) 52 | } 53 | } 54 | 55 | func (this *Client) getStream(service string) Ipc_TransferClient { 56 | this.serverStreamMutex.Lock() 57 | defer this.serverStreamMutex.Unlock() 58 | 59 | //检测是否已经存在 60 | stream, ok := this.serverStreams[service] 61 | if ok { 62 | return stream 63 | } 64 | 65 | //创建新的stream 66 | transferClient := this.grpcClient.Call(service, "Transfer", nil) 67 | if transferClient == nil { 68 | return nil 69 | } 70 | stream = transferClient.(Ipc_TransferClient) 71 | this.serverStreams[service] = stream 72 | go this.loop(service, stream) 73 | 74 | return stream 75 | } 76 | 77 | func (this *Client) removeStream(service string) { 78 | this.serverStreamMutex.Lock() 79 | if stream, ok := this.serverStreams[service]; ok { 80 | stream.Context().Done() 81 | stream.CloseSend() 82 | delete(this.serverStreams, service) 83 | } 84 | this.serverStreamMutex.Unlock() 85 | } 86 | 87 | func (this *Client) GetServiceByRandom() string { 88 | return this.grpcClient.GetServiceByRandom() 89 | } 90 | 91 | func (this *Client) GetServiceByFlag(flag string) string { 92 | return this.grpcClient.GetServiceByFlag(flag) 93 | } 94 | 95 | func (this *Client) Send(senderServiceIdentify string, userSessionId uint64, data []byte, receiverService string) error { 96 | if receiverService == "" { 97 | return errors.New("service is null") 98 | } 99 | 100 | stream := this.getStream(receiverService) 101 | if stream == nil { 102 | return errors.New("stream is null") 103 | } 104 | 105 | return stream.Send(&Req{ 106 | ServiceIdentify: senderServiceIdentify, 107 | UserSessionId: userSessionId, 108 | Data: data, 109 | }) 110 | } 111 | -------------------------------------------------------------------------------- /core/libs/dict/dict.go: -------------------------------------------------------------------------------- 1 | package dict 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func getValue(data interface{}, key interface{}) interface{} { 8 | dataType := reflect.TypeOf(data).Kind() 9 | if dataType != reflect.Map { 10 | return nil 11 | } 12 | 13 | dataValue := reflect.ValueOf(data) 14 | keyValue := reflect.ValueOf(key) 15 | value := dataValue.MapIndex(keyValue) 16 | if value.IsValid() { 17 | return value.Interface() 18 | } 19 | return nil 20 | } 21 | 22 | func GetBool(data interface{}, key interface{}) bool { 23 | result := false 24 | value := getValue(data, key) 25 | if value != nil && reflect.TypeOf(value).Kind() == reflect.Bool { 26 | result = value.(bool) 27 | } 28 | return result 29 | } 30 | 31 | func GetString(data interface{}, key interface{}) string { 32 | result := "" 33 | value := getValue(data, key) 34 | if value != nil && reflect.TypeOf(value).Kind() == reflect.String { 35 | result = value.(string) 36 | } 37 | return result 38 | } 39 | 40 | func GetStringMap(data interface{}, key interface{}) map[string]interface{} { 41 | var result map[string]interface{} 42 | value := getValue(data, key) 43 | if value != nil && reflect.TypeOf(value).Kind() == reflect.TypeOf(result).Kind() { 44 | result = value.(map[string]interface{}) 45 | } 46 | return result 47 | } 48 | 49 | func GetUint16(data interface{}, key interface{}) uint16 { 50 | var result uint16 = 0 51 | value := getValue(data, key) 52 | if value != nil { 53 | valueType := reflect.TypeOf(value).Kind() 54 | if valueType == reflect.Float64 { 55 | result = uint16(value.(float64)) 56 | } else if valueType == reflect.Uint16 { 57 | result = value.(uint16) 58 | } 59 | } 60 | return result 61 | } 62 | 63 | func GetUint32(data interface{}, key interface{}) uint32 { 64 | var result uint32 = 0 65 | value := getValue(data, key) 66 | if value != nil { 67 | valueType := reflect.TypeOf(value).Kind() 68 | if valueType == reflect.Float64 { 69 | result = uint32(value.(float64)) 70 | } else if valueType == reflect.Uint32 { 71 | result = value.(uint32) 72 | } 73 | } 74 | return result 75 | } 76 | 77 | func GetUint64(data interface{}, key interface{}) uint64 { 78 | var result uint64 = 0 79 | value := getValue(data, key) 80 | if value != nil { 81 | valueType := reflect.TypeOf(value).Kind() 82 | if valueType == reflect.Float64 { 83 | result = uint64(value.(float64)) 84 | } else if valueType == reflect.Uint64 { 85 | result = value.(uint64) 86 | } 87 | } 88 | return result 89 | } 90 | 91 | func GetInt64(data interface{}, key interface{}) int64 { 92 | var result int64 = 0 93 | value := getValue(data, key) 94 | if value != nil { 95 | valueType := reflect.TypeOf(value).Kind() 96 | if valueType == reflect.Float64 { 97 | result = int64(value.(float64)) 98 | } else if valueType == reflect.Int64 { 99 | result = value.(int64) 100 | } 101 | } 102 | return result 103 | } 104 | 105 | func GetUint8(data interface{}, key interface{}) uint8 { 106 | var result uint8 = 0 107 | value := getValue(data, key) 108 | if value != nil { 109 | valueType := reflect.TypeOf(value).Kind() 110 | if valueType == reflect.Float64 { 111 | result = uint8(value.(float64)) 112 | } else if valueType == reflect.Uint8 { 113 | result = value.(uint8) 114 | } 115 | } 116 | return result 117 | } 118 | 119 | func GetInt(data interface{}, key interface{}) int { 120 | var result int = 0 121 | value := getValue(data, key) 122 | if value != nil { 123 | valueType := reflect.TypeOf(value).Kind() 124 | if valueType == reflect.Float64 { 125 | result = int(value.(float64)) 126 | } else if valueType == reflect.Int { 127 | result = value.(int) 128 | } 129 | } 130 | return result 131 | } 132 | -------------------------------------------------------------------------------- /core/libs/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/natefinch/lumberjack" 7 | "go.uber.org/zap" 8 | "go.uber.org/zap/zapcore" 9 | ) 10 | 11 | var ( 12 | fileLogger *zap.Logger 13 | consoleLogger *zap.Logger 14 | conf option 15 | ) 16 | 17 | type option struct { 18 | debug bool 19 | both bool 20 | file bool 21 | name string 22 | } 23 | 24 | // 默认参数 25 | func defaultOption() option { 26 | return option{ 27 | debug: false, 28 | both: true, 29 | file: true, 30 | name: "log", 31 | } 32 | } 33 | 34 | // Option 参数 35 | type Option func(*option) 36 | 37 | // Init Init 38 | func Init(opts ...Option) { 39 | conf := defaultOption() 40 | for _, opt := range opts { 41 | opt(&conf) 42 | } 43 | 44 | var logLevel = zapcore.InfoLevel 45 | if conf.debug { 46 | logLevel = zapcore.DebugLevel 47 | } 48 | 49 | if conf.both { 50 | createConsoleLogger(conf.name, logLevel) 51 | } 52 | 53 | if conf.file { 54 | createFileLogger(conf.name, logLevel) 55 | } 56 | } 57 | 58 | func createFileLogger(name string, logLevel zapcore.Level) { 59 | lumberJackLogger := &lumberjack.Logger{ 60 | Filename: "./logs/" + name + ".log", 61 | MaxSize: 10, 62 | MaxBackups: 5, 63 | MaxAge: 30, 64 | Compress: false, 65 | } 66 | writeSyncer := zapcore.AddSync(lumberJackLogger) 67 | 68 | encoderConfig := zap.NewProductionEncoderConfig() 69 | encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 70 | encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder 71 | encoder := zapcore.NewJSONEncoder(encoderConfig) 72 | 73 | fileLogger = zap.New(zapcore.NewCore(encoder, writeSyncer, logLevel)) 74 | fileLogger = fileLogger.Named(name) 75 | } 76 | 77 | func createConsoleLogger(fileName string, logLevel zapcore.Level) { 78 | writeSyncer := os.Stderr 79 | 80 | encoderConfig := zap.NewProductionEncoderConfig() 81 | encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder 82 | encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder 83 | encoder := zapcore.NewConsoleEncoder(encoderConfig) 84 | 85 | consoleLogger = zap.New(zapcore.NewCore(encoder, writeSyncer, logLevel)) 86 | consoleLogger = consoleLogger.Named(fileName) 87 | } 88 | 89 | // WithDebug 是否开启Debug参数 90 | func WithDebug(debug bool) Option { 91 | return func(o *option) { 92 | o.debug = debug 93 | } 94 | } 95 | 96 | // WithBoth 是否开启Both参数 97 | func WithBoth(both bool) Option { 98 | return func(o *option) { 99 | o.both = both 100 | } 101 | } 102 | 103 | // WithFile 是否开启File参数 104 | func WithFile(file bool) Option { 105 | return func(o *option) { 106 | o.file = file 107 | } 108 | } 109 | 110 | // WithName 设置name参数 111 | func WithName(name string) Option { 112 | return func(o *option) { 113 | o.name = name 114 | } 115 | } 116 | 117 | // Error Error 118 | func Error(msg string, fields ...zap.Field) { 119 | if consoleLogger != nil { 120 | defer consoleLogger.Sync() 121 | consoleLogger.Error(msg, fields...) 122 | } 123 | 124 | if fileLogger != nil { 125 | defer fileLogger.Sync() 126 | fileLogger.Error(msg, fields...) 127 | } 128 | } 129 | 130 | // Warn Warn 131 | func Warn(msg string, fields ...zap.Field) { 132 | if consoleLogger != nil { 133 | defer consoleLogger.Sync() 134 | consoleLogger.Warn(msg, fields...) 135 | } 136 | 137 | if fileLogger != nil { 138 | defer fileLogger.Sync() 139 | fileLogger.Warn(msg, fields...) 140 | } 141 | } 142 | 143 | // Info Info 144 | func Info(msg string, fields ...zap.Field) { 145 | if consoleLogger != nil { 146 | defer consoleLogger.Sync() 147 | consoleLogger.Info(msg, fields...) 148 | } 149 | 150 | if fileLogger != nil { 151 | defer fileLogger.Sync() 152 | fileLogger.Info(msg, fields...) 153 | } 154 | } 155 | 156 | // Debug Debug 157 | func Debug(msg string, fields ...zap.Field) { 158 | if consoleLogger != nil { 159 | defer consoleLogger.Sync() 160 | consoleLogger.Debug(msg, fields...) 161 | } 162 | 163 | if fileLogger != nil { 164 | defer fileLogger.Sync() 165 | fileLogger.Debug(msg, fields...) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /core/libs/grpc/ipc/server.go: -------------------------------------------------------------------------------- 1 | package ipc 2 | 3 | import ( 4 | "io" 5 | "sync" 6 | "sync/atomic" 7 | 8 | myGprc "github.com/yicaoyimuys/GoGameServer/core/libs/grpc" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 10 | 11 | "google.golang.org/grpc" 12 | ) 13 | 14 | type ServerRecvHandle func(stream *Stream, msg *Req) 15 | type StreamSession interface { 16 | Close() 17 | } 18 | 19 | type Stream struct { 20 | transferServer Ipc_TransferServer 21 | sessions []StreamSession 22 | sessionsMutex sync.Mutex 23 | closeFlag int32 24 | } 25 | 26 | func (this *Stream) Send(userSessionIds []uint64, data []byte) error { 27 | msg := &Res{ 28 | UserSessionIds: userSessionIds, 29 | Data: data, 30 | } 31 | return this.transferServer.Send(msg) 32 | } 33 | 34 | func (this *Stream) IsClosed() bool { 35 | return atomic.LoadInt32(&this.closeFlag) == 1 36 | } 37 | 38 | func (this *Stream) AddSession(session StreamSession) { 39 | if this.IsClosed() { 40 | return 41 | } 42 | 43 | this.sessionsMutex.Lock() 44 | defer this.sessionsMutex.Unlock() 45 | 46 | this.sessions = append(this.sessions, session) 47 | } 48 | 49 | func (this *Stream) RemoveSession(session StreamSession) { 50 | if this.IsClosed() { 51 | return 52 | } 53 | 54 | this.sessionsMutex.Lock() 55 | defer this.sessionsMutex.Unlock() 56 | 57 | for index, s := range this.sessions { 58 | if s == session { 59 | this.sessions = append(this.sessions[:index], this.sessions[index+1:]...) 60 | } 61 | } 62 | } 63 | 64 | func (this *Stream) close() { 65 | if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 66 | this.transferServer.Context().Done() 67 | 68 | this.sessionsMutex.Lock() 69 | defer this.sessionsMutex.Unlock() 70 | 71 | for _, session := range this.sessions { 72 | session.Close() 73 | } 74 | this.sessions = nil 75 | } 76 | } 77 | 78 | type Server struct { 79 | serverRecvHandle ServerRecvHandle 80 | streams []*Stream 81 | streamMutex sync.Mutex 82 | } 83 | 84 | func (this *Server) addStream(stream *Stream) { 85 | this.streamMutex.Lock() 86 | defer this.streamMutex.Unlock() 87 | 88 | this.streams = append(this.streams, stream) 89 | } 90 | 91 | func (this *Server) removeStream(stream *Stream) { 92 | this.streamMutex.Lock() 93 | defer this.streamMutex.Unlock() 94 | 95 | for index, s := range this.streams { 96 | if s == stream { 97 | this.streams = append(this.streams[:index], this.streams[index+1:]...) 98 | } 99 | } 100 | 101 | stream.close() 102 | } 103 | 104 | func (this *Server) SendToClient(stream *Stream, userSessionIds []uint64, data []byte) { 105 | stream.Send(userSessionIds, data) 106 | } 107 | 108 | func (this *Server) SendToAllClient(userSessionIds []uint64, data []byte) { 109 | this.streamMutex.Lock() 110 | defer this.streamMutex.Unlock() 111 | 112 | for _, stream := range this.streams { 113 | stream.Send(userSessionIds, data) 114 | } 115 | } 116 | 117 | func (this *Server) mustEmbedUnimplementedIpcServer() { 118 | 119 | } 120 | 121 | func (this *Server) Transfer(stream Ipc_TransferServer) error { 122 | defer stack.TryError() 123 | 124 | s := &Stream{stream, []StreamSession{}, sync.Mutex{}, 0} 125 | this.addStream(s) 126 | 127 | defer this.removeStream(s) 128 | 129 | for { 130 | in, err := s.transferServer.Recv() 131 | if err == io.EOF { 132 | return nil 133 | } 134 | if err != nil { 135 | return err 136 | } 137 | 138 | go this.dealServerRecvHandle(s, in) 139 | } 140 | } 141 | 142 | func (this *Server) dealServerRecvHandle(stream *Stream, msg *Req) { 143 | defer stack.TryError() 144 | 145 | this.serverRecvHandle(stream, msg) 146 | } 147 | 148 | func InitServer(serverRecvHandle ServerRecvHandle) (*Server, string, error) { 149 | ipcServer := &Server{ 150 | serverRecvHandle: serverRecvHandle, 151 | streams: []*Stream{}, 152 | } 153 | serverPort, err := myGprc.InitServer(func(grpcServer *grpc.Server) { 154 | //注册处理模块 155 | RegisterIpcServer(grpcServer, ipcServer) 156 | }) 157 | return ipcServer, serverPort, err 158 | } 159 | -------------------------------------------------------------------------------- /core/libs/grpc/ipc/ipc_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.14.0 5 | // source: ipc.proto 6 | 7 | package ipc 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // IpcClient is the client API for Ipc service. 22 | // 23 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 24 | type IpcClient interface { 25 | Transfer(ctx context.Context, opts ...grpc.CallOption) (Ipc_TransferClient, error) 26 | } 27 | 28 | type ipcClient struct { 29 | cc grpc.ClientConnInterface 30 | } 31 | 32 | func NewIpcClient(cc grpc.ClientConnInterface) IpcClient { 33 | return &ipcClient{cc} 34 | } 35 | 36 | func (c *ipcClient) Transfer(ctx context.Context, opts ...grpc.CallOption) (Ipc_TransferClient, error) { 37 | stream, err := c.cc.NewStream(ctx, &Ipc_ServiceDesc.Streams[0], "/Ipc/Transfer", opts...) 38 | if err != nil { 39 | return nil, err 40 | } 41 | x := &ipcTransferClient{stream} 42 | return x, nil 43 | } 44 | 45 | type Ipc_TransferClient interface { 46 | Send(*Req) error 47 | Recv() (*Res, error) 48 | grpc.ClientStream 49 | } 50 | 51 | type ipcTransferClient struct { 52 | grpc.ClientStream 53 | } 54 | 55 | func (x *ipcTransferClient) Send(m *Req) error { 56 | return x.ClientStream.SendMsg(m) 57 | } 58 | 59 | func (x *ipcTransferClient) Recv() (*Res, error) { 60 | m := new(Res) 61 | if err := x.ClientStream.RecvMsg(m); err != nil { 62 | return nil, err 63 | } 64 | return m, nil 65 | } 66 | 67 | // IpcServer is the server API for Ipc service. 68 | // All implementations must embed UnimplementedIpcServer 69 | // for forward compatibility 70 | type IpcServer interface { 71 | Transfer(Ipc_TransferServer) error 72 | mustEmbedUnimplementedIpcServer() 73 | } 74 | 75 | // UnimplementedIpcServer must be embedded to have forward compatible implementations. 76 | type UnimplementedIpcServer struct { 77 | } 78 | 79 | func (UnimplementedIpcServer) Transfer(Ipc_TransferServer) error { 80 | return status.Errorf(codes.Unimplemented, "method Transfer not implemented") 81 | } 82 | func (UnimplementedIpcServer) mustEmbedUnimplementedIpcServer() {} 83 | 84 | // UnsafeIpcServer may be embedded to opt out of forward compatibility for this service. 85 | // Use of this interface is not recommended, as added methods to IpcServer will 86 | // result in compilation errors. 87 | type UnsafeIpcServer interface { 88 | mustEmbedUnimplementedIpcServer() 89 | } 90 | 91 | func RegisterIpcServer(s grpc.ServiceRegistrar, srv IpcServer) { 92 | s.RegisterService(&Ipc_ServiceDesc, srv) 93 | } 94 | 95 | func _Ipc_Transfer_Handler(srv interface{}, stream grpc.ServerStream) error { 96 | return srv.(IpcServer).Transfer(&ipcTransferServer{stream}) 97 | } 98 | 99 | type Ipc_TransferServer interface { 100 | Send(*Res) error 101 | Recv() (*Req, error) 102 | grpc.ServerStream 103 | } 104 | 105 | type ipcTransferServer struct { 106 | grpc.ServerStream 107 | } 108 | 109 | func (x *ipcTransferServer) Send(m *Res) error { 110 | return x.ServerStream.SendMsg(m) 111 | } 112 | 113 | func (x *ipcTransferServer) Recv() (*Req, error) { 114 | m := new(Req) 115 | if err := x.ServerStream.RecvMsg(m); err != nil { 116 | return nil, err 117 | } 118 | return m, nil 119 | } 120 | 121 | // Ipc_ServiceDesc is the grpc.ServiceDesc for Ipc service. 122 | // It's only intended for direct use with grpc.RegisterService, 123 | // and not to be introspected or modified (even as a copy) 124 | var Ipc_ServiceDesc = grpc.ServiceDesc{ 125 | ServiceName: "Ipc", 126 | HandlerType: (*IpcServer)(nil), 127 | Methods: []grpc.MethodDesc{}, 128 | Streams: []grpc.StreamDesc{ 129 | { 130 | StreamName: "Transfer", 131 | Handler: _Ipc_Transfer_Handler, 132 | ServerStreams: true, 133 | ClientStreams: true, 134 | }, 135 | }, 136 | Metadata: "ipc.proto", 137 | } 138 | -------------------------------------------------------------------------------- /core/libs/sessions/backSession.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | 7 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 9 | ) 10 | 11 | type BackSession struct { 12 | id string 13 | sessionId uint64 14 | stream *ipc.Stream 15 | 16 | closeFlag int32 17 | closeChan chan int 18 | closeMutex sync.Mutex 19 | firstCloseCallback *closeCallback 20 | lastCloseCallback *closeCallback 21 | 22 | recvChan chan []byte 23 | recvMutex sync.Mutex 24 | 25 | msgHandle func(session *BackSession, msgBody []byte) 26 | userId uint64 27 | } 28 | 29 | func NewBackSession(id string, sessionId uint64, stream *ipc.Stream) *BackSession { 30 | session := &BackSession{ 31 | id: id, 32 | sessionId: sessionId, 33 | stream: stream, 34 | recvChan: make(chan []byte, 100), 35 | closeChan: make(chan int), 36 | } 37 | stream.AddSession(session) 38 | go session.loop() 39 | return session 40 | } 41 | 42 | func (this *BackSession) SessionID() uint64 { 43 | return this.sessionId 44 | } 45 | 46 | func (this *BackSession) ID() string { 47 | return this.id 48 | } 49 | 50 | func (this *BackSession) UserID() uint64 { 51 | return this.userId 52 | } 53 | 54 | func (this *BackSession) SetUserId(userId uint64) { 55 | this.userId = userId 56 | } 57 | 58 | func (this *BackSession) Receive(data []byte) error { 59 | this.recvMutex.Lock() 60 | if this.IsClosed() { 61 | this.recvMutex.Unlock() 62 | return ErrClosed 63 | } 64 | 65 | this.recvChan <- data 66 | this.recvMutex.Unlock() 67 | return nil 68 | } 69 | 70 | func (this *BackSession) Send(data []byte) error { 71 | if this.IsClosed() { 72 | return ErrClosed 73 | } 74 | 75 | return this.stream.Send([]uint64{this.sessionId}, data) 76 | } 77 | 78 | func (this *BackSession) IsClosed() bool { 79 | return atomic.LoadInt32(&this.closeFlag) == 1 80 | } 81 | 82 | func (this *BackSession) Close() { 83 | if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 84 | close(this.closeChan) 85 | 86 | this.recvMutex.Lock() 87 | close(this.recvChan) 88 | for _ = range this.recvChan { 89 | } 90 | this.recvMutex.Unlock() 91 | 92 | this.invokeCloseCallbacks() 93 | 94 | this.stream.RemoveSession(this) 95 | this.stream = nil 96 | 97 | this.msgHandle = nil 98 | } 99 | } 100 | 101 | func (this *BackSession) AddCloseCallback(handler, key interface{}, callback func()) { 102 | if this.IsClosed() { 103 | return 104 | } 105 | 106 | this.closeMutex.Lock() 107 | defer this.closeMutex.Unlock() 108 | 109 | newItem := &closeCallback{handler, key, callback, nil} 110 | 111 | if this.firstCloseCallback == nil { 112 | this.firstCloseCallback = newItem 113 | } else { 114 | this.lastCloseCallback.Next = newItem 115 | } 116 | this.lastCloseCallback = newItem 117 | } 118 | 119 | func (this *BackSession) RemoveCloseCallback(handler, key interface{}) { 120 | if this.IsClosed() { 121 | return 122 | } 123 | 124 | this.closeMutex.Lock() 125 | defer this.closeMutex.Unlock() 126 | 127 | var prev *closeCallback 128 | for callback := this.firstCloseCallback; callback != nil; prev, callback = callback, callback.Next { 129 | if callback.Handler == handler && callback.Key == key { 130 | if this.firstCloseCallback == callback { 131 | this.firstCloseCallback = callback.Next 132 | } else { 133 | prev.Next = callback.Next 134 | } 135 | if this.lastCloseCallback == callback { 136 | this.lastCloseCallback = prev 137 | } 138 | return 139 | } 140 | } 141 | } 142 | 143 | func (this *BackSession) invokeCloseCallbacks() { 144 | this.closeMutex.Lock() 145 | defer this.closeMutex.Unlock() 146 | 147 | for callback := this.firstCloseCallback; callback != nil; callback = callback.Next { 148 | callback.Func() 149 | } 150 | } 151 | 152 | func (this *BackSession) SetMsgHandle(msgHandle func(session *BackSession, msgBody []byte)) { 153 | this.msgHandle = msgHandle 154 | } 155 | 156 | func (this *BackSession) loop() { 157 | defer stack.TryError() 158 | 159 | for { 160 | select { 161 | case msg, ok := <-this.recvChan: 162 | if ok { 163 | if this.msgHandle != nil { 164 | this.msgHandle(this, msg) 165 | } 166 | } else { 167 | return 168 | } 169 | case <-this.closeChan: 170 | return 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /servives/connector/messages/frontMessageHandle.go: -------------------------------------------------------------------------------- 1 | package messages 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/yicaoyimuys/GoGameServer/core" 7 | "github.com/yicaoyimuys/GoGameServer/core/consts" 8 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 10 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 11 | "github.com/yicaoyimuys/GoGameServer/core/libs/sessions" 12 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 13 | "go.uber.org/zap" 14 | ) 15 | 16 | func dealConnectorMsg(session *sessions.FrontSession, msgBody []byte) { 17 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 18 | if protoMsg == protos.NullProtoMsg { 19 | return 20 | } 21 | 22 | //Ping消息特殊处理 23 | if protoMsg.ID == gameProto.ID_client_ping_c2s { 24 | session.UpdatePingTime() 25 | return 26 | } 27 | } 28 | 29 | func dealGameMsg(session *sessions.FrontSession, msgBody []byte) { 30 | err := sendMsgToIpcService(consts.Service_Game, session, msgBody) 31 | if err != nil { 32 | ERR("DealGameMsg", zap.Error(err)) 33 | sendErrorMsgToClient(session) 34 | } 35 | } 36 | 37 | func dealChatMsg(session *sessions.FrontSession, msgBody []byte) { 38 | err := sendMsgToIpcService(consts.Service_Chat, session, msgBody) 39 | if err != nil { 40 | ERR("DealChatMsg", zap.Error(err)) 41 | sendErrorMsgToClient(session) 42 | } 43 | } 44 | 45 | func dealLoginMsg(session *sessions.FrontSession, msgBody []byte) { 46 | err := sendMsgToIpcService(consts.Service_Login, session, msgBody) 47 | if err != nil { 48 | ERR("DealLoginMsg", zap.Error(err)) 49 | sendErrorMsgToClient(session) 50 | } 51 | } 52 | 53 | func getGameService(session *sessions.FrontSession, msgBody []byte, ipcClient *ipc.Client) string { 54 | //1: 获取用户数据,根据Token分配 55 | msgId := protos.UnmarshalProtoId(msgBody) 56 | if msgId == gameProto.ID_user_getInfo_c2s { 57 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 58 | if protoMsg == protos.NullProtoMsg { 59 | return "" 60 | } 61 | protoMsgData := protoMsg.Body.(*gameProto.UserGetInfoC2S) 62 | return ipcClient.GetServiceByFlag(protoMsgData.GetToken()) 63 | } else { 64 | return session.GetIpcService(consts.Service_Game) 65 | } 66 | } 67 | 68 | func getChatService(session *sessions.FrontSession, msgBody []byte, ipcClient *ipc.Client) string { 69 | //1: 加入聊天,根据Token分配 70 | msgId := protos.UnmarshalProtoId(msgBody) 71 | if msgId == gameProto.ID_user_joinChat_c2s { 72 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 73 | if protoMsg == protos.NullProtoMsg { 74 | return "" 75 | } 76 | protoMsgData := protoMsg.Body.(*gameProto.UserJoinChatC2S) 77 | return ipcClient.GetServiceByFlag(protoMsgData.GetToken()) 78 | } else { 79 | return session.GetIpcService(consts.Service_Chat) 80 | } 81 | } 82 | 83 | func getLoginService(session *sessions.FrontSession, msgBody []byte, ipcClient *ipc.Client) string { 84 | //1: 登录,根据Account分配 85 | msgId := protos.UnmarshalProtoId(msgBody) 86 | if msgId == gameProto.ID_user_login_c2s { 87 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 88 | if protoMsg == protos.NullProtoMsg { 89 | return "" 90 | } 91 | protoMsgData := protoMsg.Body.(*gameProto.UserLoginC2S) 92 | return ipcClient.GetServiceByFlag(protoMsgData.GetAccount()) 93 | } else { 94 | return session.GetIpcService(consts.Service_Login) 95 | } 96 | } 97 | 98 | func sendErrorMsgToClient(session *sessions.FrontSession) { 99 | sendMsg := protos.MarshalProtoMsg(&gameProto.ErrorNoticeS2C{ 100 | ErrorCode: protos.Int32(consts.ErrCode_SystemError), 101 | }) 102 | session.Send(sendMsg) 103 | } 104 | 105 | func sendMsgToIpcService(serviceName string, clientSession *sessions.FrontSession, msgBody []byte) error { 106 | ipcClient := core.Service.GetIpcClient(serviceName) 107 | if ipcClient == nil { 108 | return errors.New(serviceName + ": ipcClient not exists") 109 | } 110 | 111 | var service string 112 | if serviceName == consts.Service_Login { 113 | service = getLoginService(clientSession, msgBody, ipcClient) 114 | } else if serviceName == consts.Service_Game { 115 | service = getGameService(clientSession, msgBody, ipcClient) 116 | } else if serviceName == consts.Service_Chat { 117 | service = getChatService(clientSession, msgBody, ipcClient) 118 | } 119 | 120 | if service == "" { 121 | return errors.New(serviceName + ": service not exists") 122 | } 123 | 124 | err := ipcClient.Send(core.Service.Identify(), clientSession.ID(), msgBody, service) 125 | if err == nil { 126 | clientSession.SetIpcService(serviceName, service) 127 | } 128 | return err 129 | } 130 | -------------------------------------------------------------------------------- /core/libs/sessions/frontSession.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "time" 7 | 8 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 9 | ) 10 | 11 | type Codec interface { 12 | Receive() ([]byte, error) 13 | Send([]byte) error 14 | Close() error 15 | } 16 | 17 | type FrontSessionCreateHandle func(session *FrontSession) 18 | type FrontSessionReceiveMsgHandle func(session *FrontSession, msgBody []byte) 19 | 20 | type FrontSession struct { 21 | id uint64 22 | codec Codec 23 | recvMutex sync.Mutex 24 | sendMutex sync.RWMutex 25 | recvChan chan []byte 26 | 27 | closeFlag int32 28 | closeChan chan int 29 | closeMutex sync.Mutex 30 | firstCloseCallback *closeCallback 31 | lastCloseCallback *closeCallback 32 | 33 | msgHandle func(session *FrontSession, msgBody []byte) 34 | 35 | pingTime int64 36 | ipcServices sync.Map 37 | } 38 | 39 | func NewFontSession(id uint64, codec Codec) *FrontSession { 40 | session := &FrontSession{ 41 | id: id, 42 | codec: codec, 43 | recvChan: make(chan []byte, 100), 44 | closeChan: make(chan int), 45 | pingTime: time.Now().Unix(), 46 | } 47 | go session.loop() 48 | return session 49 | } 50 | 51 | func (this *FrontSession) ID() uint64 { 52 | return this.id 53 | } 54 | 55 | func (this *FrontSession) IsClosed() bool { 56 | return atomic.LoadInt32(&this.closeFlag) == 1 57 | } 58 | 59 | func (this *FrontSession) GetIpcService(serviceName string) string { 60 | value, _ := this.ipcServices.Load(serviceName) 61 | if value != nil { 62 | return value.(string) 63 | } 64 | return "" 65 | } 66 | 67 | func (this *FrontSession) PingTime() int64 { 68 | return this.pingTime 69 | } 70 | 71 | func (this *FrontSession) SetIpcService(serviceName string, service string) { 72 | this.ipcServices.Store(serviceName, service) 73 | } 74 | 75 | func (this *FrontSession) UpdatePingTime() { 76 | this.pingTime = time.Now().Unix() 77 | } 78 | 79 | func (this *FrontSession) Close() { 80 | if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 81 | close(this.closeChan) 82 | 83 | this.recvMutex.Lock() 84 | close(this.recvChan) 85 | for _ = range this.recvChan { 86 | } 87 | this.recvMutex.Unlock() 88 | 89 | this.invokeCloseCallbacks() 90 | this.codec.Close() 91 | 92 | this.msgHandle = nil 93 | } 94 | } 95 | 96 | func (this *FrontSession) Receive() ([]byte, error) { 97 | msg, err := this.codec.Receive() 98 | if msg != nil { 99 | this.recvMutex.Lock() 100 | if this.IsClosed() { 101 | this.recvMutex.Unlock() 102 | return nil, ErrClosed 103 | } 104 | this.recvChan <- msg 105 | this.recvMutex.Unlock() 106 | } 107 | return msg, err 108 | } 109 | 110 | func (this *FrontSession) Send(msg []byte) (err error) { 111 | if this.IsClosed() { 112 | return ErrClosed 113 | } 114 | 115 | this.sendMutex.Lock() 116 | defer this.sendMutex.Unlock() 117 | 118 | return this.codec.Send(msg) 119 | } 120 | 121 | func (this *FrontSession) AddCloseCallback(handler, key interface{}, callback func()) { 122 | if this.IsClosed() { 123 | return 124 | } 125 | 126 | this.closeMutex.Lock() 127 | defer this.closeMutex.Unlock() 128 | 129 | newItem := &closeCallback{handler, key, callback, nil} 130 | 131 | if this.firstCloseCallback == nil { 132 | this.firstCloseCallback = newItem 133 | } else { 134 | this.lastCloseCallback.Next = newItem 135 | } 136 | this.lastCloseCallback = newItem 137 | } 138 | 139 | func (this *FrontSession) RemoveCloseCallback(handler, key interface{}) { 140 | if this.IsClosed() { 141 | return 142 | } 143 | 144 | this.closeMutex.Lock() 145 | defer this.closeMutex.Unlock() 146 | 147 | var prev *closeCallback 148 | for callback := this.firstCloseCallback; callback != nil; prev, callback = callback, callback.Next { 149 | if callback.Handler == handler && callback.Key == key { 150 | if this.firstCloseCallback == callback { 151 | this.firstCloseCallback = callback.Next 152 | } else { 153 | prev.Next = callback.Next 154 | } 155 | if this.lastCloseCallback == callback { 156 | this.lastCloseCallback = prev 157 | } 158 | return 159 | } 160 | } 161 | } 162 | 163 | func (this *FrontSession) invokeCloseCallbacks() { 164 | this.closeMutex.Lock() 165 | defer this.closeMutex.Unlock() 166 | 167 | for callback := this.firstCloseCallback; callback != nil; callback = callback.Next { 168 | callback.Func() 169 | } 170 | } 171 | 172 | func (this *FrontSession) SetMsgHandle(msgHandle func(session *FrontSession, msgBody []byte)) { 173 | this.msgHandle = msgHandle 174 | } 175 | 176 | func (this *FrontSession) loop() { 177 | defer stack.TryError() 178 | 179 | for { 180 | select { 181 | case msg, ok := <-this.recvChan: 182 | if ok { 183 | if this.msgHandle != nil { 184 | this.msgHandle(this, msg) 185 | } 186 | } else { 187 | return 188 | } 189 | case <-this.closeChan: 190 | return 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /core/service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "runtime" 5 | 6 | beegoLogs "github.com/astaxie/beego/logs" 7 | beegoOrm "github.com/astaxie/beego/orm" 8 | "github.com/yicaoyimuys/GoGameServer/core" 9 | "github.com/yicaoyimuys/GoGameServer/core/config" 10 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 11 | "github.com/yicaoyimuys/GoGameServer/core/libs/common" 12 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 13 | "github.com/yicaoyimuys/GoGameServer/core/libs/grpc/ipc" 14 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 15 | "github.com/yicaoyimuys/GoGameServer/core/libs/mongo" 16 | "github.com/yicaoyimuys/GoGameServer/core/libs/mysql" 17 | "github.com/yicaoyimuys/GoGameServer/core/libs/redis" 18 | "github.com/yicaoyimuys/GoGameServer/core/libs/rpc" 19 | "github.com/yicaoyimuys/GoGameServer/core/libs/socket" 20 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 21 | "github.com/yicaoyimuys/GoGameServer/core/libs/system" 22 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 23 | "github.com/yicaoyimuys/GoGameServer/core/libs/websocket" 24 | "go.uber.org/zap" 25 | 26 | "github.com/spf13/cast" 27 | ) 28 | 29 | type Service struct { 30 | env string 31 | name string 32 | id int 33 | 34 | ip string 35 | ports map[string]string 36 | 37 | ipcServer *ipc.Server 38 | 39 | ipcClients map[string]*ipc.Client 40 | rpcClients map[string]*rpc.Client 41 | redisClients map[string]*redis.Client 42 | mysqlClients map[string]*mysql.Client 43 | mongoClients map[string]*mongo.Client 44 | 45 | websocketServer *websocket.Server 46 | socketServer *socket.Server 47 | } 48 | 49 | func NewService(name string) *Service { 50 | service := &Service{ 51 | name: name, 52 | ip: common.GetLocalIp(), 53 | ports: make(map[string]string), 54 | } 55 | service.init() 56 | 57 | core.Service = service 58 | return service 59 | } 60 | 61 | func (this *Service) init() { 62 | //错误捕获 63 | recoverErr() 64 | 65 | //初始化: 使用CPU数设置 66 | initMaxProcs() 67 | 68 | //初始化: 命令行参数 69 | initArgv(this) 70 | 71 | //初始化: 配置文件 72 | initConfig(this) 73 | 74 | //初始化: log 75 | initLog(this) 76 | 77 | //系统环境输出 78 | printEnv(this) 79 | } 80 | 81 | func initMaxProcs() { 82 | //runtime.GOMAXPROCS(1) 83 | } 84 | 85 | func initArgv(service *Service) { 86 | service.env = system.Args.Env 87 | service.id = system.Args.ServiceId 88 | } 89 | 90 | func initConfig(service *Service) { 91 | config.Init(service.env) 92 | } 93 | 94 | func initLog(service *Service) { 95 | logConfig := config.GetLogConfig() 96 | 97 | logger.Init( 98 | logger.WithDebug(logConfig.Debug), 99 | logger.WithBoth(logConfig.Both), 100 | logger.WithFile(logConfig.File), 101 | logger.WithName(service.name+"-"+cast.ToString(service.id)), 102 | ) 103 | 104 | // 设置beego logs 105 | if logConfig.Debug { 106 | beegoLogs.SetLevel(beegoLogs.LevelDebug) 107 | } else { 108 | beegoLogs.SetLevel(beegoLogs.LevelInfo) 109 | } 110 | 111 | // 设置beego orm 112 | beegoOrm.Debug = logConfig.Debug 113 | } 114 | 115 | func printEnv(service *Service) { 116 | INFO("CPU数量", zap.Int("CpuNum", runtime.GOMAXPROCS(-1))) 117 | INFO("协程数量", zap.Int("GoroutineNum", runtime.NumGoroutine())) 118 | INFO("Go版本", zap.String("GoVersion", runtime.Version())) 119 | INFO("启动路径", zap.String("Root", system.Root)) 120 | INFO("服务器环境", zap.String("ServiceEnv", service.env)) 121 | INFO("服务器名称", zap.String("ServiceName", service.name)) 122 | INFO("服务器ID", zap.Int("ServiceId", service.id)) 123 | INFO("服务器IP", zap.String("ServiceIp", common.GetLocalIp())) 124 | 125 | timer.DoTimer(20*1000, func() { 126 | INFO("协程数量", zap.Int("GoroutineNum", runtime.NumGoroutine())) 127 | }) 128 | } 129 | 130 | func recoverErr() { 131 | stack.TryError() 132 | } 133 | 134 | func packageServiceName(serviceType string, serviceName string) string { 135 | return "<" + serviceType + ">" + serviceName 136 | } 137 | 138 | func (this *Service) registerService(serviceType string, servicePort string) { 139 | if _, exists := this.ports[serviceType]; exists { 140 | ERR("该类型的Service已经在本进程内启用", zap.String("ServiceType", serviceType)) 141 | return 142 | } 143 | 144 | //注册到Consul 145 | serviceName := packageServiceName(serviceType, this.name) 146 | err := consul.NewServive(this.ip, serviceName, this.id, servicePort) 147 | CheckError(err) 148 | 149 | INFO("Join Consul Service", zap.String("ServiceName", serviceName), zap.String("ServicePort", servicePort)) 150 | 151 | //记录该进程启用的端口号 152 | this.ports[serviceType] = servicePort 153 | } 154 | 155 | func (this *Service) Env() string { 156 | return this.env 157 | } 158 | 159 | func (this *Service) ID() int { 160 | return this.id 161 | } 162 | 163 | func (this *Service) Name() string { 164 | return this.name 165 | } 166 | 167 | func (this *Service) Ip() string { 168 | return this.ip 169 | } 170 | 171 | func (this *Service) Port(serviceType string) string { 172 | return this.ports[serviceType] 173 | } 174 | 175 | func (this *Service) Identify() string { 176 | return this.ip + "_" + this.name + "_" + cast.ToString(this.id) 177 | } 178 | -------------------------------------------------------------------------------- /core/libs/rpc/client.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net" 7 | "net/rpc" 8 | "net/rpc/jsonrpc" 9 | "sync" 10 | "time" 11 | 12 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 13 | "github.com/yicaoyimuys/GoGameServer/core/libs/hash" 14 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 15 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 16 | "go.uber.org/zap" 17 | 18 | "github.com/spf13/cast" 19 | ) 20 | 21 | type Client struct { 22 | consulClient *consul.Client 23 | serviceName string 24 | 25 | services []string 26 | servicesMutex sync.Mutex 27 | 28 | links map[string]*rpc.Client 29 | linkMutex sync.Mutex 30 | } 31 | 32 | func NewClient(consulClient *consul.Client, serviceName string) *Client { 33 | client := &Client{ 34 | consulClient: consulClient, 35 | serviceName: serviceName, 36 | links: make(map[string]*rpc.Client), 37 | } 38 | client.initServices() 39 | client.loop() 40 | return client 41 | } 42 | 43 | func (this *Client) loop() { 44 | timer.SetTimeOut(5*1000, this.initServices) 45 | } 46 | 47 | func (this *Client) initServices() { 48 | this.servicesMutex.Lock() 49 | this.services = this.consulClient.GetServices(this.serviceName) 50 | this.servicesMutex.Unlock() 51 | 52 | this.initLinks() 53 | this.traceServices() 54 | } 55 | 56 | func (this *Client) initLinks() { 57 | if len(this.services) == 0 { 58 | timer.SetTimeOut(300, this.initServices) 59 | return 60 | } 61 | 62 | if len(this.links) == 0 { 63 | for _, service := range this.services { 64 | this.getLink(service) 65 | } 66 | } 67 | } 68 | 69 | func (this *Client) traceServices() { 70 | return 71 | this.servicesMutex.Lock() 72 | logger.Debug("----------rpc start " + this.serviceName + "----------") 73 | for _, value := range this.services { 74 | logger.Debug("Service", zap.String("ServiceName", this.serviceName), zap.String("ServiceAddress", value)) 75 | } 76 | logger.Debug("-----------rpc end " + this.serviceName + "-----------") 77 | this.servicesMutex.Unlock() 78 | } 79 | 80 | func (this *Client) removeService(service string) { 81 | this.servicesMutex.Lock() 82 | for index, value := range this.services { 83 | if value == service { 84 | this.services = append(this.services[:index], this.services[index+1:]...) 85 | } 86 | } 87 | this.servicesMutex.Unlock() 88 | 89 | this.traceServices() 90 | } 91 | 92 | func (this *Client) getServiceByFlag(flag string) string { 93 | this.servicesMutex.Lock() 94 | service := "" 95 | servicesLen := len(this.services) 96 | if servicesLen > 0 { 97 | num := hash.GetHash([]byte(flag)) 98 | index := int(num % uint32(servicesLen)) 99 | service = this.services[index] 100 | } 101 | this.servicesMutex.Unlock() 102 | 103 | return service 104 | } 105 | 106 | func (this *Client) getLink(service string) *rpc.Client { 107 | //监测是否已经存在 108 | this.linkMutex.Lock() 109 | link, ok := this.links[service] 110 | this.linkMutex.Unlock() 111 | 112 | if ok { 113 | return link 114 | } 115 | 116 | //连接Rpc服务器 117 | conn, err := net.DialTimeout("tcp", service, time.Second*3) 118 | if err != nil { 119 | logger.Error("RpcServer Connect Fail", zap.String("Service", service)) 120 | return nil 121 | } else { 122 | logger.Info("RpcServer Connect Success", zap.String("Service", service)) 123 | } 124 | link = jsonrpc.NewClient(conn) 125 | 126 | //防止重复链接 127 | this.linkMutex.Lock() 128 | if link2, ok := this.links[service]; ok { 129 | link.Close() 130 | link = link2 131 | } else { 132 | this.links[service] = link 133 | } 134 | this.linkMutex.Unlock() 135 | 136 | return link 137 | } 138 | 139 | func (this *Client) removeLink(service string) { 140 | this.linkMutex.Lock() 141 | if link, ok := this.links[service]; ok { 142 | link.Close() 143 | delete(this.links, service) 144 | } 145 | this.linkMutex.Unlock() 146 | 147 | logger.Error("RpcServer Disconnected", zap.String("Service", service)) 148 | } 149 | 150 | func (this *Client) Call(serviceMethod string, args interface{}, reply interface{}, flag string) error { 151 | if flag == "" { 152 | flag = cast.ToString(time.Now().Unix()) 153 | } 154 | service := this.getServiceByFlag(flag) 155 | if service == "" { 156 | return errors.New("RpcServer No Exists") 157 | } 158 | 159 | link := this.getLink(service) 160 | if link == nil { 161 | this.removeService(service) 162 | return this.Call(serviceMethod, args, reply, flag) 163 | } 164 | 165 | err := link.Call(serviceMethod, args, reply) 166 | if err == io.ErrUnexpectedEOF || err == rpc.ErrShutdown { 167 | this.removeLink(service) 168 | return this.Call(serviceMethod, args, reply, flag) 169 | } 170 | return err 171 | } 172 | 173 | func (this *Client) CallAll(serviceMethod string, args interface{}, reply interface{}) { 174 | for _, value := range this.services { 175 | link := this.getLink(value) 176 | if link == nil { 177 | continue 178 | } 179 | 180 | err := link.Call(serviceMethod, args, reply) 181 | if err == io.ErrUnexpectedEOF || err == rpc.ErrShutdown { 182 | this.removeLink(value) 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /core/libs/grpc/client.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | "sync" 7 | "time" 8 | 9 | "github.com/yicaoyimuys/GoGameServer/core/libs/consul" 10 | "github.com/yicaoyimuys/GoGameServer/core/libs/hash" 11 | "github.com/yicaoyimuys/GoGameServer/core/libs/logger" 12 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 13 | "go.uber.org/zap" 14 | 15 | "github.com/spf13/cast" 16 | "golang.org/x/net/context" 17 | "google.golang.org/grpc" 18 | ) 19 | 20 | type Client struct { 21 | consulClient *consul.Client 22 | serviceName string 23 | 24 | services []string 25 | servicesMutex sync.Mutex 26 | 27 | links map[string]*grpc.ClientConn 28 | linkMutex sync.Mutex 29 | 30 | newPbClientFunc func(*grpc.ClientConn) interface{} 31 | } 32 | 33 | func NewClient(consulClient *consul.Client, serviceName string, newPbClientFunc func(*grpc.ClientConn) interface{}) *Client { 34 | client := &Client{ 35 | consulClient: consulClient, 36 | serviceName: serviceName, 37 | links: make(map[string]*grpc.ClientConn), 38 | newPbClientFunc: newPbClientFunc, 39 | } 40 | client.initServices() 41 | client.loop() 42 | return client 43 | } 44 | 45 | func (this *Client) loop() { 46 | timer.SetTimeOut(5*1000, this.initServices) 47 | } 48 | 49 | func (this *Client) initServices() { 50 | this.servicesMutex.Lock() 51 | this.services = this.consulClient.GetServices(this.serviceName) 52 | this.servicesMutex.Unlock() 53 | 54 | this.initLinks() 55 | this.traceServices() 56 | } 57 | 58 | func (this *Client) initLinks() { 59 | if len(this.services) == 0 { 60 | timer.SetTimeOut(300, this.initServices) 61 | return 62 | } 63 | 64 | if len(this.links) == 0 { 65 | for _, service := range this.services { 66 | this.getLink(service) 67 | } 68 | } 69 | } 70 | 71 | func (this *Client) traceServices() { 72 | return 73 | this.servicesMutex.Lock() 74 | logger.Debug("----------grpc start " + this.serviceName + "----------") 75 | for _, value := range this.services { 76 | logger.Debug("Service", zap.String("ServiceName", this.serviceName), zap.String("ServiceAddress", value)) 77 | } 78 | logger.Debug("-----------grpc end " + this.serviceName + "-----------") 79 | this.servicesMutex.Unlock() 80 | } 81 | 82 | func (this *Client) removeService(service string) { 83 | this.servicesMutex.Lock() 84 | for index, value := range this.services { 85 | if value == service { 86 | this.services = append(this.services[:index], this.services[index+1:]...) 87 | } 88 | } 89 | this.servicesMutex.Unlock() 90 | 91 | this.traceServices() 92 | } 93 | 94 | func (this *Client) GetServiceByFlag(flag string) string { 95 | this.servicesMutex.Lock() 96 | service := "" 97 | servicesLen := len(this.services) 98 | if servicesLen > 0 { 99 | num := hash.GetHash([]byte(flag)) 100 | index := int(num % uint32(servicesLen)) 101 | service = this.services[index] 102 | } 103 | this.servicesMutex.Unlock() 104 | 105 | return service 106 | } 107 | 108 | func (this *Client) GetServiceByRandom() string { 109 | return this.GetServiceByFlag(cast.ToString(time.Now().Unix())) 110 | } 111 | 112 | func (this *Client) getLink(service string) *grpc.ClientConn { 113 | //监测是否已经存在 114 | this.linkMutex.Lock() 115 | link, ok := this.links[service] 116 | this.linkMutex.Unlock() 117 | 118 | if ok { 119 | return link 120 | } 121 | 122 | //连接Rpc服务器 123 | link, err := grpc.Dial(service, grpc.WithInsecure()) 124 | if err != nil { 125 | logger.Error("GrpcServer Connect Fail", zap.String("Service", service)) 126 | return nil 127 | } else { 128 | logger.Info("GrpcServer Connect Success", zap.String("Service", service)) 129 | } 130 | 131 | //防止重复链接 132 | this.linkMutex.Lock() 133 | if link2, ok := this.links[service]; ok { 134 | link.Close() 135 | link = link2 136 | } else { 137 | this.links[service] = link 138 | } 139 | this.linkMutex.Unlock() 140 | 141 | return link 142 | } 143 | 144 | func (this *Client) removeLink(service string) { 145 | this.linkMutex.Lock() 146 | if link, ok := this.links[service]; ok { 147 | link.Close() 148 | delete(this.links, service) 149 | } 150 | this.linkMutex.Unlock() 151 | 152 | logger.Error("grpcServer disconnected", zap.String("Service", service)) 153 | } 154 | 155 | func (this *Client) Call(service string, serviceMethod string, arg interface{}) interface{} { 156 | //根据Service获取链接 157 | link := this.getLink(service) 158 | if link == nil { 159 | this.removeService(service) 160 | logger.Error("service not exists", zap.String("Service", service)) 161 | return nil 162 | } 163 | 164 | //创建PbClient 165 | client := this.newPbClientFunc(link) 166 | 167 | //创建调用serviceMethod所需要的参数 168 | mArgs := []reflect.Value{ 169 | reflect.ValueOf(context.Background()), 170 | } 171 | if arg != nil { 172 | mArgs = append(mArgs, reflect.ValueOf(arg)) 173 | } 174 | 175 | //调用serviceMethod 176 | clientReflect := reflect.ValueOf(client) 177 | serviceResult := clientReflect.MethodByName(serviceMethod).Call(mArgs) 178 | 179 | //结果 180 | reply := serviceResult[0].Interface() 181 | err := serviceResult[1].Interface() 182 | if err != nil && err.(error) == io.ErrUnexpectedEOF { 183 | this.removeLink(service) 184 | logger.Error("service is error", zap.String("Service", service)) 185 | return nil 186 | } 187 | 188 | return reply 189 | } 190 | -------------------------------------------------------------------------------- /servives/test/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/json" 6 | "io" 7 | "net" 8 | "net/http" 9 | "sync" 10 | "sync/atomic" 11 | 12 | "github.com/yicaoyimuys/GoGameServer/core/consts" 13 | . "github.com/yicaoyimuys/GoGameServer/core/libs" 14 | "github.com/yicaoyimuys/GoGameServer/core/libs/array" 15 | "github.com/yicaoyimuys/GoGameServer/core/libs/hash" 16 | "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 17 | "github.com/yicaoyimuys/GoGameServer/core/libs/random" 18 | "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 19 | "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 20 | "github.com/yicaoyimuys/GoGameServer/core/service" 21 | "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 22 | "go.uber.org/zap" 23 | 24 | "github.com/spf13/cast" 25 | "google.golang.org/protobuf/proto" 26 | ) 27 | 28 | var ( 29 | servers []string 30 | 31 | connectNum = 100 32 | userAccounts = []string{} 33 | ) 34 | 35 | func main() { 36 | //初始化Service 37 | service.NewService(consts.Service_Test) 38 | 39 | //请求服务器连接地址 40 | resp, err := http.Get("http://127.0.0.1:18881/GetConnector?type=Socket") 41 | if err != nil { 42 | ERR("请求服务器地址错误", zap.Error(err)) 43 | return 44 | } 45 | defer resp.Body.Close() 46 | body, err := io.ReadAll(resp.Body) 47 | if err != nil { 48 | ERR("请求服务器地址错误", zap.Error(err)) 49 | return 50 | } 51 | json.Unmarshal(body, &servers) 52 | for _, v := range servers { 53 | DEBUG(v) 54 | } 55 | 56 | //开始测试 57 | startTest() 58 | 59 | //保持进程 60 | Run() 61 | } 62 | 63 | func startTest() { 64 | //初始化使用账号 65 | initAccount() 66 | 67 | //开启链接 68 | for i := 0; i < len(userAccounts); i++ { 69 | go startConnect(userAccounts[i]) 70 | } 71 | } 72 | 73 | func initAccount() { 74 | for { 75 | account := "ys" + cast.ToString(random.RandIntn(10000)) 76 | if array.InArray(userAccounts, account) { 77 | continue 78 | } 79 | userAccounts = append(userAccounts, account) 80 | if len(userAccounts) == connectNum { 81 | break 82 | } 83 | } 84 | } 85 | 86 | func startConnect(account string) { 87 | hashCode := hash.GetHash([]byte(account)) 88 | 89 | var serverIndex = hashCode % uint32(len(servers)) 90 | var server = servers[serverIndex] 91 | //DEBUG(myUserId, serverIndex) 92 | 93 | //服务器端ip和端口 94 | addr, err := net.ResolveTCPAddr("tcp4", server) 95 | if err != nil { 96 | ERR("连接失败", zap.String("Account", account)) 97 | return 98 | } 99 | //申请连接客户端 100 | conn, err := net.DialTCP("tcp4", nil, addr) 101 | if err != nil { 102 | ERR("连接失败", zap.String("Account", account)) 103 | return 104 | } 105 | INFO("连接成功", zap.String("Account", account)) 106 | 107 | client := new(clientSession) 108 | client.con = conn 109 | client.account = account 110 | 111 | go client.receiveMsg() 112 | 113 | client.ping() 114 | client.login() 115 | } 116 | 117 | type clientSession struct { 118 | con *net.TCPConn 119 | account string 120 | token string 121 | pingTimerId *timer.TimerEvent 122 | chatTimerId *timer.TimerEvent 123 | closeFlag int32 124 | 125 | recvMutex sync.Mutex 126 | sendMutex sync.Mutex 127 | } 128 | 129 | // 关闭 130 | func (this *clientSession) close() { 131 | if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 132 | timer.Remove(this.pingTimerId) 133 | timer.Remove(this.chatTimerId) 134 | this.con.Close() 135 | DEBUG("连接关闭", zap.String("Account", this.account)) 136 | } 137 | } 138 | 139 | // 是否关闭 140 | func (this *clientSession) isClose() bool { 141 | return atomic.LoadInt32(&this.closeFlag) == 1 142 | } 143 | 144 | // 平台登录 145 | func (this *clientSession) login() { 146 | msg := &gameProto.UserLoginC2S{ 147 | Account: protos.String(this.account), 148 | } 149 | this.sendMsg(msg) 150 | } 151 | 152 | // 获取用户数据 153 | func (this *clientSession) getInfo() { 154 | msg := &gameProto.UserGetInfoC2S{ 155 | Token: protos.String(this.token), 156 | } 157 | this.sendMsg(msg) 158 | } 159 | 160 | // 心跳 161 | func (this *clientSession) ping() { 162 | this.pingTimerId = timer.DoTimer(2000, func() { 163 | var msg = &gameProto.ClientPingC2S{} 164 | this.sendMsg(msg) 165 | }) 166 | } 167 | 168 | // 加入聊天 169 | func (this *clientSession) joinChat() { 170 | var msg = &gameProto.UserJoinChatC2S{} 171 | msg.Token = protos.String(this.token) 172 | this.sendMsg(msg) 173 | } 174 | 175 | // 聊天 176 | func (this *clientSession) chat() { 177 | delay := random.RandIntRange(10000, 20000) 178 | this.chatTimerId = timer.DoTimer(uint32(delay), func() { 179 | var msg = &gameProto.UserChatC2S{} 180 | msg.Msg = protos.String("你好啊" + cast.ToString(delay)) 181 | this.sendMsg(msg) 182 | }) 183 | } 184 | 185 | // 接收消息 186 | func (this *clientSession) receiveMsg() { 187 | defer stack.TryError() 188 | 189 | for { 190 | if this.isClose() { 191 | break 192 | } 193 | 194 | //消息头 195 | msgHead := make([]byte, 2) 196 | if _, err := io.ReadFull(this.con, msgHead); err != nil { 197 | ERR("read1", zap.Error(err)) 198 | break 199 | } 200 | msgLen := binary.BigEndian.Uint16(msgHead) 201 | 202 | //消息内容 203 | msgBody := make([]byte, msgLen) 204 | if _, err := io.ReadFull(this.con, msgBody); err != nil { 205 | ERR("read2", zap.Error(err)) 206 | break 207 | } 208 | 209 | //消息解析 210 | protoMsg := protos.UnmarshalProtoMsg(msgBody) 211 | if protoMsg == protos.NullProtoMsg { 212 | ERR("收到错误消息ID", zap.Uint16("MsgId", protos.UnmarshalProtoId(msgBody))) 213 | break 214 | } 215 | DEBUG("收到消息ID", zap.String("Account", this.account), zap.Uint16("MsgId", protoMsg.ID)) 216 | 217 | //消息处理 218 | this.handleMsg(protoMsg.ID, protoMsg.Body) 219 | } 220 | this.close() 221 | } 222 | 223 | func (this *clientSession) handleMsg(msgId uint16, msgData proto.Message) { 224 | defer stack.TryError() 225 | 226 | if msgId == gameProto.ID_user_login_s2c { 227 | //登录成功 228 | data := msgData.(*gameProto.UserLoginS2C) 229 | this.token = data.GetToken() 230 | DEBUG("登录成功", zap.String("Token", this.token)) 231 | //获取用户数据 232 | this.getInfo() 233 | } else if msgId == gameProto.ID_user_getInfo_s2c { 234 | //获取用户信息成功 235 | data := msgData.(*gameProto.UserGetInfoS2C) 236 | DEBUG("用户信息", zap.Any("Data", data.GetData())) 237 | //加入聊天 238 | this.joinChat() 239 | } else if msgId == gameProto.ID_user_joinChat_s2c { 240 | //加入聊天成功 241 | DEBUG("加入聊天成功") 242 | //开始聊天 243 | this.chat() 244 | } else if msgId == gameProto.ID_user_chat_notice_s2c { 245 | //收到聊天消息 246 | data := msgData.(*gameProto.UserChatNoticeS2C) 247 | DEBUG("收到聊天消息", zap.String("Account", this.account), zap.String("Message", data.GetUserName()+"说:"+data.GetMsg())) 248 | } else if msgId == gameProto.ID_error_notice_s2c { 249 | data := msgData.(*gameProto.ErrorNoticeS2C) 250 | errCode := data.GetErrorCode() 251 | if errCode == consts.ErrCode_SystemError { 252 | //系统服务错误 253 | this.close() 254 | //重新连接 255 | timer.SetTimeOut(3000, func() { 256 | go startConnect(this.account) 257 | }) 258 | } 259 | DEBUG("收到错误消息", zap.Any("Data", data)) 260 | } 261 | } 262 | 263 | func (this *clientSession) sendMsg(msg proto.Message) { 264 | if this.isClose() { 265 | return 266 | } 267 | 268 | defer stack.TryError() 269 | 270 | this.sendMutex.Lock() 271 | defer this.sendMutex.Unlock() 272 | 273 | msgBytes := protos.MarshalProtoMsg(msg) 274 | 275 | msgLen := uint16(len(msgBytes)) 276 | sendMsg := make([]byte, msgLen+2) 277 | binary.BigEndian.PutUint16(sendMsg[:2], msgLen) 278 | copy(sendMsg[2:], msgBytes) 279 | 280 | this.con.Write(sendMsg) 281 | } 282 | -------------------------------------------------------------------------------- /core/libs/grpc/ipc/ipc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.1 4 | // protoc v3.14.0 5 | // source: ipc.proto 6 | 7 | package ipc 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Req struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | ServiceIdentify string `protobuf:"bytes,1,opt,name=serviceIdentify,proto3" json:"serviceIdentify,omitempty"` 29 | UserSessionId uint64 `protobuf:"varint,2,opt,name=userSessionId,proto3" json:"userSessionId,omitempty"` 30 | Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` 31 | } 32 | 33 | func (x *Req) Reset() { 34 | *x = Req{} 35 | if protoimpl.UnsafeEnabled { 36 | mi := &file_ipc_proto_msgTypes[0] 37 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 38 | ms.StoreMessageInfo(mi) 39 | } 40 | } 41 | 42 | func (x *Req) String() string { 43 | return protoimpl.X.MessageStringOf(x) 44 | } 45 | 46 | func (*Req) ProtoMessage() {} 47 | 48 | func (x *Req) ProtoReflect() protoreflect.Message { 49 | mi := &file_ipc_proto_msgTypes[0] 50 | if protoimpl.UnsafeEnabled && x != nil { 51 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 52 | if ms.LoadMessageInfo() == nil { 53 | ms.StoreMessageInfo(mi) 54 | } 55 | return ms 56 | } 57 | return mi.MessageOf(x) 58 | } 59 | 60 | // Deprecated: Use Req.ProtoReflect.Descriptor instead. 61 | func (*Req) Descriptor() ([]byte, []int) { 62 | return file_ipc_proto_rawDescGZIP(), []int{0} 63 | } 64 | 65 | func (x *Req) GetServiceIdentify() string { 66 | if x != nil { 67 | return x.ServiceIdentify 68 | } 69 | return "" 70 | } 71 | 72 | func (x *Req) GetUserSessionId() uint64 { 73 | if x != nil { 74 | return x.UserSessionId 75 | } 76 | return 0 77 | } 78 | 79 | func (x *Req) GetData() []byte { 80 | if x != nil { 81 | return x.Data 82 | } 83 | return nil 84 | } 85 | 86 | type Res struct { 87 | state protoimpl.MessageState 88 | sizeCache protoimpl.SizeCache 89 | unknownFields protoimpl.UnknownFields 90 | 91 | UserSessionIds []uint64 `protobuf:"varint,1,rep,packed,name=userSessionIds,proto3" json:"userSessionIds,omitempty"` 92 | Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` 93 | } 94 | 95 | func (x *Res) Reset() { 96 | *x = Res{} 97 | if protoimpl.UnsafeEnabled { 98 | mi := &file_ipc_proto_msgTypes[1] 99 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 100 | ms.StoreMessageInfo(mi) 101 | } 102 | } 103 | 104 | func (x *Res) String() string { 105 | return protoimpl.X.MessageStringOf(x) 106 | } 107 | 108 | func (*Res) ProtoMessage() {} 109 | 110 | func (x *Res) ProtoReflect() protoreflect.Message { 111 | mi := &file_ipc_proto_msgTypes[1] 112 | if protoimpl.UnsafeEnabled && x != nil { 113 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 114 | if ms.LoadMessageInfo() == nil { 115 | ms.StoreMessageInfo(mi) 116 | } 117 | return ms 118 | } 119 | return mi.MessageOf(x) 120 | } 121 | 122 | // Deprecated: Use Res.ProtoReflect.Descriptor instead. 123 | func (*Res) Descriptor() ([]byte, []int) { 124 | return file_ipc_proto_rawDescGZIP(), []int{1} 125 | } 126 | 127 | func (x *Res) GetUserSessionIds() []uint64 { 128 | if x != nil { 129 | return x.UserSessionIds 130 | } 131 | return nil 132 | } 133 | 134 | func (x *Res) GetData() []byte { 135 | if x != nil { 136 | return x.Data 137 | } 138 | return nil 139 | } 140 | 141 | var File_ipc_proto protoreflect.FileDescriptor 142 | 143 | var file_ipc_proto_rawDesc = []byte{ 144 | 0x0a, 0x09, 0x69, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x69, 0x0a, 0x03, 0x52, 145 | 0x65, 0x71, 0x12, 0x28, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 146 | 0x6e, 0x74, 0x69, 0x66, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x72, 147 | 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x12, 0x24, 0x0a, 0x0d, 148 | 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 149 | 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 150 | 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 151 | 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x41, 0x0a, 0x03, 0x52, 0x65, 0x73, 0x12, 0x26, 0x0a, 152 | 0x0e, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x18, 153 | 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 154 | 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 155 | 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x23, 0x0a, 0x03, 0x49, 0x70, 0x63, 156 | 0x12, 0x1c, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x04, 0x2e, 0x52, 157 | 0x65, 0x71, 0x1a, 0x04, 0x2e, 0x52, 0x65, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x07, 158 | 0x5a, 0x05, 0x2e, 0x3b, 0x69, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 159 | } 160 | 161 | var ( 162 | file_ipc_proto_rawDescOnce sync.Once 163 | file_ipc_proto_rawDescData = file_ipc_proto_rawDesc 164 | ) 165 | 166 | func file_ipc_proto_rawDescGZIP() []byte { 167 | file_ipc_proto_rawDescOnce.Do(func() { 168 | file_ipc_proto_rawDescData = protoimpl.X.CompressGZIP(file_ipc_proto_rawDescData) 169 | }) 170 | return file_ipc_proto_rawDescData 171 | } 172 | 173 | var file_ipc_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 174 | var file_ipc_proto_goTypes = []interface{}{ 175 | (*Req)(nil), // 0: Req 176 | (*Res)(nil), // 1: Res 177 | } 178 | var file_ipc_proto_depIdxs = []int32{ 179 | 0, // 0: Ipc.Transfer:input_type -> Req 180 | 1, // 1: Ipc.Transfer:output_type -> Res 181 | 1, // [1:2] is the sub-list for method output_type 182 | 0, // [0:1] is the sub-list for method input_type 183 | 0, // [0:0] is the sub-list for extension type_name 184 | 0, // [0:0] is the sub-list for extension extendee 185 | 0, // [0:0] is the sub-list for field type_name 186 | } 187 | 188 | func init() { file_ipc_proto_init() } 189 | func file_ipc_proto_init() { 190 | if File_ipc_proto != nil { 191 | return 192 | } 193 | if !protoimpl.UnsafeEnabled { 194 | file_ipc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 195 | switch v := v.(*Req); i { 196 | case 0: 197 | return &v.state 198 | case 1: 199 | return &v.sizeCache 200 | case 2: 201 | return &v.unknownFields 202 | default: 203 | return nil 204 | } 205 | } 206 | file_ipc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 207 | switch v := v.(*Res); i { 208 | case 0: 209 | return &v.state 210 | case 1: 211 | return &v.sizeCache 212 | case 2: 213 | return &v.unknownFields 214 | default: 215 | return nil 216 | } 217 | } 218 | } 219 | type x struct{} 220 | out := protoimpl.TypeBuilder{ 221 | File: protoimpl.DescBuilder{ 222 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 223 | RawDescriptor: file_ipc_proto_rawDesc, 224 | NumEnums: 0, 225 | NumMessages: 2, 226 | NumExtensions: 0, 227 | NumServices: 1, 228 | }, 229 | GoTypes: file_ipc_proto_goTypes, 230 | DependencyIndexes: file_ipc_proto_depIdxs, 231 | MessageInfos: file_ipc_proto_msgTypes, 232 | }.Build() 233 | File_ipc_proto = out.File 234 | file_ipc_proto_rawDesc = nil 235 | file_ipc_proto_goTypes = nil 236 | file_ipc_proto_depIdxs = nil 237 | } 238 | -------------------------------------------------------------------------------- /servives/test/main_ws.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // import ( 4 | // "crypto/tls" 5 | // "encoding/binary" 6 | // "encoding/json" 7 | // "io" 8 | // "net/http" 9 | // "net/url" 10 | // "sync" 11 | // "sync/atomic" 12 | 13 | // "github.com/yicaoyimuys/GoGameServer/core/consts" 14 | // . "github.com/yicaoyimuys/GoGameServer/core/libs" 15 | // "github.com/yicaoyimuys/GoGameServer/core/libs/array" 16 | // "github.com/yicaoyimuys/GoGameServer/core/libs/hash" 17 | // "github.com/yicaoyimuys/GoGameServer/core/libs/protos" 18 | // "github.com/yicaoyimuys/GoGameServer/core/libs/random" 19 | // "github.com/yicaoyimuys/GoGameServer/core/libs/stack" 20 | // "github.com/yicaoyimuys/GoGameServer/core/libs/timer" 21 | // "github.com/yicaoyimuys/GoGameServer/core/service" 22 | // "github.com/yicaoyimuys/GoGameServer/servives/public/gameProto" 23 | // "go.uber.org/zap" 24 | 25 | // "github.com/gorilla/websocket" 26 | // "github.com/spf13/cast" 27 | // "google.golang.org/protobuf/proto" 28 | // ) 29 | 30 | // var ( 31 | // servers []string 32 | 33 | // connectNum = 100 34 | // userAccounts = []string{} 35 | // ) 36 | 37 | // func main() { 38 | // //初始化Service 39 | // service.NewService(consts.Service_Test) 40 | 41 | // //请求服务器连接地址 42 | // resp, err := http.Get("http://127.0.0.1:18881/GetConnector?type=WebSocket") 43 | // if err != nil { 44 | // ERR("请求服务器连接地址错误", zap.Error(err)) 45 | // return 46 | // } 47 | // defer resp.Body.Close() 48 | // body, err := io.ReadAll(resp.Body) 49 | // if err != nil { 50 | // ERR("请求服务器连接地址错误", zap.Error(err)) 51 | // return 52 | // } 53 | // json.Unmarshal(body, &servers) 54 | // for _, v := range servers { 55 | // DEBUG(v) 56 | // } 57 | 58 | // //开始测试 59 | // startTest() 60 | 61 | // //保持进程 62 | // Run() 63 | // } 64 | 65 | // func startTest() { 66 | // //初始化使用账号 67 | // initAccount() 68 | 69 | // //开启链接 70 | // for i := 0; i < len(userAccounts); i++ { 71 | // go startConnect(userAccounts[i]) 72 | // } 73 | // } 74 | 75 | // func initAccount() { 76 | // for { 77 | // account := "ys" + cast.ToString(random.RandIntn(10000)) 78 | // if array.InArray(userAccounts, account) { 79 | // continue 80 | // } 81 | // userAccounts = append(userAccounts, account) 82 | // if len(userAccounts) == connectNum { 83 | // break 84 | // } 85 | // } 86 | // } 87 | 88 | // func startConnect(account string) { 89 | // hashCode := hash.GetHash([]byte(account)) 90 | 91 | // var serverIndex = hashCode % uint32(len(servers)) 92 | // var server = servers[serverIndex] 93 | // //DEBUG(myUserId, serverIndex) 94 | 95 | // scheme := "ws" 96 | // u := url.URL{Scheme: scheme, Host: server, Path: "/"} 97 | // d := websocket.DefaultDialer 98 | // d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 99 | // c, _, err := d.Dial(u.String(), nil) 100 | // if err != nil { 101 | // ERR("连接失败", zap.String("Account", account)) 102 | // return 103 | // } 104 | 105 | // INFO("连接成功", zap.String("Account", account)) 106 | 107 | // client := new(clientSession) 108 | // client.con = c 109 | // client.account = account 110 | 111 | // go client.receiveMsg() 112 | 113 | // client.ping() 114 | // client.login() 115 | // } 116 | 117 | // type clientSession struct { 118 | // con *websocket.Conn 119 | // account string 120 | // token string 121 | // pingTimerId *timer.TimerEvent 122 | // chatTimerId *timer.TimerEvent 123 | // closeFlag int32 124 | 125 | // recvMutex sync.Mutex 126 | // sendMutex sync.Mutex 127 | // } 128 | 129 | // // 关闭 130 | // func (this *clientSession) close() { 131 | // if atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) { 132 | // timer.Remove(this.pingTimerId) 133 | // timer.Remove(this.chatTimerId) 134 | // this.con.Close() 135 | // DEBUG("连接关闭", zap.String("Account", this.account)) 136 | // } 137 | // } 138 | 139 | // // 是否关闭 140 | // func (this *clientSession) isClose() bool { 141 | // return atomic.LoadInt32(&this.closeFlag) == 1 142 | // } 143 | 144 | // // 平台登录 145 | // func (this *clientSession) login() { 146 | // msg := &gameProto.UserLoginC2S{ 147 | // Account: protos.String(this.account), 148 | // } 149 | // this.sendMsg(msg) 150 | // } 151 | 152 | // // 获取用户数据 153 | // func (this *clientSession) getInfo() { 154 | // msg := &gameProto.UserGetInfoC2S{ 155 | // Token: protos.String(this.token), 156 | // } 157 | // this.sendMsg(msg) 158 | // } 159 | 160 | // // 心跳 161 | // func (this *clientSession) ping() { 162 | // this.pingTimerId = timer.DoTimer(2000, func() { 163 | // var msg = &gameProto.ClientPingC2S{} 164 | // this.sendMsg(msg) 165 | // }) 166 | // } 167 | 168 | // // 加入聊天 169 | // func (this *clientSession) joinChat() { 170 | // var msg = &gameProto.UserJoinChatC2S{} 171 | // msg.Token = protos.String(this.token) 172 | // this.sendMsg(msg) 173 | // } 174 | 175 | // // 聊天 176 | // func (this *clientSession) chat() { 177 | // delay := random.RandIntRange(10000, 20000) 178 | // this.chatTimerId = timer.DoTimer(uint32(delay), func() { 179 | // var msg = &gameProto.UserChatC2S{} 180 | // msg.Msg = protos.String("你好啊") 181 | // this.sendMsg(msg) 182 | // }) 183 | // } 184 | 185 | // // 接收消息 186 | // func (this *clientSession) receiveMsg() { 187 | // defer stack.TryError() 188 | 189 | // for { 190 | // if this.isClose() { 191 | // break 192 | // } 193 | 194 | // _, message, err := this.con.ReadMessage() 195 | // if err != nil { 196 | // ERR("read", zap.Error(err)) 197 | // break 198 | // } 199 | 200 | // //消息内容 201 | // msgBody := message[2:] 202 | // //消息解析 203 | // protoMsg := protos.UnmarshalProtoMsg(msgBody) 204 | // if protoMsg == protos.NullProtoMsg { 205 | // ERR("收到错误消息ID", zap.Uint16("MsgId", protos.UnmarshalProtoId(msgBody))) 206 | // break 207 | // } 208 | // DEBUG("收到消息ID", zap.String("Account", this.account), zap.Uint16("MsgId", protoMsg.ID)) 209 | // //消息处理 210 | // this.handleMsg(protoMsg.ID, protoMsg.Body) 211 | // } 212 | // this.close() 213 | // } 214 | 215 | // func (this *clientSession) handleMsg(msgId uint16, msgData proto.Message) { 216 | // defer stack.TryError() 217 | 218 | // if msgId == gameProto.ID_user_login_s2c { 219 | // //登录成功 220 | // data := msgData.(*gameProto.UserLoginS2C) 221 | // this.token = data.GetToken() 222 | // DEBUG("登录成功", zap.String("Token", this.token)) 223 | // //获取用户数据 224 | // this.getInfo() 225 | // } else if msgId == gameProto.ID_user_getInfo_s2c { 226 | // //获取用户信息成功 227 | // data := msgData.(*gameProto.UserGetInfoS2C) 228 | // DEBUG("用户信息", zap.Any("Data", data.GetData())) 229 | // //加入聊天 230 | // this.joinChat() 231 | // } else if msgId == gameProto.ID_user_joinChat_s2c { 232 | // //加入聊天成功 233 | // DEBUG("加入聊天成功") 234 | // //开始聊天 235 | // this.chat() 236 | // } else if msgId == gameProto.ID_user_chat_notice_s2c { 237 | // //收到聊天消息 238 | // data := msgData.(*gameProto.UserChatNoticeS2C) 239 | // DEBUG("收到聊天消息", zap.String("Account", this.account), zap.String("Message", data.GetUserName()+"说:"+data.GetMsg())) 240 | // } else if msgId == gameProto.ID_error_notice_s2c { 241 | // data := msgData.(*gameProto.ErrorNoticeS2C) 242 | // errCode := data.GetErrorCode() 243 | // if errCode == consts.ErrCode_SystemError { 244 | // //系统服务错误 245 | // this.close() 246 | // //重新连接 247 | // timer.SetTimeOut(3000, func() { 248 | // go startConnect(this.account) 249 | // }) 250 | // } 251 | // DEBUG("收到错误消息", zap.Any("Data", data)) 252 | // } 253 | // } 254 | 255 | // func (this *clientSession) sendMsg(msg proto.Message) { 256 | // if this.isClose() { 257 | // return 258 | // } 259 | 260 | // defer stack.TryError() 261 | 262 | // this.sendMutex.Lock() 263 | // defer this.sendMutex.Unlock() 264 | 265 | // msgBytes := protos.MarshalProtoMsg(msg) 266 | 267 | // msgLen := uint16(len(msgBytes)) 268 | // sendMsg := make([]byte, msgLen+2) 269 | // binary.BigEndian.PutUint16(sendMsg[:2], msgLen) 270 | // copy(sendMsg[2:], msgBytes) 271 | 272 | // this.con.WriteMessage(websocket.BinaryMessage, sendMsg) 273 | // } 274 | -------------------------------------------------------------------------------- /servives/public/gameProto/gameProto.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.1 4 | // protoc v3.14.0 5 | // source: gameProto.proto 6 | 7 | package gameProto 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | //错误消息(500) 24 | type ErrorNoticeS2C struct { 25 | state protoimpl.MessageState 26 | sizeCache protoimpl.SizeCache 27 | unknownFields protoimpl.UnknownFields 28 | 29 | ErrorCode *int32 `protobuf:"varint,1,req,name=errorCode" json:"errorCode,omitempty"` 30 | } 31 | 32 | func (x *ErrorNoticeS2C) Reset() { 33 | *x = ErrorNoticeS2C{} 34 | if protoimpl.UnsafeEnabled { 35 | mi := &file_gameProto_proto_msgTypes[0] 36 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 37 | ms.StoreMessageInfo(mi) 38 | } 39 | } 40 | 41 | func (x *ErrorNoticeS2C) String() string { 42 | return protoimpl.X.MessageStringOf(x) 43 | } 44 | 45 | func (*ErrorNoticeS2C) ProtoMessage() {} 46 | 47 | func (x *ErrorNoticeS2C) ProtoReflect() protoreflect.Message { 48 | mi := &file_gameProto_proto_msgTypes[0] 49 | if protoimpl.UnsafeEnabled && x != nil { 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | if ms.LoadMessageInfo() == nil { 52 | ms.StoreMessageInfo(mi) 53 | } 54 | return ms 55 | } 56 | return mi.MessageOf(x) 57 | } 58 | 59 | // Deprecated: Use ErrorNoticeS2C.ProtoReflect.Descriptor instead. 60 | func (*ErrorNoticeS2C) Descriptor() ([]byte, []int) { 61 | return file_gameProto_proto_rawDescGZIP(), []int{0} 62 | } 63 | 64 | func (x *ErrorNoticeS2C) GetErrorCode() int32 { 65 | if x != nil && x.ErrorCode != nil { 66 | return *x.ErrorCode 67 | } 68 | return 0 69 | } 70 | 71 | //客户端ping(1001) 72 | type ClientPingC2S struct { 73 | state protoimpl.MessageState 74 | sizeCache protoimpl.SizeCache 75 | unknownFields protoimpl.UnknownFields 76 | } 77 | 78 | func (x *ClientPingC2S) Reset() { 79 | *x = ClientPingC2S{} 80 | if protoimpl.UnsafeEnabled { 81 | mi := &file_gameProto_proto_msgTypes[1] 82 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 83 | ms.StoreMessageInfo(mi) 84 | } 85 | } 86 | 87 | func (x *ClientPingC2S) String() string { 88 | return protoimpl.X.MessageStringOf(x) 89 | } 90 | 91 | func (*ClientPingC2S) ProtoMessage() {} 92 | 93 | func (x *ClientPingC2S) ProtoReflect() protoreflect.Message { 94 | mi := &file_gameProto_proto_msgTypes[1] 95 | if protoimpl.UnsafeEnabled && x != nil { 96 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 97 | if ms.LoadMessageInfo() == nil { 98 | ms.StoreMessageInfo(mi) 99 | } 100 | return ms 101 | } 102 | return mi.MessageOf(x) 103 | } 104 | 105 | // Deprecated: Use ClientPingC2S.ProtoReflect.Descriptor instead. 106 | func (*ClientPingC2S) Descriptor() ([]byte, []int) { 107 | return file_gameProto_proto_rawDescGZIP(), []int{1} 108 | } 109 | 110 | //用户登录C2S(2001) 111 | type UserLoginC2S struct { 112 | state protoimpl.MessageState 113 | sizeCache protoimpl.SizeCache 114 | unknownFields protoimpl.UnknownFields 115 | 116 | Account *string `protobuf:"bytes,1,req,name=account" json:"account,omitempty"` 117 | } 118 | 119 | func (x *UserLoginC2S) Reset() { 120 | *x = UserLoginC2S{} 121 | if protoimpl.UnsafeEnabled { 122 | mi := &file_gameProto_proto_msgTypes[2] 123 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 124 | ms.StoreMessageInfo(mi) 125 | } 126 | } 127 | 128 | func (x *UserLoginC2S) String() string { 129 | return protoimpl.X.MessageStringOf(x) 130 | } 131 | 132 | func (*UserLoginC2S) ProtoMessage() {} 133 | 134 | func (x *UserLoginC2S) ProtoReflect() protoreflect.Message { 135 | mi := &file_gameProto_proto_msgTypes[2] 136 | if protoimpl.UnsafeEnabled && x != nil { 137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 138 | if ms.LoadMessageInfo() == nil { 139 | ms.StoreMessageInfo(mi) 140 | } 141 | return ms 142 | } 143 | return mi.MessageOf(x) 144 | } 145 | 146 | // Deprecated: Use UserLoginC2S.ProtoReflect.Descriptor instead. 147 | func (*UserLoginC2S) Descriptor() ([]byte, []int) { 148 | return file_gameProto_proto_rawDescGZIP(), []int{2} 149 | } 150 | 151 | func (x *UserLoginC2S) GetAccount() string { 152 | if x != nil && x.Account != nil { 153 | return *x.Account 154 | } 155 | return "" 156 | } 157 | 158 | //用户登录S2C(2002) 159 | type UserLoginS2C struct { 160 | state protoimpl.MessageState 161 | sizeCache protoimpl.SizeCache 162 | unknownFields protoimpl.UnknownFields 163 | 164 | Token *string `protobuf:"bytes,1,req,name=token" json:"token,omitempty"` 165 | } 166 | 167 | func (x *UserLoginS2C) Reset() { 168 | *x = UserLoginS2C{} 169 | if protoimpl.UnsafeEnabled { 170 | mi := &file_gameProto_proto_msgTypes[3] 171 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 172 | ms.StoreMessageInfo(mi) 173 | } 174 | } 175 | 176 | func (x *UserLoginS2C) String() string { 177 | return protoimpl.X.MessageStringOf(x) 178 | } 179 | 180 | func (*UserLoginS2C) ProtoMessage() {} 181 | 182 | func (x *UserLoginS2C) ProtoReflect() protoreflect.Message { 183 | mi := &file_gameProto_proto_msgTypes[3] 184 | if protoimpl.UnsafeEnabled && x != nil { 185 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 186 | if ms.LoadMessageInfo() == nil { 187 | ms.StoreMessageInfo(mi) 188 | } 189 | return ms 190 | } 191 | return mi.MessageOf(x) 192 | } 193 | 194 | // Deprecated: Use UserLoginS2C.ProtoReflect.Descriptor instead. 195 | func (*UserLoginS2C) Descriptor() ([]byte, []int) { 196 | return file_gameProto_proto_rawDescGZIP(), []int{3} 197 | } 198 | 199 | func (x *UserLoginS2C) GetToken() string { 200 | if x != nil && x.Token != nil { 201 | return *x.Token 202 | } 203 | return "" 204 | } 205 | 206 | //其他客户端登录S2C(2004) 207 | type UserOtherLoginNoticeS2C struct { 208 | state protoimpl.MessageState 209 | sizeCache protoimpl.SizeCache 210 | unknownFields protoimpl.UnknownFields 211 | } 212 | 213 | func (x *UserOtherLoginNoticeS2C) Reset() { 214 | *x = UserOtherLoginNoticeS2C{} 215 | if protoimpl.UnsafeEnabled { 216 | mi := &file_gameProto_proto_msgTypes[4] 217 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 218 | ms.StoreMessageInfo(mi) 219 | } 220 | } 221 | 222 | func (x *UserOtherLoginNoticeS2C) String() string { 223 | return protoimpl.X.MessageStringOf(x) 224 | } 225 | 226 | func (*UserOtherLoginNoticeS2C) ProtoMessage() {} 227 | 228 | func (x *UserOtherLoginNoticeS2C) ProtoReflect() protoreflect.Message { 229 | mi := &file_gameProto_proto_msgTypes[4] 230 | if protoimpl.UnsafeEnabled && x != nil { 231 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 232 | if ms.LoadMessageInfo() == nil { 233 | ms.StoreMessageInfo(mi) 234 | } 235 | return ms 236 | } 237 | return mi.MessageOf(x) 238 | } 239 | 240 | // Deprecated: Use UserOtherLoginNoticeS2C.ProtoReflect.Descriptor instead. 241 | func (*UserOtherLoginNoticeS2C) Descriptor() ([]byte, []int) { 242 | return file_gameProto_proto_rawDescGZIP(), []int{4} 243 | } 244 | 245 | //用户数据 246 | type UserInfo struct { 247 | state protoimpl.MessageState 248 | sizeCache protoimpl.SizeCache 249 | unknownFields protoimpl.UnknownFields 250 | 251 | Id *uint64 `protobuf:"varint,1,req,name=id" json:"id,omitempty"` 252 | Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"` 253 | Money *int32 `protobuf:"varint,3,req,name=money" json:"money,omitempty"` 254 | } 255 | 256 | func (x *UserInfo) Reset() { 257 | *x = UserInfo{} 258 | if protoimpl.UnsafeEnabled { 259 | mi := &file_gameProto_proto_msgTypes[5] 260 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 261 | ms.StoreMessageInfo(mi) 262 | } 263 | } 264 | 265 | func (x *UserInfo) String() string { 266 | return protoimpl.X.MessageStringOf(x) 267 | } 268 | 269 | func (*UserInfo) ProtoMessage() {} 270 | 271 | func (x *UserInfo) ProtoReflect() protoreflect.Message { 272 | mi := &file_gameProto_proto_msgTypes[5] 273 | if protoimpl.UnsafeEnabled && x != nil { 274 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 275 | if ms.LoadMessageInfo() == nil { 276 | ms.StoreMessageInfo(mi) 277 | } 278 | return ms 279 | } 280 | return mi.MessageOf(x) 281 | } 282 | 283 | // Deprecated: Use UserInfo.ProtoReflect.Descriptor instead. 284 | func (*UserInfo) Descriptor() ([]byte, []int) { 285 | return file_gameProto_proto_rawDescGZIP(), []int{5} 286 | } 287 | 288 | func (x *UserInfo) GetId() uint64 { 289 | if x != nil && x.Id != nil { 290 | return *x.Id 291 | } 292 | return 0 293 | } 294 | 295 | func (x *UserInfo) GetName() string { 296 | if x != nil && x.Name != nil { 297 | return *x.Name 298 | } 299 | return "" 300 | } 301 | 302 | func (x *UserInfo) GetMoney() int32 { 303 | if x != nil && x.Money != nil { 304 | return *x.Money 305 | } 306 | return 0 307 | } 308 | 309 | //获取用户信息C2S(3001) 310 | type UserGetInfoC2S struct { 311 | state protoimpl.MessageState 312 | sizeCache protoimpl.SizeCache 313 | unknownFields protoimpl.UnknownFields 314 | 315 | Token *string `protobuf:"bytes,1,req,name=token" json:"token,omitempty"` 316 | } 317 | 318 | func (x *UserGetInfoC2S) Reset() { 319 | *x = UserGetInfoC2S{} 320 | if protoimpl.UnsafeEnabled { 321 | mi := &file_gameProto_proto_msgTypes[6] 322 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 323 | ms.StoreMessageInfo(mi) 324 | } 325 | } 326 | 327 | func (x *UserGetInfoC2S) String() string { 328 | return protoimpl.X.MessageStringOf(x) 329 | } 330 | 331 | func (*UserGetInfoC2S) ProtoMessage() {} 332 | 333 | func (x *UserGetInfoC2S) ProtoReflect() protoreflect.Message { 334 | mi := &file_gameProto_proto_msgTypes[6] 335 | if protoimpl.UnsafeEnabled && x != nil { 336 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 337 | if ms.LoadMessageInfo() == nil { 338 | ms.StoreMessageInfo(mi) 339 | } 340 | return ms 341 | } 342 | return mi.MessageOf(x) 343 | } 344 | 345 | // Deprecated: Use UserGetInfoC2S.ProtoReflect.Descriptor instead. 346 | func (*UserGetInfoC2S) Descriptor() ([]byte, []int) { 347 | return file_gameProto_proto_rawDescGZIP(), []int{6} 348 | } 349 | 350 | func (x *UserGetInfoC2S) GetToken() string { 351 | if x != nil && x.Token != nil { 352 | return *x.Token 353 | } 354 | return "" 355 | } 356 | 357 | //获取用户信息S2C(3002) 358 | type UserGetInfoS2C struct { 359 | state protoimpl.MessageState 360 | sizeCache protoimpl.SizeCache 361 | unknownFields protoimpl.UnknownFields 362 | 363 | Data *UserInfo `protobuf:"bytes,1,req,name=data" json:"data,omitempty"` 364 | } 365 | 366 | func (x *UserGetInfoS2C) Reset() { 367 | *x = UserGetInfoS2C{} 368 | if protoimpl.UnsafeEnabled { 369 | mi := &file_gameProto_proto_msgTypes[7] 370 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 371 | ms.StoreMessageInfo(mi) 372 | } 373 | } 374 | 375 | func (x *UserGetInfoS2C) String() string { 376 | return protoimpl.X.MessageStringOf(x) 377 | } 378 | 379 | func (*UserGetInfoS2C) ProtoMessage() {} 380 | 381 | func (x *UserGetInfoS2C) ProtoReflect() protoreflect.Message { 382 | mi := &file_gameProto_proto_msgTypes[7] 383 | if protoimpl.UnsafeEnabled && x != nil { 384 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 385 | if ms.LoadMessageInfo() == nil { 386 | ms.StoreMessageInfo(mi) 387 | } 388 | return ms 389 | } 390 | return mi.MessageOf(x) 391 | } 392 | 393 | // Deprecated: Use UserGetInfoS2C.ProtoReflect.Descriptor instead. 394 | func (*UserGetInfoS2C) Descriptor() ([]byte, []int) { 395 | return file_gameProto_proto_rawDescGZIP(), []int{7} 396 | } 397 | 398 | func (x *UserGetInfoS2C) GetData() *UserInfo { 399 | if x != nil { 400 | return x.Data 401 | } 402 | return nil 403 | } 404 | 405 | //用户加入聊天C2S(4001) 406 | type UserJoinChatC2S struct { 407 | state protoimpl.MessageState 408 | sizeCache protoimpl.SizeCache 409 | unknownFields protoimpl.UnknownFields 410 | 411 | Token *string `protobuf:"bytes,1,req,name=token" json:"token,omitempty"` 412 | } 413 | 414 | func (x *UserJoinChatC2S) Reset() { 415 | *x = UserJoinChatC2S{} 416 | if protoimpl.UnsafeEnabled { 417 | mi := &file_gameProto_proto_msgTypes[8] 418 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 419 | ms.StoreMessageInfo(mi) 420 | } 421 | } 422 | 423 | func (x *UserJoinChatC2S) String() string { 424 | return protoimpl.X.MessageStringOf(x) 425 | } 426 | 427 | func (*UserJoinChatC2S) ProtoMessage() {} 428 | 429 | func (x *UserJoinChatC2S) ProtoReflect() protoreflect.Message { 430 | mi := &file_gameProto_proto_msgTypes[8] 431 | if protoimpl.UnsafeEnabled && x != nil { 432 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 433 | if ms.LoadMessageInfo() == nil { 434 | ms.StoreMessageInfo(mi) 435 | } 436 | return ms 437 | } 438 | return mi.MessageOf(x) 439 | } 440 | 441 | // Deprecated: Use UserJoinChatC2S.ProtoReflect.Descriptor instead. 442 | func (*UserJoinChatC2S) Descriptor() ([]byte, []int) { 443 | return file_gameProto_proto_rawDescGZIP(), []int{8} 444 | } 445 | 446 | func (x *UserJoinChatC2S) GetToken() string { 447 | if x != nil && x.Token != nil { 448 | return *x.Token 449 | } 450 | return "" 451 | } 452 | 453 | //用户加入聊天S2C(4002) 454 | type UserJoinChatS2C struct { 455 | state protoimpl.MessageState 456 | sizeCache protoimpl.SizeCache 457 | unknownFields protoimpl.UnknownFields 458 | } 459 | 460 | func (x *UserJoinChatS2C) Reset() { 461 | *x = UserJoinChatS2C{} 462 | if protoimpl.UnsafeEnabled { 463 | mi := &file_gameProto_proto_msgTypes[9] 464 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 465 | ms.StoreMessageInfo(mi) 466 | } 467 | } 468 | 469 | func (x *UserJoinChatS2C) String() string { 470 | return protoimpl.X.MessageStringOf(x) 471 | } 472 | 473 | func (*UserJoinChatS2C) ProtoMessage() {} 474 | 475 | func (x *UserJoinChatS2C) ProtoReflect() protoreflect.Message { 476 | mi := &file_gameProto_proto_msgTypes[9] 477 | if protoimpl.UnsafeEnabled && x != nil { 478 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 479 | if ms.LoadMessageInfo() == nil { 480 | ms.StoreMessageInfo(mi) 481 | } 482 | return ms 483 | } 484 | return mi.MessageOf(x) 485 | } 486 | 487 | // Deprecated: Use UserJoinChatS2C.ProtoReflect.Descriptor instead. 488 | func (*UserJoinChatS2C) Descriptor() ([]byte, []int) { 489 | return file_gameProto_proto_rawDescGZIP(), []int{9} 490 | } 491 | 492 | //用户聊天消息C2S(4003) 493 | type UserChatC2S struct { 494 | state protoimpl.MessageState 495 | sizeCache protoimpl.SizeCache 496 | unknownFields protoimpl.UnknownFields 497 | 498 | Msg *string `protobuf:"bytes,1,req,name=msg" json:"msg,omitempty"` 499 | } 500 | 501 | func (x *UserChatC2S) Reset() { 502 | *x = UserChatC2S{} 503 | if protoimpl.UnsafeEnabled { 504 | mi := &file_gameProto_proto_msgTypes[10] 505 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 506 | ms.StoreMessageInfo(mi) 507 | } 508 | } 509 | 510 | func (x *UserChatC2S) String() string { 511 | return protoimpl.X.MessageStringOf(x) 512 | } 513 | 514 | func (*UserChatC2S) ProtoMessage() {} 515 | 516 | func (x *UserChatC2S) ProtoReflect() protoreflect.Message { 517 | mi := &file_gameProto_proto_msgTypes[10] 518 | if protoimpl.UnsafeEnabled && x != nil { 519 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 520 | if ms.LoadMessageInfo() == nil { 521 | ms.StoreMessageInfo(mi) 522 | } 523 | return ms 524 | } 525 | return mi.MessageOf(x) 526 | } 527 | 528 | // Deprecated: Use UserChatC2S.ProtoReflect.Descriptor instead. 529 | func (*UserChatC2S) Descriptor() ([]byte, []int) { 530 | return file_gameProto_proto_rawDescGZIP(), []int{10} 531 | } 532 | 533 | func (x *UserChatC2S) GetMsg() string { 534 | if x != nil && x.Msg != nil { 535 | return *x.Msg 536 | } 537 | return "" 538 | } 539 | 540 | //用户聊天消息S2C(4004) 541 | type UserChatNoticeS2C struct { 542 | state protoimpl.MessageState 543 | sizeCache protoimpl.SizeCache 544 | unknownFields protoimpl.UnknownFields 545 | 546 | UserId *uint64 `protobuf:"varint,1,req,name=userId" json:"userId,omitempty"` 547 | UserName *string `protobuf:"bytes,2,req,name=userName" json:"userName,omitempty"` 548 | Msg *string `protobuf:"bytes,3,req,name=msg" json:"msg,omitempty"` 549 | } 550 | 551 | func (x *UserChatNoticeS2C) Reset() { 552 | *x = UserChatNoticeS2C{} 553 | if protoimpl.UnsafeEnabled { 554 | mi := &file_gameProto_proto_msgTypes[11] 555 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 556 | ms.StoreMessageInfo(mi) 557 | } 558 | } 559 | 560 | func (x *UserChatNoticeS2C) String() string { 561 | return protoimpl.X.MessageStringOf(x) 562 | } 563 | 564 | func (*UserChatNoticeS2C) ProtoMessage() {} 565 | 566 | func (x *UserChatNoticeS2C) ProtoReflect() protoreflect.Message { 567 | mi := &file_gameProto_proto_msgTypes[11] 568 | if protoimpl.UnsafeEnabled && x != nil { 569 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 570 | if ms.LoadMessageInfo() == nil { 571 | ms.StoreMessageInfo(mi) 572 | } 573 | return ms 574 | } 575 | return mi.MessageOf(x) 576 | } 577 | 578 | // Deprecated: Use UserChatNoticeS2C.ProtoReflect.Descriptor instead. 579 | func (*UserChatNoticeS2C) Descriptor() ([]byte, []int) { 580 | return file_gameProto_proto_rawDescGZIP(), []int{11} 581 | } 582 | 583 | func (x *UserChatNoticeS2C) GetUserId() uint64 { 584 | if x != nil && x.UserId != nil { 585 | return *x.UserId 586 | } 587 | return 0 588 | } 589 | 590 | func (x *UserChatNoticeS2C) GetUserName() string { 591 | if x != nil && x.UserName != nil { 592 | return *x.UserName 593 | } 594 | return "" 595 | } 596 | 597 | func (x *UserChatNoticeS2C) GetMsg() string { 598 | if x != nil && x.Msg != nil { 599 | return *x.Msg 600 | } 601 | return "" 602 | } 603 | 604 | var File_gameProto_proto protoreflect.FileDescriptor 605 | 606 | var file_gameProto_proto_rawDesc = []byte{ 607 | 0x0a, 0x0f, 0x67, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 608 | 0x6f, 0x22, 0x30, 0x0a, 0x10, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x63, 609 | 0x65, 0x5f, 0x73, 0x32, 0x63, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 610 | 0x64, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 611 | 0x6f, 0x64, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x69, 612 | 0x6e, 0x67, 0x5f, 0x63, 0x32, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 613 | 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x63, 0x32, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 614 | 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 615 | 0x6e, 0x74, 0x22, 0x26, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 616 | 0x5f, 0x73, 0x32, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 617 | 0x02, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1c, 0x0a, 0x1a, 0x75, 0x73, 618 | 0x65, 0x72, 0x5f, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 619 | 0x74, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x32, 0x63, 0x22, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 620 | 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 621 | 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x02, 622 | 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x6e, 0x65, 623 | 0x79, 0x18, 0x03, 0x20, 0x02, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x22, 0x28, 624 | 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x5f, 0x63, 625 | 0x32, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 626 | 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x31, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 627 | 0x5f, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x5f, 0x73, 0x32, 0x63, 0x12, 0x1d, 0x0a, 0x04, 628 | 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x75, 0x73, 0x65, 629 | 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x29, 0x0a, 0x11, 0x75, 630 | 0x73, 0x65, 0x72, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x74, 0x5f, 0x63, 0x32, 0x73, 631 | 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 632 | 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x13, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6a, 633 | 0x6f, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x74, 0x5f, 0x73, 0x32, 0x63, 0x22, 0x21, 0x0a, 0x0d, 0x75, 634 | 0x73, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x74, 0x5f, 0x63, 0x32, 0x73, 0x12, 0x10, 0x0a, 0x03, 635 | 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x5c, 636 | 0x0a, 0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 637 | 0x63, 0x65, 0x5f, 0x73, 0x32, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 638 | 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 639 | 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 640 | 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 641 | 0x67, 0x18, 0x03, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x42, 0x0d, 0x5a, 0x0b, 642 | 0x2e, 0x3b, 0x67, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 643 | } 644 | 645 | var ( 646 | file_gameProto_proto_rawDescOnce sync.Once 647 | file_gameProto_proto_rawDescData = file_gameProto_proto_rawDesc 648 | ) 649 | 650 | func file_gameProto_proto_rawDescGZIP() []byte { 651 | file_gameProto_proto_rawDescOnce.Do(func() { 652 | file_gameProto_proto_rawDescData = protoimpl.X.CompressGZIP(file_gameProto_proto_rawDescData) 653 | }) 654 | return file_gameProto_proto_rawDescData 655 | } 656 | 657 | var file_gameProto_proto_msgTypes = make([]protoimpl.MessageInfo, 12) 658 | var file_gameProto_proto_goTypes = []interface{}{ 659 | (*ErrorNoticeS2C)(nil), // 0: error_notice_s2c 660 | (*ClientPingC2S)(nil), // 1: client_ping_c2s 661 | (*UserLoginC2S)(nil), // 2: user_login_c2s 662 | (*UserLoginS2C)(nil), // 3: user_login_s2c 663 | (*UserOtherLoginNoticeS2C)(nil), // 4: user_otherLogin_notice_s2c 664 | (*UserInfo)(nil), // 5: userInfo 665 | (*UserGetInfoC2S)(nil), // 6: user_getInfo_c2s 666 | (*UserGetInfoS2C)(nil), // 7: user_getInfo_s2c 667 | (*UserJoinChatC2S)(nil), // 8: user_joinChat_c2s 668 | (*UserJoinChatS2C)(nil), // 9: user_joinChat_s2c 669 | (*UserChatC2S)(nil), // 10: user_chat_c2s 670 | (*UserChatNoticeS2C)(nil), // 11: user_chat_notice_s2c 671 | } 672 | var file_gameProto_proto_depIdxs = []int32{ 673 | 5, // 0: user_getInfo_s2c.data:type_name -> userInfo 674 | 1, // [1:1] is the sub-list for method output_type 675 | 1, // [1:1] is the sub-list for method input_type 676 | 1, // [1:1] is the sub-list for extension type_name 677 | 1, // [1:1] is the sub-list for extension extendee 678 | 0, // [0:1] is the sub-list for field type_name 679 | } 680 | 681 | func init() { file_gameProto_proto_init() } 682 | func file_gameProto_proto_init() { 683 | if File_gameProto_proto != nil { 684 | return 685 | } 686 | if !protoimpl.UnsafeEnabled { 687 | file_gameProto_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 688 | switch v := v.(*ErrorNoticeS2C); i { 689 | case 0: 690 | return &v.state 691 | case 1: 692 | return &v.sizeCache 693 | case 2: 694 | return &v.unknownFields 695 | default: 696 | return nil 697 | } 698 | } 699 | file_gameProto_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 700 | switch v := v.(*ClientPingC2S); i { 701 | case 0: 702 | return &v.state 703 | case 1: 704 | return &v.sizeCache 705 | case 2: 706 | return &v.unknownFields 707 | default: 708 | return nil 709 | } 710 | } 711 | file_gameProto_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 712 | switch v := v.(*UserLoginC2S); i { 713 | case 0: 714 | return &v.state 715 | case 1: 716 | return &v.sizeCache 717 | case 2: 718 | return &v.unknownFields 719 | default: 720 | return nil 721 | } 722 | } 723 | file_gameProto_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 724 | switch v := v.(*UserLoginS2C); i { 725 | case 0: 726 | return &v.state 727 | case 1: 728 | return &v.sizeCache 729 | case 2: 730 | return &v.unknownFields 731 | default: 732 | return nil 733 | } 734 | } 735 | file_gameProto_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 736 | switch v := v.(*UserOtherLoginNoticeS2C); i { 737 | case 0: 738 | return &v.state 739 | case 1: 740 | return &v.sizeCache 741 | case 2: 742 | return &v.unknownFields 743 | default: 744 | return nil 745 | } 746 | } 747 | file_gameProto_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 748 | switch v := v.(*UserInfo); i { 749 | case 0: 750 | return &v.state 751 | case 1: 752 | return &v.sizeCache 753 | case 2: 754 | return &v.unknownFields 755 | default: 756 | return nil 757 | } 758 | } 759 | file_gameProto_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { 760 | switch v := v.(*UserGetInfoC2S); i { 761 | case 0: 762 | return &v.state 763 | case 1: 764 | return &v.sizeCache 765 | case 2: 766 | return &v.unknownFields 767 | default: 768 | return nil 769 | } 770 | } 771 | file_gameProto_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { 772 | switch v := v.(*UserGetInfoS2C); i { 773 | case 0: 774 | return &v.state 775 | case 1: 776 | return &v.sizeCache 777 | case 2: 778 | return &v.unknownFields 779 | default: 780 | return nil 781 | } 782 | } 783 | file_gameProto_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { 784 | switch v := v.(*UserJoinChatC2S); i { 785 | case 0: 786 | return &v.state 787 | case 1: 788 | return &v.sizeCache 789 | case 2: 790 | return &v.unknownFields 791 | default: 792 | return nil 793 | } 794 | } 795 | file_gameProto_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { 796 | switch v := v.(*UserJoinChatS2C); i { 797 | case 0: 798 | return &v.state 799 | case 1: 800 | return &v.sizeCache 801 | case 2: 802 | return &v.unknownFields 803 | default: 804 | return nil 805 | } 806 | } 807 | file_gameProto_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { 808 | switch v := v.(*UserChatC2S); i { 809 | case 0: 810 | return &v.state 811 | case 1: 812 | return &v.sizeCache 813 | case 2: 814 | return &v.unknownFields 815 | default: 816 | return nil 817 | } 818 | } 819 | file_gameProto_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { 820 | switch v := v.(*UserChatNoticeS2C); i { 821 | case 0: 822 | return &v.state 823 | case 1: 824 | return &v.sizeCache 825 | case 2: 826 | return &v.unknownFields 827 | default: 828 | return nil 829 | } 830 | } 831 | } 832 | type x struct{} 833 | out := protoimpl.TypeBuilder{ 834 | File: protoimpl.DescBuilder{ 835 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 836 | RawDescriptor: file_gameProto_proto_rawDesc, 837 | NumEnums: 0, 838 | NumMessages: 12, 839 | NumExtensions: 0, 840 | NumServices: 0, 841 | }, 842 | GoTypes: file_gameProto_proto_goTypes, 843 | DependencyIndexes: file_gameProto_proto_depIdxs, 844 | MessageInfos: file_gameProto_proto_msgTypes, 845 | }.Build() 846 | File_gameProto_proto = out.File 847 | file_gameProto_proto_rawDesc = nil 848 | file_gameProto_proto_goTypes = nil 849 | file_gameProto_proto_depIdxs = nil 850 | } 851 | --------------------------------------------------------------------------------