|
| 1 | +--- |
| 2 | +layout: lab |
| 3 | +toc: true |
| 4 | +title: Chat Client |
| 5 | +number: 7 |
| 6 | +--- |
| 7 | + |
| 8 | +> Programs must be written for people to read, and only incidentally for machines to execute. |
| 9 | +> |
| 10 | +> [Harold Abelson](https://en.wikipedia.org/wiki/Hal_Abelson) |
| 11 | +
|
| 12 | +## GitHub Classroom |
| 13 | + |
| 14 | +Use the GitHub Classroom link posted in the Teams channel for the lab to accept the assignment. |
| 15 | + |
| 16 | +## Historical Time Spent on Lab |
| 17 | + |
| 18 | +N/A |
| 19 | + |
| 20 | +## Overview |
| 21 | + |
| 22 | +For this lab, you will be writing a chat client using [MQTT](https://mqtt.org) in Python. Your chat client will need to be able to chat with other students through the MQTT broker. There are two parts to this lab, the "protocol" (how to format the payload) and the user interface. |
| 23 | + |
| 24 | +MQTT is a different type of application layer protocol from what you have seen in the past. It will be worth your time to understand how it works before you dive into implementing a client. We discussed it in lecture, but reading some [articles](https://www.hivemq.com/blog/how-to-get-started-with-mqtt/) and/or watching some [videos](https://youtu.be/LKz1jYngpcU) will help you understand it better. It is a fairly complex protocol when you get into the details of how it works. |
| 25 | + |
| 26 | +To use MQTT, you need a few pieces of information: |
| 27 | + |
| 28 | +- **Hostname**. This is the hostname of the broker. (In MQTT, they call the server a broker.) |
| 29 | +- **Port number**. This is the port number that the broker is bound to. For MQTT, the standard ports are 1883 and 8883. |
| 30 | +- **Client ID**. A string to uniquely represent the client that has connected to the broker. |
| 31 | +- **Topic**. The topic that you are subscribing to or publishing to. Topics are just strings but are typically hierarchical. Different namespaces are separated by slashes `/`. For example, in home automation, if you want to communicate with a light, the topic might be `home/upstairs/bedroom/light`. A topic is needed to publish or subscribe to. |
| 32 | +- **Message**. The message you want to publish (if applicable). |
| 33 | +- **Username and password** *(optional)*. Brokers can require that clients provide a username and password. Without a username and password, clients are anonymous. The username can be the same as the client ID. |
| 34 | + |
| 35 | +We will not be using a username and password for this lab. |
| 36 | + |
| 37 | + |
| 38 | +### Protocol |
| 39 | + |
| 40 | +For this lab to work with other students, we need to standardize some way of formatting the MQTT message's payload and topic. There are two different topic sets: `<netid>/message` where all messages get published and `<netid>/status` where all status updates get published. |
| 41 | + |
| 42 | +Your chat client will subscribe to two topics: `+/message` and `+/status`. These topics will allow you to receive all messages that are published from any NetID (including your own...). When you want to send a message, and assuming your NetId is "le0nh4rt", your client will publish to `le0nh4rt/message`, and when you want to update your status, you will publish to `le0nh4rt/status`. |
| 43 | + |
| 44 | +The payload for the `<netid>/message` publications must contain [`json`](https://www.json.org/json-en.html) data with the following keys: |
| 45 | + |
| 46 | +- `timestamp`: The time the message was published, formatted as the [epoch time (or Unix time)](https://en.wikipedia.org/wiki/Unix_time). |
| 47 | +- `name`: The name of the person sending the message. |
| 48 | +- `message`: The message you are sending. |
| 49 | + |
| 50 | +For example, if you are publishing a message, "Hello world" at 8:13:00 AM on Nov 24, 2020, then the payload would be the following: |
| 51 | + |
| 52 | +```json |
| 53 | +{"timestamp": 1606230780, "name": "Dr. Phil", "message": "Hello world"} |
| 54 | +``` |
| 55 | + |
| 56 | +The payload for the `<netid>/status` publications must contain `json` data with the following keys: |
| 57 | + |
| 58 | +- `name`: The name of the person sending the message. |
| 59 | +- `online`: An integer showing if the person is online or not. 0 for offline and any other value for online. |
| 60 | + |
| 61 | +For example, to update your status to "online", the payload of the status update would be: |
| 62 | + |
| 63 | +```json |
| 64 | +{"name": "Dr. Phil", "online": 1} |
| 65 | +``` |
| 66 | + |
| 67 | +You must publish an "online" message when you start your client and register a [last will](https://mntolia.com/mqtt-last-will-testament-explained-with-examples/) with the broker that publishes an "offline" message when you disconnect. To make the status messages more useful, you must set the [retain flag](https://www.hivemq.com/blog/mqtt-essentials-part-8-retained-messages/) for all status message publications. |
| 68 | + |
| 69 | +### User Interface |
| 70 | + |
| 71 | +This interface will be different from any other lab. Rather than using a command-line interface, you will be building an interactive interface. You have a couple of options for how you want to approach this interface: |
| 72 | + |
| 73 | +1. Build a terminal user interface (TUI). You can use the [ncurses](https://en.wikipedia.org/wiki/Ncurses) library (through the [curses](https://docs.python.org/3/library/curses.html) module in Python) to build a TUI. However, in my opinion, ncurses is a outdated and there are better TUI tools, such as [Texual](https://textual.textualize.io/getting_started/). This approach will allow you to run your chat client in a terminal window. You will need to handle user input, display messages, and update the list of online users. There are many tutorials online for how to use ncurses to build TUIs. |
| 74 | + |
| 75 | +2. Build a graphical user interface (GUI). You can use a GUI library like [Tkinter](https://docs.python.org/3/library/tkinter.html) (which is included with Python). This approach will allow you to create a more user-friendly interface with buttons, text boxes, and other widgets. There are many tutorials online for how to use Tkinter to build GUIs. |
| 76 | + |
| 77 | +Regardless of which option you choose, you must provide the following usage pattern to start your program: |
| 78 | + |
| 79 | +``` |
| 80 | +Usage: chat.py [--help] [-v] [-h HOST] [-p PORT] [-n NAME] NETID |
| 81 | +
|
| 82 | +Arguments: |
| 83 | + NETID The NetID of the user. |
| 84 | +
|
| 85 | +Options: |
| 86 | + --help |
| 87 | + -v, --verbose |
| 88 | + --host HOSTNAME, -h HOSTNAME |
| 89 | + --port PORT, -p PORT |
| 90 | + --name NAME, -n NAME |
| 91 | +``` |
| 92 | + |
| 93 | +If no name is provided, then use NETID as the name. |
| 94 | + |
| 95 | +<!-- Here is a demonstration of the chat client: |
| 96 | +
|
| 97 | +<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/-3XYROryln8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> --> |
| 98 | + |
| 99 | +## Objectives |
| 100 | + |
| 101 | +- Build something that interfaces with third party code. |
| 102 | + |
| 103 | +- Get exposure to integrating with UI code or writing your own UI code. |
| 104 | + |
| 105 | +- Have fun! |
| 106 | + |
| 107 | + |
| 108 | +## Requirements |
| 109 | + |
| 110 | +- The name of your program must be named `chat.py`. |
| 111 | + |
| 112 | +- Your program must have the usage pattern provided above and parse all of the options and arguments correctly. |
| 113 | + |
| 114 | +- You are allowed to use the following third-party Python libraries. All other third-party libraries are off limits. |
| 115 | + - [Paho MQTT Client library](https://www.eclipse.org/paho/index.php?page=clients/python/docs/index.php) |
| 116 | + - [Texual](https://textual.textualize.io/getting_started/) *(if you are building a TUI)* |
| 117 | + |
| 118 | +- The default port must be `1883`, and the default hostname must be `localhost`. |
| 119 | + |
| 120 | +- Your client must be able to work with other chat clients. *This might require you to coordinate with other students to make sure they are online when you are testing*. |
| 121 | + |
| 122 | +- Your client must subscribe and publish using QoS of 1. |
| 123 | + |
| 124 | +- Your client must publish an "online" status message when first connecting to the broker and register a last will to publish an "offline" status for when your client disconnects. |
| 125 | + |
| 126 | +- Your status messages must set the retain flag to `true`. |
| 127 | + |
| 128 | +- To support multiple instances of your chat client, you must add randomness to the client ID you use to connect to the broker. You are free to choose how you want to add randomness to your client ID. |
| 129 | + |
| 130 | +- Your user interface must show the following information: |
| 131 | + - Messages that have been sent and received. It must include the time the message was sent, the name of the person that sent the message, and the message itself. The timestamp must be human-readable and not in epoch time format. |
| 132 | + |
| 133 | + - Show when people have left or joined the chat server. This can be inline with the chat messages. |
| 134 | + |
| 135 | +## Testing |
| 136 | + |
| 137 | +The chat server will be hosted at lundrigan.byu.edu:1883. |
| 138 | + |
| 139 | +One good way of testing your chat client is to bring up multiple instances of your client. That way, you can see how it responds to people coming online and offline. |
| 140 | + |
| 141 | +## Submission |
| 142 | + |
| 143 | +Since this is using a TUI or a GUI, it is hard to do automated testing. Therefore, you will need to record a short video (1 to 2 minutes) demonstrating your chat client fulfills **all of the requirements**. You will submit this video to Learning Suite. |
| 144 | + |
| 145 | + |
| 146 | +## Resources |
| 147 | + |
| 148 | +- [Textual tutorial](https://textual.textualize.io/tutorial/) |
| 149 | + |
| 150 | +- [Paho MQTT Python documentation](https://eclipse.dev/paho/files/paho.mqtt.python/html/index.html) |
| 151 | + |
| 152 | +- [Paho MQTT Python client publication example](https://github.com/eclipse/paho.mqtt.python/blob/master/examples/client_pub-wait.py) |
| 153 | + |
| 154 | +- [Paho MQTT Python client subscription example](https://github.com/eclipse/paho.mqtt.python/blob/master/examples/client_sub.py) |
0 commit comments