Per installare il frontend, è sufficiente scaricare il file MSI (per Windows) o il file DMG (per macOS) dalla sezione release e seguire la normale procedura di installazione prevista dal sistema operativo.
Per MacOS è necessario svolgere un passo aggiuntivo: non avendo a disposizione un account Apple Developer, il cui costo è 99$ all'anno, di base non sarebbe possibile eseguire delle applicazioni non firmate digitalmente. Per questo motivo, bisogna anche lanciare il seguente comando dopo aver recuperato il file .app:
$ xattr -d com.apple.quarantine rustruggine.app 2>/dev/nullAl primo avvio dell’applicazione, verrà mostrata la schermata di registrazione:
Da qui è possibile creare un nuovo account oppure passare alla schermata di login se si possiede già un profilo.
Dopo la prima autenticazione, i successivi avvii porteranno direttamente alla homepage.
Nella parte superiore della schermata principale sono disponibili le seguenti funzioni:
-
Crea gruppo – Permette di creare un nuovo gruppo. Cliccando sul pulsante si accede a una schermata in cui inserire il nome del gruppo.

-
Usa invito – Consente di entrare in un gruppo già esistente inserendo il token di invito ricevuto da un membro. La generazione del token è descritta in seguito nel manuale.

-
Logout / Elimina account – Apre una schermata dalla quale è possibile effettuare il logout o eliminare definitivamente il proprio account.

-
Switch light/dark mode – Attiva la modalità chiara o scura. Come impostazione di default default, l’app segue il tema del sistema operativo. Di seguito viene mostrato un esempio della homepage in dark mode.

Per accedere alla chat, è sufficiente selezionare il gruppo desiderato dalla lista. Verrà così mostrata la schermata dei messaggi:
In alto a destra sono presenti due pulsanti:
-
uno per cambiare il tema light/dark
-
uno per accedere alla schermata di gestione del gruppo

Da questa sezione è possibile:
- abbandonare il gruppo
- generare un token di invito per nuovi membri
- visualizzare la lista dei partecipanti attuali
Per installare il backend è necessario avere MySQL già disponibile sul proprio sistema. È possibile installarlo nativamente oppure eseguirlo come container tramite Docker. Per i dettagli sull’installazione si rimanda alla documentazione ufficiale:
Una volta completata questa fase, è sufficiente avviare il server con il comando:
$ cargo run mainQuesto comando provvederà automaticamente a:
- Creare il database - se non esiste di già;
- Eseguire le migrazioni per aggiungere le tabelle necessarie;
- Avviare il server basato su axum, in ascolto sulla porta 3000, pronto a ricevere le richieste degli utenti.
Il compito del backend è quello di fornire un’API per la gestione di utenti, gruppi e messaggi. La maggior parte delle operazioni avviene tramite richieste HTTP, con l’eccezione della ricezione dei messaggi in tempo reale, che utilizza WebSocket. La maggioranza delle risorse sono protette tramite autenticazione basata su sessioni. Viene garantito che solo gli utenti autenticati abbiano accesso alle risorse. Inoltre viene garantito che solo gli utenti autorizzati possano accedere a determinate risorse, come i messaggi di un gruppo specifico.
Il backend è strutturato come un monolite, in cui tutte le funzionalità risiedono all’interno di un unico progetto Rust. Il codice è suddiviso in moduli, ciascuno responsabile di una specifica area: autenticazione, gestione utenti, gestione gruppi e gestione messaggi. Le richieste HTTP vengono instradate dal router principale verso il modulo appropriato.
In seguito al login al client viene fornito un token di sessione, che deve essere incluso in tutte le richieste successive tramite cookie HTTP. Un middleware si occupa di estrarre il token dalla richiesta, verificarne la validità e recuperare l’ID utente associato. Se il token non è valido o assente, la richiesta viene respinta con errore 401. L'autente ora autenticato viene poi passato agli handler delle API per l'elaborazione. Le singole API verificano inoltre che l'utente abbia i permessi(autorizzazione) necessari per accedere alla risorsa richiesta, restituendo errore 403 in caso contrario.
Ogni modulo segue una suddivisione interna tra controller (che gestiscono le richieste HTTP e la logica applicativa) e repository (che si occupano dell’accesso e della manipolazione dei dati nel database). Le risposte alle richieste sono generalmente in formato JSON, ad eccezione della ricezione dei messaggi in tempo reale, che avviene tramite WebSocket.
La comunicazione in tempo reale è gestita così: quando un utente si connette a un gruppo, viene aperto un canale WebSocket dedicato che rimane attivo finché l’utente non abbandona il gruppo o chiude la connessione. Al momento della connessione, il client invia l’ID dell’ultimo messaggio che possiede per quel gruppo; il server risponde inviando tutti i messaggi più recenti, permettendo così la sincronizzazione. I nuovi messaggi inviati da un utente vengono trasmessi in tempo reale a tutti gli altri membri del gruppo. Un utente può appartenere a più gruppi contemporaneamente, e ogni gruppo dispone di un proprio canale WebSocket indipendente.
Il backend è stato sviluppato utilizzando il framework web axum per la gestione delle richieste HTTP e WebSocket. Per l’interazione con il database MySQL viene utilizzato SeaORM, un ORM asincrono che consente di modellare le entità e gestire le query in modo type-safe. Le migrazioni del database sono gestite tramite refinery, che permette di definire e applicare le migrazioni in file SQL separati. Il runtime asincrono Tokio viene utilizzato per la gestione delle operazioni concorrenti e non bloccanti.
Per l’autenticazione, il sistema implementa una libreria interna che si occupa della generazione, verifica e storage dei token di sessione. La crittografia delle password è affidata a bcrypt, un algoritmo di hashing sicuro e ampiamente utilizzato. La comunicazione tra client e server avviene tramite JSON, con l’ausilio della libreria serde per la serializzazione e deserializzazione dei dati.
Il backend mostra un consumo di CPU estremamente contenuto durante il funzionamento ordinario. Dai log raccolti, l’utilizzo della CPU si mantiene quasi sempre al di sotto dello 0.15%, con valori tipici compresi tra 0.00% e 0.14%, anche durante periodi prolungati di attività.
Questo risultato è dovuto sia all’efficienza del runtime asincrono Tokio, sia alla natura event-driven dell’applicazione: le risorse vengono utilizzate principalmente in risposta a richieste degli utenti o a eventi WebSocket, mentre nei periodi di inattività il carico sul processore è trascurabile.
Il consumo di CPU potrebbe aumentare in presenza di un numero elevato di connessioni WebSocket simultanee o di traffico intenso, ma per i carichi osservati il sistema risulta molto leggero e reattivo.
La gestione degli errori avviene direttamente all’interno dei singoli handler delle API. Ogni endpoint verifica l’esito delle operazioni e restituisce un codice di stato HTTP appropriato prelevato da Axum StatusCode (ad esempio 400, 401, 403, 404, 409 o 500) insieme a un messaggio di errore in formato JSON.
Non è presente un sistema di gestione centralizzata degli errori: ogni handler si occupa di intercettare e gestire i possibili errori relativi alla propria logica, loggando eventuali problemi e restituendo risposte chiare al client.
Il backend implementa un sistema di autenticazione basato su token di sessione generati al momento del login. Quando un utente effettua il login con successo, il server genera un token casuale e lo associa all’ID utente in una mappa in memoria (session_map). Questo token viene inviato al client tramite un cookie HTTP (Set-Cookie: session=...), che il browser include automaticamente in tutte le richieste successive.
Per ogni richiesta a un endpoint protetto, il middleware (require_auth) estrae il token di sessione dal cookie, verifica la validità e recupera l’ID utente associato. Se il token non è valido o assente, la richiesta viene respinta con errore 401.
Il sistema attuale non implementa protezioni contro attacchi XSRF (Cross-Site Request Forgery). Poiché il token di sessione è gestito tramite cookie http-only, un sito malevolo potrebbe potenzialmente inviare richieste autenticandosi come l’utente se il browser ha il cookie di sessione attivo.
Il backend è accompagnato da una suite di test automatizzati che coprono sia la logica delle funzioni principali (unit test) sia i flussi di integrazione, in particolare per la comunicazione WebSocket. I test verificano la corretta gestione delle sessioni, l’autorizzazione degli utenti, la persistenza e il broadcast dei messaggi, l’isolamento tra gruppi e la gestione concorrente delle connessioni.
Sono presenti:
- Unit test per le funzioni di supporto e la logica dei canali.
- Test di integrazione per le API e per la messaggistica in tempo reale tramite WebSocket, anche con mock del database.
- Test di concorrenza per garantire la robustezza del sistema in presenza di più utenti e gruppi.
Attualmente il backend deve essere eseguito su un unico server (singola istanza). Questo requisito nasce dal fatto che sia le sessioni utente sia i canali di comunicazione WebSocket sono gestiti in memoria locale al processo. In caso di deployment su più istanze, ogni server avrebbe una propria mappa delle sessioni e dei canali, causando inconsistenze e problemi di sincronizzazione tra utenti.
Per garantire il corretto funzionamento del sistema, è quindi necessario che tutte le richieste degli utenti vengano gestite dalla stessa istanza del backend. Per scenari di scalabilità orizzontale (più server), sarebbe necessario adottare soluzioni di storage condiviso per le sessioni (es. Redis) e un sistema di pub/sub distribuito per i messaggi in tempo reale.
Le sessioni utente sono gestite tramite una mappa (session_map) residente in memoria sul singolo processo. In caso di deployment di più istanze avremmo più mappe indipendenti, ciascuna con le proprie sessioni. Per scalare orizzontalmente il sistema, sarebbe necessario implementare una soluzione di storage condiviso per le sessioni, come Redis.
I canali di comunicazione tra utenti di un gruppo (broadcast channel) sono anch’essi mantenuti in memoria. In caso di deployment di più istanze si avrebbero più canali indipendenti per lo stesso gruppo.
Lo stato responsabile della comuncazione in tempo reale e delle sessioni è volatile e non persistente. In caso di crash o riavvio di un’istanza, tutte le sessioni e i canali vengono persi.
Ogni connessione WebSocket occupa risorse sul server.Con molti utenti e gruppi il numero di task crescerebbe linearmente ma in modo significativo, potenzialmente saturando le risorse del server.
| Metodo | Endpoint | Descrizione | Autenticazione |
|---|---|---|---|
| POST | /api/login | Effettua il login di un utente | No |
| POST | /api/register | Registra un nuovo utente | No |
| POST | /api/logout | Effettua il logout | No |
| DELETE | /api/auth/delete/me | Elimina l’utente | Sì |
| POST | /api/protected/group/create | Crea un nuovo gruppo | Sì |
| GET | /api/protected/group/:group_id/invite | Genera un token di invito | Sì |
| POST | /api/protected/group/join/:token | Entra in un gruppo | Sì |
| GET | /api/protected/group | Ottiene i gruppi dell’utente | Sì |
| POST | /api/protected/group/:group_id/leave | Abbandona un gruppo | Sì |
| GET | /api/protected/group/:group_id | Ottiene i dettagli del gruppo | Sì |
| GET | /api/protected/verify_session | Verifica la validità del token | Sì |
| GET | /protected/group/:group_id/ws | Connessione WebSocket | Sì |
Il frontend è responsabile della presentazione grafica e dell’interazione con l’utente. Si tratta di un’applicazione desktop sviluppata in Rust che utilizza il framework Iced per la GUI. L’interfaccia è a finestra singola con navigazione interna tra diverse schermate (registrazione, login, homepage, chat).
Il frontend comunica con il backend per tutte le operazioni di autenticazione, gestione gruppi e scambio messaggi. Inoltre, mantiene un database locale per la persistenza dei dati e supporta la ricezione di messaggi in tempo reale tramite WebSocket.
L’architettura è organizzata in moduli Rust, ciascuno con responsabilità specifiche:
- app.rs – Stato globale e gestione della GUI, con tutte le view.
- client_api.rs – Chiamate HTTP al backend.
- client_db.rs – Interazione con il database locale tramite Diesel.
- messages.rs – Definizione delle struct usate nei messaggi interni all’app.
- models.rs – Modelli per la serializzazione/deserializzazione (
serde). - paths.rs – Gestione dei percorsi delle immagini e delle risorse statiche.
- schema.rs – Definizione delle tabelle Diesel per SQLite.
- style.rs – Definizione dello stile grafico dell’interfaccia.
- subscription.rs – Gestione dei canali WebSocket per la chat.
- log.rs – Monitoraggio delle performance e salvataggio in
cpu_usage.log. - main.rs – Punto di ingresso dell’applicazione.
La gestione dello stato avviene tramite una struct globale definita in app.rs. Questa rappresenta il Model principale e centralizza i dati e la logica di navigazione tra le schermate.
Le tecnologie principali del frontend sono:
- Iced – framework grafico per la creazione dell’interfaccia reattiva.
- Tokio – runtime asincrono per task concorrenti e comunicazione di rete.
- Serde – serializzazione e deserializzazione di dati JSON.
- Diesel – ORM per l’accesso al database SQLite locale.
Il frontend comunica con il backend tramite:
- HTTP (Reqwest) per login, gestione utenti e gruppi.
- WebSocket (tokio-tungstenite) per la ricezione dei messaggi in tempo reale.
Gli errori lato frontend vengono gestiti mostrando messaggi di avviso all’interno dell’interfaccia grafica, in modo da informare l’utente senza interrompere l’esecuzione.
Gli errori critici sono loggati tramite il modulo log.
La logica di sicurezza è demandata principalmente al backend. Il frontend inoltra le credenziali e i token ricevuti, senza applicare controlli locali oltre a quelli basilari.
Il frontend risulta leggero e reattivo. Dalle misurazioni effettuate emerge un consumo di CPU tipico intorno allo 0.25%:
[2025-08-27 19:19:58] App CPU usage: 0.24509805440903%
La gestione asincrona tramite Tokio e l’architettura event-driven di Iced contribuiscono all’efficienza complessiva.
Ogni modulo (a eccezione di quelli puramente grafici) include test definiti a fondo file, che verificano la correttezza della logica implementata.
Sono coperti in particolare:
- funzioni di accesso al DB
- parsing e serializzazione dei dati
- logica di comunicazione API
- gestione dei messaggi
| Libreria | Versione | Scopo principale |
|---|---|---|
| tokio | 1 | Runtime asincrono multi-thread, necessario per gestire task concorrenti. |
| iced | 0.13.1 | Framework per interfacce grafiche in Rust (UI reattiva, gestione eventi). |
| iced_core | 0.13.2 | Componenti di base interni di Iced. |
| iced_futures | 0.13.2 | Integrazione tra Iced e il sistema asincrono di Rust. |
| futures | 0.3 | Primitive asincrone (Future, Stream, combinatori). |
| futures-util | 0.3.31 | Utility avanzate per la gestione di future e stream. |
| reqwest | 0.12.22 | Client HTTP/HTTPS asincrono, supporta JSON e multipart. |
| reqwest_cookie_store | 0.8.2 | Estensione di reqwest per la gestione automatica dei cookie. |
| cookie_store | 0.21 | Gestione di cookie persistenti, con supporto a serde. |
| cookie | 0.18.1 | Parsing e gestione di cookie HTTP. |
| serde | 1.0.219 | Serializzazione e deserializzazione dei dati. |
| serde_json | 1.0.141 | Supporto per JSON con serde. |
| http | 1.3.1 | Tipi e costanti per protocolli HTTP. |
| warp | 0.3 | Web framework asincrono, utile per API e routing. |
| tokio-tungstenite | 0.27.0 | WebSocket asincrono integrato con tokio. |
| tungstenite | 0.21 | Implementazione WebSocket standard. |
| httpmock | 0.6 | Mock di server HTTP per testing. |
| chrono | 0.4 | Gestione di date e orari (con supporto serde). |
| dotenvy | 0.15 | Gestione variabili d’ambiente tramite file .env. |
| sysinfo | 0.36.1 | Recupero di informazioni sul sistema (CPU, RAM, processi). |
| url | 2.5.4 | Parsing e manipolazione di URL. |
| rustc-hash | 2.1.1 | Hash map ad alte prestazioni per Rust. |
| tempfile | 3.20.0 | Creazione di file temporanei sicuri. |
| dark-light | 2.0.0 | Rilevamento tema scuro/chiaro dal sistema operativo. |
| dirs | 6.0.0 | Gestione percorsi standard (config, cache, dati utente). |
| include_dir | 0.7.4 | Inclusione di directory statiche in fase di compilazione (es. assets/). |
- Il progetto supporta modalità light/dark (libreria
dark-light). - La gestione del database avviene principalmente tramite SQLite (
dieselcon featuresqlite). - È incluso supporto a migrazioni (
diesel_migrations). - Le funzionalità di rete coprono:
- richieste HTTP/HTTPS (
reqwest) - gestione cookie (
reqwest_cookie_store,cookie_store,cookie) - WebSocket (
tokio-tungstenite,tungstenite)
- richieste HTTP/HTTPS (
- È stato scelta
icedin quanto è stata individuata come un buon compromesso tra prestazioni e semplicità nella personalizzazione. Un'altra opzione sarebbe stataegui, indubbiamente più efficiente, ma al tempo stesso con un look poco moderno e difficilmente personalizzabile. - Il database
sqliteè stato inserito per aumentare le performance del lato frontend, in quanto permette di salvarsi i messaggi in locale senza doverli richiedere in ogni momento al server.
La dimensione occupata su disco del backend (file ruggine.exe ) si attesta a:
18,9 MB per il sistema operativo MS Windows;
35,0 MB per il sistema operativo MacOS.
La dimensione occupata su disco del frontend (file rustruggine.exe ) si attesta a:
16,8 MB per il sistema operativo MS Windows;
17,0 MB per il sistema operativo MacOS.
Gli assets occupano una dimensione di 0,2 MB.
Il pacchetto di Windows Installer (.msi) occupa 7,91 MB; il pacchetto d'installazione MacOS (.dmg) occupa 7,69 MB.



