mpc_client/
meeting.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Create and join meeting points so session participants
//! can exchange public keys.
//!
//! The meeting identifier is the shared secret that participants
//! can use to exchange public keys so should only be given to parties
//! that should be included in a session.
use crate::{
    Client, ClientOptions, Error, NetworkTransport, Result,
    ServerOptions,
};
use futures::StreamExt;
use mpc_protocol::{
    serde_json::Value, Event, Keypair, MeetingId, UserId,
};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;

/// Options for creating or joining a meeting point.
#[derive(Serialize, Deserialize)]
pub struct MeetingOptions {
    /// Keypair for the participant.
    pub keypair: Keypair,
    /// Server options.
    pub server: ServerOptions,
}

/// Create a new meeting point.
pub async fn create(
    options: MeetingOptions,
    identifiers: Vec<UserId>,
    initiator: UserId,
    data: Value,
) -> Result<MeetingId> {
    let num_ids = identifiers.len();
    let slots: HashSet<UserId> = identifiers.into_iter().collect();

    if slots.len() != num_ids {
        return Err(Error::MeetingIdentifiersNotUnique);
    }

    if slots.get(&initiator).is_none() {
        return Err(Error::MeetingInitiatorNotExist);
    }

    let ServerOptions {
        server_url,
        server_public_key,
        ..
    } = options.server;
    let options = ClientOptions {
        keypair: options.keypair,
        server_public_key,
        pattern: None,
    };
    let url = options.url(&server_url);
    let (mut client, event_loop) = Client::new(&url, options).await?;

    client.connect().await?;

    let mut stream = event_loop.run();
    while let Some(event) = stream.next().await {
        let event = event?;
        match event {
            Event::ServerConnected { .. } => {
                client
                    .new_meeting(
                        initiator.clone(),
                        slots.clone(),
                        data.clone(),
                    )
                    .await?;
            }
            Event::MeetingCreated(meeting) => {
                let _ = client.close().await;
                return Ok(meeting.meeting_id);
            }
            _ => {}
        }
    }
    unreachable!();
}

/// Join a meeting point.
///
/// When all participants have joined the meeting point the public
/// keys of all participants are returned.
///
/// When  the user identifier is not given then the user is
/// the creator of the meeting point who has already been
/// registered as a participant when creating the meeting.
pub async fn join(
    options: MeetingOptions,
    meeting_id: MeetingId,
    user_id: Option<UserId>,
) -> Result<(Vec<Vec<u8>>, Value)> {
    let ServerOptions {
        server_url,
        server_public_key,
        ..
    } = options.server;
    let options = ClientOptions {
        keypair: options.keypair,
        server_public_key,
        pattern: None,
    };
    let url = options.url(&server_url);
    let (mut client, event_loop) = Client::new(&url, options).await?;

    client.connect().await?;

    let mut stream = event_loop.run();
    while let Some(event) = stream.next().await {
        let event = event?;
        match event {
            Event::ServerConnected { .. } => {
                if let Some(user_id) = &user_id {
                    client
                        .join_meeting(meeting_id, user_id.clone())
                        .await?;
                }
            }
            Event::MeetingReady(meeting) => {
                let _ = client.close().await;
                let public_keys: Vec<Vec<u8>> = meeting
                    .registered_participants
                    .into_iter()
                    .collect();
                return Ok((public_keys, meeting.data));
            }
            _ => {}
        }
    }
    unreachable!();
}