Default Offline messages
There is helpers for using the IOfflineQueue
but you can of course you the plugin framework to get the module and use it directly
var q = Composable.GetExport<IOfflineQueue>();
However, this section will show how to use the extensions for the IOfflineQueue
Saving messages while being offline
When a connection is closed you should tell the server that you would like it to save messages with specific topics. This is done by using the OfflineSubscribe
helper. You might not wanna save all the messages that will arrive during your offline period (only specific topics).
Below we subscribe for the topics bar
and baz
while being offline
public override async Task OnClosed()
{
await this.OfflineSubscribe("bar", "baz");
}
Note: You can also pass in a parameter that says for how long the messages will be saved. By default this value is 30 seconds, but if you implement something like MSMQ this might be infinite.
Retrieving messages when online
When we get back online we use the OnlinePublish
helper to retrieve all messages that arrived while the connection was closed. Notice that we use the OnReopened
method since that is when there might be messages stored for the client.
public override async Task OnReopened()
{
await this.OnlinePublish();
}
Pushing messages to the OfflineQueue
By default messages are not stored on the OfflineQueue
. So we have to push messages that we want to store for offline clients. This is done by using the Queue
helper.
public async Task Bar(string m)
{
await this.InvokeToAll(m, "bar");
await this.Queue(DeliveryType.Rpc, m.AsMessage("bar"));
}
So first we send the message to all clients online, and then we store the message for clients that are currently offline and subscribing to the topic bar
.
In a real implementation you would probably build a custom extension for this to avoid having 2 lines of code in the method. So something like below could be the complete solution.
Complete Sample
using XSockets.Core.XSocket;
using System.Threading.Tasks;
using XSockets.Core.XSocket.Helpers;
using XSockets.Core.Common.Protocol;
using XSockets.Core.Common.Socket;
using XSockets.Core.XSocket.Model;
public class Foo : XSocketController
{
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(string m)
{
//Send to all online clients and store for clients being offline
await this.InvokeToAndQueue(m, "bar");
}
}
/// <summary>
/// Queue extentions
/// </summary>
public static class QueueHelpers
{
public static async Task InvokeToAndQueue<T>(this T controller, object o, string topic) where T : class, IXSocketController
{
var m = new Message(o,topic,controller.Alias);
await controller.InvokeToAll(m);
await controller.Queue(DeliveryType.Rpc, m);
}
}
Test The Sample
Testing this is pretty simple. Notice that I have set the storage timeout in the sample code to be 60 seconds so that I have enough time to play with Putty.
Open two Putty clients
We need 2 clients to be able to send some messages while one of them is offline. We will not close and reopen the clients with the same PersistentId
. That would mimic a real life scenario, but in here we will only use the reserved topics to close and reopen a controller.
So the scenario will be that:
- both clients is connected and use the
Bar
method in theFoo
controller. - Then one of them will close the controller
- The client being online send a message to the
Bar
method on theFoo
controller - The client that closed the controller reconnects
- The message that was sent while the client was offline will be sent to the client.
2 clients connect
We open 2 Putty clients and open the Foo
controller by sending in foo|1|
.
Messages sent
The client on the top send a message Hello all
and both client receive it
One client closes the controller
The client at the bottom closes the Foo
controller by sending in foo|3|
The other client sends a message
The client on the top (still connected) send a message This will be stored in a offline queue
and only the client on top receives that message instantly.
The client reopens the controller & receives the message
Now the client at the bottom reopen/reconnect to the Foo
controller by sending in foo|1|
.
The message that was stored for this client is sent out as soon as the reopen method get invoked.