# Extension Hook

The Extension Hook is supported by the emqx-exhook plugin. It allows users to process EMQ X's Hooks using other programming languages.

In this way, other programming languages can handle emqx events for the purpose of customizing and extending emqx. For example, users can use other programming languages to implement:

  • Authorization for client access
  • ACL authentication for publishing/subscribing
  • Persistence and bridging for messages
  • Process client connected/disconnected events

# Design

The emqx-exhook plugin uses gRPC (opens new window) as the communication framework for RPC.

The architecture is as illustrated below:

  EMQ X
+========================+                 +========+==========+
|    ExHook              |                 |        |          |
|   +----------------+   |      gRPC       | gRPC   |  User's  |
|   |   gRPC Client  | ------------------> | Server |  Codes   |
|   +----------------+   |    (HTTP/2)     |        |          |
|                        |                 |        |          |
+========================+                 +========+==========+
1
2
3
4
5
6
7
8

It indicates that EMQ X acts as a gRPC client, sending hook events from EMQ X to the user's gRPC server.

Consistent with EMQ X's native hooks, it also supports a chained approach to calculating and returning.

chain_of_responsiblity

# APIs

As the event handler, i.e. user implemented server side of gRPC. It can define the list of hooks that need to be mounted, and the implement callback functions for how to go about handling each event when it arrives.

These interfaces are defined as a gRPC service called HookProvider:

syntax = "proto3";

package emqx.exhook.v1;

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 OnClientCheckAcl(ClientCheckAclRequest) 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 OnSessionTakeovered(SessionTakeoveredRequest) 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) {};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

The HookProvider part:

  • OnProviderLoaded: Defines how the HookProvider will be loaded. This method returns the list of hooks that need to be mounted. Only the hooks in this list will be called back to the user's HookProvider service.
  • OnProviderUnloaded: Notify the user that the HookProvier has been uninstalled from emqx

The hook events part:

  • The methods prefixed with OnClient, OnSession, and OnMessage correspond to the methods in hooks. They have the same call timing and a similar argument list.
  • Only OnClientAuthenticate, OnClientCheckAcl, OnMessagePublish are allowed to carry the return values to EMQ X, other callbacks are not supported.

For details of the interface and parameter data structures refer to: exhook.proto (opens new window)

# Developing Guide

The user needs to implement the gRPC service of HookProvider to receive callback events from EMQ X.

The main development steps are as following:

  1. Copy the lib/emqx_exhook-<x.y.z>/priv/protos/exhook.proto file to your project.
  2. Generate the code for the gRPC server side of exhook.proto using the gRPC framework for the corresponding programming language.
  3. Implement the interfaces defined in exhook.proto on demand

Once the development is complete, the service needs to be deployed to a server that can communicate with EMQ X and ensure that the ports are open.

Then modify the server configuration in etc/plugins/emqx_exhook.conf, for example:

exhook.server.default.url = http://127.0.0.1:9000
1

Start the emqx_exhook plugin and observe the output.

One of the gRPC frameworks for each language can be found at: grpc-ecosystem/awesome-grpc (opens new window)

We also provide sample programs for some common programming languages: emqx-extension-examples (opens new window)