您的位置:首页 > 运维架构

云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第4篇

2021-02-17 19:48 246 查看

游客登录鉴权之业务代码实战

系列文章

  1. 从0到1使用Golang开发生产级麻将游戏服务器—第1篇
  2. 从0到1使用Golang开发生产级麻将游戏服务器—第2篇
  3. 从0到1使用Golang开发生产级麻将游戏服务器—第3篇

介绍

这将是一个完整的,完全践行

DevOps/GitOps
Kubernetes
上云流程的 Golang 游戏服务器开发的系列教程。

这个系列教程是对开源项目

Nanoserver
的完整拆解,旨在帮助大家快速上手 Golang(游戏)服务器后端开发。通过实践去理解 Golang 开发的精髓 ——
Share memory by communication(通过通信共享内存)

同时这个项目可能还会涉及到

Linux
性能调优(
BPF
相关的工具)和系统保障(
SRE
)的相关的工作。

Step-By-Step 开发 Mahjong Server

  • 单体架构
    理解
    Mahjong Server
    业务 ->
    Nano Distributed Game Server(分布式)
    +
    微服务
    改造。
  • Demo:go-mahjong-server

VSCode REST Client 插件

如果你是用 VSCode 作为 IDE,这个插件不错:

游客登录业务

业务分析

从0到1使用Golang开发生产级麻将游戏服务器—第3篇

业务 E-R 图

API:查询游客登录是否启用

REST Client 测试 API

Request

POST http://192.168.31.125:12307/v1/user/login/query HTTP/1.1
content-type: application/json

{
"channelId": "konglai",
"appId": "konglai"
}

Response

HTTP/1.1 200 OK
Access-Control-Allow-Headers: Origin, Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Sun, 07 Feb 2021 15:00:16 GMT
Content-Length: 24
Connection: close

{
"code": 0,
"guest": true
}

业务逻辑分析

  1. 比较简单,就是根据服务器
    configs/config.toml
    文件的配置,进行验证:
...
[login]
guest = true
lists = ["test", "konglai"]
...

API:游客登录

REST Client 测试 API

Request

POST http://127.0.0.1:12307/v1/user/login/guest HTTP/1.1
content-type: application/json

{
"channelId": "konglai",
"appId": "konglai",
"imei": "c0a4ce912c48a3d0b17b59e6b97f1dca"
}

Response

{
"code": 0,
"name": "G1",
"uid": 1,
"headUrl": "http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0",
"fangka": 10,
"sex": 1,
"ip": "192.168.31.125",
"port": 33251,
"playerIp": "192.168.31.125",
"config": {
"version": "1.9.3",
"android": "https://fir.im/tand",
"ios": "https://fir.im/tios",
"heartbeat": 30,
"forceUpdat
ad8
e": true,
"title": "血战到底",
"desc": "纯正四川玩法,快捷便利的掌上血战,轻松组局,随时随地尽情游戏",
"daili1": "kefuweixin01",
"daili2": "kefuweixin01",
"kefu1": "kefuweixin01",
"appId": "xxx",
"appKey": "xxx"
},
"messages": ["系统消息:健康游戏,禁止赌博", "欢迎进入游戏"],
"clubList": [],
"debug": 0
}

业务逻辑分析

DB Model

db/model/struct.go

type User struct {
Id              int64
Algo            string `xorm:"not null VARCHAR(16) default"`
Hash            string `xorm:"not null VARCHAR(64) default"`
Salt            string `xorm:"not null VARCHAR(64) default"`
Role            int    `xorm:"not null TINYINT(3) default 1"`
Status          int    `xorm:"not null TINYINT(3) default 1"`
IsOnline        int    `xorm:"not null TINYINT(1) default 1"`
LastLoginAt     int64  `xorm:"not null index BIGINT(11) default"`
PrivKey         string `xorm:"not null VARCHAR(512) default"`
PubKey          string `xorm:"not null VARCHAR(128) default"`
Coin            int64  `xorm:"not null BIGINT(20) default 0"`
RegisterAt      int64  `xorm:"not null index BIGINT(20) default 0"`
FirstRechargeAt int64  `xorm:"not null index BIGINT(20) default 0"`
Debug           int    `xorm:"not null index TINYINT(1) default 0"`
}
用户表 描述
Id 自增ID
Algo 加密算法
Hash 加密hash
Salt 加密撒盐
Role 账号类型(RoleTypeAdmin=1 管理员账号,RoleTypeThird=2 三方平台账号)
Status 账号状态(StatusNormal=1 正常,StatusDeleted=2 删除,StatusFreezed=3 冻结,StatusBound=4 绑定)
IsOnline 是否在线(UserOffline=1 离线,UserOnline=2 在线)
LastLoginAt 最后登录时间
PrivKey 账号证书私钥
PubKey 账号证书公钥
Coin 房卡数量
RegisterAt 注册时间
FirstRechargeAt 首充时间
Debug 用户信息调试
type Register struct {
Id           int64
Uid          int64  `xorm:"not null index BIGINT(20) default"`
Remote       string `xorm:"not null VARCHAR(40) default"`
Ip           string `xorm:"not null VARCHAR(40) default"`
Imei         string `xorm:"not null VARCHAR(
ad0
128) default"`
Os           string `xorm:"not null VARCHAR(20) default"`
Model        string `xorm:"not null VARCHAR(20) default"`
AppId        string `xorm:"not null index VARCHAR(32) default"`
ChannelId    string `xorm:"not null index VARCHAR(32) default"`
RegisterAt   int64  `xorm:"not null index BIGINT(11) default"`
RegisterType int    `xorm:"not null index TINYINT(8) default"`
}
用户注册记录表 描述
Id 自增ID
Uid 用户ID
Remote 外网IP
Ip 内网IP
Model 硬件型号
Imei 设备的imei号
Os os版本号
AppId 应用id
ChannelId 渠道id
RegisterAt 注册时间
RegisterType 注册类型(RegTypeThird=5 三方平台添加账号)
type Login struct {
Id        int64
Uid       int64  `xorm:"not null index BIGINT(20) default"`
Remote    string `xorm:"not null VARCHAR(40) default"`
Ip        string `xorm:"not null VARCHAR(40) default"`
Model     string `xorm:"not null VARCHAR(64) default"`
Imei      string `xorm:"not null VARCHAR(32) default"`
Os        string `xorm:"not null VARCHAR(64) default"`
AppId     string `xorm:"not null VARCHAR(64) default"`
ChannelId string `xorm:"not null VARCHAR(32) default"`
LoginAt   int64  `xorm:"not null BIGINT(11) default"`
LogoutAt  int64  `xorm:"not null BIGINT(11) default"`
}
用户登录记录表 描述
Id 自增ID
Uid 用户ID
Remote 外网IP
Ip 内网IP
Model 硬件型号
Imei 设备的imei号
Os os版本号
AppId 应用id
ChannelId 渠道id
LoginAt 登录时间
LogoutAt 注销时间
  1. 根据
    AppID
    (
    用户来自于哪一个应用
    ) 与
    Device.IMEI
    (
    设备的imei号
    ),确定当前游客是否已经注册
user, err := db.QueryGuestUser(data.AppID, data.Device.IMEI)

db.QueryGuestUser
,会从
register
user
表中去查找用户是否存在。

相关 218b

protocol
的定义:

protocol/login.go

type LoginRequest struct {
AppID     string `json:"appId"`     //用户来自于哪一个应用
ChannelID string `json:"channelId"` //用户来自于哪一个渠道
IMEI      string `json:"imei"`
Device    Device `json:"device"`
}

protocol/common.go

type Device struct {
IMEI   string `json:"imei"`   //设备的imei号
OS     string `json:"os"`     //os版本号
Model  string `json:"model"`  //硬件型号
IP     string `json:"ip"`     //内网IP
Remote string `json:"remote"` //外网IP
}
  1. 如果没有注册,则生成一个新用户,并且注册一条用户记录

涉及到的相关

db
常量的定义:

db/const.go

const (
StatusNormal  = 1 //正常
StatusDeleted = 2 //删除
StatusFreezed = 3 //冻结
StatusBound   = 4 //绑定
)

const (
UserOffline = 1 //离线
UserOnline  = 2 //在线
)

// Users表中role字段的取值
const (
RoleTypeAdmin = 1 //管理员账号
RoleTypeThird = 2 //三方平台账号
)

生成一个新用户:

const defaultCoin = 10 // 默认给的房卡数量是 10

user = &model.User{
Status:   db.StatusNormal,
IsOnline: db.UserOffline,
Role:     db.RoleTypeThird,
Coin:     defaultCoin,
}

db.InsertUser(user)

注册一条用户记录

db.RegisterUserLog(user, data.Device, data.AppID, data.ChannelID, protocol.RegTypeThird) //注册记录
  1. 构造
    login
    响应数据

相关

protocol
的定义:

protocol/login.go

type LoginResponse struct {
Code     int          `json:"code"`
Name     string       `json:"name"`
Uid      int64        `json:"uid"`
HeadUrl  string       `json:"headUrl"`
FangKa   int64        `json:"fangka"`
Sex      int          `json:"sex"` //[0]未知 [1]男 [2]女
IP       string       `json:"ip"`
Port     int          `json:"port"`
PlayerIP string       `json:"playerIp"`
Config   ClientConfig `json:"config"`
Messages []string     `json:"messages"`
ClubList []ClubItem   `json:"clubList"`
Debug    int          `json:"debug"`
}

type ClientConfig struct {
Version     string `json:"version"`
Android     string `json:"android"`
IOS         string `json:"ios"`
Heartbeat   int    `json:"heartbeat"`
ForceUpdate bool   `json:"forceUpdate"`

Title string `json:"title"` // 分享标题
Desc  string `json:"desc"`  // 分享描述

Daili1 string `json:"daili1"`
Daili2 string `json:"daili2"`
Kefu1  string `json:"kefu1"`

AppId  string `json:"appId"`
AppKey string `json:"appKey"`
}

protocol/club.go

type (
ClubItem struct {
Id        int64  `json:"id"`
Name      string `json:"name"`
Desc      string `json:"desc"`
Member    int    `json:"member"`
MaxMember int    `json:"maxMember"`
}
// ....
)
  1. 插入登录记录,返回客户端所需数据
device := protocol.Device{
IP:     ip(r.RemoteAddr),
Remote: r.RemoteAddr,
}
db.InsertLoginLog(user.Id, device, data.AppID, data.ChannelID)

return resp, nil
  1. 一图胜千言,秒懂

关于游戏服务器登录与 Nano 游戏服务器通信相关代码实战,我们下篇再详细讨论。

我是为少
微信:uuhells123
公众号:黑客下午茶
加我微信(互相学习交流),关注公众号(获取更多学习资料~)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐