Skip to content

Commit b4220bd

Browse files
committed
Reduce the size of Client
… by moving all of its fields into an inner reference-counted type rather than using reference counting for all fields individually. Some fields are still refcounted individually and thus go through an extra layer of indirection, but the size and clone simplification should still make this change worthwhile.
1 parent 73c5bfe commit b4220bd

File tree

5 files changed

+155
-118
lines changed

5 files changed

+155
-118
lines changed

crates/matrix-sdk/src/client.rs

Lines changed: 92 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -108,27 +108,31 @@ pub enum LoopCtrl {
108108
/// All of the state is held in an `Arc` so the `Client` can be cloned freely.
109109
#[derive(Clone)]
110110
pub struct Client {
111+
pub(crate) inner: Arc<ClientInner>,
112+
}
113+
114+
pub(crate) struct ClientInner {
111115
/// The URL of the homeserver to connect to.
112116
homeserver: Arc<RwLock<Url>>,
113117
/// The underlying HTTP client.
114118
http_client: HttpClient,
115119
/// User session data.
116-
pub(crate) base_client: BaseClient,
120+
base_client: BaseClient,
117121
/// Locks making sure we only have one group session sharing request in
118122
/// flight per room.
119123
#[cfg(feature = "encryption")]
120-
pub(crate) group_session_locks: Arc<DashMap<RoomId, Arc<Mutex<()>>>>,
124+
pub(crate) group_session_locks: DashMap<RoomId, Arc<Mutex<()>>>,
121125
#[cfg(feature = "encryption")]
122126
/// Lock making sure we're only doing one key claim request at a time.
123-
pub(crate) key_claim_lock: Arc<Mutex<()>>,
124-
pub(crate) members_request_locks: Arc<DashMap<RoomId, Arc<Mutex<()>>>>,
125-
pub(crate) typing_notice_times: Arc<DashMap<RoomId, Instant>>,
127+
pub(crate) key_claim_lock: Mutex<()>,
128+
pub(crate) members_request_locks: DashMap<RoomId, Arc<Mutex<()>>>,
129+
pub(crate) typing_notice_times: DashMap<RoomId, Instant>,
126130
/// Event handlers. See `register_event_handler`.
127-
event_handlers: Arc<RwLock<EventHandlerMap>>,
131+
event_handlers: RwLock<EventHandlerMap>,
128132
/// Custom event handler context. See `register_event_handler_context`.
129-
event_handler_data: Arc<StdRwLock<AnyMap>>,
133+
event_handler_data: StdRwLock<AnyMap>,
130134
/// Notification handlers. See `register_notification_handler`.
131-
notification_handlers: Arc<RwLock<Vec<NotificationHandlerFn>>>,
135+
notification_handlers: RwLock<Vec<NotificationHandlerFn>>,
132136
/// Whether the client should operate in application service style mode.
133137
/// This is low-level functionality. For an high-level API check the
134138
/// `matrix_sdk_appservice` crate.
@@ -141,7 +145,7 @@ pub struct Client {
141145
/// synchronization, e.g. if we send out a request to create a room, we can
142146
/// wait for the sync to get the data to fetch a room object from the state
143147
/// store.
144-
pub(crate) sync_beat: Arc<event_listener::Event>,
148+
pub(crate) sync_beat: event_listener::Event,
145149
}
146150

147151
#[cfg(not(tarpaulin_include))]
@@ -185,7 +189,7 @@ impl Client {
185189
let http_client =
186190
HttpClient::new(client, homeserver.clone(), session, config.request_config);
187191

188-
Ok(Self {
192+
let inner = Arc::new(ClientInner {
189193
homeserver,
190194
http_client,
191195
base_client,
@@ -200,8 +204,10 @@ impl Client {
200204
notification_handlers: Default::default(),
201205
appservice_mode: config.appservice_mode,
202206
use_discovery_response: config.use_discovery_response,
203-
sync_beat: event_listener::Event::new().into(),
204-
})
207+
sync_beat: event_listener::Event::new(),
208+
});
209+
210+
Ok(Self { inner })
205211
}
206212

207213
/// Create a new [`Client`] using homeserver auto discovery.
@@ -267,6 +273,24 @@ impl Client {
267273
Ok(client)
268274
}
269275

276+
pub(crate) fn base_client(&self) -> &BaseClient {
277+
&self.inner.base_client
278+
}
279+
280+
#[cfg(feature = "encryption")]
281+
pub(crate) async fn olm_machine(&self) -> Option<matrix_sdk_base::crypto::OlmMachine> {
282+
self.base_client().olm_machine().await
283+
}
284+
285+
#[cfg(feature = "encryption")]
286+
pub(crate) async fn mark_request_as_sent(
287+
&self,
288+
request_id: &matrix_sdk_base::uuid::Uuid,
289+
response: impl Into<matrix_sdk_base::crypto::IncomingResponse<'_>>,
290+
) -> Result<(), matrix_sdk_base::Error> {
291+
self.base_client().mark_request_as_sent(request_id, response).await
292+
}
293+
270294
fn homeserver_from_user_id(user_id: &UserId) -> Result<Url> {
271295
let homeserver = format!("https://{}", user_id.server_name());
272296
#[allow(unused_mut)]
@@ -289,7 +313,7 @@ impl Client {
289313
///
290314
/// * `homeserver_url` - The new URL to use.
291315
pub async fn set_homeserver(&self, homeserver_url: Url) {
292-
let mut homeserver = self.homeserver.write().await;
316+
let mut homeserver = self.inner.homeserver.write().await;
293317
*homeserver = homeserver_url;
294318
}
295319

@@ -323,23 +347,23 @@ impl Client {
323347

324348
/// Is the client logged in.
325349
pub async fn logged_in(&self) -> bool {
326-
self.base_client.logged_in().await
350+
self.inner.base_client.logged_in().await
327351
}
328352

329353
/// The Homeserver of the client.
330354
pub async fn homeserver(&self) -> Url {
331-
self.homeserver.read().await.clone()
355+
self.inner.homeserver.read().await.clone()
332356
}
333357

334358
/// Get the user id of the current owner of the client.
335359
pub async fn user_id(&self) -> Option<UserId> {
336-
let session = self.base_client.session().read().await;
360+
let session = self.inner.base_client.session().read().await;
337361
session.as_ref().cloned().map(|s| s.user_id)
338362
}
339363

340364
/// Get the device id that identifies the current session.
341365
pub async fn device_id(&self) -> Option<DeviceIdBox> {
342-
let session = self.base_client.session().read().await;
366+
let session = self.inner.base_client.session().read().await;
343367
session.as_ref().map(|s| s.device_id.clone())
344368
}
345369

@@ -350,7 +374,7 @@ impl Client {
350374
/// Can be used with [`Client::restore_login`] to restore a previously
351375
/// logged in session.
352376
pub async fn session(&self) -> Option<Session> {
353-
self.base_client.session().read().await.clone()
377+
self.inner.base_client.session().read().await.clone()
354378
}
355379

356380
/// Fetches the display name of the owner of the client.
@@ -468,7 +492,7 @@ impl Client {
468492

469493
/// Get a reference to the store.
470494
pub fn store(&self) -> &Store {
471-
self.base_client.store()
495+
self.inner.base_client.store()
472496
}
473497

474498
/// Sets the mxc avatar url of the client's owner. The avatar gets unset if
@@ -610,34 +634,39 @@ impl Client {
610634
<H::Future as Future>::Output: EventHandlerResult,
611635
{
612636
let event_type = H::ID.1;
613-
self.event_handlers.write().await.entry(H::ID).or_default().push(Box::new(move |data| {
614-
let maybe_fut = serde_json::from_str(data.raw.get())
615-
.map(|ev| handler.clone().handle_event(ev, data));
616-
617-
Box::pin(async move {
618-
match maybe_fut {
619-
Ok(Some(fut)) => {
620-
fut.await.print_error(event_type);
621-
}
622-
Ok(None) => {
623-
error!("Event handler for {} has an invalid context argument", event_type);
624-
}
625-
Err(e) => {
626-
warn!(
627-
"Failed to deserialize `{}` event, skipping event handler.\n\
637+
self.inner.event_handlers.write().await.entry(H::ID).or_default().push(Box::new(
638+
move |data| {
639+
let maybe_fut = serde_json::from_str(data.raw.get())
640+
.map(|ev| handler.clone().handle_event(ev, data));
641+
642+
Box::pin(async move {
643+
match maybe_fut {
644+
Ok(Some(fut)) => {
645+
fut.await.print_error(event_type);
646+
}
647+
Ok(None) => {
648+
error!(
649+
"Event handler for {} has an invalid context argument",
650+
event_type
651+
);
652+
}
653+
Err(e) => {
654+
warn!(
655+
"Failed to deserialize `{}` event, skipping event handler.\n\
628656
Deserialization error: {}",
629-
event_type, e,
630-
);
657+
event_type, e,
658+
);
659+
}
631660
}
632-
}
633-
})
634-
}));
661+
})
662+
},
663+
));
635664

636665
self
637666
}
638667

639668
pub(crate) async fn event_handlers(&self) -> RwLockReadGuard<'_, EventHandlerMap> {
640-
self.event_handlers.read().await
669+
self.inner.event_handlers.read().await
641670
}
642671

643672
/// Add an arbitrary value for use as event handler context.
@@ -681,15 +710,15 @@ impl Client {
681710
where
682711
T: Clone + Send + Sync + 'static,
683712
{
684-
self.event_handler_data.write().unwrap().insert(ctx);
713+
self.inner.event_handler_data.write().unwrap().insert(ctx);
685714
self
686715
}
687716

688717
pub(crate) fn event_handler_context<T>(&self) -> Option<T>
689718
where
690719
T: Clone + Send + Sync + 'static,
691720
{
692-
let map = self.event_handler_data.read().unwrap();
721+
let map = self.inner.event_handler_data.read().unwrap();
693722
map.get::<T>().cloned()
694723
}
695724

@@ -703,7 +732,7 @@ impl Client {
703732
H: Fn(Notification, room::Room, Client) -> Fut + Send + Sync + 'static,
704733
Fut: Future<Output = ()> + Send + 'static,
705734
{
706-
self.notification_handlers.write().await.push(Box::new(
735+
self.inner.notification_handlers.write().await.push(Box::new(
707736
move |notification, room, client| Box::pin((handler)(notification, room, client)),
708737
));
709738

@@ -713,7 +742,7 @@ impl Client {
713742
pub(crate) async fn notification_handlers(
714743
&self,
715744
) -> RwLockReadGuard<'_, Vec<NotificationHandlerFn>> {
716-
self.notification_handlers.read().await
745+
self.inner.notification_handlers.read().await
717746
}
718747

719748
/// Get all the rooms the client knows about.
@@ -1183,15 +1212,15 @@ impl Client {
11831212
///
11841213
/// * `response` - A successful login response.
11851214
async fn receive_login_response(&self, response: &login::Response) -> Result<()> {
1186-
if self.use_discovery_response {
1215+
if self.inner.use_discovery_response {
11871216
if let Some(well_known) = &response.well_known {
11881217
if let Ok(homeserver) = Url::parse(&well_known.homeserver.base_url) {
11891218
self.set_homeserver(homeserver).await;
11901219
}
11911220
}
11921221
}
11931222

1194-
self.base_client.receive_login_response(response).await?;
1223+
self.inner.base_client.receive_login_response(response).await?;
11951224

11961225
Ok(())
11971226
}
@@ -1254,7 +1283,7 @@ impl Client {
12541283
///
12551284
/// [`login`]: #method.login
12561285
pub async fn restore_login(&self, session: Session) -> Result<()> {
1257-
Ok(self.base_client.restore_login(session).await?)
1286+
Ok(self.inner.base_client.restore_login(session).await?)
12581287
}
12591288

12601289
/// Register a user to the server.
@@ -1301,8 +1330,8 @@ impl Client {
13011330
let homeserver = self.homeserver().await;
13021331
info!("Registering to {}", homeserver);
13031332

1304-
let config = if self.appservice_mode {
1305-
Some(self.http_client.request_config.force_auth())
1333+
let config = if self.inner.appservice_mode {
1334+
Some(self.inner.http_client.request_config.force_auth())
13061335
} else {
13071336
None
13081337
};
@@ -1367,14 +1396,14 @@ impl Client {
13671396
filter_name: &str,
13681397
definition: FilterDefinition<'_>,
13691398
) -> Result<String> {
1370-
if let Some(filter) = self.base_client.get_filter(filter_name).await? {
1399+
if let Some(filter) = self.inner.base_client.get_filter(filter_name).await? {
13711400
Ok(filter)
13721401
} else {
13731402
let user_id = self.user_id().await.ok_or(Error::AuthenticationRequired)?;
13741403
let request = FilterUploadRequest::new(&user_id, definition);
13751404
let response = self.send(request, None).await?;
13761405

1377-
self.base_client.receive_filter_upload(filter_name, &response).await?;
1406+
self.inner.base_client.receive_filter_upload(filter_name, &response).await?;
13781407

13791408
Ok(response.filter_id)
13801409
}
@@ -1586,8 +1615,8 @@ impl Client {
15861615
content_type: Some(content_type.essence_str()),
15871616
});
15881617

1589-
let request_config = self.http_client.request_config.timeout(timeout);
1590-
Ok(self.http_client.upload(request, Some(request_config)).await?)
1618+
let request_config = self.inner.http_client.request_config.timeout(timeout);
1619+
Ok(self.inner.http_client.upload(request, Some(request_config)).await?)
15911620
}
15921621

15931622
/// Send an arbitrary request to the server, without updating client state.
@@ -1639,7 +1668,7 @@ impl Client {
16391668
Request: OutgoingRequest + Debug,
16401669
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
16411670
{
1642-
Ok(self.http_client.send(request, config).await?)
1671+
Ok(self.inner.http_client.send(request, config).await?)
16431672
}
16441673

16451674
/// Get information of all our own devices.
@@ -1832,9 +1861,9 @@ impl Client {
18321861
timeout: sync_settings.timeout,
18331862
});
18341863

1835-
let request_config = self.http_client.request_config.timeout(
1864+
let request_config = self.inner.http_client.request_config.timeout(
18361865
sync_settings.timeout.unwrap_or_else(|| Duration::from_secs(0))
1837-
+ self.http_client.request_config.timeout,
1866+
+ self.inner.http_client.request_config.timeout,
18381867
);
18391868

18401869
let response = self.send(request, Some(request_config)).await?;
@@ -1845,7 +1874,7 @@ impl Client {
18451874
error!(error =? e, "Error while sending outgoing E2EE requests");
18461875
};
18471876

1848-
self.sync_beat.notify(usize::MAX);
1877+
self.inner.sync_beat.notify(usize::MAX);
18491878

18501879
Ok(response)
18511880
}
@@ -2050,7 +2079,7 @@ impl Client {
20502079
/// Get the current, if any, sync token of the client.
20512080
/// This will be None if the client didn't sync at least once.
20522081
pub async fn sync_token(&self) -> Option<String> {
2053-
self.base_client.sync_token().await
2082+
self.inner.base_client.sync_token().await
20542083
}
20552084

20562085
/// Get a media file's content.
@@ -2069,7 +2098,7 @@ impl Client {
20692098
use_cache: bool,
20702099
) -> Result<Vec<u8>> {
20712100
let content = if use_cache {
2072-
self.base_client.store().get_media_content(request).await?
2101+
self.inner.base_client.store().get_media_content(request).await?
20732102
} else {
20742103
None
20752104
};
@@ -2113,7 +2142,7 @@ impl Client {
21132142
};
21142143

21152144
if use_cache {
2116-
self.base_client.store().add_media_content(request, content.clone()).await?;
2145+
self.inner.base_client.store().add_media_content(request, content.clone()).await?;
21172146
}
21182147

21192148
Ok(content)
@@ -2126,7 +2155,7 @@ impl Client {
21262155
///
21272156
/// * `request` - The `MediaRequest` of the content.
21282157
pub async fn remove_media_content(&self, request: &MediaRequest) -> Result<()> {
2129-
Ok(self.base_client.store().remove_media_content(request).await?)
2158+
Ok(self.inner.base_client.store().remove_media_content(request).await?)
21302159
}
21312160

21322161
/// Delete all the media content corresponding to the given
@@ -2136,7 +2165,7 @@ impl Client {
21362165
///
21372166
/// * `uri` - The `MxcUri` of the files.
21382167
pub async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
2139-
Ok(self.base_client.store().remove_media_content_for_uri(uri).await?)
2168+
Ok(self.inner.base_client.store().remove_media_content_for_uri(uri).await?)
21402169
}
21412170

21422171
/// Get the file of the given media event content.
@@ -2655,7 +2684,7 @@ pub(crate) mod test {
26552684
.add_state_event(EventsJson::PowerLevels)
26562685
.build_sync_response();
26572686

2658-
client.base_client.receive_sync_response(response).await.unwrap();
2687+
client.inner.base_client.receive_sync_response(response).await.unwrap();
26592688
let room_id = room_id!("!SVkFJHzfwvuaIEawgC:localhost");
26602689

26612690
assert_eq!(client.homeserver().await, Url::parse(&mockito::server_url()).unwrap());

0 commit comments

Comments
 (0)