Grading procedure

Deadlines

First deadline: 4th of October, 23:59.
Final deadline: 18th of October, 23:59.

chat bubbles

Introduction to CCHAT

Check how to install Erlang/OTP in your computer!

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 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.

Architecture

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 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})

Where Name is the nick of the author and Msg is their message. 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.

Variable 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.

Errors

Fatal errors in the protocol

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 saw at the lectures if it helps you.

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

Component Files Description
GUI
 gui.erl lexgrm.erl grm.yrl lex.xrl 
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(client_st, {gui}). defines the record client_st (client state) where field gui stores the name of the GUI.
Client process
 client.erl 
The exported function client:loop/2 handles each different kind of request, returning a tuple of the response and the updated state. You also need to implement initial_state(Nick, GUIName) which generates the initial state for the client.
Server process
 server.erl 
The exported function server:loop/2 handling messages from the GUI process in a loop, in a similar way to the client. It is up to you to decide the protocol between the client and the server! You also need to implement initial_state(ServerName) which generates the initial state for the server.
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.
Generic Server
 genserver.erl 
This file contains functions for spawning and running Erlang processes as servers. and implementing synchronous message passing. It is used internally, so do not modify this file... but you might want to use its functions yourselves!

Obtaining the code

Skeleton code repository on GitHub

Easy method

To download the skeleton code as an archive, click on the button that says "Download ZIP" on the repository page. Be advised that we may make improvements to the skeleton and you may be required to update some files manually. For a better solution, use Git (below).

Using Git

First clone the repository locally, naming the upstream remote as skeleton (instead of the default origin):

git clone -o skeleton https://github.com/Chalmers-TDA382/tda382-lab3-code-skeleton.git cchat

Then enter the cchat folder and start working on your solution!

If you want to push your changes to your own private repository, set that up as the origin remote and push to it:

git remote add origin 
git push -u origin master

As with any other coding project, we suggest that you commit and push frequently:


git commit -am "Informative commit message"
git push origin

Whenever you need to update the skeleton, pull from the skeleton remote:

git pull skeleton master

Unless you have made modifications to the skeleton files, you shouldn't have any merge conflicts. If you have uncommited local changes, try stashing them first:

git stash
git pull skeleton master
<...>
git stash pop

Compiling for the first time

After you download it (and extract the files) you should 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!

Alternatives to make

If you do not have make command, 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().

Tips

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 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.

Robustness tests

Included in the unit tests are robustness tests, which test your use of concurrency. The robust_channel test checks if your chat server can continue to operate when some of your requests are caused to hang. It works as follows (actual values may change):

  1. A server is started and 4 channels are created.
  2. Each channel is joined by 3 users. No user is in more than one channel, making the total number of users 4 × 3 = 12.
  3. Every user sends 2 messages on their respective channel. The test framework will automatically make some of these requests hang.
  4. We count how many messages get through successfully. If you use concurrency correctly, only the blocked messages should get stuck, and all others should be delivered successfully.

The robust_server test checks how independent your channels are from your server. It does this by killing the server process during an ongoing chat. If this causes the entire CCHAT system to die then the test will fail, which is a sure sign that your solution is not very concurrent.

To run just the robustness tests, use:

$ make -s run_robustness_tests

Alternatives to make

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

$ erlc *.erl
$ erl -noshell -eval "eunit:test(test_client), 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.