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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
//! Definition and creation of `Daily` meeting tokens.
use serde::{Deserialize, Serialize};
use crate::client::parse_dailyco_response;
use crate::configuration::{DailyLang, RecordingType};
use crate::utils::default_as_true;
use crate::Client;
/// A `CreateMeetingToken` can be used to create a `Daily` meeting token for gaining
/// access to a private room.
#[derive(Debug, Copy, Clone, Serialize, Default)]
pub struct CreateMeetingToken<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) room_name: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) eject_at_token_exp: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) eject_after_elapsed: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) nbf: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) exp: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) is_owner: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) user_name: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) user_id: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) enable_screenshare: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) start_video_off: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) start_audio_off: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) enable_recording: Option<RecordingType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) enable_prejoin_ui: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) enable_terse_logging: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) start_cloud_recording: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) close_tab_on_exit: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) redirect_on_meeting_exit: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) lang: Option<DailyLang>,
}
impl<'a> CreateMeetingToken<'a> {
/// Constructs a new `CreateMeetingToken`.
#[must_use]
pub fn new() -> Self {
Self::default()
}
/// The room for which this token is valid. If `room_name` isn't set, the token is
/// valid for all rooms in your domain.
pub fn room_name(&mut self, room_name: &'a str) -> &mut Self {
self.room_name = Some(room_name);
self
}
/// Kick this user out of the meeting at the time this meeting token expires.
pub fn eject_at_token_exp(&mut self, eject_at_token_exp: bool) -> &mut Self {
self.eject_at_token_exp = Some(eject_at_token_exp);
self
}
/// Kick this user out of the meeting this many seconds after they join the meeting.
pub fn eject_after_elapsed(&mut self, eject_after_elapsed: i64) -> &mut Self {
self.eject_after_elapsed = Some(eject_after_elapsed);
self
}
/// UTC timestamp before which the token cannot be used.
pub fn nbf(&mut self, nbf: i64) -> &mut Self {
self.nbf = Some(nbf);
self
}
/// UTC timestamp for expiration of the token.
pub fn exp(&mut self, exp: i64) -> &mut Self {
self.exp = Some(exp);
self
}
/// The user has meeting owner privileges.
pub fn is_owner(&mut self, is_owner: bool) -> &mut Self {
self.is_owner = Some(is_owner);
self
}
/// The user's name in this meeting.
pub fn user_name(&mut self, user_name: &'a str) -> &mut Self {
self.user_name = Some(user_name);
self
}
/// The user's id for this meeting session.
pub fn user_id(&mut self, user_id: &'a str) -> &mut Self {
self.user_id = Some(user_id);
self
}
/// The user is allowed to screenshare.
pub fn enable_screenshare(&mut self, enable_screenshare: bool) -> &mut Self {
self.enable_screenshare = Some(enable_screenshare);
self
}
/// When a participant first joins a meeting, keep their camera off.
pub fn start_video_off(&mut self, start_video_off: bool) -> &mut Self {
self.start_video_off = Some(start_video_off);
self
}
/// When a participant first joins a meeting, keep their microphone muted.
pub fn start_audio_off(&mut self, start_audio_off: bool) -> &mut Self {
self.start_audio_off = Some(start_audio_off);
self
}
/// Allowed recording type
pub fn enable_recording(&mut self, enable_recording: RecordingType) -> &mut Self {
self.enable_recording = Some(enable_recording);
self
}
/// Determines whether participant enters a waiting room with a camera, mic, and
/// browser check before joining a call.
pub fn enable_prejoin_ui(&mut self, enable_prejoin_ui: bool) -> &mut Self {
self.enable_prejoin_ui = Some(enable_prejoin_ui);
self
}
/// Reduces the volume of log messages. This feature should be enabled when there
/// are more than 300 participants in a meeting to help improve performance.
pub fn enable_terse_logging(&mut self, enable_terse_logging: bool) -> &mut Self {
self.enable_terse_logging = Some(enable_terse_logging);
self
}
/// Start cloud recording when the user joins the room. This can be used to always record and
/// archive meetings, for example in a customer support context.
pub fn start_cloud_recording(&mut self, start_cloud_recording: bool) -> &mut Self {
self.start_cloud_recording = Some(start_cloud_recording);
self
}
/// When a user leaves a meeting using the button in the in-call menu bar,
/// the browser tab closes.
pub fn close_tab_on_exit(&mut self, close_tab_on_exit: bool) -> &mut Self {
self.close_tab_on_exit = Some(close_tab_on_exit);
self
}
/// When a user leaves a meeting using the button in the in-call menu bar,
/// the browser loads this URL.
pub fn redirect_on_meeting_exit(&mut self, redirect_on_meeting_exit: &'a str) -> &mut Self {
self.redirect_on_meeting_exit = Some(redirect_on_meeting_exit);
self
}
/// The default language of the Daily prebuilt video call UI, for this room.
pub fn lang(&mut self, lang: DailyLang) -> &mut Self {
self.lang = Some(lang);
self
}
/// Make the request to create the custom `Daily` meeting token for joining a room.
///
/// # Examples
///
/// Create a token to join a room with owner privileges.
///
/// ```no_run
/// # use dailyco::{Client, Result};
/// # use dailyco::meeting_token::CreateMeetingToken;
/// # async fn run() -> Result<String> {
/// let client = Client::new("test-api-key")?;
/// let token = CreateMeetingToken::new()
/// .room_name("room-user-should-own")
/// .is_owner(true)
/// .send(&client)
/// .await?;
/// # Ok(token)
/// # }
/// ```
pub async fn send(&self, client: &Client) -> crate::Result<String> {
#[derive(Deserialize)]
/// Response from Daily for successful meeting token creation
struct MeetingTokenResponse {
/// The token created
token: String,
}
#[derive(Serialize)]
struct MeetingTokenBody<'a> {
properties: &'a CreateMeetingToken<'a>,
}
// This should not be able to fail
let token_url = client.base_url.join("meeting-tokens/").unwrap();
let body = MeetingTokenBody { properties: self };
let resp = client.client.post(token_url).json(&body).send().await?;
parse_dailyco_response(resp)
.await
.map(|token_resp: MeetingTokenResponse| token_resp.token)
}
#[cfg(feature = "self-signed-tokens")]
#[cfg_attr(docsrs, doc(cfg(feature = "self-signed-tokens")))]
/// Self-sign a `Daily` meeting token corresponding to this configuration,
/// skipping the round-trip required by [create](#method.create).
///
/// # Optional
///
/// This requires the optional `self-signed-tokens` feature enabled.
///
/// # Examples
///
/// Create a token to join a room with owner privileges.
///
/// ```no_run
/// # use dailyco::meeting_token::CreateMeetingToken;
/// # fn run() -> String {
/// let token = CreateMeetingToken::new()
/// .room_name("room-user-should-own")
/// .is_owner(true)
/// .self_sign("domain_id", "test-api-key");
/// # token
/// # }
/// ```
pub fn self_sign(&self, domain_id: &str, secret_key: &str) -> String {
crate::self_sign_token::self_sign_token(*self, domain_id, secret_key)
}
}
/// A `MeetingToken` describes the configuration of a meeting token used to join a
/// `Daily` private meeting room.
#[derive(Debug, Clone, Default, Deserialize, Eq, PartialEq)]
pub struct MeetingToken {
/// The room for which this token is valid. If `room_name` isn't set, the token is
/// valid for all rooms in your domain.
pub room_name: Option<String>,
/// Kick this user out of the meeting at the time this meeting token expires.
#[serde(default)]
pub eject_at_token_exp: bool,
/// Kick this user out of the meeting this many seconds after they join the meeting.
pub eject_after_elapsed: Option<i64>,
/// UTC timestamp before which the token cannot be used.
pub nbf: Option<i64>,
/// UTC timestamp for expiration of the token.
pub exp: Option<i64>,
/// The user has meeting owner privileges.
#[serde(default)]
pub is_owner: bool,
/// The user's name in this meeting.
pub user_name: Option<String>,
/// The user's id for this meeting session.
pub user_id: Option<String>,
/// The user is allowed to screenshare.
#[serde(default = "default_as_true")]
pub enable_screenshare: bool,
/// When a participant first joins a meeting, keep their camera off.
#[serde(default)]
pub start_video_off: bool,
/// When a participant first joins a meeting, keep their microphone muted.
#[serde(default)]
pub start_audio_off: bool,
/// Allowed recording type
pub enable_recording: Option<RecordingType>,
/// Determines whether participant enters a waiting room with a camera, mic, and
/// browser check before joining a call.
pub enable_prejoin_ui: Option<bool>,
/// Reduces the volume of log messages. This feature should be enabled when there
/// are more than 300 participants in a meeting to help improve performance.
#[serde(default)]
pub enable_terse_logging: bool,
/// Start cloud recording when the user joins the room. This can be used to always record and
/// archive meetings, for example in a customer support context.
#[serde(default)]
pub start_cloud_recording: bool,
/// When a user leaves a meeting using the button in the in-call menu bar,
/// the browser tab closes.
#[serde(default)]
pub close_tab_on_exit: bool,
/// When a user leaves a meeting using the button in the in-call menu bar,
/// the browser loads this URL.
pub redirect_on_meeting_exit: Option<String>,
/// The default language of the Daily prebuilt video call UI, for this room.
pub lang: Option<DailyLang>,
}
fn option_str_to_string(str: Option<&str>) -> Option<String> {
str.map(|s| s.to_string())
}
impl From<CreateMeetingToken<'_>> for MeetingToken {
fn from(builder: CreateMeetingToken) -> Self {
Self {
room_name: option_str_to_string(builder.room_name),
eject_at_token_exp: builder.eject_at_token_exp.unwrap_or_default(),
eject_after_elapsed: builder.eject_after_elapsed,
nbf: builder.nbf,
exp: builder.exp,
is_owner: builder.is_owner.unwrap_or_default(),
user_name: option_str_to_string(builder.user_name),
user_id: option_str_to_string(builder.user_id),
enable_screenshare: builder.enable_screenshare.unwrap_or(true),
start_video_off: builder.start_video_off.unwrap_or_default(),
start_audio_off: builder.start_audio_off.unwrap_or_default(),
enable_recording: builder.enable_recording,
enable_prejoin_ui: builder.enable_prejoin_ui,
enable_terse_logging: builder.enable_terse_logging.unwrap_or_default(),
start_cloud_recording: builder.start_cloud_recording.unwrap_or_default(),
close_tab_on_exit: builder.close_tab_on_exit.unwrap_or_default(),
redirect_on_meeting_exit: option_str_to_string(builder.redirect_on_meeting_exit),
lang: builder.lang,
}
}
}