Minimalist Rust Chat
In this document, we will create a minimalistic Chat application that will allow you to discuss with yourself. While not super useful, it introduces the different concept used by Discret
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.
Setup
Let 's start by creating a new Rust project named rust_simple_chat
cargo new rust_simple_chat
cd rust_simple_chat
Open the Cargo.toml file to add the required dependencies:
[]
= "0.6.0"
= { = "1.38.0", = ["full"] }
= { = "1.0.203", = ["derive"] }
= "1.0.117"
Discret Initialisation
Discret requires some parameters:
- a data model: defines the kind of data that can be used in Discret,
- an application unique identifier: once the application in production, this identifier cannot be changed anymore. It is used to derive some secrets that will be used by Discret. If this identifier is changed, the secrets will change and users will not be able to connect anymore.
- a user master secret: this per user secret is used with the application identifier to create the user secrets. In this this example we will use a password derivation function to create this secret.
- a data folder: where data is stored.
- A configuration: we will use the default configuration.
Replace src/main.rs default file by this one:
1 use ;
2
3 use 4 5 6 ;
7 use Deserialize;
8
9 //application unique identifier
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
Line 10 defines the application unique identifier:
9 //...
10 const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
11 //...
Lines 15 to 19 define the data model used by this application. It creates a namespace chat that contains an Entity names Message, which contains an unique field named content of the String type.
You can learn more about data models in the documentation Schema and Entities.
14 //...
15 let model = "chat {
16 Message{
17 content:String
18 }
19 }";
20 //...
Line 24 creates the user master secret. It will be used by Discret to create:
- the database encryption key. All data is encrypted at rest.
- A signature/verifying key that will be used to identify the user to other peers and sign data created and modified by this user.
The derive_pass_phrase uses the Argon2id key derivation function with the parameters recommended by owasp.org
23 //...
24 let key_material: = derive_pass_phrase;
25 //...
Insert Messages
Once Discret initialized, we can insert new data. This example will read the messages from the console and write them into the Discret database.
Insert the following lines after line 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
Line 34 retrieves the user's private Room. Rooms are the access rights system used to synchronized data with other peers. Data inserted in a Room is synchronized only with peers that have access rights to it.
In this example we will only use the user's private Room, meaning that only him will able to access the data. If this user's is connected on several devices, data will be synchronized between devices.
You can learn more about access right in the Room section of the documentation.
Lines 47 to 57 defines the query used to insert messages:
46 //...
47 app.mutate 48 49 50 51 52 53 54 55 .await.unwrap;
56 //...
This is a mutation query to insert a new tuple of the chat.Message entity defined in the data model.
You can notice that the room_id has not been manually defined in the data model. It is a system field available for every entities. $room_id and $message are query parameters that are passed by the Some(params) object.
You can lean more about data insertion and modification in the Mutations and Deletions section of the documentation.
If you run the application, you should be able to write messages.
cargo run
Read synchronized data
At this point, inserted data will be synchronized between each instance of the application.
To retrieve the synchronized messages, we will listen to the events sent by Discret and read messages from the database when we receive an event saying that new data is available.
Insert the following code between ligne 33 ).await.unwrap(); and line 34: let private_room: String = app.private_room();
33 //this struct is used to parse the query result
34
35 36 37 38 39
40
41 //listen for events
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 ;
Lines 42 to 86 Les lignes 42 à 86 define the loop that will listen for the Discret events. it is launched as an asynchronous task to avoid blocking the application.
When a DataChanged event is triggered, we query the database to retrieve the new data:
58 //...
59 let result: String = event_app.query 60 61 62 63 64 65 66 67 68 69 70 71 72 .await.unwrap;
73 //...
You can learn more about reading database data in the Query section of the documentation.
Lines 74 and 75 parse the JSON result to transform it into a list of Chat object.
73 //...
74 let mut query_result = new.unwrap;
75 let res: = query_result.take_array.unwrap;
76 //...
Now, if you run this example in different folders or different devices on your local network, you should be able to chat with yourself!
Going Further
This tutorial provided the basis to use Discret, you should now be able to create applications that requires only one user to be synchronized. For example you could create a password manager that synchronize data across your devices.
To learn more about discret you can follow the Flutter tutorials. Flutter chat with multiple users creates a multi user chat and introduces you to Room creations and how to create Invitations to be sent to other peers.
The Learn section will provide deeper explanations on how to use Discret
Full Source Code
use ;
use ;
use Deserialize;
//application unique identifier
const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
async