Skip to content
Snippets Groups Projects
Readme.md 4.71 KiB
Newer Older
# Problem 2: Actors

## Setup

Use the following commands to make a fresh clone of your repository:

```
git clone -b concpar21final02 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar21final02
```

If you have issues with the IDE, try [reimporting the
build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting),
if you still have problems, use `compile` in sbt instead.

## Useful links

  * [A guide to the Scala parallel collections](https://docs.scala-lang.org/overviews/parallel-collections/overview.html)
  * [The API documentation of the Scala parallel collections](https://www.javadoc.io/doc/org.scala-lang.modules/scala-parallel-collections_2.13/latest/scala/collection/index.html)
  * [The API documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.4)
  * [The API documentation of the Java standard library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html)

## Exercise

Your task is to implement a couple of actors in Discord like service. You will only focus on two actors in the system: (1) the `NotificationService` and (2) and a `DiscordChannel`.

A user will be able to post messages on the channel and retrieve the messages from the channel.
A user also has the ability to (un)register from the notifications.
Before it can receive requests, each channel is initialized with a notification service.
When a message is posted to the channel, it tells its notification service to notify the users.

The following diagram shows how the communication between actors works. Requests are within `()` and responses are within `[]`.

```none
           (Post)                                     [Active]
       (GetLastPosts)       ┏━━━━━━━━━━━━━━━━━━┓  [AlreadyActive]  ┏━━━━━━━━━┓
    ┌──────────────────────>┃                  ┃──────────────────►┃         ┃
    │                       ┃  DiscordChannel  ┃                   ┃ System  ┃
    │                       ┃                  ┃◄──────────────────┨         ┃
    │          [Posts]      ┗━┯━━━━━━━━━━━━━━━┯┛      (Init)       ┗━━━━━━━━━┛
 ┏━━┷━━━┓    [NotActive]      │               │
 ┃      ┃◄────────────────────┘               │
 ┃ User ┃                                     │
 ┃      ┃◄────────────────┐                   │
 ┗━━┯━━━┛  [Registered]   │                   │ (NotifyAll)
    │     [Notification]  │                   │
    │                     │                   │
    │                ┏━━━━┷━━━━━━━━━━━━━━━━┓  │
    └───────────────►┃                     ┃  │
     (Register)      ┃ NotificationService ┃◄─┘
    (UnRegister)     ┃                     ┃
                     ┗━━━━━━━━━━━━━━━━━━━━━┛
```

Your tasks in the exercise will be to:

TASK 1: Complete the implementation of the `NotificationService` by implementing method `receive` to handle messages from `NotificationService.Protocol`:

```scala
def receive: Receive = ???
```
TASK 2: Complete the implementation of the `DiscordChannel` by implementing methods `nonActive` and `active` to handle messages from `DiscordChannel.Protocol`:

```scala
def nonActive: Receive = ???
def active(notificationService: ActorRef): Receive = ???
```

### NotificationService protocol

* __Register__: Registers the user for notifications and responds with a `Registered(true)`.
* __UnRegister__: Un-registers the user for notifications and responds with a `Registered(false)`.
* __NotifyAll__: Sends a `Notification` to all registered users.


### DiscordService protocol

The channel can be in one of two states: _non-active_ or _active_.

* __Init__: When _non-active_, responds with `Active` and the state becomes _active_. Otherwise responds `AlreadyActive`.
* __Post__: When _active_, stores the message and sends `NotifyAll` to its `NotificationService`. Otherwise responds `NotActive`.
* __GetLastPosts__: When _active_, responds with `Posts` containing the latest messages (ordered from most to least recent). Otherwise responds `NotActive`.

### Running the code

Apart from the grading tests, we include a `@main def debug` method, where you can write your own tests to help you debug your implementation. This method is __not__ graded. It can be executed using `run` within SBT.