mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
add writer to set_dht_value, allow multiple open_dht_record
This commit is contained in:
parent
fac9937cf4
commit
0c3271b3b9
@ -433,6 +433,7 @@ impl StorageManager {
|
|||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
subkey: ValueSubkey,
|
subkey: ValueSubkey,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
writer: Option<KeyPair>,
|
||||||
) -> VeilidAPIResult<Option<ValueData>> {
|
) -> VeilidAPIResult<Option<ValueData>> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
|
|
||||||
@ -451,6 +452,9 @@ impl StorageManager {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use the specified writer, or if not specified, the default writer when the record was opened
|
||||||
|
let opt_writer = writer.or(opt_writer);
|
||||||
|
|
||||||
// If we don't have a writer then we can't write
|
// If we don't have a writer then we can't write
|
||||||
let Some(writer) = opt_writer else {
|
let Some(writer) = opt_writer else {
|
||||||
apibail_generic!("value is not writable");
|
apibail_generic!("value is not writable");
|
||||||
|
@ -308,11 +308,6 @@ impl StorageManagerInner {
|
|||||||
writer: Option<KeyPair>,
|
writer: Option<KeyPair>,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> VeilidAPIResult<Option<DHTRecordDescriptor>> {
|
) -> VeilidAPIResult<Option<DHTRecordDescriptor>> {
|
||||||
// Ensure the record is closed
|
|
||||||
if self.opened_records.contains_key(&key) {
|
|
||||||
apibail_generic!("record is already open and should be closed first");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get local record store
|
// Get local record store
|
||||||
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
let Some(local_record_store) = self.local_record_store.as_mut() else {
|
||||||
apibail_not_initialized!();
|
apibail_not_initialized!();
|
||||||
|
@ -42,10 +42,16 @@ impl OpenedRecord {
|
|||||||
pub fn writer(&self) -> Option<&KeyPair> {
|
pub fn writer(&self) -> Option<&KeyPair> {
|
||||||
self.writer.as_ref()
|
self.writer.as_ref()
|
||||||
}
|
}
|
||||||
|
// pub fn set_writer(&mut self, writer: Option<KeyPair>) {
|
||||||
|
// self.writer = writer;
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn safety_selection(&self) -> SafetySelection {
|
pub fn safety_selection(&self) -> SafetySelection {
|
||||||
self.safety_selection
|
self.safety_selection
|
||||||
}
|
}
|
||||||
|
// pub fn set_safety_selection(&mut self, safety_selection: SafetySelection) {
|
||||||
|
// self.safety_selection = safety_selection;
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn set_active_watch(&mut self, active_watch: ActiveWatch) {
|
pub fn set_active_watch(&mut self, active_watch: ActiveWatch) {
|
||||||
self.active_watch = Some(active_watch);
|
self.active_watch = Some(active_watch);
|
||||||
|
@ -114,7 +114,7 @@ pub async fn test_set_get_dht_value(api: VeilidAPI) {
|
|||||||
|
|
||||||
let test_value = String::from("BLAH BLAH BLAH").as_bytes().to_vec();
|
let test_value = String::from("BLAH BLAH BLAH").as_bytes().to_vec();
|
||||||
// convert string to byte array
|
// convert string to byte array
|
||||||
let set_dht_value_result = rc.set_dht_value(dht_key, 0, test_value.clone()).await;
|
let set_dht_value_result = rc.set_dht_value(dht_key, 0, test_value.clone(), None).await;
|
||||||
assert_eq!(set_dht_value_result.expect("should be Ok(None)"), None);
|
assert_eq!(set_dht_value_result.expect("should be Ok(None)"), None);
|
||||||
|
|
||||||
let get_dht_value_result_0_non_force = rc.get_dht_value(dht_key, 0, false).await;
|
let get_dht_value_result_0_non_force = rc.get_dht_value(dht_key, 0, false).await;
|
||||||
@ -184,7 +184,7 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
// 5. Read data from subkey 0 with force_refresh, check data
|
// 5. Read data from subkey 0 with force_refresh, check data
|
||||||
// 6. Read data from subkey 1 with force_refresh, check data
|
// 6. Read data from subkey 1 with force_refresh, check data
|
||||||
// 7. Overwrite value 1 twice, check that there's no errors
|
// 7. Overwrite value 1 twice, check that there's no errors
|
||||||
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_value_1.clone()).await;
|
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_value_1.clone(), None).await;
|
||||||
assert!(set_dht_test_value_1_result.is_ok());
|
assert!(set_dht_test_value_1_result.is_ok());
|
||||||
|
|
||||||
let get_dht_value_result_1_non_force = rc.get_dht_value(key, 1, false).await;
|
let get_dht_value_result_1_non_force = rc.get_dht_value(key, 1, false).await;
|
||||||
@ -202,7 +202,7 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
None
|
None
|
||||||
);
|
);
|
||||||
|
|
||||||
let set_dht_test_value_0_result = rc.set_dht_value(key, 0, test_data_2.clone()).await;
|
let set_dht_test_value_0_result = rc.set_dht_value(key, 0, test_data_2.clone(), None).await;
|
||||||
assert!(set_dht_test_value_0_result.is_ok());
|
assert!(set_dht_test_value_0_result.is_ok());
|
||||||
|
|
||||||
let get_dht_value_result_0_force = rc.get_dht_value(key, 0, true).await;
|
let get_dht_value_result_0_force = rc.get_dht_value(key, 0, true).await;
|
||||||
@ -223,10 +223,10 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
test_value_1
|
test_value_1
|
||||||
);
|
);
|
||||||
|
|
||||||
let overwrite_value_1_result_1 = rc.set_dht_value(key, 1, test_value_1.clone()).await;
|
let overwrite_value_1_result_1 = rc.set_dht_value(key, 1, test_value_1.clone(), None).await;
|
||||||
assert!(overwrite_value_1_result_1.is_ok());
|
assert!(overwrite_value_1_result_1.is_ok());
|
||||||
|
|
||||||
let overwrite_value_1_result_2 = rc.set_dht_value(key, 1, test_data_2.clone()).await;
|
let overwrite_value_1_result_2 = rc.set_dht_value(key, 1, test_data_2.clone(), None).await;
|
||||||
assert!(overwrite_value_1_result_2.is_ok());
|
assert!(overwrite_value_1_result_2.is_ok());
|
||||||
|
|
||||||
// Now that we initialized some subkeys
|
// Now that we initialized some subkeys
|
||||||
@ -258,7 +258,7 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
));
|
));
|
||||||
|
|
||||||
//Verify subkey 1 can be set before it is get but newer is available online
|
//Verify subkey 1 can be set before it is get but newer is available online
|
||||||
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_data_3.clone()).await;
|
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_data_3.clone(), None).await;
|
||||||
assert!(set_dht_test_value_1_result.is_ok());
|
assert!(set_dht_test_value_1_result.is_ok());
|
||||||
let vdtemp = set_dht_test_value_1_result.unwrap().unwrap();
|
let vdtemp = set_dht_test_value_1_result.unwrap().unwrap();
|
||||||
assert_eq!(vdtemp.data(), test_data_2);
|
assert_eq!(vdtemp.data(), test_data_2);
|
||||||
@ -266,7 +266,7 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
assert_eq!(vdtemp.writer(), owner);
|
assert_eq!(vdtemp.writer(), owner);
|
||||||
|
|
||||||
// Verify subkey 1 can be set a second time and it updates because seq is newer
|
// Verify subkey 1 can be set a second time and it updates because seq is newer
|
||||||
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_data_3.clone()).await;
|
let set_dht_test_value_1_result = rc.set_dht_value(key, 1, test_data_3.clone(), None).await;
|
||||||
assert!(set_dht_test_value_1_result.is_ok());
|
assert!(set_dht_test_value_1_result.is_ok());
|
||||||
|
|
||||||
// Verify the network got the subkey update with a refresh check
|
// Verify the network got the subkey update with a refresh check
|
||||||
@ -308,11 +308,17 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Verify subkey 1 can NOT be set because we have the wrong writer
|
// Verify subkey 1 can NOT be set because we have the wrong writer
|
||||||
let set_dht_test_value_0_result = rc.set_dht_value(key, 1, test_value_1.clone()).await;
|
let set_dht_test_value_0_result = rc.set_dht_value(key, 1, test_value_1.clone(), None).await;
|
||||||
assert_err!(set_dht_test_value_0_result);
|
assert_err!(set_dht_test_value_0_result);
|
||||||
|
|
||||||
// Verify subkey 0 can NOT be set because we have the wrong writer
|
// Verify subkey 0 can NOT be set because we have the wrong writer
|
||||||
let set_dht_test_value_0_result = rc.set_dht_value(key, 0, test_value_1.clone()).await;
|
let set_dht_test_value_0_result = rc.set_dht_value(key, 0, test_value_1.clone(), None).await;
|
||||||
|
assert_err!(set_dht_test_value_0_result);
|
||||||
|
|
||||||
|
// Verify subkey 0 can be set because we have overridden with the correct writer
|
||||||
|
let set_dht_test_value_0_result = rc
|
||||||
|
.set_dht_value(key, 0, test_value_1.clone(), Some(keypair))
|
||||||
|
.await;
|
||||||
assert_err!(set_dht_test_value_0_result);
|
assert_err!(set_dht_test_value_0_result);
|
||||||
|
|
||||||
rc.close_dht_record(key).await.unwrap();
|
rc.close_dht_record(key).await.unwrap();
|
||||||
|
@ -1517,9 +1517,14 @@ impl VeilidAPI {
|
|||||||
let (key, rc) = get_opened_dht_record_context(&args, "debug_record_set", "key", 1)?;
|
let (key, rc) = get_opened_dht_record_context(&args, "debug_record_set", "key", 1)?;
|
||||||
let subkey = get_debug_argument_at(&args, 2, "debug_record_set", "subkey", get_number)?;
|
let subkey = get_debug_argument_at(&args, 2, "debug_record_set", "subkey", get_number)?;
|
||||||
let data = get_debug_argument_at(&args, 3, "debug_record_set", "data", get_data)?;
|
let data = get_debug_argument_at(&args, 3, "debug_record_set", "data", get_data)?;
|
||||||
|
let writer =
|
||||||
|
get_debug_argument_at(&args, 4, "debug_record_set", "writer", get_keypair).ok();
|
||||||
|
|
||||||
// Do a record set
|
// Do a record set
|
||||||
let value = match rc.set_dht_value(key, subkey as ValueSubkey, data).await {
|
let value = match rc
|
||||||
|
.set_dht_value(key, subkey as ValueSubkey, data, writer)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Ok(format!("Can't set DHT value: {}", e));
|
return Ok(format!("Can't set DHT value: {}", e));
|
||||||
}
|
}
|
||||||
|
@ -323,13 +323,18 @@ impl JsonRequestProcessor {
|
|||||||
.await,
|
.await,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
RoutingContextRequestOp::SetDhtValue { key, subkey, data } => {
|
RoutingContextRequestOp::SetDhtValue {
|
||||||
RoutingContextResponseOp::SetDhtValue {
|
key,
|
||||||
result: to_json_api_result(
|
subkey,
|
||||||
routing_context.set_dht_value(key, subkey, data).await,
|
data,
|
||||||
),
|
writer,
|
||||||
}
|
} => RoutingContextResponseOp::SetDhtValue {
|
||||||
}
|
result: to_json_api_result(
|
||||||
|
routing_context
|
||||||
|
.set_dht_value(key, subkey, data, writer)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
|
},
|
||||||
RoutingContextRequestOp::WatchDhtValues {
|
RoutingContextRequestOp::WatchDhtValues {
|
||||||
key,
|
key,
|
||||||
subkeys,
|
subkeys,
|
||||||
|
@ -70,6 +70,8 @@ pub enum RoutingContextRequestOp {
|
|||||||
#[serde(with = "as_human_base64")]
|
#[serde(with = "as_human_base64")]
|
||||||
#[schemars(with = "String")]
|
#[schemars(with = "String")]
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
#[schemars(with = "Option<String>")]
|
||||||
|
writer: Option<KeyPair>,
|
||||||
},
|
},
|
||||||
WatchDhtValues {
|
WatchDhtValues {
|
||||||
#[schemars(with = "String")]
|
#[schemars(with = "String")]
|
||||||
|
@ -215,19 +215,24 @@ impl RoutingContext {
|
|||||||
|
|
||||||
/// Opens a DHT record at a specific key
|
/// Opens a DHT record at a specific key
|
||||||
///
|
///
|
||||||
/// Associates a secret if one is provided to provide writer capability.
|
/// Associates a 'default_writer' secret if one is provided to provide writer capability. The
|
||||||
/// Records may only be opened or created. To re-open with a different routing context, first close the value.
|
/// writer can be overridden if specified here via the set_dht_value writer.
|
||||||
|
///
|
||||||
|
/// Records may only be opened or created. If a record is re-opened it will use the new writer and routing context
|
||||||
|
/// ignoring the settings of the last time it was opened. This allows one to open a record a second time
|
||||||
|
/// without first closing it, which will keep the active 'watches' on the record but change the default writer or
|
||||||
|
/// safety selection.
|
||||||
///
|
///
|
||||||
/// Returns the DHT record descriptor for the opened record if successful
|
/// Returns the DHT record descriptor for the opened record if successful
|
||||||
pub async fn open_dht_record(
|
pub async fn open_dht_record(
|
||||||
&self,
|
&self,
|
||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
writer: Option<KeyPair>,
|
default_writer: Option<KeyPair>,
|
||||||
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
||||||
Crypto::validate_crypto_kind(key.kind)?;
|
Crypto::validate_crypto_kind(key.kind)?;
|
||||||
let storage_manager = self.api.storage_manager()?;
|
let storage_manager = self.api.storage_manager()?;
|
||||||
storage_manager
|
storage_manager
|
||||||
.open_record(key, writer, self.unlocked_inner.safety_selection)
|
.open_record(key, default_writer, self.unlocked_inner.safety_selection)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,6 +274,9 @@ impl RoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a changed subkey value to the network
|
/// Pushes a changed subkey value to the network
|
||||||
|
/// The DHT record must first by opened via open_dht_record or create_dht_record.
|
||||||
|
///
|
||||||
|
/// The writer, if specified, will override the 'default_writer' specified when the record is opened.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the value was successfully put
|
/// Returns `None` if the value was successfully put
|
||||||
/// Returns `Some(data)` if the value put was older than the one available on the network
|
/// Returns `Some(data)` if the value put was older than the one available on the network
|
||||||
@ -277,10 +285,11 @@ impl RoutingContext {
|
|||||||
key: TypedKey,
|
key: TypedKey,
|
||||||
subkey: ValueSubkey,
|
subkey: ValueSubkey,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
writer: Option<KeyPair>,
|
||||||
) -> VeilidAPIResult<Option<ValueData>> {
|
) -> VeilidAPIResult<Option<ValueData>> {
|
||||||
Crypto::validate_crypto_kind(key.kind)?;
|
Crypto::validate_crypto_kind(key.kind)?;
|
||||||
let storage_manager = self.api.storage_manager()?;
|
let storage_manager = self.api.storage_manager()?;
|
||||||
storage_manager.set_value(key, subkey, data).await
|
storage_manager.set_value(key, subkey, data, writer).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a watch to a DHT value that informs the user via an VeilidUpdate::ValueChange callback when the record has subkeys change.
|
/// Add a watch to a DHT value that informs the user via an VeilidUpdate::ValueChange callback when the record has subkeys change.
|
||||||
|
@ -312,11 +312,13 @@ abstract class VeilidRoutingContext {
|
|||||||
// DHT Operations
|
// DHT Operations
|
||||||
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
|
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
|
||||||
{CryptoKind kind = 0});
|
{CryptoKind kind = 0});
|
||||||
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key, KeyPair? writer);
|
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key, {KeyPair? writer});
|
||||||
Future<void> closeDHTRecord(TypedKey key);
|
Future<void> closeDHTRecord(TypedKey key);
|
||||||
Future<void> deleteDHTRecord(TypedKey key);
|
Future<void> deleteDHTRecord(TypedKey key);
|
||||||
Future<ValueData?> getDHTValue(TypedKey key, int subkey, bool forceRefresh);
|
Future<ValueData?> getDHTValue(TypedKey key, int subkey,
|
||||||
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data);
|
{bool forceRefresh = false});
|
||||||
|
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||||
|
{KeyPair? writer});
|
||||||
Future<Timestamp> watchDHTValues(TypedKey key,
|
Future<Timestamp> watchDHTValues(TypedKey key,
|
||||||
{List<ValueSubkeyRange>? subkeys, Timestamp? expiration, int? count});
|
{List<ValueSubkeyRange>? subkeys, Timestamp? expiration, int? count});
|
||||||
Future<bool> cancelDHTWatch(TypedKey key, {List<ValueSubkeyRange>? subkeys});
|
Future<bool> cancelDHTWatch(TypedKey key, {List<ValueSubkeyRange>? subkeys});
|
||||||
|
@ -81,9 +81,9 @@ typedef _RoutingContextDeleteDHTRecordDart = void Function(
|
|||||||
typedef _RoutingContextGetDHTValueDart = void Function(
|
typedef _RoutingContextGetDHTValueDart = void Function(
|
||||||
int, int, Pointer<Utf8>, int, bool);
|
int, int, Pointer<Utf8>, int, bool);
|
||||||
// fn routing_context_set_dht_value(port: i64,
|
// fn routing_context_set_dht_value(port: i64,
|
||||||
// id: u32, key: FfiStr, subkey: u32, data: FfiStr)
|
// id: u32, key: FfiStr, subkey: u32, data: FfiStr, writer: FfiStr)
|
||||||
typedef _RoutingContextSetDHTValueDart = void Function(
|
typedef _RoutingContextSetDHTValueDart = void Function(
|
||||||
int, int, Pointer<Utf8>, int, Pointer<Utf8>);
|
int, int, Pointer<Utf8>, int, Pointer<Utf8>, Pointer<Utf8>);
|
||||||
// fn routing_context_watch_dht_values(port: i64,
|
// fn routing_context_watch_dht_values(port: i64,
|
||||||
// id: u32, key: FfiStr, subkeys: FfiStr, expiration: FfiStr, count: u32)
|
// id: u32, key: FfiStr, subkeys: FfiStr, expiration: FfiStr, count: u32)
|
||||||
typedef _RoutingContextWatchDHTValuesDart = void Function(
|
typedef _RoutingContextWatchDHTValuesDart = void Function(
|
||||||
@ -603,8 +603,8 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DHTRecordDescriptor> openDHTRecord(
|
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key,
|
||||||
TypedKey key, KeyPair? writer) async {
|
{KeyPair? writer}) async {
|
||||||
_ctx.ensureValid();
|
_ctx.ensureValid();
|
||||||
final nativeKey = jsonEncode(key).toNativeUtf8();
|
final nativeKey = jsonEncode(key).toNativeUtf8();
|
||||||
final nativeWriter =
|
final nativeWriter =
|
||||||
@ -641,8 +641,8 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ValueData?> getDHTValue(
|
Future<ValueData?> getDHTValue(TypedKey key, int subkey,
|
||||||
TypedKey key, int subkey, bool forceRefresh) async {
|
{bool forceRefresh = false}) async {
|
||||||
_ctx.ensureValid();
|
_ctx.ensureValid();
|
||||||
final nativeKey = jsonEncode(key).toNativeUtf8();
|
final nativeKey = jsonEncode(key).toNativeUtf8();
|
||||||
final recvPort = ReceivePort('routing_context_get_dht_value');
|
final recvPort = ReceivePort('routing_context_get_dht_value');
|
||||||
@ -655,16 +655,18 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ValueData?> setDHTValue(
|
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||||
TypedKey key, int subkey, Uint8List data) async {
|
{KeyPair? writer}) async {
|
||||||
_ctx.ensureValid();
|
_ctx.ensureValid();
|
||||||
final nativeKey = jsonEncode(key).toNativeUtf8();
|
final nativeKey = jsonEncode(key).toNativeUtf8();
|
||||||
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
|
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
|
||||||
|
final nativeWriter =
|
||||||
|
writer != null ? jsonEncode(writer).toNativeUtf8() : nullptr;
|
||||||
|
|
||||||
final recvPort = ReceivePort('routing_context_set_dht_value');
|
final recvPort = ReceivePort('routing_context_set_dht_value');
|
||||||
final sendPort = recvPort.sendPort;
|
final sendPort = recvPort.sendPort;
|
||||||
_ctx.ffi._routingContextSetDHTValue(
|
_ctx.ffi._routingContextSetDHTValue(sendPort.nativePort, _ctx.id!,
|
||||||
sendPort.nativePort, _ctx.id!, nativeKey, subkey, nativeData);
|
nativeKey, subkey, nativeData, nativeWriter);
|
||||||
final valueData =
|
final valueData =
|
||||||
await processFutureOptJson(ValueData.fromJson, recvPort.first);
|
await processFutureOptJson(ValueData.fromJson, recvPort.first);
|
||||||
return valueData;
|
return valueData;
|
||||||
@ -1236,7 +1238,8 @@ class VeilidFFI extends Veilid {
|
|||||||
Void Function(Int64, Uint32, Pointer<Utf8>, Uint32, Bool),
|
Void Function(Int64, Uint32, Pointer<Utf8>, Uint32, Bool),
|
||||||
_RoutingContextGetDHTValueDart>('routing_context_get_dht_value'),
|
_RoutingContextGetDHTValueDart>('routing_context_get_dht_value'),
|
||||||
_routingContextSetDHTValue = dylib.lookupFunction<
|
_routingContextSetDHTValue = dylib.lookupFunction<
|
||||||
Void Function(Int64, Uint32, Pointer<Utf8>, Uint32, Pointer<Utf8>),
|
Void Function(Int64, Uint32, Pointer<Utf8>, Uint32, Pointer<Utf8>,
|
||||||
|
Pointer<Utf8>),
|
||||||
_RoutingContextSetDHTValueDart>('routing_context_set_dht_value'),
|
_RoutingContextSetDHTValueDart>('routing_context_set_dht_value'),
|
||||||
_routingContextWatchDHTValues = dylib.lookupFunction<
|
_routingContextWatchDHTValues = dylib.lookupFunction<
|
||||||
Void Function(Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>,
|
Void Function(Int64, Uint32, Pointer<Utf8>, Pointer<Utf8>,
|
||||||
|
@ -129,8 +129,8 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DHTRecordDescriptor> openDHTRecord(
|
Future<DHTRecordDescriptor> openDHTRecord(TypedKey key,
|
||||||
TypedKey key, KeyPair? writer) async {
|
{KeyPair? writer}) async {
|
||||||
final id = _ctx.requireId();
|
final id = _ctx.requireId();
|
||||||
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
|
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
|
||||||
.callMethod(wasm, 'routing_context_open_dht_record', [
|
.callMethod(wasm, 'routing_context_open_dht_record', [
|
||||||
@ -155,8 +155,8 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ValueData?> getDHTValue(
|
Future<ValueData?> getDHTValue(TypedKey key, int subkey,
|
||||||
TypedKey key, int subkey, bool forceRefresh) async {
|
{bool forceRefresh = false}) async {
|
||||||
final id = _ctx.requireId();
|
final id = _ctx.requireId();
|
||||||
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
|
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
|
||||||
wasm,
|
wasm,
|
||||||
@ -170,13 +170,17 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ValueData?> setDHTValue(
|
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||||
TypedKey key, int subkey, Uint8List data) async {
|
{KeyPair? writer}) async {
|
||||||
final id = _ctx.requireId();
|
final id = _ctx.requireId();
|
||||||
final opt = await _wrapApiPromise<String?>(js_util.callMethod(
|
final opt = await _wrapApiPromise<String?>(
|
||||||
wasm,
|
js_util.callMethod(wasm, 'routing_context_set_dht_value', [
|
||||||
'routing_context_set_dht_value',
|
id,
|
||||||
[id, jsonEncode(key), subkey, base64UrlNoPadEncode(data)]));
|
jsonEncode(key),
|
||||||
|
subkey,
|
||||||
|
base64UrlNoPadEncode(data),
|
||||||
|
if (writer != null) jsonEncode(writer) else null
|
||||||
|
]));
|
||||||
if (opt == null) {
|
if (opt == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -667,12 +667,16 @@ pub extern "C" fn routing_context_set_dht_value(
|
|||||||
key: FfiStr,
|
key: FfiStr,
|
||||||
subkey: u32,
|
subkey: u32,
|
||||||
data: FfiStr,
|
data: FfiStr,
|
||||||
|
writer: FfiStr,
|
||||||
) {
|
) {
|
||||||
let key: veilid_core::TypedKey =
|
let key: veilid_core::TypedKey =
|
||||||
veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap();
|
veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap();
|
||||||
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
.decode(data.into_opt_string().unwrap().as_bytes())
|
.decode(data.into_opt_string().unwrap().as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let writer: Option<veilid_core::KeyPair> = writer
|
||||||
|
.into_opt_string()
|
||||||
|
.map(|s| veilid_core::deserialize_json(&s).unwrap());
|
||||||
|
|
||||||
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
DartIsolateWrapper::new(port).spawn_result_json(async move {
|
||||||
let routing_context = {
|
let routing_context = {
|
||||||
@ -686,7 +690,9 @@ pub extern "C" fn routing_context_set_dht_value(
|
|||||||
};
|
};
|
||||||
routing_context.clone()
|
routing_context.clone()
|
||||||
};
|
};
|
||||||
let res = routing_context.set_dht_value(key, subkey, data).await?;
|
let res = routing_context
|
||||||
|
.set_dht_value(key, subkey, data, writer)
|
||||||
|
.await?;
|
||||||
APIResult::Ok(res)
|
APIResult::Ok(res)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ class RoutingContext(ABC):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def set_dht_value(
|
async def set_dht_value(
|
||||||
self, key: types.TypedKey, subkey: types.ValueSubkey, data: bytes
|
self, key: types.TypedKey, subkey: types.ValueSubkey, data: bytes, writer: Optional[types.KeyPair]
|
||||||
) -> Optional[types.ValueData]:
|
) -> Optional[types.ValueData]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -626,7 +626,7 @@ class _JsonRoutingContext(RoutingContext):
|
|||||||
return None if ret is None else ValueData.from_json(ret)
|
return None if ret is None else ValueData.from_json(ret)
|
||||||
|
|
||||||
async def set_dht_value(
|
async def set_dht_value(
|
||||||
self, key: TypedKey, subkey: ValueSubkey, data: bytes
|
self, key: TypedKey, subkey: ValueSubkey, data: bytes, writer: Optional[KeyPair]
|
||||||
) -> Optional[ValueData]:
|
) -> Optional[ValueData]:
|
||||||
ret = raise_api_result(
|
ret = raise_api_result(
|
||||||
await self.api.send_ndjson_request(
|
await self.api.send_ndjson_request(
|
||||||
@ -637,6 +637,7 @@ class _JsonRoutingContext(RoutingContext):
|
|||||||
key=key,
|
key=key,
|
||||||
subkey=subkey,
|
subkey=subkey,
|
||||||
data=data,
|
data=data,
|
||||||
|
writer=writer,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return None if ret is None else ValueData.from_json(ret)
|
return None if ret is None else ValueData.from_json(ret)
|
||||||
|
@ -451,6 +451,12 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "uint32",
|
"format": "uint32",
|
||||||
"minimum": 0.0
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"writer": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -581,11 +581,19 @@ pub fn routing_context_get_dht_value(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen()]
|
#[wasm_bindgen()]
|
||||||
pub fn routing_context_set_dht_value(id: u32, key: String, subkey: u32, data: String) -> Promise {
|
pub fn routing_context_set_dht_value(
|
||||||
|
id: u32,
|
||||||
|
key: String,
|
||||||
|
subkey: u32,
|
||||||
|
data: String,
|
||||||
|
writer: Option<String>,
|
||||||
|
) -> Promise {
|
||||||
let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
|
||||||
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||||
.decode(data.as_bytes())
|
.decode(data.as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let writer: Option<veilid_core::KeyPair> =
|
||||||
|
writer.map(|s| veilid_core::deserialize_json(&s).unwrap());
|
||||||
|
|
||||||
wrap_api_future_json(async move {
|
wrap_api_future_json(async move {
|
||||||
let routing_context = {
|
let routing_context = {
|
||||||
@ -599,7 +607,9 @@ pub fn routing_context_set_dht_value(id: u32, key: String, subkey: u32, data: St
|
|||||||
};
|
};
|
||||||
routing_context.clone()
|
routing_context.clone()
|
||||||
};
|
};
|
||||||
let res = routing_context.set_dht_value(key, subkey, data).await?;
|
let res = routing_context
|
||||||
|
.set_dht_value(key, subkey, data, writer)
|
||||||
|
.await?;
|
||||||
APIResult::Ok(res)
|
APIResult::Ok(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -285,12 +285,18 @@ impl VeilidRoutingContext {
|
|||||||
key: String,
|
key: String,
|
||||||
subKey: u32,
|
subKey: u32,
|
||||||
data: Box<[u8]>,
|
data: Box<[u8]>,
|
||||||
|
writer: Option<String>,
|
||||||
) -> APIResult<Option<ValueData>> {
|
) -> APIResult<Option<ValueData>> {
|
||||||
let key = TypedKey::from_str(&key)?;
|
let key = TypedKey::from_str(&key)?;
|
||||||
let data = data.into_vec();
|
let data = data.into_vec();
|
||||||
|
let writer = writer
|
||||||
|
.map(|writer| KeyPair::from_str(&writer))
|
||||||
|
.map_or(APIResult::Ok(None), |r| r.map(Some))?;
|
||||||
|
|
||||||
let routing_context = self.getRoutingContext()?;
|
let routing_context = self.getRoutingContext()?;
|
||||||
let res = routing_context.set_dht_value(key, subKey, data).await?;
|
let res = routing_context
|
||||||
|
.set_dht_value(key, subKey, data, writer)
|
||||||
|
.await?;
|
||||||
APIResult::Ok(res)
|
APIResult::Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
veilid-wasm/tests/package-lock.json
generated
18
veilid-wasm/tests/package-lock.json
generated
@ -4726,9 +4726,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ip": {
|
"node_modules/ip": {
|
||||||
"version": "1.1.8",
|
"version": "1.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
|
||||||
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==",
|
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
@ -7836,9 +7836,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socks/node_modules/ip": {
|
"node_modules/socks/node_modules/ip": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
||||||
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
|
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
@ -8489,9 +8489,9 @@
|
|||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
|
@ -167,6 +167,31 @@ describe('VeilidRoutingContext', () => {
|
|||||||
);
|
);
|
||||||
expect(setValueRes).toBeUndefined();
|
expect(setValueRes).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should open readonly record and specify writer during the set', async () => {
|
||||||
|
await routingContext.closeDhtRecord(dhtRecord.key);
|
||||||
|
|
||||||
|
const writeableDhtRecord = await routingContext.openDhtRecord(
|
||||||
|
dhtRecord.key,
|
||||||
|
);
|
||||||
|
expect(writeableDhtRecord).toBeDefined();
|
||||||
|
const setValueResFail = routingContext.setDhtValue(
|
||||||
|
dhtRecord.key,
|
||||||
|
0,
|
||||||
|
textEncoder.encode(`${data}👋`),
|
||||||
|
);
|
||||||
|
await expect(setValueResFail).rejects.toEqual({
|
||||||
|
kind: 'Generic',
|
||||||
|
message: 'value is not writable',
|
||||||
|
});
|
||||||
|
const setValueRes = await routingContext.setDhtValue(
|
||||||
|
dhtRecord.key,
|
||||||
|
0,
|
||||||
|
textEncoder.encode(`${data}👋`),
|
||||||
|
`${dhtRecord.owner}:${dhtRecord.owner_secret}`
|
||||||
|
);
|
||||||
|
expect(setValueRes).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user