Deadlines

First deadline: 8th of October
Final deadline: 12th of October
Check how to install Erlang/OTP in your computer!

chat bubbles

Introduction to CCHAT

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

The topic

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.

A first look

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

Here, some details about the demo.

Arquitecture

CCHAT will use a client-server architecture. It consists on a client part, which runs the GUI and a client process, and a server which runs the chat service (server process) and host the discussions groups. The graphic below illustrates the situation.

architecture

In the graphic above, the client process (blue circle with double lines) has the goal to be 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 two fold. 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 that. 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 a communication with the GUI.

The client process sends the message {income_msg, Name, Chatroom, Msg} when it wishes to print out the line Name++"> "++Msg in the chat room Chatroom.

Client to GUI

For that, it is used the following line of code

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

Observe that gen_server is not the same as genserver (the module that it has been shown in class). Module gen_server is the OTP implementation of a generic server. You should keep using the module genserver which is simpler, although less generic, than gen_server.

Variable GUIName contains the name for the GUI process. In the module gui.erl you will find the following code:

GUIName = find_unique_name("gui_", ?MAX_CONNECTIONS )

Variable GUIName is the one that you need to pass to the client process when creating it. Do not worry, we give you the code already to handle these type of messages. See more details in the Section code skeleton.

Errors

Fatal errors in the protocol

Code skeleton

In this lab, you are required to build the client and server processes using the generic server given at the lectures. 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 saw at the lectures if it helps you.

We will give you the following files:

Component Files Description
GUI
 gui.erl lexgrm.erl grm.erl lex.erl 
These files contain the implementation of the GUI. Do not modify them.
Testing
 test_client.erl dummy_gui.erl 
Files used for testing. Do not modify them.
Record definitions
 defs.hrl 
This file contain record definitions. The state of the client, server, or any other entity that you wish to add should represent its state as a record. We provide you with some incomplete definitions already. For instance, -record(cl_st, {gui}). defines the record cl_st (client state) where field gui stores the name of the GUI.
Client process
 client.erl 
You should implement the client process loop used to handle the requests from the GUI. For that, you need to implement function loop and initial_state(Nick, GUI) (the latter function generates the initial state for the client). These functions are used to launch the client process with genserver:start/3 when starting the GUI.
Server process
 server.erl 
You should implement the server process loop used to handle the requests. For that, you need to implement function loop and initial_state(Server). This last function generates the initial state for the server. Variable Server contains the name of the server. For the purpose of the lab, it will always be "shire". These functions are used to launch the server process with genserver:start/3 in the module cchat.
CCHAT
 cchat.erl 
This is the top level module. It is used to launch the server and several clients with their respective GUIs. Do not modify this file.

Here, you can get the code skeleton! To download it, click on the button that says "Download ZIP". After you download it, you can start perform the same demo as in the first video. Unfortunately, Bilbo and Frodo are not able to communicate. It is your task to make sure that they can!

See the next video to see how to get the code skeleton and launch the GUI.

If you do not have GNUMakefile, you should run the following commands in the Erlang shell.

  cd("the directory where the skeleton code is").
  c(lexgrm).
  lexgrm:start().
  cover:compile_directory(). 

Requirements

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 (see below for alternatives to using make). There are two sets of tests, correctness and performance tests.

The video below shows how to use the test suite (includes audio):

Correctness

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

Performance

We have also included two cases which test the performance of your solution by spawning large numbers of clients and channels simultaneously. To run them, use the command:

$ make -s run_perf_tests

This will run the performance tests 3 times: once using 4 cores, once with 2 cores, and once with only 1 core enabled. In each case you will see the time elapsed for the test case to complete. To test your use of concurrency, we expect that your solution will be significantly faster with more cores. The actual times do not matter much, as long as there is a noticeable improvement.

We will run these tests on the remote[n].student.chalmers.se machines (which have 4 cores), and we suggest you do the same.

Alternatives to make

If your system doesn't have the make command, you can run the test suites like so:

Correctness

$ erl +P 1000000 -eval "cover:compile_directory(), eunit:test(test_client), halt()"

Performance

The number 4 below specifies the number of cores to use. Make sure to run this command with values 4, 2, and 1:

$ erl -smp +S 4 +P 1000000 -eval "cover:compile_directory(), eunit:test([{timeout, 60, {test,test_client,many_users_one_channel}},{timeout, 60, {test,test_client,many_users_many_channels}}]),halt()"

Turning off colour codes

If you don't have a colour-enabled terminal, you will see a lot of ugly colour 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.

Submission

You should submit your code based on the skeleton code and whatever other files are needed for your solution to work. In addition, you should comment your code so that graders can easily review your submission.