Skip to main content

xmtp_mls/
lib.rs

1#![recursion_limit = "256"]
2#![warn(clippy::unwrap_used)]
3
4pub mod attachments;
5pub mod builder;
6pub mod client;
7pub mod context;
8mod definitions;
9#[cfg(any(test, feature = "test-utils"))]
10pub mod diagnostics;
11pub mod groups;
12pub mod identity;
13pub mod identity_updates;
14pub mod inbox_handles;
15mod intents;
16pub mod messages;
17pub mod mls_store;
18mod mutex_registry;
19pub mod server_configuration;
20mod state_tx;
21pub mod storage_location;
22pub use client::VisibilityConfirmationOptions;
23pub mod subscriptions;
24pub mod utils;
25pub mod worker;
26pub use definitions::*;
27
28#[cfg(any(test, feature = "test-utils"))]
29pub mod test;
30mod traits;
31
32#[cfg(test)]
33use crate::groups::GroupError;
34pub use client::{Client, Network};
35#[cfg(test)]
36use parking_lot::Mutex;
37#[cfg(test)]
38use std::collections::HashMap;
39#[cfg(test)]
40use std::sync::Arc;
41#[cfg(test)]
42use tokio::sync::Mutex as TokioMutex;
43pub use xmtp_common as common;
44pub use xmtp_db as db;
45#[cfg(test)]
46use xmtp_db::DuplicateItem;
47use xmtp_db::StorageError;
48pub use xmtp_id::InboxOwner;
49pub use xmtp_mls_common as mls_common;
50pub use xmtp_mls_validation as mls_validation;
51pub use xmtp_proto::api_client::*;
52#[cfg(test)]
53use xmtp_proto::types::GroupId;
54
55pub fn version() -> &'static str {
56    env!("CARGO_PKG_VERSION")
57}
58
59/// A manager for group-specific semaphores
60#[cfg(test)]
61#[derive(Debug)]
62pub struct GroupCommitLock {
63    // Storage for group-specific semaphores
64    locks: Mutex<HashMap<GroupId, Arc<TokioMutex<()>>>>,
65}
66
67#[cfg(test)]
68impl Default for GroupCommitLock {
69    fn default() -> Self {
70        Self::new()
71    }
72}
73#[cfg(test)]
74impl GroupCommitLock {
75    /// Create a new `GroupCommitLock`
76    pub fn new() -> Self {
77        Self {
78            locks: Mutex::new(HashMap::new()),
79        }
80    }
81
82    /// Get or create a semaphore for a specific group and acquire it, returning a guard
83    pub async fn get_lock_async(&self, group_id: GroupId) -> MlsGroupGuard {
84        let lock = {
85            let mut locks = self.locks.lock();
86            locks
87                .entry(group_id)
88                .or_insert_with(|| Arc::new(TokioMutex::new(())))
89                .clone()
90        };
91
92        MlsGroupGuard {
93            _permit: lock.lock_owned().await,
94        }
95    }
96
97    /// Get or create a semaphore for a specific group and acquire it synchronously
98    pub fn get_lock_sync(&self, group_id: GroupId) -> Result<MlsGroupGuard, GroupError> {
99        let lock = {
100            let mut locks = self.locks.lock();
101            locks
102                .entry(group_id)
103                .or_insert_with(|| Arc::new(TokioMutex::new(())))
104                .clone()
105        };
106
107        // Synchronously acquire the permit
108        let permit = lock
109            .try_lock_owned()
110            .map_err(|_| GroupError::LockUnavailable)?;
111        Ok(MlsGroupGuard { _permit: permit })
112    }
113}
114/// A guard that releases the semaphore when dropped
115#[cfg(test)]
116pub struct MlsGroupGuard {
117    _permit: tokio::sync::OwnedMutexGuard<()>,
118}
119
120#[cfg_attr(not(target_arch = "wasm32"), ctor::ctor(unsafe))]
121#[cfg(all(test, not(target_arch = "wasm32")))]
122fn test_setup() {
123    xmtp_common::logger();
124    let _ = fdlimit::raise_fd_limit();
125}