Target Clients Offline Based on State
In the previous section we used the queue extension and the IOfflineQueue
module to automatically store messages for clients being offline and the sent the messages when they reconnect.
However, a big part of XSockets is state. State is what enables you to target client with lambda expressions in a very efficient way. Doing this for client that is currently offline is not so different from the previous sample.
Let's say that we have a integer property on our Foo controller. Now we want to target clients where the value of this property is lower that the value sent. Maybe this is some kind of sensor data with a conditional send.
Extending the helpers
In the previous section we added a helper class for both sending and queuing messages. Now we add and extra method that also handles targeting clients based on lambda expressions
/// <summary>
/// Queue extentions
/// </summary>
public static class QueueHelpers
{
//Other method removed for readability
public static async Task InvokeToAndQueue<T>(this T controller, Func<T, bool> exp, object o, string topic) where T : class, IXSocketController
{
var m = new Message(o, topic, controller.Alias);
await controller.InvokeTo(exp,m);
await controller.Queue(DeliveryType.Rpc, m, exp);
}
}
The controller
The controller will look almost the same as in the previous section. The new things is a property with the PersistentProperty
attribute and the lambda expression to target clients based on the new property
public class Foo : XSocketController
{
[PersistentProperty]
public int Limit { get; set; }
public override async Task OnClosed()
{
//Store messgages with the topics bar,baz while I am offline
await this.OfflineSubscribe(60000,"bar", "baz");
}
public override async Task OnReopened()
{
//Get all messages (with topics bar,baz) that was sent while I was offline
await this.OnlinePublish();
}
public async Task Bar(int v)
{
//Send to all online clients and store for clients being offline
//But we only send to client where the limit is lower than v
await this.InvokeToAndQueue(x => x.Limit < v, v, "bar");
}
}
Testing
Once again we can use Putty to test this. Just like in the previous section we will have 2 clients. The difference this time is that they will set the property Limit
and based on that value the client might get data.
Connecting and setting the property
In the first picture both client connect and set the limit. The client on top sets the limit to 25, and the client at the bottom sets it to 50. So messages under 51 will only arrive at the client on the top.
We verified that it works by sending foo|bar|40
from the client at the bottom, and only the client on the top got the message. So it works for clients online!
Send data with one client offline
We now closed the client on the top (the one with limit set to 25). Then the client at the bottom sent two values foo|bar|43
and foo|bar|45
. Neither of these messages arrived back at the client since it has the Limit
set to 50.
Reconnect the upper client
In the picture below you can see that we closed the Foo
controller by sending in foo|3|
. Now we send in foo|1|
to reopen the controller. The server then publish both foo|bar|43
and foo|bar|45
since the Limit was set to 25 for the upper client. The server knows about the limit being set to 25 since we had the PersistentProperty
attribute set on the Limit
property