Python 3.13.7
C#.Net 8.0.400
Clients are written in python, there is a requirements.txt in the root folder to use with pip
Run the student client:
pip install -r requirements.txt
cd StudentClient
python StudentClient.pyRun the supervisor client:
pip install -r requirements.txt
cd SupervisorClient
python SupervisorClient.pyServer is written in C# using .Net with dependencies managed using NuGet
To run the server, from DS_Assignment root:
cd Server
dotnet restore
dotnet runAPI extensions are documented in APIextensions.md and are also included at the end of this file.
Tinyqueue has a ZeroMQ (ZMQ) interface allowing client applications to join the queue and follow any events. All communication between clients and servers take the form of JSON objects.
Client and server communicates through two ZMQ patterns, a publisher/subscriber pattern where the server broadcasts updates to all clients, and a request/reply pattern where clients can send requests and get individual responses from the server. The two patterns use different network ports and as such both server and client maintain two sockets for communication, one for each communication pattern. The request/reply and publisher/subscriber patterns are described in Chapter 1 and Chapter 2 of the ZMQ Guide, respectively.
Broadcast messages are published by server to all subscribed clients using the ZMQ pub/sub pattern.
Sent to all clients in response to new subscribers or changes in the queue, for example new clients entering the queue or students receiving supervision. The queue status is an ordered array of Queue tickets, where the first element represent the first student in the queue.
- Sent by: server
- Topic: queue
[
{"ticket": <index>, "name": "<name>"},
...
]Sent to all clients in response to new subscribers or changes in the list of supervisors, for example new supervisors connecting or when the status of a supervisor changes.
- Sent by: server
- Topic: supervisors
[
{"name": <name>, "status": "pending"|"available"|"occupied", "client": undefined|{"ticket":<index>,"name":"<name>"}},
...
]Note: an undefined key in JSON implies a key that is absent.
The server will also publish messages directly to individual users (students). These messages are received by all clients representing that user. These messages may for example indicate that it's the user's turn to receive supervision.
- Sent by: server
- Topic: name of user
{
"supervisor":"<name of supervisor>",
"message":"<message from supervisor>"
}Requests are sent by clients with individual responses from the server.
Each request must specify a clientId. The clientId is a universally unique identifier (UUID) chosen by each client. Requests may also comprise a name. The name may be shared between several clients and identifies the queuing user. Two or more clients connected with the same name represent the same user, and thus holds a single shared place in the queue.
Indicates that a user with specified name want to enter the queue.
- Sent by: client
- Expected response from server: Queue ticket
{
"clientId": "<unique id string>",
"name": "<name>",
"enterQueue": true
}Indicates that the client with specified name and ticket has entered the queue.
- Sent by: server
{
"name": "<name>",
"ticket": <index>
}The server accepts message requests from supervisor clients. A message request results in a User message being sent to listening clients. For test purposes, student clients can send messages to themselves, simulating the presence of a supervisor.
- Sent by: client
{
"clientId": "<unique id string>",
"name": "<name>",
"message": {"recipient": "<name>", "body": "<message content>"}
}All clients are expected to send regular messages (heartbeats) to indicate that they want to maintain their place in the queue. Clients with a heartbeat interval larger than 4 seconds will be considered inactive, and will be removed from queue.
- Sent by: client
- Expected response from server:
{}
{
"clientId": "<unique id string>"
}Sent in response to any client message that does not follow the specified API. The server may also use this message type to indicate other types of errors, for example invalid name strings.
- Sent by: server
{
"error": "<error type>",
"msg": "<error description>"
}Sent by supervisor client. Connect to server and enter the list of supervisors:
{
"clientId": "<unique id string>",
"name": "<name>",
"startSupervising": true
}Expected response from server: {}
Sent by supervisor client. Change client status:
{
"clientId": "<unique id string>",
"status": "<status>"
}Expected response from server: {}
Sent by supervisor client. Tells server that supervisor wants to help next in queue:
{
"clientId": "<unique id string>",
"name": "<name>",
"message": {"recipient": null, "body": "<message content>"}
}Recipient gets filled in by server before being sent out on broadcast channels. Expected response from server: {}