Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mcfilib/dropcure

Toy project demonstrating WebSockets in Haskell
https://github.com/mcfilib/dropcure

haskell websockets

Last synced: 23 days ago
JSON representation

Toy project demonstrating WebSockets in Haskell

Awesome Lists containing this project

README

        

# dropcure

`dropcure` was a take home assignment I did as part of a job interview. It consists of two services and
one library.

- `producer` - publishes messages received on websockets to a message queue.
- `consumer` - broadbasts messages from the message queue to clients connected via websockets.
- `common` - shared code for both services.

## Overview

Both `producer` and `consumer` follow a similar pattern in that each implements
a client and a server as a subcommand.

### producer

#### Server

The `producer` server operates as follows:

- Wait for RabbitMQ service to become available.
- Connect to RabbitMQ server and create queue and channel if it doesn't exist.
- Disconnect from RabbitMQ.
- On new websocket connection:
- Connect to RabbitMQ.
- Send handshake message.
- Repeatedly publish any message to RabbitMQ.

#### Client

The `producer` client is intended to be used for debugging purposes and operates
as follows:

- Connect to server.
- Receive handshake.
- Every `n` seconds emit a static message (`"beep"`).

### consumer

#### Sever

The `consumer` server operates as follows:

- Initialise an empty mapping between unique identifiers and websocket.
- Wait for RabbitMQ service to become available.
- Connect to RabbitMQ server and create queue and channel if it doesn't exist.
- Subscribe to the queue.
- On new websocket connection:
- Create unique identifier.
- Add connection to mapping for given identifier.
- On websocket disconnection:
- Remove connection from mapping.
- On new message in the queue:
- Enumerate all connections in mapping and emit message via websockets.

#### Client

The `consumer` client is intended to be used for debugging purposes and operates
as follows:

- Connect to server.
- Receive handshake.
- On new message emitted by the server:
- Print it to `stdout`.

## Future Enhancements

### Functionality

- [ ] Handle situation when RabbitMQ goes down.

### Testing

- [ ] Add more tests.
- [ ] Add mocks to test `IO` without doing `IO` as outlined in [this blog post](https://lexi-lambda.github.io/blog/2017/06/29/unit-testing-effectful-haskell-with-monad-mock/).

### Operations

- [ ] Add Docker build image so that it doesn't rely on the host OS being the same as the target.
- [ ] Shrink Docker image e.g. use Alpine with `glibc` to keep the image sizes down.
- [ ] Re-enable layer caching.

## Usage

The instructions below assume that you are
running [Ubuntu](https://www.ubuntu.com/),
have [Stack](https://docs.haskellstack.org/en/stable/README/) installed and have
the [Docker](https://www.docker.com/) daemon running.

```
$ make up # start necessary services
$ WEBSOCKET_PORT=8001 consumer client # run the consumer client
$ WEBSOCKET_PORT=8000 producer client # run the producer client
```

### Dependencies

- `docker`
- `stack`
- `ubuntu`

## Development

### Tasks

```
% make
build Build producer and consumer Docker containers
clean Clean up build artefacts
help Print available tasks
install Compile producer and consumer
up Start services
```