Chat Minimaliste
Nous allons créer un application de chat vraiment minimaliste qui ne permettra de discuter qu'avec vous même. Bien que peut utile, cela permet d'introduire les différents mécanismes utilisés par Discret.
Préparation
Pour commencer, nous allons créer un nouveau projet rust nommé rust_simple_chat:
cargo new rust_simple_chat
cd rust_simple_chat
Éditez le fichier Cargo.toml pour rajouter les dépendances suivantes:
[]
= "0.6.0"
= { = "1.38.0", = ["full"] }
= { = "1.0.203", = ["derive"] }
= "1.0.117"
Initialiser Discret
Discret nécessite un certain nombre de paramètres pour être lancé:
- Un modèle de données: définit les types de données qui peuvent être utilisés dans Discret.
- Un identifiant unique pour l'application: une fois définit, cet identifiant ne devra jamais changer une fois l'application mise en production. Cet identifiant est utilisé pour dériver des secrets utilisés par Discret. Si cet identifiant change, les utilisateurs ne pourront plus se connecter.
- Un secret maître: ce secret sera utilisé avec l'identifiant unique pour dériver les secrets de l'utilisateur. Nous utiliserons dans cet exemple un secret dérivé d'un nom d'utilisateur et d'un mot de passe.
- Un repertoire: où stocker des données.
- Une configuration: nous utiliserons la configuration par défaut.
Remplacer le fichier src/main.rs par défaut par le suivant
1 use ;
2
3 use 4 5 6 ;
7 use Deserialize;
8
9 //identifiant unique de l'application
10 const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
11
12
13 async 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
La ligne 10 définit un nom unique de l'application:
9 //...
10 const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
11 //...
Les lignes 15 à 19 définissent le modèle de données qui pourra être utilisé dans l'application. Ce modèle définit un espace de nom nommé chat qui contient l'entité Message, qui elle même contient un unique champ nommé content qui peut contenir une chaine de caractères.
Vous pourrez en apprendre plus dans la section Schémas et Entités de la documentation.
14 //...
15 let model = "chat {
16 Message{
17 content:String
18 }
19 }";
20 //...
La Ligne 24 crée le secret maitre. Ce secret est utilisé par Discret pour créer, en autre:
- La clé de chiffrement de la base de données. Toutes les donnes sont cryptées avant d'être stockées
- Un couple clé publique/clé privé qui sera utilisé pour signer toutes les données insérées et modifiées par cet utilisateurs. Toutes les données échangées par les pairs sont signées et vérifiées.
la fonction derive_pass_phrase utilise la fonction de dérivation Argon2id avec les paramètres recommandés par owasp.org
23 //...
24 let key_material: = derive_pass_phrase;
25 //...
L'application ne fait rien encore, mais Discret est maintenant prêt à être utilisé.
Insérer des messages
Nous allons maintenant pouvoir insérer des données. Le programme va lire les messages écrit dans la console et les insérer en base de données.
Insérer les lignes suivantes apres la ligne 33 ).await.unwrap();
34 let private_room: String = app.private_room;
35 let stdin = stdin;
36 let mut line = String new;
37 println!;
38 loop 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
La ligne 34 récupère la Room privée de l'utilisateur. Le concept de Room définit le système d'autorisations utilisé par Discret pour synchroniser les données avec ses Pairs. Les données insérées dans une Room ne seront synchronisées qu'avec les Pairs ayant accès à cette Room.
Nous allons utiliser la Room Privée de l'utilisateur, donc lui seul sera capable d'y acceder. Si l'utilisateur se connecte sur plusieurs machines, les données seront synchronisées entre les machines.
Vous pourrez en apprendre plus dans la section Room de la documentation.
Les lignes 47 à 57 définissent la requête utilisée pour insérer des messages:
46 //...
47 app.mutate 48 49 50 51 52 53 54 55 .await.unwrap;
56 //...
Nous utilisons une requête de type mutation pour insérer un tuple de l'entité chat.Message définie dans le modèle de données.
Vous noterez que room_id n'a pas été défini dans le modèle de données. C'est un champ système disponible pour toutes les entités. $room_id et $message sont des paramètres de la requête qui sont passés par l'objet Some(params).
Vous pourrez en apprendre plus sur l'insertion et la modification de données dans la section Mutations et Suppression de la documentation.
Si vous lancez l'application, vous devriez pouvoir écrire des messages
cargo run
Lire les données synchronisées
A ce stade, les données que vous insérez seront synchronisées entre chaque instance de l'application. Si vous copiez le programme dans deux répertoires ou appareils différents, les données seront synchronisées. Par contre vous ne verrez pas les messages des autres.
Pour récupérer les messages synchronisés, nous allons écouter les évènements envoyé par Discret, et lire les messages quand un évènements indiquera que de nouvelles données sont disponibles. Pour ce faire, insérez le code suivant entre la ligne 33 ).await.unwrap(); et la ligne 34: let private_room: String = app.private_room();
33 //cette structure permet de désérialiser les messages
34
35 36 37 38 39
40
41 //écoute les évènements créés par Discret
42 let mut events = app.subscribe_for_events.await;
43 let event_app: Discret = app.clone;
44 spawn 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 ;
Les lignes 42 à 86 définissent la boucle qui va écouter les événements Discret. Elle est lancée dans une tache asynchrone pour que l'application ait ainsi deux boucles indépendantes:
- la boucle de lecture des évènements
- la boucle lisant les messages écrit dans la console
Lors qu'un événement de type DataChanged est détecté, nous effectuons une requête pour récupérer les données nouvellement reçues:
58 //...
59 let result: String = event_app.query 60 61 62 63 64 65 66 67 68 69 70 71 72 .await.unwrap;
73 //...
Vous pourrez en apprendre plus sur les requêtes de selection de données dans la section Requête de la documentation.
Les lignes 74 et 75 permettent de lire le résultat JSON de la requête et de les transformer en liste d'objects Chat
73 //...
74 let mut query_result = new.unwrap;
75 let res: = query_result.take_array.unwrap;
76 //...
Si vous lancez ce code dans deux repertoires ou sur deux machines différentes en réseau local, vous pourrez voir les messages s'afficher sur les différentes consoles.
Félicitation! vous pouvez désormais discuter avec vous même en communicant en Peer to Peer!
Aller plus loin
Ce tutorial vous a donné un aperçu des bases nécessaires à l'utilisation de Discret. Ces connaissances sont suffisantes pour créer des applications ne nécessitant la synchronisation qu'avec un seul utilisateur.
Par exemple, vous pouvez créer un gestionnaire de mot de passes qui se synchronisera entre vos différent appareils en réseau local.
Pour en apprendre plus, vous pouvez suivre les tutorials Flutter, en particulier le chat multi utilisateurs qui introduit la gestion des invitations et la création de Room.
La section Apprendre vous permettra d'approfondir vos connaissances.
Le code source complet
use ;
use ;
use Deserialize;
//identifiant unique de l'application
const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
async