Message Filtering

Introduction

Messages can be filtered by using wildcards in sub-channels or by subscribing to partial channels. These two filtering concepts will be explained through example: Suppose there is a house with one temperature sensor in each room of the house. Each sensor publishes its state once per minute. The inhabitants of the house have an app on their smart phones to check all temperatures, even if they are not at home. Each sensor publishes its state in a fashion as shown below.

// publish a message to a channel
emitter.publish({
  key: "<channel key>",
  channel: "house/firstfloor/bedroom1/temperature",
  message: "21 Celcius"
});

In this example above channel house/firstfloor/bedroom1/temperature is used for the temperature sensor in the first bedroom of the first floor. In order to receive the temperature from this sensor, one can simply subscribe to the channel of that particular sensor as shown below.

emitter.subscribe({
  key: "<channel key>",
  channel: "house/firstfloor/bedroom1/temperature"
});

Filtering Using Wildcards

In order to receive all temperatures at the first floor, one should subscribe to a channel using the + as a wildcard:

mitter.subscribe({
  key: "<channel key>",
  channel: "house/firstfloor/+/temperature"
}); 

In this fashion one could easily create a program to give the average temperature at the first floor. Even if an extra room would be added to the system no code needs to be changed on the subscriber side. In a similar way one can use multiple wildcards to receive all temperatures of the entire house:

emitter.subscribe({
  key: "<channel key>",
  channel: "house/+/+/temperature"
});

The + serves as a wildcard and can be placed at any level of a channel name. There is no limitation in the number of wildcards used when subscribing, but it cannot be used to replace the root channel (house in this case).

Filtering Using Partial Channels

Now suppose the user installs multiple temperature sensors in one room. In that case a publish statement could look as follows:

// publish a message to a channel
emitter.publish({
  key: "<channel key>",
  channel: "house/firstfloor/bedroom1/temperature/sensor2",
  message: "21 Celcius"
});

In that case the previously defined subscribe statements are all still valid. In the below example the temperature of all temperature sensors of bedroom 1 on the first floor will be received.

emitter.subscribe({
  key: "<channel key>",
  channel: "house/firstfloor/bedroom1/temperature"
});

By specifying only the first part of a complete channel, Emitter assumes you want to subscribe to all sub channels too. This also works in combination with wildcards. So you could subscribe to channel house/+/+/temperature in case you want to receive all temperature statuses.

If you simply want to receive all statuses of the first floor of the house, you could even simply subscribe to house/firstfloor. So by specifying only the first part of a complete channel,Emitter assumes you want to subscribe to all sub channels too (multi-level sub channels if applicable).

Publisher-Subscriber Matrix

The matrix below is intended to provide you with a better understanding on how subscriptions and filtering work in Emitter by summarizing some of the points from this guide.

  • First column is channel to publish to
  • First row is channel that subscriber is listening to
  • ✔️ Subscriber will receive the message
  • ❌ Subscriber won't receive the message
Publish to ⬇️ / Subscribe ➡️CC/AC/+C/A/BC/+/BC/D
C✔️
C/A✔️✔️✔️
C/A/B✔️✔️✔️✔️
C/D✔️✔️✔️
C/D/B✔️✔️✔️

Channel structure for key generation

All examples above suppose you got a key that grant you access to the channel you're subscribing to, or publishing through. To generate such a key, you must provide the key generator with a valid channel pattern. Here is an example of a key generation request :

emitter.keygen({
	key: "<channel key>",
	channel: "chat/#/",
	type: "rwls",
	ttl: 600
}); 
  • The channel specified to the key generator must end with a slash.
  • #/ means the key must grant access to any subchannels.
  • /+/ allows to skip any intermediary levels.
  • The channel can contains up to 23 levels.

Example 1

We have a key that has read permission to a/.

  • The user is authorized to access the channel a.
  • The user is not authorized to access the channel a/b.

Example 2

We have a key that has read permission to a/#/.

  • The user is authorized to access the channel a.
  • The user is also authorized to access the channels a/b, a/c, a/b/c, etc.

Example 3

We have a key that has read permission to a/+/c/#/.

  • The user is authorized to access the channels a/b/c, a/d/c, a/b/c/d, a/b/c/d/e, etc.

Note : keys generated before the introduction of this feature always grant access to any sub-channels.