use indexed_db_futures::{
Build, error::OpenDbError, query_source::QuerySource, transaction::TransactionMode,
};
use matrix_sdk_crypto::olm::InboundGroupSession;
use tracing::{debug, info};
use wasm_bindgen::JsValue;
use crate::{
IndexeddbCryptoStoreError,
crypto_store::{
Result, keys,
migrations::{MigrationDb, add_nonunique_index, do_schema_upgrade, old_keys, v7},
},
serializer::SafeEncodeSerializer,
};
pub(crate) async fn schema_add(name: &str) -> Result<(), OpenDbError> {
do_schema_upgrade(name, 6, |tx, _| {
let db = tx.db();
let object_store = db.create_object_store(old_keys::INBOUND_GROUP_SESSIONS_V2).build()?;
add_nonunique_index(
&object_store,
keys::INBOUND_GROUP_SESSIONS_BACKUP_INDEX,
"needs_backup",
)?;
Ok(())
})
.await
}
pub(crate) async fn data_migrate(name: &str, serializer: &SafeEncodeSerializer) -> Result<()> {
let db = MigrationDb::new(name, 7).await?;
let txn = db
.transaction([old_keys::INBOUND_GROUP_SESSIONS_V1, old_keys::INBOUND_GROUP_SESSIONS_V2])
.with_mode(TransactionMode::Readwrite)
.build()?;
let old_store = txn.object_store(old_keys::INBOUND_GROUP_SESSIONS_V1)?;
let new_store = txn.object_store(old_keys::INBOUND_GROUP_SESSIONS_V2)?;
let row_count = old_store.count().await?;
info!(row_count, "Migrating inbound group session data from v1 to v2");
if let Some(mut cursor) = old_store.open_cursor().await? {
let mut idx = 0;
while let Some(value) = cursor.next_record::<JsValue>().await? {
idx += 1;
let key =
cursor.key::<JsValue>()?.ok_or(matrix_sdk_crypto::CryptoStoreError::Backend(
"inbound_group_sessions v1 cursor has no key".into(),
))?;
if idx % 100 == 0 {
debug!("Migrating session {idx} of {row_count}");
}
let igs = InboundGroupSession::from_pickle(serializer.deserialize_value(value)?)
.map_err(|e| IndexeddbCryptoStoreError::CryptoStoreError(e.into()))?;
let new_data =
serde_wasm_bindgen::to_value(&v7::InboundGroupSessionIndexedDbObject2 {
pickled_session: serializer.serialize_value_as_bytes(&igs.pickle().await)?,
needs_backup: !igs.backed_up(),
})?;
new_store.add(&new_data).with_key(key).build()?;
cursor.delete()?;
}
}
old_store.clear()?.await?;
Ok(txn.commit().await?)
}
pub(crate) async fn schema_delete(name: &str) -> Result<(), OpenDbError> {
do_schema_upgrade(name, 7, |tx, _| {
tx.db().delete_object_store(old_keys::INBOUND_GROUP_SESSIONS_V1)?;
Ok(())
})
.await
}