checkpoint
This commit is contained in:
parent
99d840e281
commit
de8349004d
@ -132,7 +132,7 @@ impl Crypto {
|
|||||||
drop(db);
|
drop(db);
|
||||||
table_store.delete("crypto_caches").await?;
|
table_store.delete("crypto_caches").await?;
|
||||||
db = table_store.open("crypto_caches", 1).await?;
|
db = table_store.open("crypto_caches", 1).await?;
|
||||||
db.store(0, b"node_id", &node_id.unwrap().bytes)?;
|
db.store(0, b"node_id", &node_id.unwrap().bytes).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule flushing
|
// Schedule flushing
|
||||||
@ -159,7 +159,7 @@ impl Crypto {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let db = table_store.open("crypto_caches", 1).await?;
|
let db = table_store.open("crypto_caches", 1).await?;
|
||||||
db.store(0, b"dh_cache", &cache_bytes)?;
|
db.store(0, b"dh_cache", &cache_bytes).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::intf::table_db::*;
|
use crate::intf::table_db::TableDBInner;
|
||||||
|
pub use crate::intf::table_db::{TableDB, TableDBTransaction};
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use keyvaluedb_sqlite::*;
|
use keyvaluedb_sqlite::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -83,42 +83,42 @@ impl TableDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key with a value in a column in the TableDB. Performs a single transaction immediately.
|
/// Store a key with a value in a column in the TableDB. Performs a single transaction immediately.
|
||||||
pub fn store(&self, col: u32, key: &[u8], value: &[u8]) -> EyreResult<()> {
|
pub async fn store(&self, col: u32, key: &[u8], value: &[u8]) -> EyreResult<()> {
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let mut dbt = db.transaction();
|
let mut dbt = db.transaction();
|
||||||
dbt.put(col, key, value);
|
dbt.put(col, key, value);
|
||||||
db.write(dbt).wrap_err("failed to store key")
|
db.write(dbt).await.wrap_err("failed to store key")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key in rkyv format with a value in a column in the TableDB. Performs a single transaction immediately.
|
/// Store a key in rkyv format with a value in a column in the TableDB. Performs a single transaction immediately.
|
||||||
pub fn store_rkyv<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
pub async fn store_rkyv<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
||||||
where
|
where
|
||||||
T: RkyvSerialize<rkyv::ser::serializers::AllocSerializer<1024>>,
|
T: RkyvSerialize<rkyv::ser::serializers::AllocSerializer<1024>>,
|
||||||
{
|
{
|
||||||
let v = to_rkyv(value)?;
|
let v = to_rkyv(value)?;
|
||||||
|
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let mut dbt = db.transaction();
|
let mut dbt = db.transaction();
|
||||||
dbt.put(col, key, v.as_slice());
|
dbt.put(col, key, v.as_slice());
|
||||||
db.write(dbt).wrap_err("failed to store key")
|
db.write(dbt).await.wrap_err("failed to store key")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key in json format with a value in a column in the TableDB. Performs a single transaction immediately.
|
/// Store a key in json format with a value in a column in the TableDB. Performs a single transaction immediately.
|
||||||
pub fn store_json<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
pub async fn store_json<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
||||||
where
|
where
|
||||||
T: serde::Serialize,
|
T: serde::Serialize,
|
||||||
{
|
{
|
||||||
let v = serde_json::to_vec(value)?;
|
let v = serde_json::to_vec(value)?;
|
||||||
|
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let mut dbt = db.transaction();
|
let mut dbt = db.transaction();
|
||||||
dbt.put(col, key, v.as_slice());
|
dbt.put(col, key, v.as_slice());
|
||||||
db.write(dbt).wrap_err("failed to store key")
|
db.write(dbt).await.wrap_err("failed to store key")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a key from a column in the TableDB immediately.
|
/// Read a key from a column in the TableDB immediately.
|
||||||
pub fn load(&self, col: u32, key: &[u8]) -> EyreResult<Option<Vec<u8>>> {
|
pub fn load(&self, col: u32, key: &[u8]) -> EyreResult<Option<Vec<u8>>> {
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
db.get(col, key).wrap_err("failed to get key")
|
db.get(col, key).wrap_err("failed to get key")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ impl TableDB {
|
|||||||
<T as RkyvArchive>::Archived:
|
<T as RkyvArchive>::Archived:
|
||||||
RkyvDeserialize<T, rkyv::de::deserializers::SharedDeserializeMap>,
|
RkyvDeserialize<T, rkyv::de::deserializers::SharedDeserializeMap>,
|
||||||
{
|
{
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let out = db.get(col, key).wrap_err("failed to get key")?;
|
let out = db.get(col, key).wrap_err("failed to get key")?;
|
||||||
let b = match out {
|
let b = match out {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
@ -148,7 +148,7 @@ impl TableDB {
|
|||||||
where
|
where
|
||||||
T: for<'de> serde::Deserialize<'de>,
|
T: for<'de> serde::Deserialize<'de>,
|
||||||
{
|
{
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let out = db.get(col, key).wrap_err("failed to get key")?;
|
let out = db.get(col, key).wrap_err("failed to get key")?;
|
||||||
let b = match out {
|
let b = match out {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
@ -161,15 +161,15 @@ impl TableDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Delete key with from a column in the TableDB
|
/// Delete key with from a column in the TableDB
|
||||||
pub fn delete(&self, col: u32, key: &[u8]) -> EyreResult<bool> {
|
pub async fn delete(&self, col: u32, key: &[u8]) -> EyreResult<bool> {
|
||||||
let db = &self.inner.lock().database;
|
let db = self.inner.lock().database.clone();
|
||||||
let found = db.get(col, key).wrap_err("failed to get key")?;
|
let found = db.get(col, key).wrap_err("failed to get key")?;
|
||||||
match found {
|
match found {
|
||||||
None => Ok(false),
|
None => Ok(false),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let mut dbt = db.transaction();
|
let mut dbt = db.transaction();
|
||||||
dbt.delete(col, key);
|
dbt.delete(col, key);
|
||||||
db.write(dbt).wrap_err("failed to delete key")?;
|
db.write(dbt).await.wrap_err("failed to delete key")?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,55 +212,58 @@ impl TableDBTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the transaction. Performs all actions atomically.
|
/// Commit the transaction. Performs all actions atomically.
|
||||||
pub fn commit(mut self) -> EyreResult<()> {
|
pub async fn commit(self) -> EyreResult<()> {
|
||||||
let dbt = {
|
let dbt = {
|
||||||
let inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner
|
inner
|
||||||
.dbt
|
.dbt
|
||||||
.take()
|
.take()
|
||||||
.ok_or_else(|| Err(eyre!("transaction already completed")))?
|
.ok_or_else(|| eyre!("transaction already completed"))?
|
||||||
};
|
};
|
||||||
self.db
|
let db = self.db.inner.lock().database.clone();
|
||||||
.inner
|
db.write(dbt)
|
||||||
.lock()
|
.await
|
||||||
.database
|
|
||||||
.write(dbt)
|
|
||||||
.wrap_err("commit failed, transaction lost")
|
.wrap_err("commit failed, transaction lost")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rollback the transaction. Does nothing to the TableDB.
|
/// Rollback the transaction. Does nothing to the TableDB.
|
||||||
pub fn rollback(mut self) {
|
pub fn rollback(self) {
|
||||||
self.dbt = None;
|
let mut inner = self.inner.lock();
|
||||||
|
inner.dbt = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key with a value in a column in the TableDB
|
/// Store a key with a value in a column in the TableDB
|
||||||
pub fn store(&mut self, col: u32, key: &[u8], value: &[u8]) {
|
pub fn store(&self, col: u32, key: &[u8], value: &[u8]) {
|
||||||
self.dbt.as_mut().unwrap().put(col, key, value);
|
let mut inner = self.inner.lock();
|
||||||
|
inner.dbt.as_mut().unwrap().put(col, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key in rkyv format with a value in a column in the TableDB
|
/// Store a key in rkyv format with a value in a column in the TableDB
|
||||||
pub fn store_rkyv<T>(&mut self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
pub fn store_rkyv<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
||||||
where
|
where
|
||||||
T: RkyvSerialize<rkyv::ser::serializers::AllocSerializer<1024>>,
|
T: RkyvSerialize<rkyv::ser::serializers::AllocSerializer<1024>>,
|
||||||
{
|
{
|
||||||
let v = to_rkyv(value)?;
|
let v = to_rkyv(value)?;
|
||||||
self.dbt.as_mut().unwrap().put(col, key, v.as_slice());
|
let mut inner = self.inner.lock();
|
||||||
|
inner.dbt.as_mut().unwrap().put(col, key, v.as_slice());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a key in rkyv format with a value in a column in the TableDB
|
/// Store a key in rkyv format with a value in a column in the TableDB
|
||||||
pub fn store_json<T>(&mut self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
pub fn store_json<T>(&self, col: u32, key: &[u8], value: &T) -> EyreResult<()>
|
||||||
where
|
where
|
||||||
T: serde::Serialize,
|
T: serde::Serialize,
|
||||||
{
|
{
|
||||||
let v = serde_json::to_vec(value)?;
|
let v = serde_json::to_vec(value)?;
|
||||||
self.dbt.as_mut().unwrap().put(col, key, v.as_slice());
|
let mut inner = self.inner.lock();
|
||||||
|
inner.dbt.as_mut().unwrap().put(col, key, v.as_slice());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete key with from a column in the TableDB
|
/// Delete key with from a column in the TableDB
|
||||||
pub fn delete(&mut self, col: u32, key: &[u8]) {
|
pub fn delete(&self, col: u32, key: &[u8]) {
|
||||||
self.dbt.as_mut().unwrap().delete(col, key);
|
let mut inner = self.inner.lock();
|
||||||
|
inner.dbt.as_mut().unwrap().delete(col, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::intf::table_db::*;
|
use crate::intf::table_db::TableDBInner;
|
||||||
|
pub use crate::intf::table_db::{TableDB, TableDBTransaction};
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use keyvaluedb_web::*;
|
use keyvaluedb_web::*;
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ impl RoutingTable {
|
|||||||
let table_store = self.network_manager().table_store();
|
let table_store = self.network_manager().table_store();
|
||||||
let tdb = table_store.open("routing_table", 1).await?;
|
let tdb = table_store.open("routing_table", 1).await?;
|
||||||
let bucket_count = bucketvec.len();
|
let bucket_count = bucketvec.len();
|
||||||
let mut dbx = tdb.transact();
|
let dbx = tdb.transact();
|
||||||
if let Err(e) = dbx.store_rkyv(0, b"bucket_count", &bucket_count) {
|
if let Err(e) = dbx.store_rkyv(0, b"bucket_count", &bucket_count) {
|
||||||
dbx.rollback();
|
dbx.rollback();
|
||||||
return Err(e);
|
return Err(e);
|
||||||
@ -250,7 +250,7 @@ impl RoutingTable {
|
|||||||
for (n, b) in bucketvec.iter().enumerate() {
|
for (n, b) in bucketvec.iter().enumerate() {
|
||||||
dbx.store(0, format!("bucket_{}", n).as_bytes(), b)
|
dbx.store(0, format!("bucket_{}", n).as_bytes(), b)
|
||||||
}
|
}
|
||||||
dbx.commit()?;
|
dbx.commit().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ impl RouteSpecStore {
|
|||||||
.network_manager()
|
.network_manager()
|
||||||
.table_store();
|
.table_store();
|
||||||
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
let rsstdb = table_store.open("RouteSpecStore", 1).await?;
|
||||||
rsstdb.store_rkyv(0, b"content", &content)?;
|
rsstdb.store_rkyv(0, b"content", &content).await?;
|
||||||
|
|
||||||
// // Keep secrets in protected store as well
|
// // Keep secrets in protected store as well
|
||||||
let pstore = self
|
let pstore = self
|
||||||
|
@ -63,7 +63,7 @@ pub async fn test_store_delete_load(ts: TableStore) {
|
|||||||
"should not load missing key"
|
"should not load missing key"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
db.store(1, b"foo", b"1234567890").is_ok(),
|
db.store(1, b"foo", b"1234567890").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -74,23 +74,25 @@ pub async fn test_store_delete_load(ts: TableStore) {
|
|||||||
assert_eq!(db.load(1, b"foo").unwrap(), Some(b"1234567890".to_vec()));
|
assert_eq!(db.load(1, b"foo").unwrap(), Some(b"1234567890".to_vec()));
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
db.store(1, b"bar", b"FNORD").is_ok(),
|
db.store(1, b"bar", b"FNORD").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
db.store(0, b"bar", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").is_ok(),
|
db.store(0, b"bar", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
.await
|
||||||
|
.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
db.store(2, b"bar", b"FNORD").is_ok(),
|
db.store(2, b"bar", b"FNORD").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
db.store(2, b"baz", b"QWERTY").is_ok(),
|
db.store(2, b"baz", b"QWERTY").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
db.store(2, b"bar", b"QWERTYUIOP").is_ok(),
|
db.store(2, b"bar", b"QWERTYUIOP").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -102,10 +104,10 @@ pub async fn test_store_delete_load(ts: TableStore) {
|
|||||||
assert_eq!(db.load(2, b"bar").unwrap(), Some(b"QWERTYUIOP".to_vec()));
|
assert_eq!(db.load(2, b"bar").unwrap(), Some(b"QWERTYUIOP".to_vec()));
|
||||||
assert_eq!(db.load(2, b"baz").unwrap(), Some(b"QWERTY".to_vec()));
|
assert_eq!(db.load(2, b"baz").unwrap(), Some(b"QWERTY".to_vec()));
|
||||||
|
|
||||||
assert_eq!(db.delete(1, b"bar").unwrap(), true);
|
assert_eq!(db.delete(1, b"bar").await.unwrap(), true);
|
||||||
assert_eq!(db.delete(1, b"bar").unwrap(), false);
|
assert_eq!(db.delete(1, b"bar").await.unwrap(), false);
|
||||||
assert!(
|
assert!(
|
||||||
db.delete(4, b"bar").is_err(),
|
db.delete(4, b"bar").await.is_err(),
|
||||||
"can't delete from column that doesn't exist"
|
"can't delete from column that doesn't exist"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -128,7 +130,7 @@ pub async fn test_frozen(ts: TableStore) {
|
|||||||
let db = ts.open("test", 3).await.expect("should have opened");
|
let db = ts.open("test", 3).await.expect("should have opened");
|
||||||
let (dht_key, _) = generate_secret();
|
let (dht_key, _) = generate_secret();
|
||||||
|
|
||||||
assert!(db.store_rkyv(0, b"asdf", &dht_key).is_ok());
|
assert!(db.store_rkyv(0, b"asdf", &dht_key).await.is_ok());
|
||||||
|
|
||||||
assert_eq!(db.load_rkyv::<DHTKey>(0, b"qwer").unwrap(), None);
|
assert_eq!(db.load_rkyv::<DHTKey>(0, b"qwer").unwrap(), None);
|
||||||
|
|
||||||
@ -141,7 +143,7 @@ pub async fn test_frozen(ts: TableStore) {
|
|||||||
assert_eq!(d, Some(dht_key), "keys should be equal");
|
assert_eq!(d, Some(dht_key), "keys should be equal");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
db.store(1, b"foo", b"1234567890").is_ok(),
|
db.store(1, b"foo", b"1234567890").await.is_ok(),
|
||||||
"should store new key"
|
"should store new key"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ pub use crypto::Crypto;
|
|||||||
pub use crypto::{generate_secret, sign, verify, DHTKey, DHTKeySecret, DHTSignature, Nonce};
|
pub use crypto::{generate_secret, sign, verify, DHTKey, DHTKeySecret, DHTSignature, Nonce};
|
||||||
pub use intf::BlockStore;
|
pub use intf::BlockStore;
|
||||||
pub use intf::ProtectedStore;
|
pub use intf::ProtectedStore;
|
||||||
pub use intf::TableStore;
|
pub use intf::{TableDB, TableDBTransaction, TableStore};
|
||||||
pub use network_manager::NetworkManager;
|
pub use network_manager::NetworkManager;
|
||||||
pub use routing_table::{NodeRef, NodeRefBase};
|
pub use routing_table::{NodeRef, NodeRefBase};
|
||||||
|
|
||||||
|
@ -1849,10 +1849,26 @@ abstract class VeilidRoutingContext {
|
|||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
/// VeilidTableDB
|
/// VeilidTableDB
|
||||||
|
abstract class VeilidTableDBTransaction {
|
||||||
|
Future<void> commit();
|
||||||
|
Future<void> rollback();
|
||||||
|
Future<void> store(int col, Uint8List key, Uint8List value);
|
||||||
|
Future<void> storeJson(int col, Uint8List key, Object? object,
|
||||||
|
{Object? Function(Object? nonEncodable) toEncodable});
|
||||||
|
Future<bool> delete(int col, Uint8List key);
|
||||||
|
}
|
||||||
|
|
||||||
abstract class VeilidTableDB {
|
abstract class VeilidTableDB {
|
||||||
int getColumnCount();
|
int getColumnCount();
|
||||||
List<Uint8List> getKeys();
|
List<Uint8List> getKeys(int col);
|
||||||
VeilidTableDBTransaction transact()
|
VeilidTableDBTransaction transact();
|
||||||
|
Future<void> store(int col, Uint8List key, Uint8List value);
|
||||||
|
Future<void> storeJson(int col, Uint8List key, Object? object,
|
||||||
|
{Object? Function(Object? nonEncodable) toEncodable});
|
||||||
|
Future<Uint8List?> load(int col, Uint8List key);
|
||||||
|
Future<Object?> loadJson(int col, Uint8List key,
|
||||||
|
{Object? Function(Object? key, Object? value) reviver});
|
||||||
|
Future<bool> delete(int col, Uint8List key);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
@ -2,6 +2,7 @@ use crate::dart_isolate_wrapper::*;
|
|||||||
use crate::tools::*;
|
use crate::tools::*;
|
||||||
use allo_isolate::*;
|
use allo_isolate::*;
|
||||||
use cfg_if::*;
|
use cfg_if::*;
|
||||||
|
use data_encoding::BASE64URL_NOPAD;
|
||||||
use ffi_support::*;
|
use ffi_support::*;
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
use opentelemetry::sdk::*;
|
use opentelemetry::sdk::*;
|
||||||
@ -23,6 +24,10 @@ lazy_static! {
|
|||||||
Mutex::new(BTreeMap::new());
|
Mutex::new(BTreeMap::new());
|
||||||
static ref ROUTING_CONTEXTS: Mutex<BTreeMap<u32, veilid_core::RoutingContext>> =
|
static ref ROUTING_CONTEXTS: Mutex<BTreeMap<u32, veilid_core::RoutingContext>> =
|
||||||
Mutex::new(BTreeMap::new());
|
Mutex::new(BTreeMap::new());
|
||||||
|
static ref TABLE_DBS: Mutex<BTreeMap<u32, veilid_core::TableDB>> =
|
||||||
|
Mutex::new(BTreeMap::new());
|
||||||
|
static ref TABLE_DB_TRANSACTIONS: Mutex<BTreeMap<u32, veilid_core::TableDBTransaction>> =
|
||||||
|
Mutex::new(BTreeMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
|
async fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
|
||||||
@ -551,6 +556,266 @@ pub extern "C" fn app_call_reply(port: i64, id: FfiStr, message: FfiStr) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_table_db(table_db: veilid_core::TableDB) -> u32 {
|
||||||
|
let mut next_id: u32 = 1;
|
||||||
|
let mut rc = TABLE_DBS.lock();
|
||||||
|
while rc.contains_key(&next_id) {
|
||||||
|
next_id += 1;
|
||||||
|
}
|
||||||
|
rc.insert(next_id, table_db);
|
||||||
|
next_id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn open_table_db(port: i64, name: FfiStr, column_count: u32) {
|
||||||
|
let name = name.into_opt_string().unwrap_or_default();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result(async move {
|
||||||
|
let veilid_api = get_veilid_api().await?;
|
||||||
|
let tstore = veilid_api.table_store()?;
|
||||||
|
let table_db = tstore.open(&name, column_count).await.map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
let new_id = add_table_db(table_db);
|
||||||
|
APIResult::Ok(new_id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn release_table_db(id: u32) -> i32 {
|
||||||
|
let mut rc = TABLE_DBS.lock();
|
||||||
|
if rc.remove(&id).is_none() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn delete_table_db(port: i64, name: FfiStr) {
|
||||||
|
let name = name.into_opt_string().unwrap_or_default();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result(async move {
|
||||||
|
let veilid_api = get_veilid_api().await?;
|
||||||
|
let tstore = veilid_api.table_store()?;
|
||||||
|
let deleted = tstore.delete(&name).await.map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
APIResult::Ok(deleted)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_get_column_count(id: u32) -> u32 {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
let Ok(cc) = table_db.clone().get_column_count() else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_get_keys(id: u32, col: u32) -> *mut c_char {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
};
|
||||||
|
let Ok(keys) = table_db.clone().get_keys(col) else {
|
||||||
|
return std::ptr::null_mut();
|
||||||
|
};
|
||||||
|
let keys: Vec<String> = keys.into_iter().map(|k| BASE64URL_NOPAD.encode(&k)).collect();
|
||||||
|
let out = veilid_core::serialize_json(keys);
|
||||||
|
out.into_ffi_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_table_db_transaction(tdbt: veilid_core::TableDBTransaction) -> u32 {
|
||||||
|
let mut next_id: u32 = 1;
|
||||||
|
let mut tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
while tdbts.contains_key(&next_id) {
|
||||||
|
next_id += 1;
|
||||||
|
}
|
||||||
|
tdbts.insert(next_id, tdbt);
|
||||||
|
next_id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_transact(id: u32) -> u32 {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
let tdbt = table_db.clone().transact();
|
||||||
|
let tdbtid = add_table_db_transaction(tdbt);
|
||||||
|
return tdbtid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn release_table_db_transaction(id: u32) -> i32 {
|
||||||
|
let mut tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
if tdbts.remove(&id).is_none() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_transaction_commit(port: i64, id: u32) {
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let tdbt = {
|
||||||
|
let tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
let Some(tdbt) = tdbts.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_transaction_commit", "id", id));
|
||||||
|
};
|
||||||
|
tdbt.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
tdbt.commit().await.map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
APIRESULT_VOID
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_transaction_rollback(port: i64, id: u32) {
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let tdbt = {
|
||||||
|
let tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
let Some(tdbt) = tdbts.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_transaction_rollback", "id", id));
|
||||||
|
};
|
||||||
|
tdbt.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
tdbt.rollback();
|
||||||
|
APIRESULT_VOID
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_transaction_store(port: i64, id: u32, col: u32, key: FfiStr, value: FfiStr) {
|
||||||
|
let key: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(key.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let value: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(value.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let tdbt = {
|
||||||
|
let tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
let Some(tdbt) = tdbts.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_transaction_store", "id", id));
|
||||||
|
};
|
||||||
|
tdbt.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
tdbt.store(col, &key, &value);
|
||||||
|
APIRESULT_VOID
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_transaction_delete(port: i64, id: u32, col: u32, key: FfiStr) {
|
||||||
|
let key: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(key.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let tdbt = {
|
||||||
|
let tdbts = TABLE_DB_TRANSACTIONS.lock();
|
||||||
|
let Some(tdbt) = tdbts.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_transaction_delete", "id", id));
|
||||||
|
};
|
||||||
|
tdbt.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = tdbt.delete(col, &key);
|
||||||
|
APIResult::Ok(out)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_store(port: i64, id: u32, col: u32, key: FfiStr, value: FfiStr) {
|
||||||
|
let key: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(key.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let value: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(value.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let table_db = {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_store", "id", id));
|
||||||
|
};
|
||||||
|
table_db.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
table_db.store(col, &key, &value).await.map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
APIRESULT_VOID
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_load(port: i64, id: u32, col: u32, key: FfiStr) {
|
||||||
|
let key: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(key.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let table_db = {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_load", "id", id));
|
||||||
|
};
|
||||||
|
table_db.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = table_db.load(col, &key).map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
APIResult::Ok(out)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn table_db_delete(port: i64, id: u32, col: u32, key: FfiStr) {
|
||||||
|
let key: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
|
.decode(
|
||||||
|
veilid_core::deserialize_opt_json::<String>(key.into_opt_string())
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
|
let table_db = {
|
||||||
|
let table_dbs = TABLE_DBS.lock();
|
||||||
|
let Some(table_db) = table_dbs.get(&id) else {
|
||||||
|
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("table_db_delete", "id", id));
|
||||||
|
};
|
||||||
|
table_db.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = table_db.delete(col, &key).await.map_err(veilid_core::VeilidAPIError::generic)?;
|
||||||
|
APIResult::Ok(out)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn debug(port: i64, command: FfiStr) {
|
pub extern "C" fn debug(port: i64, command: FfiStr) {
|
||||||
let command = command.into_opt_string().unwrap_or_default();
|
let command = command.into_opt_string().unwrap_or_default();
|
||||||
|
Loading…
Reference in New Issue
Block a user