• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use mls_rs::error::IntoAnyError;
2 use std::fmt::Debug;
3 #[cfg(not(mls_build_async))]
4 use std::sync::Mutex;
5 #[cfg(mls_build_async)]
6 use tokio::sync::Mutex;
7 
8 use crate::Error;
9 
10 // TODO(mulmarta): we'd like to use EpochRecord from mls-rs-core but
11 // this breaks the Python tests because using two crates makes UniFFI
12 // generate a Python module which must be in a subdirectory of the
13 // directory with test scripts which is not supported by the script we
14 // use.
15 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, uniffi::Record)]
16 pub struct EpochRecord {
17     /// A unique epoch identifier within a particular group.
18     pub id: u64,
19     pub data: Vec<u8>,
20 }
21 
22 impl From<mls_rs_core::group::EpochRecord> for EpochRecord {
23     fn from(mls_rs_core::group::EpochRecord { id, data }: mls_rs_core::group::EpochRecord) -> Self {
24         Self { id, data }
25     }
26 }
27 
28 impl From<EpochRecord> for mls_rs_core::group::EpochRecord {
29     fn from(EpochRecord { id, data }: EpochRecord) -> Self {
30         Self { id, data }
31     }
32 }
33 
34 // When building for async, uniffi::export has to be applied _after_
35 // maybe-async's injection of the async trait. When building for sync,
36 // the order has to be the opposite.
37 #[cfg_attr(mls_build_async, uniffi::export(with_foreign))]
38 #[cfg_attr(mls_build_async, maybe_async::must_be_async)]
39 #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
40 #[cfg_attr(not(mls_build_async), uniffi::export(with_foreign))]
41 pub trait GroupStateStorage: Send + Sync + Debug {
state(&self, group_id: Vec<u8>) -> Result<Option<Vec<u8>>, Error>42     async fn state(&self, group_id: Vec<u8>) -> Result<Option<Vec<u8>>, Error>;
epoch(&self, group_id: Vec<u8>, epoch_id: u64) -> Result<Option<Vec<u8>>, Error>43     async fn epoch(&self, group_id: Vec<u8>, epoch_id: u64) -> Result<Option<Vec<u8>>, Error>;
44 
write( &self, group_id: Vec<u8>, group_state: Vec<u8>, epoch_inserts: Vec<EpochRecord>, epoch_updates: Vec<EpochRecord>, ) -> Result<(), Error>45     async fn write(
46         &self,
47         group_id: Vec<u8>,
48         group_state: Vec<u8>,
49         epoch_inserts: Vec<EpochRecord>,
50         epoch_updates: Vec<EpochRecord>,
51     ) -> Result<(), Error>;
52 
max_epoch_id(&self, group_id: Vec<u8>) -> Result<Option<u64>, Error>53     async fn max_epoch_id(&self, group_id: Vec<u8>) -> Result<Option<u64>, Error>;
54 }
55 
56 /// Adapt a mls-rs `GroupStateStorage` implementation.
57 ///
58 /// This is used to adapt a mls-rs `GroupStateStorage` implementation
59 /// to our own `GroupStateStorage` trait. This way we can use any
60 /// standard mls-rs group state storage from the FFI layer.
61 #[derive(Debug)]
62 pub(crate) struct GroupStateStorageAdapter<S>(Mutex<S>);
63 
64 impl<S> GroupStateStorageAdapter<S> {
new(group_state_storage: S) -> GroupStateStorageAdapter<S>65     pub fn new(group_state_storage: S) -> GroupStateStorageAdapter<S> {
66         Self(Mutex::new(group_state_storage))
67     }
68 
69     #[cfg(not(mls_build_async))]
inner(&self) -> std::sync::MutexGuard<'_, S>70     fn inner(&self) -> std::sync::MutexGuard<'_, S> {
71         self.0.lock().unwrap()
72     }
73 
74     #[cfg(mls_build_async)]
inner(&self) -> tokio::sync::MutexGuard<'_, S>75     async fn inner(&self) -> tokio::sync::MutexGuard<'_, S> {
76         self.0.lock().await
77     }
78 }
79 
80 #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
81 #[cfg_attr(mls_build_async, maybe_async::must_be_async)]
82 impl<S, Err> GroupStateStorage for GroupStateStorageAdapter<S>
83 where
84     S: mls_rs::GroupStateStorage<Error = Err> + Debug,
85     Err: IntoAnyError,
86 {
state(&self, group_id: Vec<u8>) -> Result<Option<Vec<u8>>, Error>87     async fn state(&self, group_id: Vec<u8>) -> Result<Option<Vec<u8>>, Error> {
88         self.inner()
89             .await
90             .state(&group_id)
91             .await
92             .map_err(|err| err.into_any_error().into())
93     }
94 
epoch(&self, group_id: Vec<u8>, epoch_id: u64) -> Result<Option<Vec<u8>>, Error>95     async fn epoch(&self, group_id: Vec<u8>, epoch_id: u64) -> Result<Option<Vec<u8>>, Error> {
96         self.inner()
97             .await
98             .epoch(&group_id, epoch_id)
99             .await
100             .map_err(|err| err.into_any_error().into())
101     }
102 
write( &self, id: Vec<u8>, data: Vec<u8>, epoch_inserts: Vec<EpochRecord>, epoch_updates: Vec<EpochRecord>, ) -> Result<(), Error>103     async fn write(
104         &self,
105         id: Vec<u8>,
106         data: Vec<u8>,
107         epoch_inserts: Vec<EpochRecord>,
108         epoch_updates: Vec<EpochRecord>,
109     ) -> Result<(), Error> {
110         self.inner()
111             .await
112             .write(
113                 mls_rs_core::group::GroupState { id, data },
114                 epoch_inserts.into_iter().map(Into::into).collect(),
115                 epoch_updates.into_iter().map(Into::into).collect(),
116             )
117             .await
118             .map_err(|err| err.into_any_error().into())
119     }
120 
max_epoch_id(&self, group_id: Vec<u8>) -> Result<Option<u64>, Error>121     async fn max_epoch_id(&self, group_id: Vec<u8>) -> Result<Option<u64>, Error> {
122         self.inner()
123             .await
124             .max_epoch_id(&group_id)
125             .await
126             .map_err(|err| err.into_any_error().into())
127     }
128 }
129