Getting Started - Windows
Here we write a simple notifier, publisher, and subscriber in the Windows environment.
Installation
Install and start the distributor. The instructions can be found here.
Write some code
Notifier
We'll start by writing a notifier. The notifier listens to other client's subscriptions.
Open Visual Studio and create a new C# console project call "SimpleNotifier" using the target framework ".NET Core 3.1".
Once the project has been created right-click on the "Dependencies" and
select "Manage Nuget Packages...". In the "Browse" tab search for the package
JetBlack.MessageBus.Adapters
, and install it.
Change the file Program.cs
to have the following content:
using System;
using JetBlack.MessageBus.Adapters;
namespace SimpleNotifier
{
class Program
{
static void Main(string[] args)
{
// Create the client.
var client = Client.Create("localhost", 9001);
client.OnForwardedSubscription +=
(sender, args) => Console.WriteLine(args);
// Request notifications on the "TEST" feed.
Console.WriteLine("Requesting notifications on feed \"TEST\".");
client.AddNotification("TEST");
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
client.Dispose();
}
}
}
The program is pretty simple. It creates a client which connects to localhost
on port 9001
, which matches the distributor. It adds an event handler for
the event OnForwardedSubscription
. These are subscriptions made
by another client that have been "forwarded" to this client. The event handler
writes the event to the console. Finally it calls AddNotification
for the
feed TEST
then waits for the ENTER
key to be pressed after which it will
dispose of the client and exit.
When we run the program it responds:
Requesting notifications on feed "TEST".
Press ENTER to quit
Looking at the console for the distributor we see the following new lines:
2021-07-29 12:49:45.2520206 info: JetBlack.MessageBus.Distributor.Interactors.Interactor[0]
Authenticated with NULL as nobody
2021-07-29 12:49:45.2591651 info: JetBlack.MessageBus.Distributor.Interactors.InteractorManager[0]
Adding interactor: 46e44dfc-961b-4fae-b6e3-78cabfea9df5: nobody() DESKTOP-011OALS()
2021-07-29 12:49:46.2827504 dbug: JetBlack.MessageBus.Distributor.Server[0]
OnMessage(sender=46e44dfc-961b-4fae-b6e3-78cabfea9df5: nobody() DESKTOP-011OALS(), message=MessageType=NotificationRequest,Feed="TEST",IsAdd=True
2021-07-29 12:49:46.2836294 info: JetBlack.MessageBus.Distributor.Notifiers.NotificationManager[0]
Handling notification request for 46e44dfc-961b-4fae-b6e3-78cabfea9df5: nobody() DESKTOP-011OALS() on MessageType=NotificationRequest,Feed="TEST",IsAdd=True
We can see the client (or interactor) connecting. Then the receipt and handling of the notification request.
Subscriber
Leave the notifier running and create a new C# console project called "SimpleSubscriber" in the same way we did for "SimpleNotifier", adding the nuget package for adapters.
Change the code in "Program.cs" to be:
using System;
using System.Text;
using JetBlack.MessageBus.Adapters;
namespace SimpleSubscriber
{
class Program
{
static void Main(string[] args)
{
var client = Client.Create("localhost", 9001);
client.OnDataReceived += OnDataReceived;
Console.WriteLine("Subscribing to feed \"TEST\" topic \"FOO\".");
client.AddSubscription("TEST", "FOO");
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
client.Dispose();
}
private static void OnDataReceived(
object sender,
DataReceivedEventArgs e)
{
if (e.DataPackets == null)
{
Console.WriteLine("No data");
return;
}
foreach (var packet in e.DataPackets)
{
if (packet.Data != null)
{
var message = Encoding.UTF8.GetString(packet.Data);
Console.WriteLine($"Received: \"{message}\"");
}
}
}
}
}
The subscriber creates the client in the same way as the notifier. This time
it adds an event handler for OnDataReceived
, which just writes the data it
receives to the console. The message bus is agnostic to the format of the
data. In this case we will be receiving utf-8
strings. Note that the data
is presented as packets. This is the mechanism by which authorisation is
implemented. There is no authentication or authorisation in this example, but
if there was the client would only receive packets for which it was authorised.
After adding the event handler the client calls AddSubscription
to the feed TEST
and the topic FOO
.
Running the program provides the following output:
Subscribing to feed "TEST" topic "FOO".
Press ENTER to quit
However in the notifier we see the following:
User="nobody",Host="DESKTOP-011OALS",ClientId=0098299b-e985-4c3e-a617-b45c53bf078b,Feed="TEST",Topic="FOO",IsAdd=True
The notifier has received the forwarded subscription. It receives the clients credntials, it's Id, the feed, topic, and whether the subscription has been added or removed.
In the distributor console we see a bunch of information:
2021-07-29 13:39:26.1057383 info: JetBlack.MessageBus.Distributor.Interactors.Interactor[0]
Authenticated with NULL as nobody
2021-07-29 13:39:26.1093019 info: JetBlack.MessageBus.Distributor.Interactors.InteractorManager[0]
Adding interactor: 0098299b-e985-4c3e-a617-b45c53bf078b: nobody() DESKTOP-011OALS()
2021-07-29 13:39:26.7359492 dbug: JetBlack.MessageBus.Distributor.Server[0]
OnMessage(sender=0098299b-e985-4c3e-a617-b45c53bf078b: nobody() DESKTOP-011OALS(), message=MessageType=SubscriptionRequest,Feed="TEST",Topic="FOO",IsAdd=True
2021-07-29 13:39:26.7511101 info: JetBlack.MessageBus.Distributor.Subscribers.SubscriptionManager[0]
Received subscription from 0098299b-e985-4c3e-a617-b45c53bf078b: nobody() DESKTOP-011OALS() on "MessageType=SubscriptionRequest,Feed="TEST",Topic="FOO",IsAdd=True"
2021-07-29 13:39:26.7526426 dbug: JetBlack.MessageBus.Distributor.Interactors.InteractorManager[0]
Requesting authorization Interactor=0098299b-e985-4c3e-a617-b45c53bf078b: nobody() DESKTOP-011OALS(), Feed=TEST, Topic=FOO
2021-07-29 13:39:26.7533329 dbug: JetBlack.MessageBus.Distributor.Interactors.InteractorManager[0]
No authorization required
2021-07-29 13:39:26.7558562 dbug: JetBlack.MessageBus.Distributor.Interactors.InteractorManager[0]
Accepting an authorization response from 0098299b-e985-4c3e-a617-b45c53bf078b: nobody() DESKTOP-011OALS() with MessageType=AuthorizationResponse,ClientId=0098299b-e985-4c3e-a617-b45c53bf078b,Feed="TEST",Topic="FOO",IsAuthorizationRequired=False,Entitlements.Count=0.
2021-07-29 13:39:26.7655983 dbug: JetBlack.MessageBus.Distributor.Notifiers.NotificationManager[0]
Notifying interactors[46e44dfc-961b-4fae-b6e3-78cabfea9df5: nobody() DESKTOP-011OALS()] of subscription MessageType=ForwardedSubscriptionRequest,User="nobody",Host="DESKTOP-011OALS",ClientId=0098299b-e985-4c3e-a617-b45c53bf078b,Feed="TEST",Topic="FOO",IsAdd=True
First we see the subscriber connect. Next the distributor receives the subscription request. It checks for authorization, then finally informs clients requesting notifications of the subscription.
Lastly let's run another subscriber. Right click over "Program.cs" and click
"Open Containg Folder". Navigate to the bin\Debug\net6.0
and double-click
on SimpleSubscriber.exe
. This will start a second subscriber.
The notifier should now receive a second forwarded subscription from the second subscriber.
Publisher
Leave the subscriber and publisher running and create a new c# console app "SimplePublisher.cs", adding the adapters nuget package. Replace the "Program.cs" with the following:
using System;
using System.Text;
using JetBlack.MessageBus.Adapters;
using JetBlack.MessageBus.Common.IO;
namespace SimplePublisher
{
class Program
{
static void Main(string[] args)
{
var client = Client.Create("localhost", 9001);
Console.WriteLine("Publishing message to feed \"TEST\" and topic \"FOO\".");
var dataPackets = new[]
{
new DataPacket(null, Encoding.UTF8.GetBytes("Hello, World!"))
};
client.Publish("TEST", "FOO", true, dataPackets);
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
client.Dispose();
}
}
}
We create a client as before. Then we create an array of a single DataPacket
.
The first argument to the DataPacket is the entitlements, for which we pass
null as this feed is not using authorisation. The contents must be a byte[]
,
to we encode the string. Finally we called Publish
with the packets and the feed
TEST
and the topic FOO
.
Running the publisher gives the following output.
Publishing message to feed "TEST" and topic "FOO".
Press ENTER to quit
There's nothing new in the notifier, but both subscribers have the following output.
Subscribing to feed "TEST" topic "FOO".
Press ENTER to quit
Received: "Hello, World!"
Go to the publisher's console and hit ENTER
to quit. The publisher should stop.
In the window for the subscribers we can see the following output:
Subscribing to feed "TEST" topic "FOO".
Press ENTER to quit
Received: "Hello, World!"
No data
When all publishers on a topic have disconnected the distributor will send an empty message to all the subscribers. This can be used as a staleness" indicator.
Now press ENTER
in the window of one of the subscribers.
Looking in the notifier window we see the following:
Requesting notifications on feed "TEST".
Press ENTER to quit
User="nobody",Host="DESKTOP-011OALS",ClientId=df250556-98bb-4916-b860-47221be39ea4,Feed="TEST",Topic="FOO",IsAdd=True
User="nobody",Host="DESKTOP-011OALS",ClientId=83f8c7c5-e143-4ae2-860f-2dfd00d0a3ed,Feed="TEST",Topic="FOO",IsAdd=True
User="nobody",Host="DESKTOP-011OALS",ClientId=df250556-98bb-4916-b860-47221be39ea4,Feed="TEST",Topic="FOO",IsAdd=False
The notifier has been informed that the client that disconnected is not subscribing
to the feed/topic any more. Pressing ENTER
on the other subscriber shows the following in the notifier.
Requesting notifications on feed "TEST".
Press ENTER to quit
User="nobody",Host="DESKTOP-011OALS",ClientId=df250556-98bb-4916-b860-47221be39ea4,Feed="TEST",Topic="FOO",IsAdd=True
User="nobody",Host="DESKTOP-011OALS",ClientId=83f8c7c5-e143-4ae2-860f-2dfd00d0a3ed,Feed="TEST",Topic="FOO",IsAdd=True
User="nobody",Host="DESKTOP-011OALS",ClientId=df250556-98bb-4916-b860-47221be39ea4,Feed="TEST",Topic="FOO",IsAdd=False
User="nobody",Host="DESKTOP-011OALS",ClientId=83f8c7c5-e143-4ae2-860f-2dfd00d0a3ed,Feed="TEST",Topic="FOO",IsAdd=False
Now noone is listening!
Now we have a basic understanding of how this work we can build a selectfeed.