[Pitaya Demo解读笔记]5.pipeline demo

项目目录:examples/demo/custom_metrics

本例展示了如何使用结构体验证 (struct validation)和处理函数钩子(handler hooks)

运行

服务器开起来

sh 复制代码
 go run main.go

服务监听了 3251 端口,使用命令行跑一下基本功能

有一点需要注意一下,之前的 demo 都设置了 component.WithNameFunc(strings.ToLower),所以之前的 router 都是全小写,这个示例程序并没有设置,访问的时候是大小写敏感的,否则会找不到服务器或 handler:

sh 复制代码
 > pitaya-cli
 Pitaya REPL Client
 >>> request metagameDemo.metagamehandler.createplayercheat {"name":"test", "email":"test@gmail.com", "softCurrency":10, "hardCurrency":20}
 >>> sv->{"code":"PIT-404","msg":"pitaya/handler: metagameDemo.metagamehandler.createplayercheat not found"}
 >>> request metagameDemo.metagameHandler.CreatePlayerCheat {"name":"test", "email":"test@gmail.com", "softCurrency":10, "hardCurrency":20}
 >>> sv->{"msg":"ok"}

服务器端输出日志如下:

sh 复制代码
 time="2023-10-16T16:13:59+08:00" level=info msg="Simple Before exec" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="Name: test" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="Email: test@gmail.com" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="SoftCurrency: 10" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="HardCurrency: 20" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=debug msg="SID=4, Data={"name":"test","email":"test@gmail.com","softCurrency":10,"hardCurrency":20}" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="CreatePlayerChest called" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=
 time="2023-10-16T16:13:59+08:00" level=info msg="Simple After exec - response: &{ok} , error: <nil>" requestId=BJIiSpBZ1Pue7CIr9md6iz route=metagameDemo.metagameHandler.CreatePlayerCheat source=pitaya userId=

钩子方法输出了 Simple Before 和 Simple After...

如果我们给一个不满足验证的值,hardCurrency = 2000,服务器会验证输入,返回错误信息:

sh 复制代码
 >>> request metagameDemo.metagameHandler.CreatePlayerCheat {"name":"test", "email":"test@gmail.com", "softCurrency":10, "hardCurrency":2000}
 >>> sv->{"code":"PIT-000","msg":"Key: 'CreatePlayerCheatArgs.HardCurrency' Error:Field validation for 'HardCurrency' failed on the 'lte' tag"}

代码分析

结构体验证

开启结构体验证:

go 复制代码
 // main.go:101
 config.DefaultPipelines.StructValidation.Enabled = true

使用 tag validate 设置验证规则:

go 复制代码
 type CreatePlayerCheatArgs struct {
     Name         string `json:"name"`
     Email        string `json:"email" validate:"email"`
     SoftCurrency int    `json:"softCurrency" validate:"gte=0,lte=1000"`
     HardCurrency int    `json:"hardCurrency" validate:"gte=0,lte=200"`
 }

Pitaya 默认的验证器是这个包:github.com/go-playgrou...

这个功能很强大啊,在游戏开发里,默认客户端是不可信的,需要对大部分上行参数做数据验证,自己手动写就很麻烦,在 pitaya 框架里,我们可以使用 StructValidation 来实现,优雅!

结构体验证的实现用到了我们接下来要说的钩子方法,开启验证,就是在 BeforeHandler 添加了验证方法:

go 复制代码
 // builder.go: 314
 func configureDefaultPipelines(handlerHooks *pipeline.HandlerHooks) {
     handlerHooks.BeforeHandler.PushBack(defaultpipelines.StructValidatorInstance.Validate)
 }

钩子方法 BeforeHandler AfterHandler

pitaya 提供了钩子方法集:

  • BeforeHandler 在消息处理方法前执行,结构体验证就是在这里调用的
  • AfterHandler 在消息处理方法后执行

这两种钩子方法集在 ProcessHandlerMessage 里被调用:

go 复制代码
 // handler_pool.go:43
 func (h *HandlerPool) ProcessHandlerMessage(
     ctx context.Context,
     rt *route.Route,
     serializer serialize.Serializer,
     handlerHooks *pipeline.HandlerHooks,
     session session.Session,
     data []byte,
     msgTypeIface interface{},
     remote bool,
 ) ([]byte, error) {
     ...
     ctx, arg, err = handlerHooks.BeforeHandler.ExecuteBeforePipeline(ctx, arg)
     if err != nil {
         return nil, err
     }
     ...
     resp, err := util.Pcall(handler.Method, args)
     ...
     resp, err = handlerHooks.AfterHandler.ExecuteAfterPipeline(ctx, resp, err)
     ...
 }

ExecuteBeforePipelineExecuteAfterPipeline 就是遍历切片,依次调用注册的方法

相关推荐
苹果酱05671 小时前
一文读懂SpringCLoud
java·开发语言·spring boot·后端·中间件
掐指一算乀缺钱1 小时前
SpringBoot 数据库表结构文档生成
java·数据库·spring boot·后端·spring
计算机学姐3 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
JustinNeil4 小时前
简化Java对象转换:高效实现大对象的Entity、VO、DTO互转与代码优化
后端
青灯文案14 小时前
SpringBoot 项目统一 API 响应结果封装示例
java·spring boot·后端
微尘85 小时前
C语言存储类型 auto,register,static,extern
服务器·c语言·开发语言·c++·后端
计算机学姐5 小时前
基于PHP的电脑线上销售系统
开发语言·vscode·后端·mysql·编辑器·php·phpstorm
码拉松6 小时前
千万不要错过,优惠券设计与思考初探
后端·面试·架构
白总Server6 小时前
MongoDB解说
开发语言·数据库·后端·mongodb·golang·rust·php
计算机学姐7 小时前
基于python+django+vue的家居全屋定制系统
开发语言·vue.js·后端·python·django·numpy·web3.py