Project for the course "System Programming" of the Master's Degree in Computer Engineering at the Polytechnic University of Turin.
The contributors are:
Ruggine is a cross-platform chat application written entirely in Rust, featuring:
- A multi-threaded TCP server managing client connections.
- A desktop GUI client using the
icedcrate - A shared protocol for communication between client and server
- A SQLite database for users, groups, messages, and invitations
π‘ Scroll all down to see the GUI screenshots!
To get a local copy up and running, follow these simple steps.
- Rust
- SQLite
- Clone the repo
git clone <repository-url>
- Build the project
cargo build
- Initialize the database
sqlite3 server/database/ruggine.db < server/database/init.sqlNote: Make sure you have SQLite3 installed on your system. If the database file already exists, you can skip this step.
- Run the server
cargo run --bin server
- Run one or more instances of the client and try it out
cargo run --bin client
ruggine/
βββ client/
β βββ src/
| β βββ communication/
| β β βββ mod.rs
| β β βββ server_communication.rs
| β βββ update/
| β β βββ mod.rs
| β β βββ update_commands.rs
| β β βββ update_handlers.rs
| β βββ view/
| β β βββ mod.rs
| β β βββ ui.rs
| β β βββ util_ui.rs
| β β βββ gui_messages.rs
| β βββ main.rs
| β βββ app_states.rs
β βββ Cargo.toml
βββ server/
β βββ src/
β β βββ main.rs
β β βββ handler.rs
β β βββ logger.rs
β β βββ utils.rs
β β βββ database_management.rs
β βββ database/
β β βββ init.sql
β β βββ ruggine.db
β βββ log/
β β βββ cpu_log.txt
β βββ Cargo.toml
β
βββ protocol/
β βββ src/
β β βββ lib.rs
β β βββ message.rs
β β βββ data_structures.rs
β βββ Cargo.toml
β
βββ Cargo.toml (workspace)
- User authentication with auto-registration for new users
- Direct messaging between users:
- One-to-one chat
- Message history
- Unread message notifications
- Group chat with:
- Real-time messaging
- Member management, owner can add/remove members
- Invitations
- Group history
- Unread message notifications
- Unread messages indicator and auto-update on message receipt
- Desktop GUI:
- Welcome/Login
- Group and direct chat lists
- Invitation management
- Group management (owner can remove users or delete the group)
- Direct chat management (search users, start new chats)
- Logging:
- CPU usage logged every 2 minutes
- Messages stored in SQLite
- Error handling:
- Informative error messages on failed actions (e.g., wrong password, user not found, connection issues...), including server-side and client-side handling
The client is responsible for handling the user interface (UI) and communication with the server.
The communication module is responsible for managing asynchronous communication between the client and the server. It leverages the protocol crate to serialize messages and handle communication over TCP.
server_communication.rs: Contains functions for sending and receiving messages between the client and the server. Asynchronous functions are defined to sendMessagevariants (such as login credentials, chat messages, and group invitations) and process server responses.
The update module manages state transitions and interactions between the client and the server.
-
update_commands.rs: Contains commands that trigger asynchronous actions, calling functions defined inserver_communication.rsto communicate with the server. It handles network-related commands such as login, sending messages, or requesting user chats. -
update_handlers.rs: Defines the logic for each application state (ViewState). It contains handlers that manage incoming messages and update the clientβs state based on the message type. For example, when the server sends a new chat message, the handler updates the UI to display it, and when an error occurs, it triggers the error display logic.
The view module is responsible for building the GUI components and rendering the UI based on the current application state.
-
gui_messages.rs: Defines all the messages that are generated by the view and passed to theupdatefunction. These messages are used to reflect changes in the applicationβs state (like switching from login to chat view). -
ui.rs: Contains the functions that define the layout and structure of the user interface for eachViewState. For each state (e.g.,Username,Chats), there is a corresponding function to render the UI components dynamically. -
util_ui.rs: Defines custom UI elements like buttons, containers, and input fields. It also contains utility functions to create error messages, headers, and other reusable components for the UI.
-
app_states.rs: Contains definitions for allViewStatevariants (e.g.,Connecting,Username,Chats,Invitation). Each state holds the variables that are relevant to that screen and helps manage the transitions between views. -
main.rs: Contains the global state of the application, including the currentViewState, any potential errors, and thewriterandreceiverfor communicating with the server. It defines the main logic for the Iced application, including handling user interactions and rendering the appropriate UI based on state.
The server is responsible for managing the backend logic, including user authentication, message routing, and database interactions.
This module defines the data access layer for interacting with the serverβs database. It handles all queries related to users, messages, groups, and invitations.
- It defines methods to read/write data to the database, such as checking if a user exists, retrieving chat histories, or adding/removing group members.
The handler module is responsible for processing incoming messages from clients, handling user authentication, chat management, and responding to client requests.
- It includes logic for parsing messages like
Username,Password,ChatMessage, andInvitation. Based on the message type, it performs the necessary actions and sends appropriate responses back to the client.
The logger module periodically logs server activity, such as CPU usage, to help monitor system performance.
- Every 2 minutes, it logs the serverβs CPU usage to a file (
cpu_log.txt), using thesysinfocrate to gather resource metrics.
The main.rs file serves as the entry point for the server application.
- It initializes all necessary data structures (e.g., user sessions, chat history) and starts listening for incoming TCP connections. For each new connection, it spawns a new handler to process requests asynchronously.
The utils module contains helper functions and macros used throughout the server to manage various tasks like message dispatching and error handling.
The protocol module defines all shared data types and message structures used for communication between the client and the server.
This module contains the core data structures that represent entities in the application, such as:
User: Represents a user with anusername.Chat: Represents a chat, which can be a direct message or a group.Group: Represents a group, including its name and owner.Invitation: Represents an invitation to join a group.
This module defines all the message types that can be sent and received between the client and server.
Message: The central enum that includes all message variants, such asUsername,Password,ChatMessage,Invitation,ErrorType, andAckType. This is the backbone of the client-server communication.
The lib.rs module acts as a barrel for exporting all types and messages defined in the protocol module. It ensures that both the client and the server can access the same types and structures for communication.
So, the project is divided into three main modules: client, server, and protocol. The client module is responsible for the user interface and communication with the server, the server module handles all backend operations like user authentication and message routing, and the protocol module defines the shared types and messages exchanged between the two.
This structure ensures clear separation of concerns, making the application maintainable and scalable while allowing for easy communication between the client and server.
Ruggine implements a structured error-handling system, ensuring that the client and server can gracefully handle most common failure scenarios.
Errors are exchanged using the Message::Error(ErrorType) variant from the shared protocol.
The server can generate different types of errors, all defined in ErrorType:
| Error Type | Scenario |
|---|---|
InternalServerError |
An unexpected error occurred on the server side |
WrongPassword |
User entered a wrong password during login |
InvalidUsername |
Logout request or action received with a mismatched username |
InvalidMessage |
A malformed or unexpected message was received |
InvalidSender |
A Chat or Invite message was sent by a user different from from |
GroupNotFound |
Requested group does not exist |
UserNotFound |
Invitation sent to a user that does not exist |
UserAlreadyInGroup |
Attempt to invite a user who is already in the group |
InvalidInvitation |
User tried to join a group without a valid invitation |
GroupAlreadyExists |
Attempt to create a group that already exists |
UserAlreadyLoggedIn |
User attempted to log in while already logged in |
InvitationAlreadySent |
User tried to send an invitation that has already been sent |
OwnerAccessRightsRequired |
Non-owner user tried to perform an action that requires owner rights |
When these errors occur, they are sent to the client as a Message::Error(ErrorType):
{
"Error": "InternalServerError",
} On the client side, errors received from the server are clearly displayed in the GUI, using a red text area positioned below the relevant input fields or sections. This ensures users are promptly informed of any issues without interrupting their workflow.
Where errors are shown:
- Login/Password errors: Displayed on the login or registration screens.
- Group/Invite errors: Shown in the invitation or group management views.
Example scenarios:
- If login fails (e.g., due to a wrong password), the user sees a clear error message such as βWrong passwordβ without the application crashing.
- Invitation errors (e.g., user already invited) are displayed in the invitation management section.
This approach ensures that all error messages are user-friendly and contextually relevant, improving the overall user experience.
| Component | Technology / Crate | Purpose |
|---|---|---|
| Server | Rust + tokio |
Async TCP handling and concurrency |
| Client | Rust + iced |
Cross-platform GUI |
| Protocol | serde, serde_json |
Message serialization/deserialization |
| Database | SQLite + rusqlite |
Persistent storage for users and chats |
| Logging | Custom in logger.rs |
CPU usage logging |
Below are the sizes of the compiled executables for both the server and client applications:
| Executable | Size |
|---|---|
server.exe |
~ 4,91 MB |
client.exe |
~ 23,3 MB |
![]() |
|---|
| Welcome and Login Screen |
![]() |
|---|
| Password Entry and Registration Screen |
![]() |
|---|
| Connecting State with Error Message |
![]() |
|---|
| Direct Chat and Direct List View |
![]() |
|---|
| Group Chat and Group List View |
![]() |
|---|
| Invitation Management |
![]() |
|---|
| Direct Chat Management |
![]() |
|---|
| User Search for New Direct Chat |
![]() |
|---|
| Member Management (Group Owner) |
![]() |
|---|
| Group Management (Member Can Leave Group) |









