EMQX Exhook 钩子函数调用

Exhook

今天 学习一个小知识点,Exhook钩子函数的使用。钩子是EMQX提供的一种机制,通过拦截模块间的函数调用、消息传递、事件传递修改或者扩展系统功能。

多语言-钩子扩展

由emqx-exhook插件进行支持,允许其他编程语言直接向EMQX挂在钩子(只需要在挂载点实现自己的业务代码即可),以接受并处理EMQX系统事件,达到扩展、定制EMQX的目的。例如,用户可以使用其他编程语言来实现:

  • 客户端接入的认证鉴权
  • 发布/订阅权限检查
  • 消息的持久化,桥接
  • 发布/订阅,或者客户端上下线事件的通知处理

设计思想

emqx-exhook使用grpc作为rpc的通信框架。grpc是由google开发的一个高性能、通用的开源rpc框架,基于Http2标准协议,更重要的是支持大多数变成语言。emqx-exhook的架构图如下:

  EMQX
+========================+                 +========+==========+
|    ExHook              |                 |        |          |
|   +----------------+   |      gRPC       | gRPC   |  User's  |
|   |   gRPC Client  | ------------------> | Server |  Codes   |
|   +----------------+   |    (HTTP/2)     |        |          |
|                        |                 |        |          |
+========================+                 +========+==========+
   

可以看出EMQX作为grpc的客户端,将系统中的钩子事件暴露出去,通过grpc协议暴露用户自定义的服务端程序。

接口设计

grpc服务端需要自定义实现需要挂载的钩子列表,以及每个钩子事件到达后的业务处理逻辑。接口名为HookProvider,里面定义了需要实现的钩子列表。它是使用protobuf编码协议实现,代码如下:

syntax = "proto3";

package emqx.exhook.v2;

service HookProvider {

  rpc OnProviderLoaded(ProviderLoadedRequest) returns (LoadedResponse) {};

  rpc OnProviderUnloaded(ProviderUnloadedRequest) returns (EmptySuccess) {};

  rpc OnClientConnect(ClientConnectRequest) returns (EmptySuccess) {};

  rpc OnClientConnack(ClientConnackRequest) returns (EmptySuccess) {};

  rpc OnClientConnected(ClientConnectedRequest) returns (EmptySuccess) {};

  rpc OnClientDisconnected(ClientDisconnectedRequest) returns (EmptySuccess) {};

  rpc OnClientAuthenticate(ClientAuthenticateRequest) returns (ValuedResponse) {};

  rpc OnClientAuthorize(ClientAuthorizeRequest) returns (ValuedResponse) {};

  rpc OnClientSubscribe(ClientSubscribeRequest) returns (EmptySuccess) {};

  rpc OnClientUnsubscribe(ClientUnsubscribeRequest) returns (EmptySuccess) {};

  rpc OnSessionCreated(SessionCreatedRequest) returns (EmptySuccess) {};

  rpc OnSessionSubscribed(SessionSubscribedRequest) returns (EmptySuccess) {};

  rpc OnSessionUnsubscribed(SessionUnsubscribedRequest) returns (EmptySuccess) {};

  rpc OnSessionResumed(SessionResumedRequest) returns (EmptySuccess) {};

  rpc OnSessionDiscarded(SessionDiscardedRequest) returns (EmptySuccess) {};

  rpc OnSessionTakenover(SessionTakenoverRequest) returns (EmptySuccess) {};

  rpc OnSessionTerminated(SessionTerminatedRequest) returns (EmptySuccess) {};

  rpc OnMessagePublish(MessagePublishRequest) returns (ValuedResponse) {};

  rpc OnMessageDelivered(MessageDeliveredRequest) returns (EmptySuccess) {};

  rpc OnMessageDropped(MessageDroppedRequest) returns (EmptySuccess) {};

  rpc OnMessageAcked(MessageAckedRequest) returns (EmptySuccess) {};
}

其中 HookProvider 部分:

  • OnProviderLoaded:定义 HookProvider 如何被加载,返回需要挂载的钩子列表。仅在该列表中的钩子会被回调到 HookProivder 服务。
  • OnProviderUnloaded:通知用户该 HookProvier 已经从 emqx 中卸载。

钩子事件部分:

  • OnClient*OnSession*OnMessage* 为前缀的方法与 钩子 的当中的方法一一对应。它们有着相同的调用时机和相似的参数列表。
  • OnClientAuthenticateOnClientCheckAclOnMessagePublish 允许携带返回值到 EMQX 系统,其它回调则不支持。

开发指南

由于接口是使用protobuf定义的,因此天然支持多语言的扩展,只要按照接口约定实现业务逻辑即可。其步骤如下

  1. 按照protoc 客户端工具,参考 protoc安装
  2. 使用对应编程语言的 gRPC 框架,生成 exhook.proto 的 gRPC 服务端的代码。
  3. 按需实现 exhook.proto 中定义的接口。

开发完成后,需将该服务部署到与 EMQX 能够通信的服务器上,并保证端口的开放。

Golang 代码实战

常见编程语言的示例程序:emqx-extension-examples,我们使用golang语言做一些案例

下载代码

AndydeMacBook-Pro:github-demo andy$ git clone https://github.com/emqx/emqx-extension-examples.git
Cloning into 'emqx-extension-examples'...
remote: Enumerating objects: 628, done.
remote: Counting objects: 100% (104/104), done.
remote: Compressing objects: 100% (74/74), done.
remote: Total 628 (delta 27), reused 60 (delta 16), pack-reused 524
Receiving objects: 100% (628/628), 4.69 MiB | 1.78 MiB/s, done.
Resolving deltas: 100% (252/252), done.

下载依赖

#1. 跳转到指定目录
 cd exhook-svr-go/

#2. 下载依赖
go mod tidy

在设备链接、断开事件中输出日志

func (s *server) OnClientConnected(ctx context.Context, in *pb.ClientConnectedRequest) (*pb.EmptySuccess, error) {
	fmt.Println("OnClientConnected:", in.Clientinfo.Clientid)
	cnter.Count(1)
	return &pb.EmptySuccess{}, nil
}

func (s *server) OnClientDisconnected(ctx context.Context, in *pb.ClientDisconnectedRequest) (*pb.EmptySuccess, error) {
	fmt.Println("OnClientDisconnected:", in.Clientinfo.Clientid)
	cnter.Count(1)
	return &pb.EmptySuccess{}, nil
}	

运行grpc服务端程序

在这里插入图片描述

开启exhooks功能

登录emqx dashboard ,点击菜单:插件扩展 -> Exhook -> 添加

在这里插入图片描述

特别注意:由于本机使用docker安装EMQX服务器,因此上面的地址不能填写locahost(127.0.0.1). 自己踩过坑。

开启exhook插件

在这里插入图片描述

客户端上/下线测试

在这里插入图片描述

​ 如上所示 测试成功。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值