Labs

  1. Trainspotting
  2. Trainmonitoring
  3. CCHAT
  4. Workers

Lab 3: CCHAT

Deadlines

Lab description

Building a “real” concurrent system is not easy. In this lab, we aim to put you through some of that experience. You will need to make design decisions, evaluate trade-offs between performance, simplicity, and ease of debugging, and much more. While challenging, it is plenty of fun!

Programming language

This lab assignment must be developed in Erlang.

How to install Erlang/OTP in your computer.

Background

Nowadays, messaging systems are very popular (Whatsapp, Snapchat, Facebook chat, etc.). They provide great connectivity to users as well as different features like stickers, videos clips, etc. In this lab, you will build a simple (but still quite real) text-based messaging system called CCHAT (the first C is from Chalmers). CCHAT is very much inspired by IRC, an old but still valid standard designed for group discussions. For simplicity, and reasons of time, your implementation of CCHAT is not going to use IRC’s protocol nor low-level TCP/IP communication. Instead, it will leverage Erlang’s processes and message passing features.

Overview

Below, you can find a short video of how CCHAT should look and work.

Some details about the demo:

Architecture

CCHAT uses a client/server architecture. It consists of a client part, which runs the GUI and a client process, and a server, which runs the chat service (server process) and hosts the discussions groups. This picture illustrates the situation.

architecture

The client process (blue circle with double lines) has the goal of building a bridge between the GUI and the server process (the other blue circle with double lines).

The GUI and the client process

The protocol

The protocol between the GUI and the client process is partly fixed. The reason for that is twofold. Firstly, by following the protocol, you will be able to use the GUI without knowing its internal implementation details. Secondly, and more importantly, we will test your code assuming that your client process follow the protocol. If you do not follow it, your code will not pass the tests (see the test section below) and your submission will be immediately rejected.

The protocol scheme is as follows.

Protocol

The GUI sends a message Message requesting some operations. Then, the Client either replies with the atom ok or {error, Atom, Text}. Atom ok indicates that the operation succeeded. Tuple {error, Atom, Text} denotes that something went wrong while processing the request. These errors are not fatal and the GUI can recover from them. Variable Text contains the text to be reported in the System tab of the GUI. You are free to choose the value of Text. However, you should strictly use the values for Atom as described by the protocol.

Until this point, the protocol describes communications initiated by the GUI. There is only one occasion when the client process starts communication with the GUI: when something is written to a channel, the client needs to tell the GUI to display the new text. The client process sends the message {msg_to_GUI, Chatroom, Msg} when it wishes to print out the line Msg in the chat room Chatroom.

Client to GUI

For that, we use the following line of code (which you do not need to change):

gen_server:call(list_to_atom(GUIName), {msg_to_GUI, Chatroom, Name ++ "> " ++ Msg})

Name is the nick of the author, Msg is the message and GUIName contains the name for the GUI process, which is generated in the gui.erl module and passed onto your client in client:initial_state/2.

Observe that gen_server is not the same as genserver (the module that has been shown in class). Module gen_server is the OTP implementation of a generic server.

Error handling

Fatal errors in the protocol

Assignment

Your assignment is to implement the chat server described here, based on the skeleton available in the code skeleton section.

Successful solution requires performing these steps (and more):

Code skeleton

In this lab, you are required to build the client and server processes based on the structure in the skeleton code. The main reason for that is to make it easier to have your lab up and running. You could use any Erlang code that we discussed during the lectures if it helps you.

It is up to you to decide the protocol between the client and the server!

We will give you the following files. Do not edit the ones highlighted in red.

Download material for the lab

To get started, you need the skeleton code package.

First compilation

After you have downloaded the skeleton code, compile everything with the command:

make all

You can then open the Erlang shell (erl) and start a client with cchat:start(). You should be able to start the server and open up chat windows, but Bilbo and Frodo will not able to communicate because most of the functions are not implemented. It is your task to make sure that they can!

Tips and tricks

Test cases

All unit tests are contained in the file test_client.erl. Tests are carried out using EUnit. We have created entries in the Makefile to make life easier for you.

There are positive and negative tests which check that your solution follows the requirements and protocol as specified above. To run these tests, execute the following:

make -s run_tests

If your submission fails any of the tests, it is a good indication that your submission will be rejected. However even if you pass all of the tests, that is not a guarantee that your submission will be accepted.

Performance and concurrency tests

In addition to the standard set of tests, we provide performance tests, which test your use of concurrency. There are three kinds of performance tests:

  1. many_users_one_channel_one_message creates many users that join the same channel. Then one of the users sends a single message to the channel. Sending of the message should be quick enough for the send operation not to time out.
  2. many_users_one_channel_many_messages creates many users that join the same channel. Then each of the users sends a message to the channel. Sending of all messages should be quick enough for the send operations not to time out. This test has a higher chance of provoking deadlocks than the other tests.
  3. many_users_many_channels creates many users and many channels. Each user joins two of the channels, and sends a message to one of them. The test fails if any of the send operations times out. Sending a message to one channel should not affect the performance of other channels in a negative way.

When the tests are run, artificial delays are introduced to receiving of some messages. The purpose of the delays is to evaluate the concurrency characteristics of your solutions.

To run the performance tests, use:

make -s run_perf_tests

The tests are not run as part of the run_tests target.

Passing or failing the performance tests is only an approximate indication of whether your submission will be accepted or rejected, due to the unpredictability of execution timing.

Turning off color codes

If you don’t have a color-enabled terminal, you will see a lot of ugly color codes in your test output. You can disable these by commenting out the colour function in test_client.erl and replacing it with:

colour(Num,S) -> S.
Menu