1mod mock;
8mod readonly;
9
10use std::{collections::HashSet, sync::Arc};
11
12use ruma_common::UserId;
13
14pub use self::{
15 mock::HomeserverConnection as MockHomeserverConnection, readonly::ReadOnlyHomeserverConnection,
16};
17
18#[derive(Debug)]
19pub struct MatrixUser {
20 pub displayname: Option<String>,
21 pub avatar_url: Option<String>,
22 pub deactivated: bool,
23}
24
25#[derive(Debug, Default)]
26enum FieldAction<T> {
27 #[default]
28 DoNothing,
29 Set(T),
30 Unset,
31}
32
33pub struct ProvisionRequest {
34 localpart: String,
35 sub: String,
36 locked: bool,
37 displayname: FieldAction<String>,
38 avatar_url: FieldAction<String>,
39 emails: FieldAction<Vec<String>>,
40}
41
42impl ProvisionRequest {
43 #[must_use]
51 pub fn new(localpart: impl Into<String>, sub: impl Into<String>, locked: bool) -> Self {
52 Self {
53 localpart: localpart.into(),
54 sub: sub.into(),
55 locked,
56 displayname: FieldAction::DoNothing,
57 avatar_url: FieldAction::DoNothing,
58 emails: FieldAction::DoNothing,
59 }
60 }
61
62 #[must_use]
64 pub fn sub(&self) -> &str {
65 &self.sub
66 }
67
68 #[must_use]
70 pub fn localpart(&self) -> &str {
71 &self.localpart
72 }
73
74 pub fn locked(&self) -> bool {
76 self.locked
77 }
78
79 #[must_use]
85 pub fn set_displayname(mut self, displayname: String) -> Self {
86 self.displayname = FieldAction::Set(displayname);
87 self
88 }
89
90 #[must_use]
92 pub fn unset_displayname(mut self) -> Self {
93 self.displayname = FieldAction::Unset;
94 self
95 }
96
97 pub fn on_displayname<F>(&self, callback: F) -> &Self
103 where
104 F: FnOnce(Option<&str>),
105 {
106 match &self.displayname {
107 FieldAction::Unset => callback(None),
108 FieldAction::Set(displayname) => callback(Some(displayname)),
109 FieldAction::DoNothing => {}
110 }
111
112 self
113 }
114
115 #[must_use]
121 pub fn set_avatar_url(mut self, avatar_url: String) -> Self {
122 self.avatar_url = FieldAction::Set(avatar_url);
123 self
124 }
125
126 #[must_use]
128 pub fn unset_avatar_url(mut self) -> Self {
129 self.avatar_url = FieldAction::Unset;
130 self
131 }
132
133 pub fn on_avatar_url<F>(&self, callback: F) -> &Self
139 where
140 F: FnOnce(Option<&str>),
141 {
142 match &self.avatar_url {
143 FieldAction::Unset => callback(None),
144 FieldAction::Set(avatar_url) => callback(Some(avatar_url)),
145 FieldAction::DoNothing => {}
146 }
147
148 self
149 }
150
151 #[must_use]
157 pub fn set_emails(mut self, emails: Vec<String>) -> Self {
158 self.emails = FieldAction::Set(emails);
159 self
160 }
161
162 #[must_use]
164 pub fn unset_emails(mut self) -> Self {
165 self.emails = FieldAction::Unset;
166 self
167 }
168
169 pub fn on_emails<F>(&self, callback: F) -> &Self
175 where
176 F: FnOnce(Option<&[String]>),
177 {
178 match &self.emails {
179 FieldAction::Unset => callback(None),
180 FieldAction::Set(emails) => callback(Some(emails)),
181 FieldAction::DoNothing => {}
182 }
183
184 self
185 }
186}
187
188#[async_trait::async_trait]
189pub trait HomeserverConnection: Send + Sync {
190 fn homeserver(&self) -> &str;
192
193 fn mxid(&self, localpart: &str) -> String {
199 format!("@{}:{}", localpart, self.homeserver())
200 }
201
202 fn localpart<'a>(&self, mxid: &'a str) -> Option<&'a str> {
211 let mxid = <&UserId>::try_from(mxid).ok()?;
212 if mxid.server_name() != self.homeserver() {
213 return None;
214 }
215 Some(mxid.localpart())
216 }
217
218 async fn verify_token(&self, token: &str) -> Result<bool, anyhow::Error>;
231
232 async fn query_user(&self, localpart: &str) -> Result<MatrixUser, anyhow::Error>;
243
244 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error>;
256
257 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error>;
267
268 async fn upsert_device(
280 &self,
281 localpart: &str,
282 device_id: &str,
283 initial_display_name: Option<&str>,
284 ) -> Result<(), anyhow::Error>;
285
286 async fn update_device_display_name(
299 &self,
300 localpart: &str,
301 device_id: &str,
302 display_name: &str,
303 ) -> Result<(), anyhow::Error>;
304
305 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error>;
317
318 async fn sync_devices(
330 &self,
331 localpart: &str,
332 devices: HashSet<String>,
333 ) -> Result<(), anyhow::Error>;
334
335 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error>;
347
348 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error>;
359
360 async fn set_displayname(
372 &self,
373 localpart: &str,
374 displayname: &str,
375 ) -> Result<(), anyhow::Error>;
376
377 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error>;
388
389 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error>;
401}
402
403#[async_trait::async_trait]
404impl<T: HomeserverConnection + Send + Sync + ?Sized> HomeserverConnection for &T {
405 fn homeserver(&self) -> &str {
406 (**self).homeserver()
407 }
408
409 async fn verify_token(&self, token: &str) -> Result<bool, anyhow::Error> {
410 (**self).verify_token(token).await
411 }
412
413 async fn query_user(&self, localpart: &str) -> Result<MatrixUser, anyhow::Error> {
414 (**self).query_user(localpart).await
415 }
416
417 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
418 (**self).provision_user(request).await
419 }
420
421 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
422 (**self).is_localpart_available(localpart).await
423 }
424
425 async fn upsert_device(
426 &self,
427 localpart: &str,
428 device_id: &str,
429 initial_display_name: Option<&str>,
430 ) -> Result<(), anyhow::Error> {
431 (**self)
432 .upsert_device(localpart, device_id, initial_display_name)
433 .await
434 }
435
436 async fn update_device_display_name(
437 &self,
438 localpart: &str,
439 device_id: &str,
440 display_name: &str,
441 ) -> Result<(), anyhow::Error> {
442 (**self)
443 .update_device_display_name(localpart, device_id, display_name)
444 .await
445 }
446
447 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> {
448 (**self).delete_device(localpart, device_id).await
449 }
450
451 async fn sync_devices(
452 &self,
453 localpart: &str,
454 devices: HashSet<String>,
455 ) -> Result<(), anyhow::Error> {
456 (**self).sync_devices(localpart, devices).await
457 }
458
459 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> {
460 (**self).delete_user(localpart, erase).await
461 }
462
463 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> {
464 (**self).reactivate_user(localpart).await
465 }
466
467 async fn set_displayname(
468 &self,
469 localpart: &str,
470 displayname: &str,
471 ) -> Result<(), anyhow::Error> {
472 (**self).set_displayname(localpart, displayname).await
473 }
474
475 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> {
476 (**self).unset_displayname(localpart).await
477 }
478
479 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> {
480 (**self).allow_cross_signing_reset(localpart).await
481 }
482}
483
484#[async_trait::async_trait]
486impl<T: HomeserverConnection + ?Sized> HomeserverConnection for Arc<T> {
487 fn homeserver(&self) -> &str {
488 (**self).homeserver()
489 }
490
491 async fn verify_token(&self, token: &str) -> Result<bool, anyhow::Error> {
492 (**self).verify_token(token).await
493 }
494
495 async fn query_user(&self, localpart: &str) -> Result<MatrixUser, anyhow::Error> {
496 (**self).query_user(localpart).await
497 }
498
499 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
500 (**self).provision_user(request).await
501 }
502
503 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
504 (**self).is_localpart_available(localpart).await
505 }
506
507 async fn upsert_device(
508 &self,
509 localpart: &str,
510 device_id: &str,
511 initial_display_name: Option<&str>,
512 ) -> Result<(), anyhow::Error> {
513 (**self)
514 .upsert_device(localpart, device_id, initial_display_name)
515 .await
516 }
517
518 async fn update_device_display_name(
519 &self,
520 localpart: &str,
521 device_id: &str,
522 display_name: &str,
523 ) -> Result<(), anyhow::Error> {
524 (**self)
525 .update_device_display_name(localpart, device_id, display_name)
526 .await
527 }
528
529 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> {
530 (**self).delete_device(localpart, device_id).await
531 }
532
533 async fn sync_devices(
534 &self,
535 localpart: &str,
536 devices: HashSet<String>,
537 ) -> Result<(), anyhow::Error> {
538 (**self).sync_devices(localpart, devices).await
539 }
540
541 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> {
542 (**self).delete_user(localpart, erase).await
543 }
544
545 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> {
546 (**self).reactivate_user(localpart).await
547 }
548
549 async fn set_displayname(
550 &self,
551 localpart: &str,
552 displayname: &str,
553 ) -> Result<(), anyhow::Error> {
554 (**self).set_displayname(localpart, displayname).await
555 }
556
557 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> {
558 (**self).unset_displayname(localpart).await
559 }
560
561 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> {
562 (**self).allow_cross_signing_reset(localpart).await
563 }
564}