1use std::{
2 borrow::Cow,
3 collections::{BTreeMap, BTreeSet, HashMap},
4 fmt, iter,
5 path::{Path, PathBuf},
6 str::FromStr as _,
7 sync::Arc,
8};
9
10use async_trait::async_trait;
11use deadpool::managed::PoolConfig;
12use matrix_sdk_base::{
13 MinimalRoomMemberEvent, ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, RoomInfo,
14 RoomMemberships, RoomState, StateChanges, StateStore, StateStoreDataKey, StateStoreDataValue,
15 deserialized_responses::{DisplayName, RawAnySyncOrStrippedState, SyncOrStrippedState},
16 store::{
17 ChildTransactionId, DependentQueuedRequest, DependentQueuedRequestKind, QueueWedgeError,
18 QueuedRequest, QueuedRequestKind, RoomLoadSettings, SentRequestKey,
19 StoredThreadSubscription, ThreadSubscriptionStatus, migration_helpers::RoomInfoV1,
20 },
21};
22use matrix_sdk_store_encryption::StoreCipher;
23use ruma::{
24 CanonicalJsonObject, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId,
25 OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UInt, UserId,
26 canonical_json::{RedactedBecause, redact},
27 events::{
28 AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncStateEvent,
29 GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
30 presence::PresenceEvent,
31 receipt::{Receipt, ReceiptThread, ReceiptType},
32 room::{
33 create::RoomCreateEventContent,
34 member::{StrippedRoomMemberEvent, SyncRoomMemberEvent},
35 },
36 },
37 profile::UserProfile,
38 serde::Raw,
39};
40use rusqlite::{OptionalExtension, Transaction};
41use serde::{Deserialize, Serialize};
42use tokio::{
43 fs,
44 sync::{Mutex, OwnedMutexGuard},
45};
46use tracing::{debug, instrument, warn};
47
48use crate::{
49 OpenStoreError, RuntimeConfig, Secret, SqliteStoreConfig,
50 connection::{self, Connection as SqliteAsyncConn, Pool as SqlitePool, SqliteConnections},
51 error::{Error, Result},
52 utils::{
53 EncryptableStore, Key, SqliteAsyncConnExt, SqliteKeyValueStoreAsyncConnExt,
54 SqliteKeyValueStoreConnExt, repeat_vars,
55 },
56};
57
58mod keys {
59 pub const KV_BLOB: &str = "kv_blob";
61 pub const ROOM_INFO: &str = "room_info";
62 pub const STATE_EVENT: &str = "state_event";
63 pub const GLOBAL_ACCOUNT_DATA: &str = "global_account_data";
64 pub const ROOM_ACCOUNT_DATA: &str = "room_account_data";
65 pub const MEMBER: &str = "member";
66 pub const PROFILE: &str = "profile";
67 pub const RECEIPT: &str = "receipt";
68 pub const DISPLAY_NAME: &str = "display_name";
69 pub const SEND_QUEUE: &str = "send_queue_events";
70 pub const DEPENDENTS_SEND_QUEUE: &str = "dependent_send_queue_events";
71 pub const THREAD_SUBSCRIPTIONS: &str = "thread_subscriptions";
72 pub const GLOBAL_PROFILES: &str = "global_profiles";
73}
74
75pub const DATABASE_NAME: &str = "matrix-sdk-state.sqlite3";
77
78#[derive(Clone)]
80pub struct SqliteStateStore {
81 store_cipher: Option<Arc<StoreCipher>>,
82
83 connections: Arc<Mutex<Option<SqliteConnections>>>,
85
86 db_path: PathBuf,
88
89 pool_config: PoolConfig,
91
92 runtime_config: RuntimeConfig,
94}
95
96#[cfg(not(tarpaulin_include))]
97impl fmt::Debug for SqliteStateStore {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 f.debug_struct("SqliteStateStore").finish_non_exhaustive()
100 }
101}
102
103impl SqliteStateStore {
104 pub async fn open(
107 path: impl AsRef<Path>,
108 passphrase: Option<&str>,
109 ) -> Result<Self, OpenStoreError> {
110 Self::open_with_config(&SqliteStoreConfig::new(path).passphrase(passphrase)).await
111 }
112
113 pub async fn open_with_key(
116 path: impl AsRef<Path>,
117 key: Option<&[u8; 32]>,
118 ) -> Result<Self, OpenStoreError> {
119 Self::open_with_config(&SqliteStoreConfig::new(path).key(key)).await
120 }
121
122 pub async fn open_with_config(config: &SqliteStoreConfig) -> Result<Self, OpenStoreError> {
124 fs::create_dir_all(&config.path).await.map_err(OpenStoreError::CreateDir)?;
125
126 let pool = config.build_pool_of_connections(DATABASE_NAME)?;
127 let pool_config = config.pool_config;
128 let runtime_config = config.runtime_config;
129
130 let this =
131 Self::open_with_pool(pool, config.secret.clone(), pool_config, runtime_config).await?;
132 this.read().await?.apply_runtime_config(runtime_config).await?;
133
134 Ok(this)
135 }
136
137 pub(crate) async fn open_with_pool(
140 pool: SqlitePool,
141 secret: Option<Secret>,
142 pool_config: PoolConfig,
143 runtime_config: RuntimeConfig,
144 ) -> Result<Self, OpenStoreError> {
145 let db_path = pool.manager().database_path.clone();
146 let conn = pool.get().await?;
147
148 let mut version = conn.db_version().await?;
149
150 if version == 0 {
151 init(&conn).await?;
152 version = 1;
153 }
154
155 let store_cipher = match secret {
156 Some(s) => Some(Arc::new(conn.get_or_create_store_cipher(s).await?)),
157 None => None,
158 };
159 let this = Self {
160 store_cipher,
161 connections: Arc::new(Mutex::new(Some(SqliteConnections {
162 pool,
163 write_connection: Arc::new(Mutex::new(conn)),
164 }))),
165 db_path,
166 pool_config,
167 runtime_config,
168 };
169 this.run_migrations(version, None).await?;
170
171 this.read().await?.wal_checkpoint().await;
172
173 Ok(this)
174 }
175
176 async fn run_migrations(&self, from: u8, to: Option<u8>) -> Result<()> {
181 if to == Some(1) {
182 return Ok(());
183 }
184
185 let conn = self.write().await?;
186
187 if from < 2 {
188 debug!("Upgrading database to version 2");
189 let this = self.clone();
190 conn.with_transaction(move |txn| {
191 txn.execute_batch(include_str!(
193 "../migrations/state_store/002_a_create_new_room_info.sql"
194 ))?;
195
196 for data in txn
198 .prepare("SELECT data FROM room_info")?
199 .query_map((), |row| row.get::<_, Vec<u8>>(0))?
200 {
201 let data = data?;
202 let room_info: RoomInfoV1 = this.deserialize_json(&data)?;
203
204 let room_id = this.encode_key(keys::ROOM_INFO, room_info.room_id());
205 let state = this
206 .encode_key(keys::ROOM_INFO, serde_json::to_string(&room_info.state())?);
207 txn.prepare_cached(
208 "INSERT OR REPLACE INTO new_room_info (room_id, state, data)
209 VALUES (?, ?, ?)",
210 )?
211 .execute((room_id, state, data))?;
212 }
213
214 txn.execute_batch(include_str!(
216 "../migrations/state_store/002_b_replace_room_info.sql"
217 ))?;
218
219 txn.set_db_version(2)?;
220 Result::<_, Error>::Ok(())
221 })
222 .await?;
223 }
224
225 if to == Some(2) {
226 return Ok(());
227 }
228
229 if from < 3 {
231 debug!("Upgrading database to version 3");
232 let this = self.clone();
233 conn.with_transaction(move |txn| {
234 for data in txn
236 .prepare("SELECT data FROM room_info")?
237 .query_map((), |row| row.get::<_, Vec<u8>>(0))?
238 {
239 let data = data?;
240 let room_info_v1: RoomInfoV1 = this.deserialize_json(&data)?;
241
242 let room_id = this.encode_key(keys::STATE_EVENT, room_info_v1.room_id());
244 let event_type =
245 this.encode_key(keys::STATE_EVENT, StateEventType::RoomCreate.to_string());
246 let create_res = txn
247 .prepare(
248 "SELECT stripped, data FROM state_event
249 WHERE room_id = ? AND event_type = ?",
250 )?
251 .query_row([room_id, event_type], |row| {
252 Ok((row.get::<_, bool>(0)?, row.get::<_, Vec<u8>>(1)?))
253 })
254 .optional()?;
255
256 let create = create_res.and_then(|(stripped, data)| {
257 let create = if stripped {
258 SyncOrStrippedState::<RoomCreateEventContent>::Stripped(
259 this.deserialize_json(&data).ok()?,
260 )
261 } else {
262 SyncOrStrippedState::Sync(this.deserialize_json(&data).ok()?)
263 };
264 Some(create)
265 });
266
267 let migrated_room_info = room_info_v1.migrate(create.as_ref());
268
269 let data = this.serialize_json(&migrated_room_info)?;
270 let room_id = this.encode_key(keys::ROOM_INFO, migrated_room_info.room_id());
271 txn.prepare_cached("UPDATE room_info SET data = ? WHERE room_id = ?")?
272 .execute((data, room_id))?;
273 }
274
275 txn.set_db_version(3)?;
276 Result::<_, Error>::Ok(())
277 })
278 .await?;
279 }
280
281 if to == Some(3) {
282 return Ok(());
283 }
284
285 if from < 4 {
286 debug!("Upgrading database to version 4");
287 conn.with_transaction(move |txn| {
288 txn.execute_batch(include_str!("../migrations/state_store/003_send_queue.sql"))?;
290 txn.set_db_version(4)
291 })
292 .await?;
293 }
294
295 if to == Some(4) {
296 return Ok(());
297 }
298
299 if from < 5 {
300 debug!("Upgrading database to version 5");
301 conn.with_transaction(move |txn| {
302 txn.execute_batch(include_str!(
304 "../migrations/state_store/004_send_queue_with_roomid_value.sql"
305 ))?;
306 txn.set_db_version(4)
307 })
308 .await?;
309 }
310
311 if to == Some(5) {
312 return Ok(());
313 }
314
315 if from < 6 {
316 debug!("Upgrading database to version 6");
317 conn.with_transaction(move |txn| {
318 txn.execute_batch(include_str!(
320 "../migrations/state_store/005_send_queue_dependent_events.sql"
321 ))?;
322 txn.set_db_version(6)
323 })
324 .await?;
325 }
326
327 if to == Some(6) {
328 return Ok(());
329 }
330
331 if from < 7 {
332 debug!("Upgrading database to version 7");
333 conn.with_transaction(move |txn| {
334 txn.execute_batch(include_str!("../migrations/state_store/006_drop_media.sql"))?;
336 txn.set_db_version(7)
337 })
338 .await?;
339 }
340
341 if to == Some(7) {
342 return Ok(());
343 }
344
345 if from < 8 {
346 debug!("Upgrading database to version 8");
347 let error = QueueWedgeError::GenericApiError {
349 msg: "local echo failed to send in a previous session".into(),
350 };
351 let default_err = self.serialize_value(&error)?;
352
353 conn.with_transaction(move |txn| {
354 txn.execute_batch(include_str!("../migrations/state_store/007_a_send_queue_wedge_reason.sql"))?;
356
357 for wedged_entries in txn
360 .prepare("SELECT room_id, transaction_id FROM send_queue_events WHERE wedged = 1")?
361 .query_map((), |row| {
362 Ok(
363 (row.get::<_, Vec<u8>>(0)?,row.get::<_, String>(1)?)
364 )
365 })? {
366
367 let (room_id, transaction_id) = wedged_entries?;
368
369 txn.prepare_cached("UPDATE send_queue_events SET wedge_reason = ? WHERE room_id = ? AND transaction_id = ?")?
370 .execute((default_err.clone(), room_id, transaction_id))?;
371 }
372
373
374 txn.execute_batch(include_str!("../migrations/state_store/007_b_send_queue_clean.sql"))?;
376
377 txn.set_db_version(8)
378 })
379 .await?;
380 }
381
382 if to == Some(8) {
383 return Ok(());
384 }
385
386 if from < 9 {
387 debug!("Upgrading database to version 9");
388 conn.with_transaction(move |txn| {
389 txn.execute_batch(include_str!("../migrations/state_store/008_send_queue.sql"))?;
391 txn.set_db_version(9)
392 })
393 .await?;
394 }
395
396 if to == Some(9) {
397 return Ok(());
398 }
399
400 if from < 10 {
401 debug!("Upgrading database to version 10");
402 conn.with_transaction(move |txn| {
403 txn.execute_batch(include_str!(
405 "../migrations/state_store/009_send_queue_priority.sql"
406 ))?;
407 txn.set_db_version(10)
408 })
409 .await?;
410 }
411
412 if to == Some(10) {
413 return Ok(());
414 }
415
416 if from < 11 {
417 debug!("Upgrading database to version 11");
418 conn.with_transaction(move |txn| {
419 txn.execute_batch(include_str!(
421 "../migrations/state_store/010_send_queue_enqueue_time.sql"
422 ))?;
423 txn.set_db_version(11)
424 })
425 .await?;
426 }
427
428 if to == Some(11) {
429 return Ok(());
430 }
431
432 if from < 12 {
433 debug!("Upgrading database to version 12");
434 conn.vacuum().await?;
438 conn.set_kv("version", vec![12]).await?;
439 }
440
441 if to == Some(12) {
442 return Ok(());
443 }
444
445 if from < 13 {
446 debug!("Upgrading database to version 13");
447 conn.with_transaction(move |txn| {
448 txn.execute_batch(include_str!(
450 "../migrations/state_store/011_thread_subscriptions.sql"
451 ))?;
452 txn.set_db_version(13)
453 })
454 .await?;
455 }
456
457 if to == Some(13) {
458 return Ok(());
459 }
460
461 if from < 14 {
462 debug!("Upgrading database to version 14");
463 conn.with_transaction(move |txn| {
464 txn.execute_batch(include_str!(
466 "../migrations/state_store/012_thread_subscriptions_bumpstamp.sql"
467 ))?;
468 txn.set_db_version(14)
469 })
470 .await?;
471 }
472
473 if to == Some(14) {
474 return Ok(());
475 }
476
477 if from < 15 {
478 debug!("Upgrading database to version 15");
479 conn.with_transaction(move |txn| {
480 txn.execute_batch(include_str!(
482 "../migrations/state_store/013_send_queue_new_parent_key_format.sql"
483 ))?;
484 txn.set_db_version(15)
485 })
486 .await?;
487 }
488
489 if to == Some(15) {
490 return Ok(());
491 }
492
493 if from < 16 {
494 debug!("Upgrading database to version 16");
495 conn.with_transaction(move |txn| {
496 txn.execute_batch(include_str!(
498 "../migrations/state_store/014_global_profiles.sql"
499 ))?;
500 txn.set_db_version(16)
501 })
502 .await?;
503 }
504
505 if to == Some(16) {
506 return Ok(());
507 }
508
509 Ok(())
510 }
511
512 fn encode_state_store_data_key(&self, key: StateStoreDataKey<'_>) -> Key {
513 let key_s = match key {
514 StateStoreDataKey::SyncToken => Cow::Borrowed(StateStoreDataKey::SYNC_TOKEN),
515 StateStoreDataKey::SupportedVersions => {
516 Cow::Borrowed(StateStoreDataKey::SUPPORTED_VERSIONS)
517 }
518 StateStoreDataKey::WellKnown => Cow::Borrowed(StateStoreDataKey::WELL_KNOWN),
519 StateStoreDataKey::Filter(f) => {
520 Cow::Owned(format!("{}:{f}", StateStoreDataKey::FILTER))
521 }
522 StateStoreDataKey::UserAvatarUrl(u) => {
523 Cow::Owned(format!("{}:{u}", StateStoreDataKey::USER_AVATAR_URL))
524 }
525 StateStoreDataKey::RecentlyVisitedRooms(b) => {
526 Cow::Owned(format!("{}:{b}", StateStoreDataKey::RECENTLY_VISITED_ROOMS))
527 }
528 StateStoreDataKey::UtdHookManagerData => {
529 Cow::Borrowed(StateStoreDataKey::UTD_HOOK_MANAGER_DATA)
530 }
531 StateStoreDataKey::OneTimeKeyAlreadyUploaded => {
532 Cow::Borrowed(StateStoreDataKey::ONE_TIME_KEY_ALREADY_UPLOADED)
533 }
534 StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
535 if let Some(thread_root) = thread_root {
536 Cow::Owned(format!(
537 "{}:{room_id}:{thread_root}",
538 StateStoreDataKey::COMPOSER_DRAFT
539 ))
540 } else {
541 Cow::Owned(format!("{}:{room_id}", StateStoreDataKey::COMPOSER_DRAFT))
542 }
543 }
544 StateStoreDataKey::SeenKnockRequests(room_id) => {
545 Cow::Owned(format!("{}:{room_id}", StateStoreDataKey::SEEN_KNOCK_REQUESTS))
546 }
547 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => {
548 Cow::Borrowed(StateStoreDataKey::THREAD_SUBSCRIPTIONS_CATCHUP_TOKENS)
549 }
550 StateStoreDataKey::HomeserverCapabilities => {
551 Cow::Borrowed(StateStoreDataKey::HOMESERVER_CAPABILITIES)
552 }
553 };
554
555 self.encode_key(keys::KV_BLOB, &*key_s)
556 }
557
558 fn encode_presence_key(&self, user_id: &UserId) -> Key {
559 self.encode_key(keys::KV_BLOB, format!("presence:{user_id}"))
560 }
561
562 fn encode_custom_key(&self, key: &[u8]) -> Key {
563 let mut full_key = b"custom:".to_vec();
564 full_key.extend(key);
565 self.encode_key(keys::KV_BLOB, full_key)
566 }
567
568 #[instrument(skip_all)]
571 async fn read(&self) -> Result<SqliteAsyncConn> {
572 let pool = {
573 let guard = self.connections.lock().await;
574 let conns = guard.as_ref().ok_or(Error::StoreClosed)?;
575 conns.pool.clone()
576 };
577 Ok(pool.get().await?)
578 }
579
580 #[instrument(skip_all)]
583 async fn write(&self) -> Result<OwnedMutexGuard<SqliteAsyncConn>> {
584 let write_conn = {
585 let guard = self.connections.lock().await;
586 let conns = guard.as_ref().ok_or(Error::StoreClosed)?;
587 conns.write_connection.clone()
588 };
589 Ok(write_conn.lock_owned().await)
590 }
591
592 fn remove_maybe_stripped_room_data(
593 &self,
594 txn: &Transaction<'_>,
595 room_id: &RoomId,
596 stripped: bool,
597 ) -> rusqlite::Result<()> {
598 let state_event_room_id = self.encode_key(keys::STATE_EVENT, room_id);
599 txn.remove_room_state_events(&state_event_room_id, Some(stripped))?;
600
601 let member_room_id = self.encode_key(keys::MEMBER, room_id);
602 txn.remove_room_members(&member_room_id, Some(stripped))
603 }
604
605 pub async fn vacuum(&self) -> Result<()> {
606 self.write().await?.vacuum().await
607 }
608
609 pub async fn get_db_size(&self) -> Result<Option<usize>> {
610 let read_conn = self.read().await?;
611 Ok(Some(read_conn.get_db_size().await?))
612 }
613}
614
615impl EncryptableStore for SqliteStateStore {
616 fn get_cypher(&self) -> Option<&StoreCipher> {
617 self.store_cipher.as_deref()
618 }
619}
620
621async fn init(conn: &SqliteAsyncConn) -> Result<()> {
623 conn.execute_batch("PRAGMA journal_mode = wal;").await?;
626 conn.with_transaction(|txn| {
627 txn.execute_batch(include_str!("../migrations/state_store/001_init.sql"))?;
628 txn.set_db_version(1)?;
629
630 Ok(())
631 })
632 .await
633}
634
635trait SqliteConnectionStateStoreExt {
636 fn set_kv_blob(&self, key: &[u8], value: &[u8]) -> rusqlite::Result<()>;
637
638 fn set_global_account_data(&self, event_type: &[u8], data: &[u8]) -> rusqlite::Result<()>;
639
640 fn set_room_account_data(
641 &self,
642 room_id: &[u8],
643 event_type: &[u8],
644 data: &[u8],
645 ) -> rusqlite::Result<()>;
646 fn remove_room_account_data(&self, room_id: &[u8]) -> rusqlite::Result<()>;
647
648 fn set_room_info(&self, room_id: &[u8], state: &[u8], data: &[u8]) -> rusqlite::Result<()>;
649 fn get_room_info(&self, room_id: &[u8]) -> rusqlite::Result<Option<Vec<u8>>>;
650 fn remove_room_info(&self, room_id: &[u8]) -> rusqlite::Result<()>;
651
652 fn set_state_event(
653 &self,
654 room_id: &[u8],
655 event_type: &[u8],
656 state_key: &[u8],
657 stripped: bool,
658 event_id: Option<&[u8]>,
659 data: &[u8],
660 ) -> rusqlite::Result<()>;
661 fn get_state_event_by_id(
662 &self,
663 room_id: &[u8],
664 event_id: &[u8],
665 ) -> rusqlite::Result<Option<Vec<u8>>>;
666 fn remove_room_state_events(
667 &self,
668 room_id: &[u8],
669 stripped: Option<bool>,
670 ) -> rusqlite::Result<()>;
671
672 fn set_member(
673 &self,
674 room_id: &[u8],
675 user_id: &[u8],
676 membership: &[u8],
677 stripped: bool,
678 data: &[u8],
679 ) -> rusqlite::Result<()>;
680 fn remove_room_members(&self, room_id: &[u8], stripped: Option<bool>) -> rusqlite::Result<()>;
681
682 fn set_profile(&self, room_id: &[u8], user_id: &[u8], data: &[u8]) -> rusqlite::Result<()>;
683 fn remove_room_profiles(&self, room_id: &[u8]) -> rusqlite::Result<()>;
684 fn remove_room_profile(&self, room_id: &[u8], user_id: &[u8]) -> rusqlite::Result<()>;
685
686 fn set_receipt(
687 &self,
688 room_id: &[u8],
689 user_id: &[u8],
690 receipt_type: &[u8],
691 thread_id: &[u8],
692 event_id: &[u8],
693 data: &[u8],
694 ) -> rusqlite::Result<()>;
695 fn remove_room_receipts(&self, room_id: &[u8]) -> rusqlite::Result<()>;
696
697 fn set_display_name(&self, room_id: &[u8], name: &[u8], data: &[u8]) -> rusqlite::Result<()>;
698 fn remove_display_name(&self, room_id: &[u8], name: &[u8]) -> rusqlite::Result<()>;
699 fn remove_room_display_names(&self, room_id: &[u8]) -> rusqlite::Result<()>;
700 fn remove_room_send_queue(&self, room_id: &[u8]) -> rusqlite::Result<()>;
701 fn remove_room_dependent_send_queue(&self, room_id: &[u8]) -> rusqlite::Result<()>;
702}
703
704impl SqliteConnectionStateStoreExt for rusqlite::Connection {
705 fn set_kv_blob(&self, key: &[u8], value: &[u8]) -> rusqlite::Result<()> {
706 self.execute("INSERT OR REPLACE INTO kv_blob VALUES (?, ?)", (key, value))?;
707 Ok(())
708 }
709
710 fn set_global_account_data(&self, event_type: &[u8], data: &[u8]) -> rusqlite::Result<()> {
711 self.prepare_cached(
712 "INSERT OR REPLACE INTO global_account_data (event_type, data)
713 VALUES (?, ?)",
714 )?
715 .execute((event_type, data))?;
716 Ok(())
717 }
718
719 fn set_room_account_data(
720 &self,
721 room_id: &[u8],
722 event_type: &[u8],
723 data: &[u8],
724 ) -> rusqlite::Result<()> {
725 self.prepare_cached(
726 "INSERT OR REPLACE INTO room_account_data (room_id, event_type, data)
727 VALUES (?, ?, ?)",
728 )?
729 .execute((room_id, event_type, data))?;
730 Ok(())
731 }
732
733 fn remove_room_account_data(&self, room_id: &[u8]) -> rusqlite::Result<()> {
734 self.prepare(
735 "DELETE FROM room_account_data
736 WHERE room_id = ?",
737 )?
738 .execute((room_id,))?;
739 Ok(())
740 }
741
742 fn set_room_info(&self, room_id: &[u8], state: &[u8], data: &[u8]) -> rusqlite::Result<()> {
743 self.prepare_cached(
744 "INSERT OR REPLACE INTO room_info (room_id, state, data)
745 VALUES (?, ?, ?)",
746 )?
747 .execute((room_id, state, data))?;
748 Ok(())
749 }
750
751 fn get_room_info(&self, room_id: &[u8]) -> rusqlite::Result<Option<Vec<u8>>> {
752 self.query_row("SELECT data FROM room_info WHERE room_id = ?", (room_id,), |row| row.get(0))
753 .optional()
754 }
755
756 fn remove_room_info(&self, room_id: &[u8]) -> rusqlite::Result<()> {
758 self.prepare_cached("DELETE FROM room_info WHERE room_id = ?")?.execute((room_id,))?;
759 Ok(())
760 }
761
762 fn set_state_event(
763 &self,
764 room_id: &[u8],
765 event_type: &[u8],
766 state_key: &[u8],
767 stripped: bool,
768 event_id: Option<&[u8]>,
769 data: &[u8],
770 ) -> rusqlite::Result<()> {
771 self.prepare_cached(
772 "INSERT OR REPLACE
773 INTO state_event (room_id, event_type, state_key, stripped, event_id, data)
774 VALUES (?, ?, ?, ?, ?, ?)",
775 )?
776 .execute((room_id, event_type, state_key, stripped, event_id, data))?;
777 Ok(())
778 }
779
780 fn get_state_event_by_id(
781 &self,
782 room_id: &[u8],
783 event_id: &[u8],
784 ) -> rusqlite::Result<Option<Vec<u8>>> {
785 self.query_row(
786 "SELECT data FROM state_event WHERE room_id = ? AND event_id = ?",
787 (room_id, event_id),
788 |row| row.get(0),
789 )
790 .optional()
791 }
792
793 fn remove_room_state_events(
799 &self,
800 room_id: &[u8],
801 stripped: Option<bool>,
802 ) -> rusqlite::Result<()> {
803 if let Some(stripped) = stripped {
804 self.prepare_cached("DELETE FROM state_event WHERE room_id = ? AND stripped = ?")?
805 .execute((room_id, stripped))?;
806 } else {
807 self.prepare_cached("DELETE FROM state_event WHERE room_id = ?")?
808 .execute((room_id,))?;
809 }
810 Ok(())
811 }
812
813 fn set_member(
814 &self,
815 room_id: &[u8],
816 user_id: &[u8],
817 membership: &[u8],
818 stripped: bool,
819 data: &[u8],
820 ) -> rusqlite::Result<()> {
821 self.prepare_cached(
822 "INSERT OR REPLACE
823 INTO member (room_id, user_id, membership, stripped, data)
824 VALUES (?, ?, ?, ?, ?)",
825 )?
826 .execute((room_id, user_id, membership, stripped, data))?;
827 Ok(())
828 }
829
830 fn remove_room_members(&self, room_id: &[u8], stripped: Option<bool>) -> rusqlite::Result<()> {
835 if let Some(stripped) = stripped {
836 self.prepare_cached("DELETE FROM member WHERE room_id = ? AND stripped = ?")?
837 .execute((room_id, stripped))?;
838 } else {
839 self.prepare_cached("DELETE FROM member WHERE room_id = ?")?.execute((room_id,))?;
840 }
841 Ok(())
842 }
843
844 fn set_profile(&self, room_id: &[u8], user_id: &[u8], data: &[u8]) -> rusqlite::Result<()> {
845 self.prepare_cached(
846 "INSERT OR REPLACE
847 INTO profile (room_id, user_id, data)
848 VALUES (?, ?, ?)",
849 )?
850 .execute((room_id, user_id, data))?;
851 Ok(())
852 }
853
854 fn remove_room_profiles(&self, room_id: &[u8]) -> rusqlite::Result<()> {
855 self.prepare("DELETE FROM profile WHERE room_id = ?")?.execute((room_id,))?;
856 Ok(())
857 }
858
859 fn remove_room_profile(&self, room_id: &[u8], user_id: &[u8]) -> rusqlite::Result<()> {
860 self.prepare("DELETE FROM profile WHERE room_id = ? AND user_id = ?")?
861 .execute((room_id, user_id))?;
862 Ok(())
863 }
864
865 fn set_receipt(
866 &self,
867 room_id: &[u8],
868 user_id: &[u8],
869 receipt_type: &[u8],
870 thread: &[u8],
871 event_id: &[u8],
872 data: &[u8],
873 ) -> rusqlite::Result<()> {
874 self.prepare_cached(
875 "INSERT OR REPLACE
876 INTO receipt (room_id, user_id, receipt_type, thread, event_id, data)
877 VALUES (?, ?, ?, ?, ?, ?)",
878 )?
879 .execute((room_id, user_id, receipt_type, thread, event_id, data))?;
880 Ok(())
881 }
882
883 fn remove_room_receipts(&self, room_id: &[u8]) -> rusqlite::Result<()> {
884 self.prepare("DELETE FROM receipt WHERE room_id = ?")?.execute((room_id,))?;
885 Ok(())
886 }
887
888 fn set_display_name(&self, room_id: &[u8], name: &[u8], data: &[u8]) -> rusqlite::Result<()> {
889 self.prepare_cached(
890 "INSERT OR REPLACE
891 INTO display_name (room_id, name, data)
892 VALUES (?, ?, ?)",
893 )?
894 .execute((room_id, name, data))?;
895 Ok(())
896 }
897
898 fn remove_display_name(&self, room_id: &[u8], name: &[u8]) -> rusqlite::Result<()> {
899 self.prepare("DELETE FROM display_name WHERE room_id = ? AND name = ?")?
900 .execute((room_id, name))?;
901 Ok(())
902 }
903
904 fn remove_room_display_names(&self, room_id: &[u8]) -> rusqlite::Result<()> {
905 self.prepare("DELETE FROM display_name WHERE room_id = ?")?.execute((room_id,))?;
906 Ok(())
907 }
908
909 fn remove_room_send_queue(&self, room_id: &[u8]) -> rusqlite::Result<()> {
910 self.prepare("DELETE FROM send_queue_events WHERE room_id = ?")?.execute((room_id,))?;
911 Ok(())
912 }
913
914 fn remove_room_dependent_send_queue(&self, room_id: &[u8]) -> rusqlite::Result<()> {
915 self.prepare("DELETE FROM dependent_send_queue_events WHERE room_id = ?")?
916 .execute((room_id,))?;
917 Ok(())
918 }
919}
920
921#[async_trait]
922trait SqliteObjectStateStoreExt: SqliteAsyncConnExt {
923 async fn get_kv_blob(&self, key: Key) -> Result<Option<Vec<u8>>> {
924 Ok(self
925 .query_row("SELECT value FROM kv_blob WHERE key = ?", (key,), |row| row.get(0))
926 .await
927 .optional()?)
928 }
929
930 async fn get_kv_blobs(&self, keys: Vec<Key>) -> Result<Vec<Vec<u8>>> {
931 let keys_length = keys.len();
932
933 self.chunk_large_query_over(keys, Some(keys_length), |txn, keys| {
934 let sql_params = repeat_vars(keys.len());
935 let sql = format!("SELECT value FROM kv_blob WHERE key IN ({sql_params})");
936
937 let params = rusqlite::params_from_iter(keys);
938
939 Ok(txn
940 .prepare(&sql)?
941 .query(params)?
942 .mapped(|row| row.get(0))
943 .collect::<Result<_, _>>()?)
944 })
945 .await
946 }
947
948 async fn set_kv_blob(&self, key: Key, value: Vec<u8>) -> Result<()>;
949
950 async fn delete_kv_blob(&self, key: Key) -> Result<()> {
951 self.execute("DELETE FROM kv_blob WHERE key = ?", (key,)).await?;
952 Ok(())
953 }
954
955 async fn get_room_infos(&self, room_id: Option<Key>) -> Result<Vec<Vec<u8>>> {
956 Ok(match room_id {
957 None => {
958 self.prepare("SELECT data FROM room_info", move |mut stmt| {
959 stmt.query_map((), |row| row.get(0))?.collect()
960 })
961 .await?
962 }
963
964 Some(room_id) => {
965 self.prepare("SELECT data FROM room_info WHERE room_id = ?", move |mut stmt| {
966 stmt.query((room_id,))?.mapped(|row| row.get(0)).collect()
967 })
968 .await?
969 }
970 })
971 }
972
973 async fn get_maybe_stripped_state_events_for_keys(
974 &self,
975 room_id: Key,
976 event_type: Key,
977 state_keys: Vec<Key>,
978 ) -> Result<Vec<(bool, Vec<u8>)>> {
979 self.chunk_large_query_over(state_keys, None, move |txn, state_keys: Vec<Key>| {
980 let sql_params = repeat_vars(state_keys.len());
981 let sql = format!(
982 "SELECT stripped, data FROM state_event
983 WHERE room_id = ? AND event_type = ? AND state_key IN ({sql_params})"
984 );
985
986 let params = rusqlite::params_from_iter(
987 [room_id.clone(), event_type.clone()].into_iter().chain(state_keys),
988 );
989
990 Ok(txn
991 .prepare(&sql)?
992 .query(params)?
993 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
994 .collect::<Result<_, _>>()?)
995 })
996 .await
997 }
998
999 async fn get_maybe_stripped_state_events(
1000 &self,
1001 room_id: Key,
1002 event_type: Key,
1003 ) -> Result<Vec<(bool, Vec<u8>)>> {
1004 Ok(self
1005 .prepare(
1006 "SELECT stripped, data FROM state_event
1007 WHERE room_id = ? AND event_type = ?",
1008 |mut stmt| {
1009 stmt.query((room_id, event_type))?
1010 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
1011 .collect()
1012 },
1013 )
1014 .await?)
1015 }
1016
1017 async fn get_profiles(
1018 &self,
1019 room_id: Key,
1020 user_ids: Vec<Key>,
1021 ) -> Result<Vec<(Vec<u8>, Vec<u8>)>> {
1022 let user_ids_length = user_ids.len();
1023
1024 self.chunk_large_query_over(user_ids, Some(user_ids_length), move |txn, user_ids| {
1025 let sql_params = repeat_vars(user_ids_length);
1026 let sql = format!(
1027 "SELECT user_id, data FROM profile WHERE room_id = ? AND user_id IN ({sql_params})"
1028 );
1029
1030 let params = rusqlite::params_from_iter(iter::once(room_id.clone()).chain(user_ids));
1031
1032 Ok(txn
1033 .prepare(&sql)?
1034 .query(params)?
1035 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
1036 .collect::<Result<_, _>>()?)
1037 })
1038 .await
1039 }
1040
1041 async fn get_global_profiles(&self, user_ids: Vec<Key>) -> Result<Vec<(Vec<u8>, Vec<u8>)>> {
1042 let user_ids_length = user_ids.len();
1043
1044 self.chunk_large_query_over(user_ids, Some(user_ids_length), move |txn, user_ids| {
1045 let sql_params = repeat_vars(user_ids_length);
1046 let sql = format!(
1047 "SELECT user_id, profile_data FROM global_profiles WHERE user_id IN ({sql_params})"
1048 );
1049
1050 let params = rusqlite::params_from_iter(user_ids);
1051
1052 Ok(txn
1053 .prepare(&sql)?
1054 .query(params)?
1055 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
1056 .collect::<Result<_, _>>()?)
1057 })
1058 .await
1059 }
1060
1061 async fn get_user_ids(&self, room_id: Key, memberships: Vec<Key>) -> Result<Vec<Vec<u8>>> {
1062 let res = if memberships.is_empty() {
1063 self.prepare("SELECT data FROM member WHERE room_id = ?", |mut stmt| {
1064 stmt.query((room_id,))?.mapped(|row| row.get(0)).collect()
1065 })
1066 .await?
1067 } else {
1068 self.chunk_large_query_over(memberships, None, move |txn, memberships| {
1069 let sql_params = repeat_vars(memberships.len());
1070 let sql = format!(
1071 "SELECT data FROM member WHERE room_id = ? AND membership IN ({sql_params})"
1072 );
1073
1074 let params =
1075 rusqlite::params_from_iter(iter::once(room_id.clone()).chain(memberships));
1076
1077 Ok(txn
1078 .prepare(&sql)?
1079 .query(params)?
1080 .mapped(|row| row.get(0))
1081 .collect::<Result<_, _>>()?)
1082 })
1083 .await?
1084 };
1085
1086 Ok(res)
1087 }
1088
1089 async fn get_global_account_data(&self, event_type: Key) -> Result<Option<Vec<u8>>> {
1090 Ok(self
1091 .query_row(
1092 "SELECT data FROM global_account_data WHERE event_type = ?",
1093 (event_type,),
1094 |row| row.get(0),
1095 )
1096 .await
1097 .optional()?)
1098 }
1099
1100 async fn get_room_account_data(
1101 &self,
1102 room_id: Key,
1103 event_type: Key,
1104 ) -> Result<Option<Vec<u8>>> {
1105 Ok(self
1106 .query_row(
1107 "SELECT data FROM room_account_data WHERE room_id = ? AND event_type = ?",
1108 (room_id, event_type),
1109 |row| row.get(0),
1110 )
1111 .await
1112 .optional()?)
1113 }
1114
1115 async fn get_display_names(
1116 &self,
1117 room_id: Key,
1118 names: Vec<Key>,
1119 ) -> Result<Vec<(Vec<u8>, Vec<u8>)>> {
1120 let names_length = names.len();
1121
1122 self.chunk_large_query_over(names, Some(names_length), move |txn, names| {
1123 let sql_params = repeat_vars(names.len());
1124 let sql = format!(
1125 "SELECT name, data FROM display_name WHERE room_id = ? AND name IN ({sql_params})"
1126 );
1127
1128 let params = rusqlite::params_from_iter(iter::once(room_id.clone()).chain(names));
1129
1130 Ok(txn
1131 .prepare(&sql)?
1132 .query(params)?
1133 .mapped(|row| Ok((row.get(0)?, row.get(1)?)))
1134 .collect::<Result<_, _>>()?)
1135 })
1136 .await
1137 }
1138
1139 async fn get_user_receipt(
1140 &self,
1141 room_id: Key,
1142 receipt_type: Key,
1143 thread: Key,
1144 user_id: Key,
1145 ) -> Result<Option<Vec<u8>>> {
1146 Ok(self
1147 .query_row(
1148 "SELECT data FROM receipt
1149 WHERE room_id = ? AND receipt_type = ? AND thread = ? and user_id = ?",
1150 (room_id, receipt_type, thread, user_id),
1151 |row| row.get(0),
1152 )
1153 .await
1154 .optional()?)
1155 }
1156
1157 async fn get_event_receipts(
1158 &self,
1159 room_id: Key,
1160 receipt_type: Key,
1161 thread: Key,
1162 event_id: Key,
1163 ) -> Result<Vec<Vec<u8>>> {
1164 Ok(self
1165 .prepare(
1166 "SELECT data FROM receipt
1167 WHERE room_id = ? AND receipt_type = ? AND thread = ? and event_id = ?",
1168 |mut stmt| {
1169 stmt.query((room_id, receipt_type, thread, event_id))?
1170 .mapped(|row| row.get(0))
1171 .collect()
1172 },
1173 )
1174 .await?)
1175 }
1176}
1177
1178#[async_trait]
1179impl SqliteObjectStateStoreExt for SqliteAsyncConn {
1180 async fn set_kv_blob(&self, key: Key, value: Vec<u8>) -> Result<()> {
1181 Ok(self.interact(move |conn| conn.set_kv_blob(&key, &value)).await.unwrap()?)
1182 }
1183}
1184
1185#[async_trait]
1186impl StateStore for SqliteStateStore {
1187 type Error = Error;
1188
1189 async fn get_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<Option<StateStoreDataValue>> {
1190 self.read()
1191 .await?
1192 .get_kv_blob(self.encode_state_store_data_key(key))
1193 .await?
1194 .map(|data| {
1195 Ok(match key {
1196 StateStoreDataKey::SyncToken => {
1197 StateStoreDataValue::SyncToken(self.deserialize_value(&data)?)
1198 }
1199 StateStoreDataKey::SupportedVersions => {
1200 StateStoreDataValue::SupportedVersions(self.deserialize_value(&data)?)
1201 }
1202 StateStoreDataKey::WellKnown => {
1203 StateStoreDataValue::WellKnown(self.deserialize_value(&data)?)
1204 }
1205 StateStoreDataKey::Filter(_) => {
1206 StateStoreDataValue::Filter(self.deserialize_value(&data)?)
1207 }
1208 StateStoreDataKey::UserAvatarUrl(_) => {
1209 StateStoreDataValue::UserAvatarUrl(self.deserialize_value(&data)?)
1210 }
1211 StateStoreDataKey::RecentlyVisitedRooms(_) => {
1212 StateStoreDataValue::RecentlyVisitedRooms(self.deserialize_value(&data)?)
1213 }
1214 StateStoreDataKey::UtdHookManagerData => {
1215 StateStoreDataValue::UtdHookManagerData(self.deserialize_value(&data)?)
1216 }
1217 StateStoreDataKey::OneTimeKeyAlreadyUploaded => {
1218 StateStoreDataValue::OneTimeKeyAlreadyUploaded
1219 }
1220 StateStoreDataKey::ComposerDraft(_, _) => {
1221 StateStoreDataValue::ComposerDraft(self.deserialize_value(&data)?)
1222 }
1223 StateStoreDataKey::SeenKnockRequests(_) => {
1224 StateStoreDataValue::SeenKnockRequests(self.deserialize_value(&data)?)
1225 }
1226 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => {
1227 StateStoreDataValue::ThreadSubscriptionsCatchupTokens(
1228 self.deserialize_value(&data)?,
1229 )
1230 }
1231 StateStoreDataKey::HomeserverCapabilities => {
1232 StateStoreDataValue::HomeserverCapabilities(self.deserialize_value(&data)?)
1233 }
1234 })
1235 })
1236 .transpose()
1237 }
1238
1239 async fn set_kv_data(
1240 &self,
1241 key: StateStoreDataKey<'_>,
1242 value: StateStoreDataValue,
1243 ) -> Result<()> {
1244 let serialized_value = match key {
1245 StateStoreDataKey::SyncToken => self.serialize_value(
1246 &value.into_sync_token().expect("Session data not a sync token"),
1247 )?,
1248 StateStoreDataKey::SupportedVersions => self.serialize_value(
1249 &value
1250 .into_supported_versions()
1251 .expect("Session data not containing supported versions"),
1252 )?,
1253 StateStoreDataKey::WellKnown => self.serialize_value(
1254 &value.into_well_known().expect("Session data not containing well-known"),
1255 )?,
1256 StateStoreDataKey::Filter(_) => {
1257 self.serialize_value(&value.into_filter().expect("Session data not a filter"))?
1258 }
1259 StateStoreDataKey::UserAvatarUrl(_) => self.serialize_value(
1260 &value.into_user_avatar_url().expect("Session data not an user avatar url"),
1261 )?,
1262 StateStoreDataKey::RecentlyVisitedRooms(_) => self.serialize_value(
1263 &value.into_recently_visited_rooms().expect("Session data not breadcrumbs"),
1264 )?,
1265 StateStoreDataKey::UtdHookManagerData => self.serialize_value(
1266 &value.into_utd_hook_manager_data().expect("Session data not UtdHookManagerData"),
1267 )?,
1268 StateStoreDataKey::OneTimeKeyAlreadyUploaded => {
1269 self.serialize_value(&true).expect("We should be able to serialize a boolean")
1270 }
1271 StateStoreDataKey::ComposerDraft(_, _) => self.serialize_value(
1272 &value.into_composer_draft().expect("Session data not a composer draft"),
1273 )?,
1274 StateStoreDataKey::SeenKnockRequests(_) => self.serialize_value(
1275 &value
1276 .into_seen_knock_requests()
1277 .expect("Session data is not a set of seen knock request ids"),
1278 )?,
1279 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => self.serialize_value(
1280 &value
1281 .into_thread_subscriptions_catchup_tokens()
1282 .expect("Session data is not a list of thread subscription catchup tokens"),
1283 )?,
1284 StateStoreDataKey::HomeserverCapabilities => self.serialize_value(
1285 &value
1286 .into_homeserver_capabilities()
1287 .expect("Session data is not the homeserver capabilities"),
1288 )?,
1289 };
1290
1291 self.write()
1292 .await?
1293 .set_kv_blob(self.encode_state_store_data_key(key), serialized_value)
1294 .await
1295 }
1296
1297 async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<()> {
1298 self.write().await?.delete_kv_blob(self.encode_state_store_data_key(key)).await
1299 }
1300
1301 async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
1302 let changes = changes.to_owned();
1303 let this = self.clone();
1304 self.write()
1305 .await?
1306 .with_transaction(move |txn| {
1307 let StateChanges {
1308 sync_token,
1309 account_data,
1310 presence,
1311 profiles,
1312 profiles_to_delete,
1313 state,
1314 room_account_data,
1315 room_infos,
1316 receipts,
1317 redactions,
1318 stripped_state,
1319 ambiguity_maps,
1320 global_profiles,
1321 } = changes;
1322
1323 if let Some(sync_token) = sync_token {
1324 let key = this.encode_state_store_data_key(StateStoreDataKey::SyncToken);
1325 let value = this.serialize_value(&sync_token)?;
1326 txn.set_kv_blob(&key, &value)?;
1327 }
1328
1329 for (event_type, event) in account_data {
1330 let event_type =
1331 this.encode_key(keys::GLOBAL_ACCOUNT_DATA, event_type.to_string());
1332 let data = this.serialize_json(&event)?;
1333 txn.set_global_account_data(&event_type, &data)?;
1334 }
1335
1336 for (room_id, events) in room_account_data {
1337 let room_id = this.encode_key(keys::ROOM_ACCOUNT_DATA, room_id);
1338 for (event_type, event) in events {
1339 let event_type =
1340 this.encode_key(keys::ROOM_ACCOUNT_DATA, event_type.to_string());
1341 let data = this.serialize_json(&event)?;
1342 txn.set_room_account_data(&room_id, &event_type, &data)?;
1343 }
1344 }
1345
1346 for (user_id, event) in presence {
1347 let key = this.encode_presence_key(&user_id);
1348 let value = this.serialize_json(&event)?;
1349 txn.set_kv_blob(&key, &value)?;
1350 }
1351
1352 for (room_id, room_info) in room_infos {
1353 let stripped = room_info.state() == RoomState::Invited;
1354 this.remove_maybe_stripped_room_data(txn, &room_id, !stripped)?;
1356
1357 let room_id = this.encode_key(keys::ROOM_INFO, room_id);
1358 let state = this
1359 .encode_key(keys::ROOM_INFO, serde_json::to_string(&room_info.state())?);
1360 let data = this.serialize_json(&room_info)?;
1361 txn.set_room_info(&room_id, &state, &data)?;
1362 }
1363
1364 for (room_id, user_ids) in profiles_to_delete {
1365 let room_id = this.encode_key(keys::PROFILE, room_id);
1366 for user_id in user_ids {
1367 let user_id = this.encode_key(keys::PROFILE, user_id);
1368 txn.remove_room_profile(&room_id, &user_id)?;
1369 }
1370 }
1371
1372 for (room_id, state_event_types) in state {
1373 let profiles = profiles.get(&room_id);
1374 let encoded_room_id = this.encode_key(keys::STATE_EVENT, &room_id);
1375
1376 for (event_type, state_events) in state_event_types {
1377 let encoded_event_type =
1378 this.encode_key(keys::STATE_EVENT, event_type.to_string());
1379
1380 for (state_key, raw_state_event) in state_events {
1381 let encoded_state_key = this.encode_key(keys::STATE_EVENT, &state_key);
1382 let data = this.serialize_json(&raw_state_event)?;
1383
1384 let event_id: Option<String> =
1385 raw_state_event.get_field("event_id").ok().flatten();
1386 let encoded_event_id =
1387 event_id.as_ref().map(|e| this.encode_key(keys::STATE_EVENT, e));
1388
1389 txn.set_state_event(
1390 &encoded_room_id,
1391 &encoded_event_type,
1392 &encoded_state_key,
1393 false,
1394 encoded_event_id.as_deref(),
1395 &data,
1396 )?;
1397
1398 if event_type == StateEventType::RoomMember {
1399 let member_event = match raw_state_event
1400 .deserialize_as_unchecked::<SyncRoomMemberEvent>()
1401 {
1402 Ok(ev) => ev,
1403 Err(e) => {
1404 debug!(event_id, "Failed to deserialize member event: {e}");
1405 continue;
1406 }
1407 };
1408
1409 let encoded_room_id = this.encode_key(keys::MEMBER, &room_id);
1410 let user_id = this.encode_key(keys::MEMBER, &state_key);
1411 let membership = this
1412 .encode_key(keys::MEMBER, member_event.membership().as_str());
1413 let data = this.serialize_value(&state_key)?;
1414
1415 txn.set_member(
1416 &encoded_room_id,
1417 &user_id,
1418 &membership,
1419 false,
1420 &data,
1421 )?;
1422
1423 if let Some(profile) =
1424 profiles.and_then(|p| p.get(member_event.state_key()))
1425 {
1426 let room_id = this.encode_key(keys::PROFILE, &room_id);
1427 let user_id = this.encode_key(keys::PROFILE, &state_key);
1428 let data = this.serialize_json(&profile)?;
1429 txn.set_profile(&room_id, &user_id, &data)?;
1430 }
1431 }
1432 }
1433 }
1434 }
1435
1436 for (room_id, stripped_state_event_types) in stripped_state {
1437 let encoded_room_id = this.encode_key(keys::STATE_EVENT, &room_id);
1438
1439 for (event_type, stripped_state_events) in stripped_state_event_types {
1440 let encoded_event_type =
1441 this.encode_key(keys::STATE_EVENT, event_type.to_string());
1442
1443 for (state_key, raw_stripped_state_event) in stripped_state_events {
1444 let encoded_state_key = this.encode_key(keys::STATE_EVENT, &state_key);
1445 let data = this.serialize_json(&raw_stripped_state_event)?;
1446 txn.set_state_event(
1447 &encoded_room_id,
1448 &encoded_event_type,
1449 &encoded_state_key,
1450 true,
1451 None,
1452 &data,
1453 )?;
1454
1455 if event_type == StateEventType::RoomMember {
1456 let member_event = match raw_stripped_state_event
1457 .deserialize_as_unchecked::<StrippedRoomMemberEvent>(
1458 ) {
1459 Ok(ev) => ev,
1460 Err(e) => {
1461 debug!("Failed to deserialize stripped member event: {e}");
1462 continue;
1463 }
1464 };
1465
1466 let room_id = this.encode_key(keys::MEMBER, &room_id);
1467 let user_id = this.encode_key(keys::MEMBER, &state_key);
1468 let membership = this.encode_key(
1469 keys::MEMBER,
1470 member_event.content.membership.as_str(),
1471 );
1472 let data = this.serialize_value(&state_key)?;
1473
1474 txn.set_member(&room_id, &user_id, &membership, true, &data)?;
1475 }
1476 }
1477 }
1478 }
1479
1480 for (room_id, receipt_event) in receipts {
1481 let room_id = this.encode_key(keys::RECEIPT, room_id);
1482
1483 for (event_id, receipt_types) in receipt_event {
1484 let encoded_event_id = this.encode_key(keys::RECEIPT, &event_id);
1485
1486 for (receipt_type, receipt_users) in receipt_types {
1487 let receipt_type =
1488 this.encode_key(keys::RECEIPT, receipt_type.as_str());
1489
1490 for (user_id, receipt) in receipt_users {
1491 let encoded_user_id = this.encode_key(keys::RECEIPT, &user_id);
1492 let thread = this.encode_key(
1495 keys::RECEIPT,
1496 rmp_serde::to_vec_named(&receipt.thread)?,
1497 );
1498 let data = this.serialize_json(&ReceiptData {
1499 receipt,
1500 event_id: event_id.clone(),
1501 user_id,
1502 })?;
1503
1504 txn.set_receipt(
1505 &room_id,
1506 &encoded_user_id,
1507 &receipt_type,
1508 &thread,
1509 &encoded_event_id,
1510 &data,
1511 )?;
1512 }
1513 }
1514 }
1515 }
1516
1517 for (room_id, redactions) in redactions {
1518 let make_redaction_rules = || {
1519 let encoded_room_id = this.encode_key(keys::ROOM_INFO, &room_id);
1520 txn.get_room_info(&encoded_room_id)
1521 .ok()
1522 .flatten()
1523 .and_then(|v| this.deserialize_json::<RoomInfo>(&v).ok())
1524 .map(|info| info.room_version_rules_or_default())
1525 .unwrap_or_else(|| {
1526 warn!(
1527 ?room_id,
1528 "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"
1529 );
1530 ROOM_VERSION_RULES_FALLBACK
1531 }).redaction
1532 };
1533
1534 let encoded_room_id = this.encode_key(keys::STATE_EVENT, &room_id);
1535 let mut redaction_rules = None;
1536
1537 for (event_id, redaction) in redactions {
1538 let event_id = this.encode_key(keys::STATE_EVENT, event_id);
1539
1540 if let Some(Ok(raw_event)) = txn
1541 .get_state_event_by_id(&encoded_room_id, &event_id)?
1542 .map(|value| this.deserialize_json::<Raw<AnySyncStateEvent>>(&value))
1543 {
1544 let event = raw_event.deserialize()?;
1545 let redacted = redact(
1546 raw_event.deserialize_as::<CanonicalJsonObject>()?,
1547 redaction_rules.get_or_insert_with(make_redaction_rules),
1548 Some(RedactedBecause::from_raw_event(&redaction)?),
1549 )
1550 .map_err(Error::Redaction)?;
1551 let data = this.serialize_json(&redacted)?;
1552
1553 let event_type =
1554 this.encode_key(keys::STATE_EVENT, event.event_type().to_string());
1555 let state_key = this.encode_key(keys::STATE_EVENT, event.state_key());
1556
1557 txn.set_state_event(
1558 &encoded_room_id,
1559 &event_type,
1560 &state_key,
1561 false,
1562 Some(&event_id),
1563 &data,
1564 )?;
1565 }
1566 }
1567 }
1568
1569 for (room_id, display_names) in ambiguity_maps {
1570 let room_id = this.encode_key(keys::DISPLAY_NAME, room_id);
1571
1572 for (name, user_ids) in display_names {
1573 let encoded_name = this.encode_key(
1574 keys::DISPLAY_NAME,
1575 name.as_normalized_str().unwrap_or_else(|| name.as_raw_str()),
1576 );
1577 let data = this.serialize_json(&user_ids)?;
1578
1579 if user_ids.is_empty() {
1580 txn.remove_display_name(&room_id, &encoded_name)?;
1581
1582 let raw_name = this.encode_key(keys::DISPLAY_NAME, name.as_raw_str());
1597 txn.remove_display_name(&room_id, &raw_name)?;
1598 } else {
1599 txn.set_display_name(&room_id, &encoded_name, &data)?;
1601 }
1602 }
1603 }
1604
1605 if !global_profiles.is_empty() {
1606 let mut select_stmt = txn.prepare_cached(
1607 "SELECT profile_data FROM global_profiles WHERE user_id = ?",
1608 )?;
1609 let mut insert_stmt = txn.prepare_cached(
1610 "INSERT OR REPLACE INTO global_profiles (user_id, profile_data) VALUES (?, ?)",
1611 )?;
1612
1613 for (user_id, profile_update) in global_profiles {
1614 let user_id = this.encode_key(keys::GLOBAL_PROFILES, &user_id);
1615 let existing_data: Option<Vec<u8>> =
1616 select_stmt.query_row([&user_id], |row| row.get(0)).optional()?;
1617
1618 let mut profile: UserProfile = existing_data
1619 .map(|data| this.deserialize_json(&data))
1620 .transpose()?
1621 .unwrap_or_default();
1622 profile.merge(profile_update);
1623
1624 let serialized = this.serialize_json(&profile)?;
1625 insert_stmt.execute((&user_id, serialized))?;
1626 }
1627 }
1628
1629 Ok::<_, Error>(())
1630 })
1631 .await?;
1632
1633 Ok(())
1634 }
1635
1636 async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
1637 self.read()
1638 .await?
1639 .get_kv_blob(self.encode_presence_key(user_id))
1640 .await?
1641 .map(|data| self.deserialize_json(&data))
1642 .transpose()
1643 }
1644
1645 async fn get_presence_events(
1646 &self,
1647 user_ids: &[OwnedUserId],
1648 ) -> Result<Vec<Raw<PresenceEvent>>> {
1649 if user_ids.is_empty() {
1650 return Ok(Vec::new());
1651 }
1652
1653 let user_ids = user_ids.iter().map(|u| self.encode_presence_key(u)).collect();
1654 self.read()
1655 .await?
1656 .get_kv_blobs(user_ids)
1657 .await?
1658 .into_iter()
1659 .map(|data| self.deserialize_json(&data))
1660 .collect()
1661 }
1662
1663 async fn get_state_event(
1664 &self,
1665 room_id: &RoomId,
1666 event_type: StateEventType,
1667 state_key: &str,
1668 ) -> Result<Option<RawAnySyncOrStrippedState>> {
1669 Ok(self
1670 .get_state_events_for_keys(room_id, event_type, &[state_key])
1671 .await?
1672 .into_iter()
1673 .next())
1674 }
1675
1676 async fn get_state_events(
1677 &self,
1678 room_id: &RoomId,
1679 event_type: StateEventType,
1680 ) -> Result<Vec<RawAnySyncOrStrippedState>> {
1681 let room_id = self.encode_key(keys::STATE_EVENT, room_id);
1682 let event_type = self.encode_key(keys::STATE_EVENT, event_type.to_string());
1683 self.read()
1684 .await?
1685 .get_maybe_stripped_state_events(room_id, event_type)
1686 .await?
1687 .into_iter()
1688 .map(|(stripped, data)| {
1689 let ev = if stripped {
1690 RawAnySyncOrStrippedState::Stripped(self.deserialize_json(&data)?)
1691 } else {
1692 RawAnySyncOrStrippedState::Sync(self.deserialize_json(&data)?)
1693 };
1694
1695 Ok(ev)
1696 })
1697 .collect()
1698 }
1699
1700 async fn get_state_events_for_keys(
1701 &self,
1702 room_id: &RoomId,
1703 event_type: StateEventType,
1704 state_keys: &[&str],
1705 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
1706 if state_keys.is_empty() {
1707 return Ok(Vec::new());
1708 }
1709
1710 let room_id = self.encode_key(keys::STATE_EVENT, room_id);
1711 let event_type = self.encode_key(keys::STATE_EVENT, event_type.to_string());
1712 let state_keys = state_keys.iter().map(|k| self.encode_key(keys::STATE_EVENT, k)).collect();
1713 self.read()
1714 .await?
1715 .get_maybe_stripped_state_events_for_keys(room_id, event_type, state_keys)
1716 .await?
1717 .into_iter()
1718 .map(|(stripped, data)| {
1719 let ev = if stripped {
1720 RawAnySyncOrStrippedState::Stripped(self.deserialize_json(&data)?)
1721 } else {
1722 RawAnySyncOrStrippedState::Sync(self.deserialize_json(&data)?)
1723 };
1724
1725 Ok(ev)
1726 })
1727 .collect()
1728 }
1729
1730 async fn get_profile(
1731 &self,
1732 room_id: &RoomId,
1733 user_id: &UserId,
1734 ) -> Result<Option<MinimalRoomMemberEvent>> {
1735 let room_id = self.encode_key(keys::PROFILE, room_id);
1736 let user_ids = vec![self.encode_key(keys::PROFILE, user_id)];
1737
1738 self.read()
1739 .await?
1740 .get_profiles(room_id, user_ids)
1741 .await?
1742 .into_iter()
1743 .next()
1744 .map(|(_, data)| self.deserialize_json(&data))
1745 .transpose()
1746 }
1747
1748 async fn get_profiles<'a>(
1749 &self,
1750 room_id: &RoomId,
1751 user_ids: &'a [OwnedUserId],
1752 ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>> {
1753 if user_ids.is_empty() {
1754 return Ok(BTreeMap::new());
1755 }
1756
1757 let room_id = self.encode_key(keys::PROFILE, room_id);
1758 let mut user_ids_map = user_ids
1759 .iter()
1760 .map(|u| (self.encode_key(keys::PROFILE, u), u.as_ref()))
1761 .collect::<BTreeMap<_, _>>();
1762 let user_ids = user_ids_map.keys().cloned().collect();
1763
1764 self.read()
1765 .await?
1766 .get_profiles(room_id, user_ids)
1767 .await?
1768 .into_iter()
1769 .map(|(user_id, data)| {
1770 Ok((
1771 user_ids_map
1772 .remove(user_id.as_slice())
1773 .expect("returned user IDs were requested"),
1774 self.deserialize_json(&data)?,
1775 ))
1776 })
1777 .collect()
1778 }
1779
1780 async fn get_user_ids(
1781 &self,
1782 room_id: &RoomId,
1783 membership: RoomMemberships,
1784 ) -> Result<Vec<OwnedUserId>> {
1785 let room_id = self.encode_key(keys::MEMBER, room_id);
1786 let memberships = membership
1787 .as_vec()
1788 .into_iter()
1789 .map(|m| self.encode_key(keys::MEMBER, m.as_str()))
1790 .collect();
1791 self.read()
1792 .await?
1793 .get_user_ids(room_id, memberships)
1794 .await?
1795 .iter()
1796 .map(|data| self.deserialize_value(data))
1797 .collect()
1798 }
1799
1800 async fn get_room_infos(&self, room_load_settings: &RoomLoadSettings) -> Result<Vec<RoomInfo>> {
1801 self.read()
1802 .await?
1803 .get_room_infos(match room_load_settings {
1804 RoomLoadSettings::All => None,
1805 RoomLoadSettings::One(room_id) => Some(self.encode_key(keys::ROOM_INFO, room_id)),
1806 })
1807 .await?
1808 .into_iter()
1809 .map(|data| self.deserialize_json(&data))
1810 .collect()
1811 }
1812
1813 async fn get_users_with_display_name(
1814 &self,
1815 room_id: &RoomId,
1816 display_name: &DisplayName,
1817 ) -> Result<BTreeSet<OwnedUserId>> {
1818 let room_id = self.encode_key(keys::DISPLAY_NAME, room_id);
1819 let names = vec![self.encode_key(
1820 keys::DISPLAY_NAME,
1821 display_name.as_normalized_str().unwrap_or_else(|| display_name.as_raw_str()),
1822 )];
1823
1824 Ok(self
1825 .read()
1826 .await?
1827 .get_display_names(room_id, names)
1828 .await?
1829 .into_iter()
1830 .next()
1831 .map(|(_, data)| self.deserialize_json(&data))
1832 .transpose()?
1833 .unwrap_or_default())
1834 }
1835
1836 async fn get_users_with_display_names<'a>(
1837 &self,
1838 room_id: &RoomId,
1839 display_names: &'a [DisplayName],
1840 ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>> {
1841 let mut result = HashMap::new();
1842
1843 if display_names.is_empty() {
1844 return Ok(result);
1845 }
1846
1847 let room_id = self.encode_key(keys::DISPLAY_NAME, room_id);
1848 let mut names_map = display_names
1849 .iter()
1850 .flat_map(|display_name| {
1851 let raw =
1861 (self.encode_key(keys::DISPLAY_NAME, display_name.as_raw_str()), display_name);
1862 let normalized = display_name.as_normalized_str().map(|normalized| {
1863 (self.encode_key(keys::DISPLAY_NAME, normalized), display_name)
1864 });
1865
1866 iter::once(raw).chain(normalized)
1867 })
1868 .collect::<BTreeMap<_, _>>();
1869 let names = names_map.keys().cloned().collect();
1870
1871 for (name, data) in self.read().await?.get_display_names(room_id, names).await?.into_iter()
1872 {
1873 let display_name =
1874 names_map.remove(name.as_slice()).expect("returned display names were requested");
1875 let user_ids: BTreeSet<_> = self.deserialize_json(&data)?;
1876
1877 result.entry(display_name).or_insert_with(BTreeSet::new).extend(user_ids);
1878 }
1879
1880 Ok(result)
1881 }
1882
1883 async fn get_account_data_event(
1884 &self,
1885 event_type: GlobalAccountDataEventType,
1886 ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>> {
1887 let event_type = self.encode_key(keys::GLOBAL_ACCOUNT_DATA, event_type.to_string());
1888 self.read()
1889 .await?
1890 .get_global_account_data(event_type)
1891 .await?
1892 .map(|value| self.deserialize_json(&value))
1893 .transpose()
1894 }
1895
1896 async fn get_room_account_data_event(
1897 &self,
1898 room_id: &RoomId,
1899 event_type: RoomAccountDataEventType,
1900 ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>> {
1901 let room_id = self.encode_key(keys::ROOM_ACCOUNT_DATA, room_id);
1902 let event_type = self.encode_key(keys::ROOM_ACCOUNT_DATA, event_type.to_string());
1903 self.read()
1904 .await?
1905 .get_room_account_data(room_id, event_type)
1906 .await?
1907 .map(|value| self.deserialize_json(&value))
1908 .transpose()
1909 }
1910
1911 async fn get_user_room_receipt_event(
1912 &self,
1913 room_id: &RoomId,
1914 receipt_type: ReceiptType,
1915 thread: ReceiptThread,
1916 user_id: &UserId,
1917 ) -> Result<Option<(OwnedEventId, Receipt)>> {
1918 let room_id = self.encode_key(keys::RECEIPT, room_id);
1919 let receipt_type = self.encode_key(keys::RECEIPT, receipt_type.to_string());
1920 let thread = self.encode_key(keys::RECEIPT, rmp_serde::to_vec_named(&thread)?);
1923 let user_id = self.encode_key(keys::RECEIPT, user_id);
1924
1925 self.read()
1926 .await?
1927 .get_user_receipt(room_id, receipt_type, thread, user_id)
1928 .await?
1929 .map(|value| {
1930 self.deserialize_json::<ReceiptData>(&value).map(|d| (d.event_id, d.receipt))
1931 })
1932 .transpose()
1933 }
1934
1935 async fn get_event_room_receipt_events(
1936 &self,
1937 room_id: &RoomId,
1938 receipt_type: ReceiptType,
1939 thread: ReceiptThread,
1940 event_id: &EventId,
1941 ) -> Result<Vec<(OwnedUserId, Receipt)>> {
1942 let room_id = self.encode_key(keys::RECEIPT, room_id);
1943 let receipt_type = self.encode_key(keys::RECEIPT, receipt_type.to_string());
1944 let thread = self.encode_key(keys::RECEIPT, rmp_serde::to_vec_named(&thread)?);
1947 let event_id = self.encode_key(keys::RECEIPT, event_id);
1948
1949 self.read()
1950 .await?
1951 .get_event_receipts(room_id, receipt_type, thread, event_id)
1952 .await?
1953 .iter()
1954 .map(|value| {
1955 self.deserialize_json::<ReceiptData>(value).map(|d| (d.user_id, d.receipt))
1956 })
1957 .collect()
1958 }
1959
1960 async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
1961 self.read().await?.get_kv_blob(self.encode_custom_key(key)).await
1962 }
1963
1964 async fn set_custom_value_no_read(&self, key: &[u8], value: Vec<u8>) -> Result<()> {
1965 let conn = self.write().await?;
1966 let key = self.encode_custom_key(key);
1967 conn.set_kv_blob(key, value).await?;
1968 Ok(())
1969 }
1970
1971 async fn set_custom_value(&self, key: &[u8], value: Vec<u8>) -> Result<Option<Vec<u8>>> {
1972 let conn = self.write().await?;
1973 let key = self.encode_custom_key(key);
1974 let previous = conn.get_kv_blob(key.clone()).await?;
1975 conn.set_kv_blob(key, value).await?;
1976 Ok(previous)
1977 }
1978
1979 async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
1980 let conn = self.write().await?;
1981 let key = self.encode_custom_key(key);
1982 let previous = conn.get_kv_blob(key.clone()).await?;
1983 if previous.is_some() {
1984 conn.delete_kv_blob(key).await?;
1985 }
1986 Ok(previous)
1987 }
1988
1989 async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
1990 let this = self.clone();
1991 let room_id = room_id.to_owned();
1992
1993 let conn = self.write().await?;
1994
1995 conn.with_transaction(move |txn| -> Result<()> {
1996 let room_info_room_id = this.encode_key(keys::ROOM_INFO, &room_id);
1997 txn.remove_room_info(&room_info_room_id)?;
1998
1999 let state_event_room_id = this.encode_key(keys::STATE_EVENT, &room_id);
2000 txn.remove_room_state_events(&state_event_room_id, None)?;
2001
2002 let member_room_id = this.encode_key(keys::MEMBER, &room_id);
2003 txn.remove_room_members(&member_room_id, None)?;
2004
2005 let profile_room_id = this.encode_key(keys::PROFILE, &room_id);
2006 txn.remove_room_profiles(&profile_room_id)?;
2007
2008 let room_account_data_room_id = this.encode_key(keys::ROOM_ACCOUNT_DATA, &room_id);
2009 txn.remove_room_account_data(&room_account_data_room_id)?;
2010
2011 let receipt_room_id = this.encode_key(keys::RECEIPT, &room_id);
2012 txn.remove_room_receipts(&receipt_room_id)?;
2013
2014 let display_name_room_id = this.encode_key(keys::DISPLAY_NAME, &room_id);
2015 txn.remove_room_display_names(&display_name_room_id)?;
2016
2017 let send_queue_room_id = this.encode_key(keys::SEND_QUEUE, &room_id);
2018 txn.remove_room_send_queue(&send_queue_room_id)?;
2019
2020 let dependent_send_queue_room_id =
2021 this.encode_key(keys::DEPENDENTS_SEND_QUEUE, &room_id);
2022 txn.remove_room_dependent_send_queue(&dependent_send_queue_room_id)?;
2023
2024 let thread_subscriptions_room_id =
2025 this.encode_key(keys::THREAD_SUBSCRIPTIONS, &room_id);
2026 txn.execute(
2027 "DELETE FROM thread_subscriptions WHERE room_id = ?",
2028 (thread_subscriptions_room_id,),
2029 )?;
2030
2031 Ok(())
2032 })
2033 .await?;
2034
2035 conn.vacuum().await
2036 }
2037
2038 async fn save_send_queue_request(
2039 &self,
2040 room_id: &RoomId,
2041 transaction_id: OwnedTransactionId,
2042 created_at: MilliSecondsSinceUnixEpoch,
2043 content: QueuedRequestKind,
2044 priority: usize,
2045 ) -> Result<(), Self::Error> {
2046 let room_id_key = self.encode_key(keys::SEND_QUEUE, room_id);
2047 let room_id_value = self.serialize_value(&room_id.to_owned())?;
2048
2049 let content = self.serialize_json(&content)?;
2050 let created_at_ts: u64 = created_at.0.into();
2056 self.write()
2057 .await?
2058 .with_transaction(move |txn| {
2059 txn.prepare_cached("INSERT INTO send_queue_events (room_id, room_id_val, transaction_id, content, priority, created_at) VALUES (?, ?, ?, ?, ?, ?)")?.execute((room_id_key, room_id_value, transaction_id.to_string(), content, priority, created_at_ts))?;
2060 Ok(())
2061 })
2062 .await
2063 }
2064
2065 async fn update_send_queue_request(
2066 &self,
2067 room_id: &RoomId,
2068 transaction_id: &TransactionId,
2069 content: QueuedRequestKind,
2070 ) -> Result<bool, Self::Error> {
2071 let room_id = self.encode_key(keys::SEND_QUEUE, room_id);
2072
2073 let content = self.serialize_json(&content)?;
2074 let transaction_id = transaction_id.to_string();
2077
2078 let num_updated = self.write()
2079 .await?
2080 .with_transaction(move |txn| {
2081 txn.prepare_cached("UPDATE send_queue_events SET wedge_reason = NULL, content = ? WHERE room_id = ? AND transaction_id = ?")?.execute((content, room_id, transaction_id))
2082 })
2083 .await?;
2084
2085 Ok(num_updated > 0)
2086 }
2087
2088 async fn remove_send_queue_request(
2089 &self,
2090 room_id: &RoomId,
2091 transaction_id: &TransactionId,
2092 ) -> Result<bool, Self::Error> {
2093 let room_id = self.encode_key(keys::SEND_QUEUE, room_id);
2094
2095 let transaction_id = transaction_id.to_string();
2097
2098 let num_deleted = self
2099 .write()
2100 .await?
2101 .with_transaction(move |txn| {
2102 txn.prepare_cached(
2103 "DELETE FROM send_queue_events WHERE room_id = ? AND transaction_id = ?",
2104 )?
2105 .execute((room_id, &transaction_id))
2106 })
2107 .await?;
2108
2109 Ok(num_deleted > 0)
2110 }
2111
2112 async fn load_send_queue_requests(
2113 &self,
2114 room_id: &RoomId,
2115 ) -> Result<Vec<QueuedRequest>, Self::Error> {
2116 let room_id = self.encode_key(keys::SEND_QUEUE, room_id);
2117
2118 let res: Vec<(String, Vec<u8>, Option<Vec<u8>>, usize, Option<u64>)> = self
2122 .read()
2123 .await?
2124 .prepare(
2125 "SELECT transaction_id, content, wedge_reason, priority, created_at FROM send_queue_events WHERE room_id = ? ORDER BY priority DESC, ROWID",
2126 |mut stmt| {
2127 stmt.query((room_id,))?
2128 .mapped(|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?)))
2129 .collect()
2130 },
2131 )
2132 .await?;
2133
2134 let mut requests = Vec::with_capacity(res.len());
2135
2136 for entry in res {
2137 let created_at = entry
2138 .4
2139 .and_then(UInt::new)
2140 .map_or_else(MilliSecondsSinceUnixEpoch::now, MilliSecondsSinceUnixEpoch);
2141
2142 requests.push(QueuedRequest {
2143 transaction_id: entry.0.into(),
2144 kind: self.deserialize_json(&entry.1)?,
2145 error: entry.2.map(|v| self.deserialize_value(&v)).transpose()?,
2146 priority: entry.3,
2147 created_at,
2148 });
2149 }
2150
2151 Ok(requests)
2152 }
2153
2154 async fn update_send_queue_request_status(
2155 &self,
2156 room_id: &RoomId,
2157 transaction_id: &TransactionId,
2158 error: Option<QueueWedgeError>,
2159 ) -> Result<(), Self::Error> {
2160 let room_id = self.encode_key(keys::SEND_QUEUE, room_id);
2161
2162 let transaction_id = transaction_id.to_string();
2164
2165 let error_value = error.map(|e| self.serialize_value(&e)).transpose()?;
2167
2168 self.write()
2169 .await?
2170 .with_transaction(move |txn| {
2171 txn.prepare_cached("UPDATE send_queue_events SET wedge_reason = ? WHERE room_id = ? AND transaction_id = ?")?.execute((error_value, room_id, transaction_id))?;
2172 Ok(())
2173 })
2174 .await
2175 }
2176
2177 async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
2178 let res: Vec<Vec<u8>> = self
2183 .read()
2184 .await?
2185 .prepare("SELECT room_id_val FROM send_queue_events", |mut stmt| {
2186 stmt.query(())?.mapped(|row| row.get(0)).collect()
2187 })
2188 .await?;
2189
2190 Ok(res
2193 .into_iter()
2194 .map(|entry| self.deserialize_value(&entry))
2195 .collect::<Result<BTreeSet<OwnedRoomId>, _>>()?
2196 .into_iter()
2197 .collect())
2198 }
2199
2200 async fn save_dependent_queued_request(
2201 &self,
2202 room_id: &RoomId,
2203 parent_txn_id: &TransactionId,
2204 own_txn_id: ChildTransactionId,
2205 created_at: MilliSecondsSinceUnixEpoch,
2206 content: DependentQueuedRequestKind,
2207 ) -> Result<()> {
2208 let room_id = self.encode_key(keys::DEPENDENTS_SEND_QUEUE, room_id);
2209 let content = self.serialize_json(&content)?;
2210
2211 let parent_txn_id = parent_txn_id.to_string();
2213 let own_txn_id = own_txn_id.to_string();
2214
2215 let created_at_ts: u64 = created_at.0.into();
2216 self.write()
2217 .await?
2218 .with_transaction(move |txn| {
2219 txn.prepare_cached(
2220 r#"INSERT INTO dependent_send_queue_events
2221 (room_id, parent_transaction_id, own_transaction_id, content, created_at)
2222 VALUES (?, ?, ?, ?, ?)"#,
2223 )?
2224 .execute((
2225 room_id,
2226 parent_txn_id,
2227 own_txn_id,
2228 content,
2229 created_at_ts,
2230 ))?;
2231 Ok(())
2232 })
2233 .await
2234 }
2235
2236 async fn update_dependent_queued_request(
2237 &self,
2238 room_id: &RoomId,
2239 own_transaction_id: &ChildTransactionId,
2240 new_content: DependentQueuedRequestKind,
2241 ) -> Result<bool> {
2242 let room_id = self.encode_key(keys::DEPENDENTS_SEND_QUEUE, room_id);
2243 let content = self.serialize_json(&new_content)?;
2244
2245 let own_txn_id = own_transaction_id.to_string();
2247
2248 let num_updated = self
2249 .write()
2250 .await?
2251 .with_transaction(move |txn| {
2252 txn.prepare_cached(
2253 r#"UPDATE dependent_send_queue_events
2254 SET content = ?
2255 WHERE own_transaction_id = ?
2256 AND room_id = ?"#,
2257 )?
2258 .execute((content, own_txn_id, room_id))
2259 })
2260 .await?;
2261
2262 if num_updated > 1 {
2263 return Err(Error::InconsistentUpdate);
2264 }
2265
2266 Ok(num_updated == 1)
2267 }
2268
2269 async fn mark_dependent_queued_requests_as_ready(
2270 &self,
2271 room_id: &RoomId,
2272 parent_txn_id: &TransactionId,
2273 parent_key: SentRequestKey,
2274 ) -> Result<usize> {
2275 let room_id = self.encode_key(keys::DEPENDENTS_SEND_QUEUE, room_id);
2276 let parent_key = self.serialize_json(&parent_key)?;
2277
2278 let parent_txn_id = parent_txn_id.to_string();
2280
2281 self.write()
2282 .await?
2283 .with_transaction(move |txn| {
2284 Ok(txn.prepare_cached(
2285 "UPDATE dependent_send_queue_events SET parent_key = ? WHERE parent_transaction_id = ? and room_id = ?",
2286 )?
2287 .execute((parent_key, parent_txn_id, room_id))?)
2288 })
2289 .await
2290 }
2291
2292 async fn remove_dependent_queued_request(
2293 &self,
2294 room_id: &RoomId,
2295 txn_id: &ChildTransactionId,
2296 ) -> Result<bool> {
2297 let room_id = self.encode_key(keys::DEPENDENTS_SEND_QUEUE, room_id);
2298
2299 let txn_id = txn_id.to_string();
2301
2302 let num_deleted = self
2303 .write()
2304 .await?
2305 .with_transaction(move |txn| {
2306 txn.prepare_cached(
2307 "DELETE FROM dependent_send_queue_events WHERE own_transaction_id = ? AND room_id = ?",
2308 )?
2309 .execute((txn_id, room_id))
2310 })
2311 .await?;
2312
2313 Ok(num_deleted > 0)
2314 }
2315
2316 async fn load_dependent_queued_requests(
2317 &self,
2318 room_id: &RoomId,
2319 ) -> Result<Vec<DependentQueuedRequest>> {
2320 let room_id = self.encode_key(keys::DEPENDENTS_SEND_QUEUE, room_id);
2321
2322 let res: Vec<(String, String, Option<Vec<u8>>, Vec<u8>, Option<u64>)> = self
2324 .read()
2325 .await?
2326 .prepare(
2327 "SELECT own_transaction_id, parent_transaction_id, parent_key, content, created_at FROM dependent_send_queue_events WHERE room_id = ? ORDER BY ROWID",
2328 |mut stmt| {
2329 stmt.query((room_id,))?
2330 .mapped(|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?)))
2331 .collect()
2332 },
2333 )
2334 .await?;
2335
2336 let mut dependent_events = Vec::with_capacity(res.len());
2337
2338 for entry in res {
2339 let created_at = entry
2340 .4
2341 .and_then(UInt::new)
2342 .map_or_else(MilliSecondsSinceUnixEpoch::now, MilliSecondsSinceUnixEpoch);
2343
2344 dependent_events.push(DependentQueuedRequest {
2345 own_transaction_id: entry.0.into(),
2346 parent_transaction_id: entry.1.into(),
2347 parent_key: entry.2.map(|json| self.deserialize_json(&json)).transpose()?,
2348 kind: self.deserialize_json(&entry.3)?,
2349 created_at,
2350 });
2351 }
2352
2353 Ok(dependent_events)
2354 }
2355
2356 async fn upsert_thread_subscriptions(
2357 &self,
2358 updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
2359 ) -> Result<(), Self::Error> {
2360 let values: Vec<_> = updates
2361 .into_iter()
2362 .map(|(room_id, thread_id, subscription)| {
2363 (
2364 self.encode_key(keys::THREAD_SUBSCRIPTIONS, room_id),
2365 self.encode_key(keys::THREAD_SUBSCRIPTIONS, thread_id),
2366 subscription.status.as_str(),
2367 subscription.bump_stamp,
2368 )
2369 })
2370 .collect();
2371
2372 self.write()
2373 .await?
2374 .with_transaction(move |txn| {
2375 let mut txn = txn.prepare_cached(
2376 "INSERT INTO thread_subscriptions (room_id, event_id, status, bump_stamp)
2377 VALUES (?, ?, ?, ?)
2378 ON CONFLICT (room_id, event_id) DO UPDATE
2379 SET
2380 status =
2381 CASE
2382 WHEN thread_subscriptions.bump_stamp IS NULL THEN EXCLUDED.status
2383 WHEN EXCLUDED.bump_stamp IS NULL THEN EXCLUDED.status
2384 WHEN thread_subscriptions.bump_stamp < EXCLUDED.bump_stamp THEN EXCLUDED.status
2385 ELSE thread_subscriptions.status
2386 END,
2387 bump_stamp =
2388 CASE
2389 WHEN thread_subscriptions.bump_stamp IS NULL THEN EXCLUDED.bump_stamp
2390 WHEN EXCLUDED.bump_stamp IS NULL THEN thread_subscriptions.bump_stamp
2391 WHEN thread_subscriptions.bump_stamp < EXCLUDED.bump_stamp THEN EXCLUDED.bump_stamp
2392 ELSE thread_subscriptions.bump_stamp
2393 END",
2394 )?;
2395
2396 for value in values {
2397 txn.execute(value)?;
2398 }
2399
2400 Result::<_, Error>::Ok(())
2401 })
2402 .await?;
2403
2404 Ok(())
2405 }
2406
2407 async fn load_thread_subscription(
2408 &self,
2409 room_id: &RoomId,
2410 thread_id: &EventId,
2411 ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
2412 let room_id = self.encode_key(keys::THREAD_SUBSCRIPTIONS, room_id);
2413 let thread_id = self.encode_key(keys::THREAD_SUBSCRIPTIONS, thread_id);
2414
2415 Ok(self
2416 .read()
2417 .await?
2418 .query_row(
2419 "SELECT status, bump_stamp FROM thread_subscriptions WHERE room_id = ? AND event_id = ?",
2420 (room_id, thread_id),
2421 |row| Ok((row.get::<_, String>(0)?, row.get::<_, Option<u64>>(1)?))
2422 )
2423 .await
2424 .optional()?
2425 .map(|(status, bump_stamp)| -> Result<_, Self::Error> {
2426 let status = ThreadSubscriptionStatus::from_str(&status).map_err(|_| {
2427 Error::InvalidData { details: format!("Invalid thread status: {status}") }
2428 })?;
2429 Ok(StoredThreadSubscription { status, bump_stamp })
2430 })
2431 .transpose()?)
2432 }
2433
2434 async fn remove_thread_subscription(
2435 &self,
2436 room_id: &RoomId,
2437 thread_id: &EventId,
2438 ) -> Result<(), Self::Error> {
2439 let room_id = self.encode_key(keys::THREAD_SUBSCRIPTIONS, room_id);
2440 let thread_id = self.encode_key(keys::THREAD_SUBSCRIPTIONS, thread_id);
2441
2442 self.write()
2443 .await?
2444 .execute(
2445 "DELETE FROM thread_subscriptions WHERE room_id = ? AND event_id = ?",
2446 (room_id, thread_id),
2447 )
2448 .await?;
2449
2450 Ok(())
2451 }
2452
2453 async fn get_global_profile(
2454 &self,
2455 user_id: &UserId,
2456 ) -> Result<Option<UserProfile>, Self::Error> {
2457 self.read()
2458 .await?
2459 .get_global_profiles(vec![self.encode_key(keys::GLOBAL_PROFILES, user_id)])
2460 .await?
2461 .into_iter()
2462 .next()
2463 .map(|(_, data)| self.deserialize_json(&data))
2464 .transpose()
2465 }
2466
2467 async fn get_global_profiles<'a>(
2468 &self,
2469 user_ids: &'a [OwnedUserId],
2470 ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
2471 if user_ids.is_empty() {
2472 return Ok(BTreeMap::new());
2473 }
2474
2475 let mut user_ids_map = user_ids
2476 .iter()
2477 .map(|u| (self.encode_key(keys::GLOBAL_PROFILES, u), u.as_ref()))
2478 .collect::<BTreeMap<_, _>>();
2479 let user_ids = user_ids_map.keys().cloned().collect();
2480
2481 self.read()
2482 .await?
2483 .get_global_profiles(user_ids)
2484 .await?
2485 .into_iter()
2486 .map(|(user_id, data)| {
2487 Ok((
2488 user_ids_map
2489 .remove(user_id.as_slice())
2490 .expect("returned user IDs were requested"),
2491 self.deserialize_json(&data)?,
2492 ))
2493 })
2494 .collect()
2495 }
2496
2497 async fn optimize(&self) -> Result<(), Self::Error> {
2498 Ok(self.vacuum().await?)
2499 }
2500
2501 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
2502 self.get_db_size().await
2503 }
2504
2505 async fn close(&self) -> Result<(), Self::Error> {
2506 connection::close_connections(&self.connections, "State store").await;
2507 Ok(())
2508 }
2509
2510 async fn reopen(&self) -> Result<(), Self::Error> {
2511 connection::reopen_connections(
2512 &self.connections,
2513 self.db_path.clone(),
2514 self.pool_config,
2515 self.runtime_config,
2516 )
2517 .await?;
2518 Ok(())
2519 }
2520}
2521
2522#[derive(Debug, Clone, Serialize, Deserialize)]
2523struct ReceiptData {
2524 receipt: Receipt,
2525 event_id: OwnedEventId,
2526 user_id: OwnedUserId,
2527}
2528
2529#[cfg(test)]
2530mod tests {
2531 use std::sync::{
2532 LazyLock,
2533 atomic::{AtomicU32, Ordering::SeqCst},
2534 };
2535
2536 use matrix_sdk_base::{StateStore, StoreError, statestore_integration_tests};
2537 use tempfile::{TempDir, tempdir};
2538
2539 use super::SqliteStateStore;
2540
2541 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
2542 static NUM: AtomicU32 = AtomicU32::new(0);
2543
2544 async fn get_store() -> Result<impl StateStore, StoreError> {
2545 let name = NUM.fetch_add(1, SeqCst).to_string();
2546 let tmpdir_path = TMP_DIR.path().join(name);
2547
2548 tracing::info!("using store @ {}", tmpdir_path.to_str().unwrap());
2549
2550 Ok(SqliteStateStore::open(tmpdir_path.to_str().unwrap(), None).await.unwrap())
2551 }
2552
2553 statestore_integration_tests!();
2554}
2555
2556#[cfg(test)]
2557mod encrypted_tests {
2558 use std::{
2559 path::PathBuf,
2560 sync::{
2561 LazyLock,
2562 atomic::{AtomicU32, Ordering::SeqCst},
2563 },
2564 };
2565
2566 use matrix_sdk_base::{StateStore, StoreError, statestore_integration_tests};
2567 use matrix_sdk_test::async_test;
2568 use tempfile::{TempDir, tempdir};
2569
2570 use super::SqliteStateStore;
2571 use crate::{SqliteStoreConfig, utils::SqliteAsyncConnExt};
2572
2573 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
2574 static NUM: AtomicU32 = AtomicU32::new(0);
2575
2576 fn new_state_store_workspace() -> PathBuf {
2577 let name = NUM.fetch_add(1, SeqCst).to_string();
2578 TMP_DIR.path().join(name)
2579 }
2580
2581 async fn get_store() -> Result<impl StateStore, StoreError> {
2582 let tmpdir_path = new_state_store_workspace();
2583
2584 tracing::info!("using store @ {}", tmpdir_path.to_str().unwrap());
2585
2586 Ok(SqliteStateStore::open(tmpdir_path.to_str().unwrap(), Some("default_test_password"))
2587 .await
2588 .unwrap())
2589 }
2590
2591 #[async_test]
2592 async fn test_pool_size() {
2593 let tmpdir_path = new_state_store_workspace();
2594 let store_open_config = SqliteStoreConfig::new(tmpdir_path).pool_max_size(42);
2595
2596 let store = SqliteStateStore::open_with_config(&store_open_config).await.unwrap();
2597
2598 let guard = store.connections.lock().await;
2599 assert_eq!(guard.as_ref().unwrap().pool.status().max_size, 42);
2600 }
2601
2602 #[async_test]
2603 async fn test_cache_size() {
2604 let tmpdir_path = new_state_store_workspace();
2605 let store_open_config = SqliteStoreConfig::new(tmpdir_path).cache_size(1500);
2606
2607 let store = SqliteStateStore::open_with_config(&store_open_config).await.unwrap();
2608
2609 let conn = store.read().await.unwrap();
2610 let cache_size =
2611 conn.query_row("PRAGMA cache_size", (), |row| row.get::<_, i32>(0)).await.unwrap();
2612
2613 assert_eq!(cache_size, -(1500 / 1024));
2617 }
2618
2619 #[async_test]
2620 async fn test_journal_size_limit() {
2621 let tmpdir_path = new_state_store_workspace();
2622 let store_open_config = SqliteStoreConfig::new(tmpdir_path).journal_size_limit(1500);
2623
2624 let store = SqliteStateStore::open_with_config(&store_open_config).await.unwrap();
2625
2626 let conn = store.read().await.unwrap();
2627 let journal_size_limit = conn
2628 .query_row("PRAGMA journal_size_limit", (), |row| row.get::<_, u32>(0))
2629 .await
2630 .unwrap();
2631
2632 assert_eq!(journal_size_limit, 1500);
2635 }
2636
2637 statestore_integration_tests!();
2638}
2639
2640#[cfg(test)]
2641mod migration_tests {
2642 use std::{
2643 path::{Path, PathBuf},
2644 sync::{
2645 Arc, LazyLock,
2646 atomic::{AtomicU32, Ordering::SeqCst},
2647 },
2648 };
2649
2650 use as_variant::as_variant;
2651 use matrix_sdk_base::{
2652 RoomState, StateStore,
2653 media::{MediaFormat, MediaRequestParameters},
2654 store::{
2655 ChildTransactionId, DependentQueuedRequestKind, RoomLoadSettings,
2656 SerializableEventContent,
2657 },
2658 sync::UnreadNotificationsCount,
2659 };
2660 use matrix_sdk_test::async_test;
2661 use ruma::{
2662 EventId, MilliSecondsSinceUnixEpoch, OwnedTransactionId, RoomId, TransactionId, UserId,
2663 events::{
2664 StateEventType,
2665 room::{MediaSource, create::RoomCreateEventContent, message::RoomMessageEventContent},
2666 },
2667 room_id, server_name, user_id,
2668 };
2669 use rusqlite::Transaction;
2670 use serde::{Deserialize, Serialize};
2671 use serde_json::json;
2672 use tempfile::{TempDir, tempdir};
2673 use tokio::{fs, sync::Mutex};
2674 use zeroize::Zeroizing;
2675
2676 use super::{DATABASE_NAME, SqliteStateStore, init, keys};
2677 use crate::{
2678 OpenStoreError, Secret, SqliteStoreConfig, connection,
2679 error::{Error, Result},
2680 utils::{EncryptableStore as _, SqliteAsyncConnExt, SqliteKeyValueStoreAsyncConnExt},
2681 };
2682
2683 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
2684 static NUM: AtomicU32 = AtomicU32::new(0);
2685 const SECRET: &str = "secret";
2686
2687 fn new_path() -> PathBuf {
2688 let name = NUM.fetch_add(1, SeqCst).to_string();
2689 TMP_DIR.path().join(name)
2690 }
2691
2692 async fn create_fake_db(path: &Path, version: u8) -> Result<SqliteStateStore> {
2693 let config = SqliteStoreConfig::new(path);
2694
2695 fs::create_dir_all(&config.path).await.map_err(OpenStoreError::CreateDir).unwrap();
2696
2697 let pool = config.build_pool_of_connections(DATABASE_NAME).unwrap();
2698 let db_path = pool.manager().database_path.clone();
2699 let conn = pool.get().await?;
2700
2701 init(&conn).await?;
2702
2703 let store_cipher = Some(Arc::new(
2704 conn.get_or_create_store_cipher(Secret::PassPhrase(Zeroizing::new(SECRET.to_owned())))
2705 .await
2706 .unwrap(),
2707 ));
2708 let this = SqliteStateStore {
2709 store_cipher,
2710 connections: Arc::new(Mutex::new(Some(connection::SqliteConnections {
2711 pool,
2712 write_connection: Arc::new(Mutex::new(conn)),
2713 }))),
2714 db_path,
2715 pool_config: deadpool::managed::PoolConfig::default(),
2716 runtime_config: crate::RuntimeConfig::default(),
2717 };
2718 this.run_migrations(1, Some(version)).await?;
2719
2720 Ok(this)
2721 }
2722
2723 fn room_info_v1_json(
2724 room_id: &RoomId,
2725 state: RoomState,
2726 name: Option<&str>,
2727 creator: Option<&UserId>,
2728 ) -> serde_json::Value {
2729 let name_content = match name {
2731 Some(name) => json!({ "name": name }),
2732 None => json!({ "name": null }),
2733 };
2734 let create_content = match creator {
2736 Some(creator) => RoomCreateEventContent::new_v1(creator.to_owned()),
2737 None => RoomCreateEventContent::new_v11(),
2738 };
2739
2740 json!({
2741 "room_id": room_id,
2742 "room_type": state,
2743 "notification_counts": UnreadNotificationsCount::default(),
2744 "summary": {
2745 "heroes": [],
2746 "joined_member_count": 0,
2747 "invited_member_count": 0,
2748 },
2749 "members_synced": false,
2750 "base_info": {
2751 "dm_targets": [],
2752 "max_power_level": 100,
2753 "name": {
2754 "Original": {
2755 "content": name_content,
2756 },
2757 },
2758 "create": {
2759 "Original": {
2760 "content": create_content,
2761 }
2762 }
2763 },
2764 })
2765 }
2766
2767 #[async_test]
2768 pub async fn test_migrating_v1_to_v2() {
2769 let path = new_path();
2770 {
2772 let db = create_fake_db(&path, 1).await.unwrap();
2773 let conn = db.read().await.unwrap();
2774
2775 let this = db.clone();
2776 conn.with_transaction(move |txn| {
2777 for i in 0..5 {
2778 let room_id = RoomId::parse(format!("!room_{i}:localhost")).unwrap();
2779 let (state, stripped) =
2780 if i < 3 { (RoomState::Joined, false) } else { (RoomState::Invited, true) };
2781 let info = room_info_v1_json(&room_id, state, None, None);
2782
2783 let room_id = this.encode_key(keys::ROOM_INFO, room_id);
2784 let data = this.serialize_json(&info)?;
2785
2786 txn.prepare_cached(
2787 "INSERT INTO room_info (room_id, stripped, data)
2788 VALUES (?, ?, ?)",
2789 )?
2790 .execute((room_id, stripped, data))?;
2791 }
2792
2793 Result::<_, Error>::Ok(())
2794 })
2795 .await
2796 .unwrap();
2797 }
2798
2799 let store = SqliteStateStore::open(path, Some(SECRET)).await.unwrap();
2801
2802 assert_eq!(store.get_room_infos(&RoomLoadSettings::default()).await.unwrap().len(), 5);
2804 }
2805
2806 fn add_room_v2(
2808 this: &SqliteStateStore,
2809 txn: &Transaction<'_>,
2810 room_id: &RoomId,
2811 name: Option<&str>,
2812 create_creator: Option<&UserId>,
2813 create_sender: Option<&UserId>,
2814 ) -> Result<(), Error> {
2815 let room_info_json = room_info_v1_json(room_id, RoomState::Joined, name, create_creator);
2816
2817 let encoded_room_id = this.encode_key(keys::ROOM_INFO, room_id);
2818 let encoded_state =
2819 this.encode_key(keys::ROOM_INFO, serde_json::to_string(&RoomState::Joined)?);
2820 let data = this.serialize_json(&room_info_json)?;
2821
2822 txn.prepare_cached(
2823 "INSERT INTO room_info (room_id, state, data)
2824 VALUES (?, ?, ?)",
2825 )?
2826 .execute((encoded_room_id, encoded_state, data))?;
2827
2828 let Some(create_sender) = create_sender else {
2830 return Ok(());
2831 };
2832
2833 let create_content = match create_creator {
2834 Some(creator) => RoomCreateEventContent::new_v1(creator.to_owned()),
2835 None => RoomCreateEventContent::new_v11(),
2836 };
2837
2838 let event_id = EventId::new_v1(server_name!("dummy.local"));
2839 let create_event = json!({
2840 "content": create_content,
2841 "event_id": event_id,
2842 "sender": create_sender.to_owned(),
2843 "origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
2844 "state_key": "",
2845 "type": "m.room.create",
2846 "unsigned": {},
2847 });
2848
2849 let encoded_room_id = this.encode_key(keys::STATE_EVENT, room_id);
2850 let encoded_event_type =
2851 this.encode_key(keys::STATE_EVENT, StateEventType::RoomCreate.to_string());
2852 let encoded_state_key = this.encode_key(keys::STATE_EVENT, "");
2853 let stripped = false;
2854 let encoded_event_id = this.encode_key(keys::STATE_EVENT, event_id);
2855 let data = this.serialize_json(&create_event)?;
2856
2857 txn.prepare_cached(
2858 "INSERT
2859 INTO state_event (room_id, event_type, state_key, stripped, event_id, data)
2860 VALUES (?, ?, ?, ?, ?, ?)",
2861 )?
2862 .execute((
2863 encoded_room_id,
2864 encoded_event_type,
2865 encoded_state_key,
2866 stripped,
2867 encoded_event_id,
2868 data,
2869 ))?;
2870
2871 Ok(())
2872 }
2873
2874 #[async_test]
2875 pub async fn test_migrating_v2_to_v3() {
2876 let path = new_path();
2877
2878 let room_a_id = room_id!("!room_a:dummy.local");
2880 let room_a_name = "Room A";
2881 let room_a_creator = user_id!("@creator:dummy.local");
2882 let room_a_create_sender = user_id!("@sender:dummy.local");
2885
2886 let room_b_id = room_id!("!room_b:dummy.local");
2888
2889 let room_c_id = room_id!("!room_c:dummy.local");
2891 let room_c_create_sender = user_id!("@creator:dummy.local");
2892
2893 {
2895 let db = create_fake_db(&path, 2).await.unwrap();
2896 let conn = db.read().await.unwrap();
2897
2898 let this = db.clone();
2899 conn.with_transaction(move |txn| {
2900 add_room_v2(
2901 &this,
2902 txn,
2903 room_a_id,
2904 Some(room_a_name),
2905 Some(room_a_creator),
2906 Some(room_a_create_sender),
2907 )?;
2908 add_room_v2(&this, txn, room_b_id, None, None, None)?;
2909 add_room_v2(&this, txn, room_c_id, None, None, Some(room_c_create_sender))?;
2910
2911 Result::<_, Error>::Ok(())
2912 })
2913 .await
2914 .unwrap();
2915 }
2916
2917 let store = SqliteStateStore::open(path, Some(SECRET)).await.unwrap();
2919
2920 let room_infos = store.get_room_infos(&RoomLoadSettings::default()).await.unwrap();
2922 assert_eq!(room_infos.len(), 3);
2923
2924 let room_a = room_infos.iter().find(|r| r.room_id() == room_a_id).unwrap();
2925 assert_eq!(room_a.name(), Some(room_a_name));
2926 assert_eq!(room_a.creators(), Some(vec![room_a_create_sender.to_owned()]));
2927
2928 let room_b = room_infos.iter().find(|r| r.room_id() == room_b_id).unwrap();
2929 assert_eq!(room_b.name(), None);
2930 assert_eq!(room_b.creators(), None);
2931
2932 let room_c = room_infos.iter().find(|r| r.room_id() == room_c_id).unwrap();
2933 assert_eq!(room_c.name(), None);
2934 assert_eq!(room_c.creators(), Some(vec![room_c_create_sender.to_owned()]));
2935 }
2936
2937 #[async_test]
2938 pub async fn test_migrating_v7_to_v9() {
2939 let path = new_path();
2940
2941 let room_id = room_id!("!room_a:dummy.local");
2942 let wedged_event_transaction_id = TransactionId::new();
2943 let local_event_transaction_id = TransactionId::new();
2944
2945 {
2947 let db = create_fake_db(&path, 7).await.unwrap();
2948 let conn = db.read().await.unwrap();
2949
2950 let wedge_tx = wedged_event_transaction_id.clone();
2951 let local_tx = local_event_transaction_id.clone();
2952
2953 conn.with_transaction(move |txn| {
2954 add_dependent_send_queue_event_v7(
2955 &db,
2956 txn,
2957 room_id,
2958 &local_tx,
2959 ChildTransactionId::new(),
2960 DependentQueuedRequestKind::RedactEvent,
2961 )?;
2962 add_send_queue_event_v7(&db, txn, &wedge_tx, room_id, true)?;
2963 add_send_queue_event_v7(&db, txn, &local_tx, room_id, false)?;
2964 Result::<_, Error>::Ok(())
2965 })
2966 .await
2967 .unwrap();
2968 }
2969
2970 let store = SqliteStateStore::open(path, Some(SECRET)).await.unwrap();
2973
2974 let requests = store.load_send_queue_requests(room_id).await.unwrap();
2975 assert!(requests.is_empty());
2976
2977 let dependent_requests = store.load_dependent_queued_requests(room_id).await.unwrap();
2978 assert!(dependent_requests.is_empty());
2979 }
2980
2981 fn add_send_queue_event_v7(
2982 this: &SqliteStateStore,
2983 txn: &Transaction<'_>,
2984 transaction_id: &TransactionId,
2985 room_id: &RoomId,
2986 is_wedged: bool,
2987 ) -> Result<(), Error> {
2988 let content =
2989 SerializableEventContent::new(&RoomMessageEventContent::text_plain("Hello").into())?;
2990
2991 let room_id_key = this.encode_key(keys::SEND_QUEUE, room_id);
2992 let room_id_value = this.serialize_value(&room_id.to_owned())?;
2993
2994 let content = this.serialize_json(&content)?;
2995
2996 txn.prepare_cached("INSERT INTO send_queue_events (room_id, room_id_val, transaction_id, content, wedged) VALUES (?, ?, ?, ?, ?)")?
2997 .execute((room_id_key, room_id_value, transaction_id.to_string(), content, is_wedged))?;
2998
2999 Ok(())
3000 }
3001
3002 fn add_dependent_send_queue_event_v7(
3003 this: &SqliteStateStore,
3004 txn: &Transaction<'_>,
3005 room_id: &RoomId,
3006 parent_txn_id: &TransactionId,
3007 own_txn_id: ChildTransactionId,
3008 content: DependentQueuedRequestKind,
3009 ) -> Result<(), Error> {
3010 let room_id_value = this.serialize_value(&room_id.to_owned())?;
3011
3012 let parent_txn_id = parent_txn_id.to_string();
3013 let own_txn_id = own_txn_id.to_string();
3014 let content = this.serialize_json(&content)?;
3015
3016 txn.prepare_cached(
3017 "INSERT INTO dependent_send_queue_events
3018 (room_id, parent_transaction_id, own_transaction_id, content)
3019 VALUES (?, ?, ?, ?)",
3020 )?
3021 .execute((room_id_value, parent_txn_id, own_txn_id, content))?;
3022
3023 Ok(())
3024 }
3025
3026 #[derive(Clone, Debug, Serialize, Deserialize)]
3027 pub enum LegacyDependentQueuedRequestKind {
3028 UploadFileWithThumbnail {
3029 content_type: String,
3030 cache_key: MediaRequestParameters,
3031 related_to: OwnedTransactionId,
3032 },
3033 }
3034
3035 #[async_test]
3036 pub async fn test_dependent_queued_request_variant_renaming() {
3037 let path = new_path();
3038 let db = create_fake_db(&path, 7).await.unwrap();
3039
3040 let cache_key = MediaRequestParameters {
3041 format: MediaFormat::File,
3042 source: MediaSource::Plain("https://server.local/foobar".into()),
3043 };
3044 let related_to = TransactionId::new();
3045 let request = LegacyDependentQueuedRequestKind::UploadFileWithThumbnail {
3046 content_type: "image/png".to_owned(),
3047 cache_key,
3048 related_to: related_to.clone(),
3049 };
3050
3051 let data = db
3052 .serialize_json(&request)
3053 .expect("should be able to serialize legacy dependent request");
3054 let deserialized: DependentQueuedRequestKind = db.deserialize_json(&data).expect(
3055 "should be able to deserialize dependent request from legacy dependent request",
3056 );
3057
3058 as_variant!(deserialized, DependentQueuedRequestKind::UploadFileOrThumbnail { related_to: de_related_to, .. } => {
3059 assert_eq!(de_related_to, related_to);
3060 });
3061 }
3062}
3063
3064#[cfg(test)]
3065mod close_reopen_tests {
3066 use std::sync::{
3067 LazyLock,
3068 atomic::{AtomicU32, Ordering::SeqCst},
3069 };
3070
3071 use matrix_sdk_base::StateStore;
3072 use matrix_sdk_test::async_test;
3073 use tempfile::{TempDir, tempdir};
3074
3075 use super::SqliteStateStore;
3076
3077 static TMP_DIR: LazyLock<TempDir> = LazyLock::new(|| tempdir().unwrap());
3078 static NUM: AtomicU32 = AtomicU32::new(0);
3079
3080 async fn new_store() -> SqliteStateStore {
3081 let name = NUM.fetch_add(1, SeqCst).to_string();
3082 let tmpdir_path = TMP_DIR.path().join(name);
3083 SqliteStateStore::open(tmpdir_path.to_str().unwrap(), None).await.unwrap()
3084 }
3085
3086 #[async_test]
3087 async fn test_close_completes_without_timeout() {
3088 let store = new_store().await;
3089
3090 let start = std::time::Instant::now();
3092 store.close().await.unwrap();
3093 let elapsed = start.elapsed();
3094
3095 assert!(
3096 elapsed < std::time::Duration::from_secs(2),
3097 "close() took {elapsed:?}, expected < 2s (no timeout)"
3098 );
3099
3100 let guard = store.connections.lock().await;
3102 assert!(guard.is_none(), "connections should be None after close");
3103 }
3104
3105 #[async_test]
3106 async fn test_reopen_restores_connections() {
3107 let store = new_store().await;
3108
3109 store.close().await.unwrap();
3110
3111 {
3113 let guard = store.connections.lock().await;
3114 assert!(guard.is_none());
3115 }
3116
3117 store.reopen().await.unwrap();
3118
3119 {
3121 let guard = store.connections.lock().await;
3122 assert!(guard.is_some(), "connections should be Some after reopen");
3123 }
3124 }
3125
3126 #[async_test]
3127 async fn test_close_is_idempotent() {
3128 let store = new_store().await;
3129
3130 store.close().await.unwrap();
3132 store.close().await.unwrap();
3134
3135 let guard = store.connections.lock().await;
3136 assert!(guard.is_none());
3137 }
3138
3139 #[async_test]
3140 async fn test_reopen_is_idempotent() {
3141 let store = new_store().await;
3142
3143 store.reopen().await.unwrap();
3145
3146 let guard = store.connections.lock().await;
3148 assert!(guard.is_some());
3149 }
3150
3151 #[async_test]
3152 async fn test_read_fails_when_closed() {
3153 let store = new_store().await;
3154 store.close().await.unwrap();
3155
3156 let err = store.get_custom_value(b"some_key").await;
3157 assert!(err.is_err(), "read should fail when closed");
3158
3159 let err_msg = err.unwrap_err().to_string();
3160 assert!(err_msg.contains("closed"), "error should mention 'closed', got: {err_msg}");
3161 }
3162
3163 #[async_test]
3164 async fn test_write_fails_when_closed() {
3165 let store = new_store().await;
3166 store.close().await.unwrap();
3167
3168 let err = store.set_custom_value(b"key", b"value".to_vec()).await;
3169 assert!(err.is_err(), "write should fail when closed");
3170
3171 let err_msg = err.unwrap_err().to_string();
3172 assert!(err_msg.contains("closed"), "error should mention 'closed', got: {err_msg}");
3173 }
3174
3175 #[async_test]
3176 async fn test_data_persists_across_close_reopen() {
3177 let store = new_store().await;
3178
3179 store.set_custom_value(b"test_key", b"test_value".to_vec()).await.unwrap();
3181
3182 let value = store.get_custom_value(b"test_key").await.unwrap();
3184 assert_eq!(value.as_deref(), Some(b"test_value".as_slice()));
3185
3186 store.close().await.unwrap();
3188 store.reopen().await.unwrap();
3189
3190 let value = store.get_custom_value(b"test_key").await.unwrap();
3192 assert_eq!(
3193 value.as_deref(),
3194 Some(b"test_value".as_slice()),
3195 "data should persist across close/reopen"
3196 );
3197 }
3198
3199 #[async_test]
3200 async fn test_multiple_close_reopen_cycles() {
3201 let store = new_store().await;
3202
3203 for i in 0..3 {
3204 let key = format!("key_{i}");
3205 let value = format!("value_{i}");
3206
3207 store.set_custom_value(key.as_bytes(), value.as_bytes().to_vec()).await.unwrap();
3208
3209 store.close().await.unwrap();
3210 store.reopen().await.unwrap();
3211
3212 for j in 0..=i {
3214 let k = format!("key_{j}");
3215 let v = format!("value_{j}");
3216 let retrieved = store.get_custom_value(k.as_bytes()).await.unwrap();
3217 assert_eq!(
3218 retrieved.as_deref(),
3219 Some(v.as_bytes()),
3220 "data for key_{j} should persist after cycle {i}"
3221 );
3222 }
3223 }
3224 }
3225
3226 #[async_test]
3227 async fn test_pool_is_fully_drained_after_close() {
3228 let store = new_store().await;
3229
3230 let _ = store.get_custom_value(b"key1").await;
3232 let _ = store.get_custom_value(b"key2").await;
3233
3234 store.close().await.unwrap();
3235
3236 let guard = store.connections.lock().await;
3239 assert!(guard.is_none(), "all connections should be released after close");
3240 }
3241
3242 #[async_test]
3243 async fn test_operations_work_immediately_after_reopen() {
3244 let store = new_store().await;
3245
3246 store.close().await.unwrap();
3247 store.reopen().await.unwrap();
3248
3249 store.set_custom_value(b"after_reopen", b"works".to_vec()).await.unwrap();
3251
3252 let value = store.get_custom_value(b"after_reopen").await.unwrap();
3254 assert_eq!(value.as_deref(), Some(b"works".as_slice()));
3255 }
3256
3257 #[async_test]
3258 async fn test_close_waits_for_held_read_connection_to_drain() {
3259 let store = new_store().await;
3260
3261 let held_conn = store.read().await.unwrap();
3263
3264 let store_clone = store.clone();
3267 let close_handle = tokio::spawn(async move {
3268 store_clone.close().await.unwrap();
3269 });
3270
3271 tokio::time::sleep(std::time::Duration::from_millis(200)).await;
3273
3274 assert!(!close_handle.is_finished(), "close should be waiting for the held connection");
3276
3277 drop(held_conn);
3279
3280 let timeout = tokio::time::timeout(std::time::Duration::from_secs(3), close_handle).await;
3282 assert!(timeout.is_ok(), "close should complete after the held connection is released");
3283 timeout.unwrap().unwrap();
3284
3285 let guard = store.connections.lock().await;
3287 assert!(guard.is_none(), "connections should be None after close");
3288 }
3289}