Creating a Chat Using Pub/Sub

I’ve been getting back into playing multiplayer games lately and I’ve started looking for interesting things to build while playing. One game I have enjoyed in particular has 16 players all spamming chat playing detective to find a group of evildoers among us. I was inspired to build a chat for games and began researching methods for sending and receiving messages. Requirements included:

  • One-to-One (Direct) and One-to-Many messaging functionality
  • Transmission method that did not require a full server to be developed

I began to explore some solutions in the space and I stumbled upon Pub/Sub. Using Google Cloud Pub/Sub, the road-map for creating a chat is:

  1. Create a topic
  2. Players subscribe to topic to receive messages
  3. Players publish messages to topic
  4. Messages are delivered to subscribers of the topic
  5. Messages are acknowledged by each subscriber
Google Cloud Pub/Sub Architecture

Looking at the architecture above you can get a visual idea of the flow of our solution. As publishers, players publish messages to a topic within Cloud Pub/Sub. Pub/Sub will handle messages and any subscribed players will receive the message.

Let’s start building out the game chat and take a deeper look at Google Cloud Pub/Sub.

Getting Started with Google Cloud PubSub

To use Google Pub/Sub, create a new project on Google Cloud Console. Take note of the Project ID after successfully creating your project. You’ll be using it later in the solution.

Once the project is created, enable the Pub/Sub API in the API Library.

Pub/Sub requires authentication for use so select Create Credentials.

For role it is recommended you add the proper role permissions for each API (in case your service account file becomes compromised) but for this example use Project->Owner. Name your service account download the service account key file. Store it in a safe location you can find easily.

To use this service account, set an environment variable using the commands in the images below.

Once we have completed these steps, we are ready to build out our chat.


Building Our Chat

We will go through all of the steps to add Pub/Sub functionality to your chat. To add in Pub/Sub functionality, I have followed the Google PubSub C# client library reference with application specific modifications. I’ve created a C# console application in Visual Studio for the chat. I’ve also added the Google.Cloud.PubSub.V1 NuGet package and included it within my source file.

Create a Topic

The first step using Pub/Sub is to create a Topic. We can do so with these four lines of code:

PublisherServiceApiClient publisherService = await PublisherServiceApiClient.CreateAsync();
TopicName topicName = new TopicName([YOUR PROJECT_ID], "General");
publisherService.CreateTopic(topicName);

The code above creates a topic for the General channel (topicId = “General”) utilizing the project ID from the Google Cloud Console. Note that in a normal chat application, you wouldn’t want your users to have the ability to create topics freely. Now that you’ve created your channel the next step is to subscribe to the topic you’ve created.

Subscribing to a Topic

SubscriberServiceApiClient subscriberService = await SubscriberServiceApiClient.CreateAsync();
SubscriptionName subscriptionName = new SubscriptionName([YOUR PROJECT_ID], "generalsubscription");
subscriberService.CreateSubscription(subscriptionName, "General", pushConfig: null, ackDeadlineSeconds: 60);

The code above creates a subscription for the General topic named generalsubcription. This will allow you to receive messages from the topic either using a pull or push method. The difference between the two mechanisms are:

  • Pull subscription requires the subscriber’s client to initiate requests for messages.
  • Push subscription will allow Cloud Pub/Sub to initiate requests to subscriber clients to deliver messages.

Find more information on pull/push subscription here.

Publishing a Message to Pub/Sub

Now that we have created a subscription, we will publish a message to our General topic. The code below publishes a message that says “Hello, Pubsub” to Pub/Sub.

// Publish a message to the topic using PublisherClient.
PublisherClient publisher = await PublisherClient.CreateAsync("General");
// PublishAsync() has various overloads. Here we're using the string overload.
string messageId = await publisher.PublishAsync("Hello, Pubsub");
// PublisherClient instance should be shutdown after use.
// The TimeSpan specifies for how long to attempt to publish locally queued messages.
await publisher.ShutdownAsync(TimeSpan.FromSeconds(15));

Pulling Messages from Pub/Sub

Using the pull subscription approach, there must be a call to the Pub/Sub server to receive messages. To illustrate this, below is a call to the Pub/Sub server to initiate the request to the generalsubscription on the general topic.

await subscriber.StartAsync((msg, cancellationToken) =>
{
Console.WriteLine($"Received message {msg.MessageId} published at {msg.PublishTime.ToDateTime()}");
Console.WriteLine($"Text: '{msg.Data.ToStringUtf8()}'");
subscriber.StopAsync(TimeSpan.FromSeconds(15));
// Return Reply.Ack to indicate this message has been handled.
return Task.FromResult(SubscriberClient.Reply.Ack);
});

The asynchronous calls used in the code above have several advantages, such as:

  • Allows for messages to come from multiple subscriptions without disrupting the application/game
  • If your application allows, creating a subscription for another user without any overhead and as low latency as possible

It is also important to note that our subscriber stops after receiving one message using subscriber.StopAsync. Feel free to remove this to continue listening but stop listening for messages at some other point in your code.

Before executing our code, add these two lines to the end of the program:

// Tidy up by deleting the subscription and the topic.
subscriberService.DeleteSubscription(subscriptionName);
publisherService.DeleteTopic(topicName);

This will ensure you delete the topic and subscription and avoid getting an error should you wish to run it again because of an existing topic. Run the code and check out the results in your console.

There you have it! After execution, you should see a message in your console that you received a message posted seconds ago and another message which is an echo of Hello, Pubsub. Had 15 others subscribed to this topic, you would have recreated the game chat I described earlier. There are many other areas to explore to give this solution additional features found in other chats. Stay tuned for more developments and improvements.

.NET Pub/Sub Client Library Reference: .NET Reference

Check out Google Pub/Sub Documentation here: Cloud Pub/Sub

Full Google Cloud Authentication Guide