mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-10-03 06:08:40 -04:00
wasm support for inspect and watchvalue
(needs tests)
This commit is contained in:
parent
cfce0a35b4
commit
ff28273a59
9 changed files with 217 additions and 54 deletions
|
@ -716,6 +716,37 @@ pub fn routing_context_cancel_dht_watch(id: u32, key: String, subkeys: String) -
|
|||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen()]
|
||||
pub fn routing_context_inspect_dht_record(
|
||||
id: u32,
|
||||
key: String,
|
||||
subkeys: String,
|
||||
scope: String,
|
||||
) -> Promise {
|
||||
let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
||||
let subkeys: veilid_core::ValueSubkeyRangeSet =
|
||||
veilid_core::deserialize_json(&subkeys).unwrap();
|
||||
let scope: veilid_core::DHTReportScope = veilid_core::deserialize_json(&scope).unwrap();
|
||||
|
||||
wrap_api_future_json(async move {
|
||||
let routing_context = {
|
||||
let rc = (*ROUTING_CONTEXTS).borrow();
|
||||
let Some(routing_context) = rc.get(&id) else {
|
||||
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument(
|
||||
"routing_context_inspect_dht_record",
|
||||
"id",
|
||||
id,
|
||||
));
|
||||
};
|
||||
routing_context.clone()
|
||||
};
|
||||
let res = routing_context
|
||||
.inspect_dht_record(key, subkeys, scope)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen()]
|
||||
pub fn new_private_route() -> Promise {
|
||||
wrap_api_future_json(async move {
|
||||
|
|
|
@ -195,6 +195,11 @@ impl VeilidClient {
|
|||
APIRESULT_UNDEFINED
|
||||
}
|
||||
|
||||
/// Get the current timestamp, in string format
|
||||
pub fn now() -> String {
|
||||
veilid_core::get_aligned_timestamp().as_u64().to_string()
|
||||
}
|
||||
|
||||
/// Execute an 'internal debug command'.
|
||||
pub async fn debug(command: String) -> APIResult<String> {
|
||||
let veilid_api = get_veilid_api()?;
|
||||
|
|
|
@ -265,13 +265,13 @@ impl VeilidRoutingContext {
|
|||
pub async fn getDhtValue(
|
||||
&self,
|
||||
key: String,
|
||||
subKey: u32,
|
||||
subkey: u32,
|
||||
forceRefresh: bool,
|
||||
) -> APIResult<Option<ValueData>> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context
|
||||
.get_dht_value(key, subKey, forceRefresh)
|
||||
.get_dht_value(key, subkey, forceRefresh)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ impl VeilidRoutingContext {
|
|||
pub async fn setDhtValue(
|
||||
&self,
|
||||
key: String,
|
||||
subKey: u32,
|
||||
subkey: u32,
|
||||
data: Box<[u8]>,
|
||||
writer: Option<String>,
|
||||
) -> APIResult<Option<ValueData>> {
|
||||
|
@ -295,49 +295,120 @@ impl VeilidRoutingContext {
|
|||
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context
|
||||
.set_dht_value(key, subKey, data, writer)
|
||||
.set_dht_value(key, subkey, data, writer)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
|
||||
// pub async fn watchDhtValues(
|
||||
// &self,
|
||||
// key: String,
|
||||
// subKeys: ValueSubkeyRangeSet,
|
||||
// expiration: Timestamp,
|
||||
// count: u32,
|
||||
// ) -> APIResult<String> {
|
||||
// let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
||||
// let subkeys: veilid_core::ValueSubkeyRangeSet =
|
||||
// veilid_core::deserialize_json(&subkeys).unwrap();
|
||||
// let expiration = veilid_core::Timestamp::from_str(&expiration).unwrap();
|
||||
/// Add or update a watch to a DHT value that informs the user via an VeilidUpdate::ValueChange callback when the record has subkeys change.
|
||||
/// One remote node will be selected to perform the watch and it will offer an expiration time based on a suggestion, and make an attempt to
|
||||
/// continue to report changes via the callback. Nodes that agree to doing watches will be put on our 'ping' list to ensure they are still around
|
||||
/// otherwise the watch will be cancelled and will have to be re-watched.
|
||||
///
|
||||
/// There is only one watch permitted per record. If a change to a watch is desired, the previous one will be overwritten.
|
||||
/// * `key` is the record key to watch. it must first be opened for reading or writing.
|
||||
/// * `subkeys` is the the range of subkeys to watch. The range must not exceed 512 discrete non-overlapping or adjacent subranges. If no range is specified, this is equivalent to watching the entire range of subkeys.
|
||||
/// * `expiration` is the desired timestamp of when to automatically terminate the watch, in microseconds. If this value is less than `network.rpc.timeout_ms` milliseconds in the future, this function will return an error immediately.
|
||||
/// * `count` is the number of times the watch will be sent, maximum. A zero value here is equivalent to a cancellation.
|
||||
///
|
||||
/// Returns a timestamp of when the watch will expire. All watches are guaranteed to expire at some point in the future,
|
||||
/// and the returned timestamp will be no later than the requested expiration, but -may- be before the requested expiration.
|
||||
/// If the returned timestamp is zero it indicates that the watch creation or update has failed. In the case of a faild update, the watch is considered cancelled.
|
||||
///
|
||||
/// DHT watches are accepted with the following conditions:
|
||||
/// * First-come first-served basis for arbitrary unauthenticated readers, up to network.dht.public_watch_limit per record
|
||||
/// * If a member (either the owner or a SMPL schema member) has opened the key for writing (even if no writing is performed) then the watch will be signed and guaranteed network.dht.member_watch_limit per writer
|
||||
///
|
||||
/// Members can be specified via the SMPL schema and do not need to allocate writable subkeys in order to offer a member watch capability.
|
||||
pub async fn watchDhtValues(
|
||||
&self,
|
||||
key: String,
|
||||
subkeys: ValueSubkeyRangeSet,
|
||||
expiration: String,
|
||||
count: u32,
|
||||
) -> APIResult<String> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
let expiration =
|
||||
veilid_core::Timestamp::from_str(&expiration).map_err(VeilidAPIError::generic)?;
|
||||
|
||||
// let routing_context = {
|
||||
// let rc = (*ROUTING_CONTEXTS).borrow();
|
||||
// let Some(routing_context) = rc.get(&id) else {
|
||||
// return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("routing_context_watch_dht_values", "id", self.id));
|
||||
// };
|
||||
// routing_context.clone()
|
||||
// };
|
||||
// let res = routing_context
|
||||
// .watch_dht_values(key, subkeys, expiration, count)
|
||||
// .await?;
|
||||
// APIResult::Ok(res.to_string())
|
||||
// }
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context
|
||||
.watch_dht_values(key, subkeys, expiration, count)
|
||||
.await?;
|
||||
APIResult::Ok(res.to_string())
|
||||
}
|
||||
|
||||
// pub async fn cancelDhtWatch(id: u32, key: String, subkeys: String) -> Promise {
|
||||
// let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
||||
// let subkeys: veilid_core::ValueSubkeyRangeSet =
|
||||
// veilid_core::deserialize_json(&subkeys).unwrap();
|
||||
/// Cancels a watch early
|
||||
///
|
||||
/// This is a convenience function that cancels watching all subkeys in a range. The subkeys specified here
|
||||
/// are subtracted from the watched subkey range. If no range is specified, this is equivalent to cancelling the entire range of subkeys.
|
||||
/// Only the subkey range is changed, the expiration and count remain the same.
|
||||
/// If no subkeys remain, the watch is entirely cancelled and will receive no more updates.
|
||||
/// Returns true if there is any remaining watch for this record
|
||||
/// Returns false if the entire watch has been cancelled
|
||||
pub async fn cancelDhtWatch(
|
||||
&self,
|
||||
key: String,
|
||||
subkeys: ValueSubkeyRangeSet,
|
||||
) -> APIResult<bool> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
|
||||
// let routing_context = {
|
||||
// let rc = (*ROUTING_CONTEXTS).borrow();
|
||||
// let Some(routing_context) = rc.get(&id) else {
|
||||
// return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("routing_context_cancel_dht_watch", "id", self.id));
|
||||
// };
|
||||
// routing_context.clone()
|
||||
// };
|
||||
// let res = routing_context.cancel_dht_watch(key, subkeys).await?;
|
||||
// APIResult::Ok(res)
|
||||
// }
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context.cancel_dht_watch(key, subkeys).await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
|
||||
/// Inspects a DHT record for subkey state.
|
||||
/// This is useful for checking if you should push new subkeys to the network, or retrieve the current state of a record from the network
|
||||
/// to see what needs updating locally.
|
||||
///
|
||||
/// * `key` is the record key to watch. it must first be opened for reading or writing.
|
||||
/// * `subkeys` is the the range of subkeys to inspect. The range must not exceed 512 discrete non-overlapping or adjacent subranges.
|
||||
/// If no range is specified, this is equivalent to inspecting the entire range of subkeys. In total, the list of subkeys returned will be truncated at 512 elements.
|
||||
/// * `scope` is what kind of range the inspection has:
|
||||
///
|
||||
/// - DHTReportScope::Local
|
||||
/// Results will be only for a locally stored record.
|
||||
/// Useful for seeing what subkeys you have locally and which ones have not been retrieved
|
||||
///
|
||||
/// - DHTReportScope::SyncGet
|
||||
/// Return the local sequence numbers and the network sequence numbers with GetValue fanout parameters
|
||||
/// Provides an independent view of both the local sequence numbers and the network sequence numbers for nodes that
|
||||
/// would be reached as if the local copy did not exist locally.
|
||||
/// Useful for determining if the current local copy should be updated from the network.
|
||||
///
|
||||
/// - DHTReportScope::SyncSet
|
||||
/// Return the local sequence numbers and the network sequence numbers with SetValue fanout parameters
|
||||
/// Provides an independent view of both the local sequence numbers and the network sequence numbers for nodes that
|
||||
/// would be reached as if the local copy did not exist locally.
|
||||
/// Useful for determining if the unchanged local copy should be pushed to the network.
|
||||
///
|
||||
/// - DHTReportScope::UpdateGet
|
||||
/// Return the local sequence numbers and the network sequence numbers with GetValue fanout parameters
|
||||
/// Provides an view of both the local sequence numbers and the network sequence numbers for nodes that
|
||||
/// would be reached as if a GetValue operation were being performed, including accepting newer values from the network.
|
||||
/// Useful for determining which subkeys would change with a GetValue operation
|
||||
///
|
||||
/// - DHTReportScope::UpdateSet
|
||||
/// Return the local sequence numbers and the network sequence numbers with SetValue fanout parameters
|
||||
/// Provides an view of both the local sequence numbers and the network sequence numbers for nodes that
|
||||
/// would be reached as if a SetValue operation were being performed, including accepting newer values from the network.
|
||||
/// This simulates a SetValue with the initial sequence number incremented by 1, like a real SetValue would when updating.
|
||||
/// Useful for determine which subkeys would change with an SetValue operation
|
||||
///
|
||||
/// Returns a DHTRecordReport with the subkey ranges that were returned that overlapped the schema, and sequence numbers for each of the subkeys in the range.
|
||||
pub async fn inspectDhtRecord(
|
||||
&self,
|
||||
key: String,
|
||||
subkeys: ValueSubkeyRangeSet,
|
||||
scope: DHTReportScope,
|
||||
) -> APIResult<DHTRecordReport> {
|
||||
let key = TypedKey::from_str(&key)?;
|
||||
|
||||
let routing_context = self.getRoutingContext()?;
|
||||
let res = routing_context
|
||||
.inspect_dht_record(key, subkeys, scope)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ describe('VeilidRoutingContext', () => {
|
|||
});
|
||||
|
||||
after('free dht record', async () => {
|
||||
await routingContext.closeDhtRecord(dhtRecord.key);
|
||||
await routingContext.deleteDhtRecord(dhtRecord.key);
|
||||
});
|
||||
|
||||
it('should set value', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue