How to Build Realtime Chat in the Terminal with Python

We’re breaking down chat in the simplest way possible. In this tutorial, we’ll walk you through building realtime chat in the terminal. Why build chat in the terminal?

  1. It’s lightweight. No opening up the browser, loading of JS libraries or any front-end code.
  2. Quickly test your idea without having to worry about UI.
  3. Deploy this app on a remote server and SSH into it if you are not allowed to chat on your local machine.

Let’s jump right into the code of terminal chat application built in Python using PubNub’s Python SDK.

Source to PubNub Code

You can find the source code for this tutorial here.

We’ll start by adding the entry point to the program:

def main():

if __name__ == "__main__":
   main()

You can read more about this here.

Import some modules we will be using:

from pubnub import Pubnub
import sys
import os

You will need to use pip3 install pubnub to install PubNub’s package.

As soon as the main() function is executed, we want to get chatroom (i.e. channel) user wants to subscribe to and their name, then acknowledge them by name and that they have entered the chatroom. We can do that by:

chatroom = input("Please enter the name of chat room you want to enter: ")
user_name = input("Please enter your name: ")
print("Hello {}. Welcome to {} chatroom".format(user_name, chatroom))

When they login, we instantiate PubNub with publish and subscribe keys. You’ll need to sign up for PubNub to get your keys if you haven’t already. Once you have, your keys are available in the PubNub Admin Dashboard.

Also, we have mentioned that UUIDs will be user_name, as that is unique to every user.

pn = Pubnub(publish_key="demo", subscribe_key="demo", ssl_on=False, uuid=user_name)

We want the dialogues in chat room to look something like this:

Username: Message

For example,

Anmol: Hi there!!!

We will be using this format in future inside some callback functions.

Then we subscribe to the channel entered by user.

channel = chatroom
pn.subscribe(channels=channel, callback=_callback)

def _callback(message, channel):
       if message['user_name'] != user_name:
           print("\n{}: {}".format(message['user_name'], message['message']))
           print("{}: ".format(user_name))

Here in the _callback function, we are checking is ‘user_name’ in ‘message’ same as current user. If it’s not, we show their message. If it is, it will show message typed by current user twice in the chatroom, which is a bad user experience. We print out the message in the format we discussed before.

Let’s get the history of a channel (i.e. old messages), if there are any. This is called as soon a user enters a chatroom.

pn.history(channel=channel, count=100, callback=_history_callback, error=_error)

def _error(error):
       print(error)

def _history_callback(message):
       for msg in message[0] :
           print("\n{}: {}".format(msg['user_name'], msg['message']))

This gets last 100 messages from the history of channel. In _history_callback, we are getting all those message and looping through them to print out the messages in format discussed before.

Now we want to get input from user and based on their input, we want to show them some result.

def get_input():
      message = input("{}: ".format(user_name))

       if str(message) in ['quit', 'QUIT', 'Quit', 'exit', 'Exit', 'EXIT']:
           print("Quitting...")
           pn.unsubscribe(channel=channel)
           sys.stdout.flush()
           os._exit(0)
       elif str(message) in ['whosonline', ‘whoisonline']:
           pn.here_now(channel=channel, callback=_whosonline_callback, error=_error)
       elif str(message) in ['howmanyonline']:
           pn.here_now(channel=channel, callback=_howmanyonline_callback, error=_error)
       else:
          msg_object = dict(user_name=user_name, message=message)
           pn.publish(channel=channel, message=msg_object)

def _whosonline_callback(message):
       print("Following are online :")
       print("-------------")
       for msg in message['uuids'] :
           print(msg)

   def _howmanyonline_callback(message):
       print("\n{} online...".format(message['occupancy']))

while True:
       get_input()

There is no UI interaction in terminal/command prompt apps. So, we have to give options to user to interact using some keywords. First of all, we get the input from user and store in a variable ‘message’.

Then we check, if message is either of these values (‘quit’, ‘QUIT’, ‘Quit’, ‘exit’, ‘Exit’, ‘EXIT’), we unsubscribe them from the chatroom and close the application.

If ‘message’ is either of these values(‘whosonline’, ‘whoisonline’), we show them the name of users online using here_now API. We get the UUIDs that are online from message we get from _whosonline_callback.

If ‘message’ is ‘howmanyonline’, we use the same here_now API. In the _howmanyonline_callback, we have ‘occupancy’ key in returned object which has the number of occupancies in the channel.

If the input is none of these, it means it’s a message from user to be published to the chatroom.

msg_object = dict(user_name=user_name, message=message)
pn.publish(channel=channel, message=msg_object)

We just create a dictionary containing the username who wants to publish with their message. Then use the publish API to send the msg_object to the channel.

Conclusion

This demo is an example of how we can create a terminal app, which doesn’t really have a UI, because of which, we have to rely a lot on commands for user to be able to interact with app.

For example, you already have a cab booking app and you type in a command in your terminal, “how far is my cab?”, it does all the logic work behind the scenes and shows you “2 minutes…”. This is a great way to work on a prototype where you emphasize more importance to functionality than UI, or may be use it in fully fledged project if it fits your need.

Try PubNub Today

Connect up to 100 devices for Free