/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
usecrate::api::{self, StorageChanges}; usecrate::db::{StorageDb, ThreadSafeStorageDb}; usecrate::error::*; usecrate::migration::{migrate, MigrationInfo}; usecrate::sync; use std::path::Path; use std::sync::Arc;
use interrupt_support::SqlInterruptHandle; use serde_json::Value as JsonValue;
/// A store is used to access `storage.sync` data. It manages an underlying /// database connection, and exposes methods for reading and writing storage /// items scoped to an extension ID. Each item is a JSON object, with one or /// more string keys, and values of any type that can serialize to JSON. /// /// An application should create only one store, and manage the instance as a /// singleton. While this isn't enforced, if you make multiple stores pointing /// to the same database file, you are going to have a bad time: each store will /// create its own database connection, using up extra memory and CPU cycles, /// and causing write contention. For this reason, you should only call /// `Store::new()` (or `webext_store_new()`, from the FFI) once. /// /// Note that our Db implementation is behind an Arc<> because we share that /// connection with our sync engines - ie, these engines also hold an Arc<> /// around the same object. pubstruct WebExtStorageStore { pub(crate) db: Arc<ThreadSafeStorageDb>,
}
impl WebExtStorageStore { /// Creates a store backed by a database at `db_path`. The path can be a /// file path or `file:` URI. pubfn new(db_path: impl AsRef<Path>) -> Result<Self> { let db = StorageDb::new(db_path)?;
Ok(Self {
db: Arc::new(ThreadSafeStorageDb::new(db)),
})
}
/// Creates a store backed by an in-memory database. #[cfg(test)] pubfn new_memory(db_path: &str) -> Result<Self> { let db = StorageDb::new_memory(db_path)?;
Ok(Self {
db: Arc::new(ThreadSafeStorageDb::new(db)),
})
}
/// Returns an interrupt handle for this store. pubfn interrupt_handle(&self) -> Arc<SqlInterruptHandle> { self.db.interrupt_handle()
}
/// Sets one or more JSON key-value pairs for an extension ID. Returns a /// list of changes, with existing and new values for each key in `val`. pubfn set(&self, ext_id: &str, val: JsonValue) -> Result<StorageChanges> { let db = &self.db.lock(); let conn = db.get_connection()?; let tx = conn.unchecked_transaction()?; let result = api::set(&tx, ext_id, val)?;
tx.commit()?;
Ok(result)
}
/// Returns information about per-extension usage pubfn usage(&self) -> Result<Vec<crate::UsageInfo>> { let db = &self.db.lock(); let conn = db.get_connection()?;
api::usage(conn)
}
/// Returns the values for one or more keys `keys` can be: /// /// - `null`, in which case all key-value pairs for the extension are /// returned, or an empty object if the extension doesn't have any /// stored data. /// - A single string key, in which case an object with only that key /// and its value is returned, or an empty object if the key doesn't // exist. /// - An array of string keys, in which case an object with only those /// keys and their values is returned. Any keys that don't exist will be /// omitted. /// - An object where the property names are keys, and each value is the /// default value to return if the key doesn't exist. /// /// This method always returns an object (that is, a /// `serde_json::Value::Object`). pubfn get(&self, ext_id: &str, keys: JsonValue) -> Result<JsonValue> { // Don't care about transactions here. let db = &self.db.lock(); let conn = db.get_connection()?;
api::get(conn, ext_id, keys)
}
/// Deletes the values for one or more keys. As with `get`, `keys` can be /// either a single string key, or an array of string keys. Returns a list /// of changes, where each change contains the old value for each deleted /// key. pubfn remove(&self, ext_id: &str, keys: JsonValue) -> Result<StorageChanges> { let db = &self.db.lock(); let conn = db.get_connection()?; let tx = conn.unchecked_transaction()?; let result = api::remove(&tx, ext_id, keys)?;
tx.commit()?;
Ok(result)
}
/// Deletes all key-value pairs for the extension. As with `remove`, returns /// a list of changes, where each change contains the old value for each /// deleted key. pubfn clear(&self, ext_id: &str) -> Result<StorageChanges> { let db = &self.db.lock(); let conn = db.get_connection()?; let tx = conn.unchecked_transaction()?; let result = api::clear(&tx, ext_id)?;
tx.commit()?;
Ok(result)
}
/// Returns the bytes in use for the specified items (which can be null, /// a string, or an array) pubfn get_bytes_in_use(&self, ext_id: &str, keys: JsonValue) -> Result<u64> { let db = &self.db.lock(); let conn = db.get_connection()?;
Ok(api::get_bytes_in_use(conn, ext_id, keys)? as u64)
}
/// Closes the store and its database connection. See the docs for /// `StorageDb::close` for more details on when this can fail. pubfn close(&self) -> Result<()> { letmut db = self.db.lock();
db.close()
}
/// Gets the changes which the current sync applied. Should be used /// immediately after the bridged engine is told to apply incoming changes, /// and can be used to notify observers of the StorageArea of the changes /// that were applied. /// The result is a Vec of already JSON stringified changes. pubfn get_synced_changes(&self) -> Result<Vec<sync::SyncedExtensionChange>> { let db = self.db.lock();
sync::get_synced_changes(&db)
}
/// Migrates data from a database in the format of the "old" kinto /// implementation. Information about how the migration went is stored in /// the database, and can be read using `Self::take_migration_info`. /// /// Note that `filename` isn't normalized or canonicalized. pubfn migrate(&self, filename: impl AsRef<Path>) -> Result<()> { let db = &self.db.lock(); let conn = db.get_connection()?; let tx = conn.unchecked_transaction()?; let result = migrate(&tx, filename.as_ref())?;
tx.commit()?; // Failing to store this information should not cause migration failure. iflet Err(e) = result.store(conn) {
debug_assert!(false, "Migration error: {:?}", e);
log::warn!("Failed to record migration telmetry: {}", e);
}
Ok(())
}
/// Read-and-delete (e.g. `take` in rust parlance, see Option::take) /// operation for any MigrationInfo stored in this database. pubfn take_migration_info(&self) -> Result<Option<MigrationInfo>> { let db = &self.db.lock(); let conn = db.get_connection()?; let tx = conn.unchecked_transaction()?; let result = MigrationInfo::take(&tx)?;
tx.commit()?;
Ok(result)
}
}
#[cfg(test)] pubmod test { usesuper::*; #[test] fn test_send() { fn ensure_send<T: Send>() {} // Compile will fail if not send.
ensure_send::<WebExtStorageStore>();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.