From 0c3271b3b97d76cbbe5e7a054b1f885b5a2b9028 Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Wed, 21 Feb 2024 20:18:07 -0500 Subject: [PATCH] add writer to set_dht_value, allow multiple open_dht_record --- veilid-core/src/storage_manager/mod.rs | 4 +++ .../storage_manager/storage_manager_inner.rs | 5 ---- .../storage_manager/types/opened_record.rs | 6 +++++ veilid-core/src/tests/common/test_dht.rs | 24 +++++++++++------- veilid-core/src/veilid_api/debug.rs | 7 +++++- .../src/veilid_api/json_api/process.rs | 19 ++++++++------ .../veilid_api/json_api/routing_context.rs | 2 ++ veilid-core/src/veilid_api/routing_context.rs | 19 ++++++++++---- veilid-flutter/lib/routing_context.dart | 8 +++--- veilid-flutter/lib/veilid_ffi.dart | 25 +++++++++++-------- veilid-flutter/lib/veilid_js.dart | 24 ++++++++++-------- veilid-flutter/rust/src/dart_ffi.rs | 8 +++++- veilid-python/veilid/api.py | 2 +- veilid-python/veilid/json_api.py | 3 ++- veilid-python/veilid/schema/Request.json | 6 +++++ veilid-wasm/src/lib.rs | 14 +++++++++-- veilid-wasm/src/veilid_routing_context_js.rs | 8 +++++- veilid-wasm/tests/package-lock.json | 18 ++++++------- .../tests/src/VeilidRoutingContext.test.ts | 25 +++++++++++++++++++ 19 files changed, 161 insertions(+), 66 deletions(-) diff --git a/veilid-core/src/storage_manager/mod.rs b/veilid-core/src/storage_manager/mod.rs index 60ae420d..a5be155c 100644 --- a/veilid-core/src/storage_manager/mod.rs +++ b/veilid-core/src/storage_manager/mod.rs @@ -433,6 +433,7 @@ impl StorageManager { key: TypedKey, subkey: ValueSubkey, data: Vec, + writer: Option, ) -> VeilidAPIResult> { 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 let Some(writer) = opt_writer else { apibail_generic!("value is not writable"); diff --git a/veilid-core/src/storage_manager/storage_manager_inner.rs b/veilid-core/src/storage_manager/storage_manager_inner.rs index 0d78a90a..0c111ed3 100644 --- a/veilid-core/src/storage_manager/storage_manager_inner.rs +++ b/veilid-core/src/storage_manager/storage_manager_inner.rs @@ -308,11 +308,6 @@ impl StorageManagerInner { writer: Option, safety_selection: SafetySelection, ) -> VeilidAPIResult> { - // 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 let Some(local_record_store) = self.local_record_store.as_mut() else { apibail_not_initialized!(); diff --git a/veilid-core/src/storage_manager/types/opened_record.rs b/veilid-core/src/storage_manager/types/opened_record.rs index 831b74fc..edd4bad2 100644 --- a/veilid-core/src/storage_manager/types/opened_record.rs +++ b/veilid-core/src/storage_manager/types/opened_record.rs @@ -42,10 +42,16 @@ impl OpenedRecord { pub fn writer(&self) -> Option<&KeyPair> { self.writer.as_ref() } + // pub fn set_writer(&mut self, writer: Option) { + // self.writer = writer; + // } pub fn safety_selection(&self) -> SafetySelection { 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) { self.active_watch = Some(active_watch); diff --git a/veilid-core/src/tests/common/test_dht.rs b/veilid-core/src/tests/common/test_dht.rs index 6c796ea3..3273c4d6 100644 --- a/veilid-core/src/tests/common/test_dht.rs +++ b/veilid-core/src/tests/common/test_dht.rs @@ -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(); // 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); 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 // 6. Read data from subkey 1 with force_refresh, check data // 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()); 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 ); - 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()); 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 ); - 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()); - 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()); // 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 - 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()); let vdtemp = set_dht_test_value_1_result.unwrap().unwrap(); 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); // 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()); // 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 - 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); // 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); rc.close_dht_record(key).await.unwrap(); diff --git a/veilid-core/src/veilid_api/debug.rs b/veilid-core/src/veilid_api/debug.rs index 0fc13136..1d54362c 100644 --- a/veilid-core/src/veilid_api/debug.rs +++ b/veilid-core/src/veilid_api/debug.rs @@ -1517,9 +1517,14 @@ impl VeilidAPI { 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 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 - 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) => { return Ok(format!("Can't set DHT value: {}", e)); } diff --git a/veilid-core/src/veilid_api/json_api/process.rs b/veilid-core/src/veilid_api/json_api/process.rs index f12ef6b6..19c783d7 100644 --- a/veilid-core/src/veilid_api/json_api/process.rs +++ b/veilid-core/src/veilid_api/json_api/process.rs @@ -323,13 +323,18 @@ impl JsonRequestProcessor { .await, ), }, - RoutingContextRequestOp::SetDhtValue { key, subkey, data } => { - RoutingContextResponseOp::SetDhtValue { - result: to_json_api_result( - routing_context.set_dht_value(key, subkey, data).await, - ), - } - } + RoutingContextRequestOp::SetDhtValue { + key, + subkey, + data, + writer, + } => RoutingContextResponseOp::SetDhtValue { + result: to_json_api_result( + routing_context + .set_dht_value(key, subkey, data, writer) + .await, + ), + }, RoutingContextRequestOp::WatchDhtValues { key, subkeys, diff --git a/veilid-core/src/veilid_api/json_api/routing_context.rs b/veilid-core/src/veilid_api/json_api/routing_context.rs index 5c8c2c41..a2643f6e 100644 --- a/veilid-core/src/veilid_api/json_api/routing_context.rs +++ b/veilid-core/src/veilid_api/json_api/routing_context.rs @@ -70,6 +70,8 @@ pub enum RoutingContextRequestOp { #[serde(with = "as_human_base64")] #[schemars(with = "String")] data: Vec, + #[schemars(with = "Option")] + writer: Option, }, WatchDhtValues { #[schemars(with = "String")] diff --git a/veilid-core/src/veilid_api/routing_context.rs b/veilid-core/src/veilid_api/routing_context.rs index 06931c5d..3fdb967e 100644 --- a/veilid-core/src/veilid_api/routing_context.rs +++ b/veilid-core/src/veilid_api/routing_context.rs @@ -215,19 +215,24 @@ impl RoutingContext { /// Opens a DHT record at a specific key /// - /// Associates a secret if one is provided to provide writer capability. - /// Records may only be opened or created. To re-open with a different routing context, first close the value. + /// Associates a 'default_writer' secret if one is provided to provide writer capability. The + /// 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 pub async fn open_dht_record( &self, key: TypedKey, - writer: Option, + default_writer: Option, ) -> VeilidAPIResult { Crypto::validate_crypto_kind(key.kind)?; let storage_manager = self.api.storage_manager()?; storage_manager - .open_record(key, writer, self.unlocked_inner.safety_selection) + .open_record(key, default_writer, self.unlocked_inner.safety_selection) .await } @@ -269,6 +274,9 @@ impl RoutingContext { } /// 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 `Some(data)` if the value put was older than the one available on the network @@ -277,10 +285,11 @@ impl RoutingContext { key: TypedKey, subkey: ValueSubkey, data: Vec, + writer: Option, ) -> VeilidAPIResult> { Crypto::validate_crypto_kind(key.kind)?; 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. diff --git a/veilid-flutter/lib/routing_context.dart b/veilid-flutter/lib/routing_context.dart index cf6e8081..996408ac 100644 --- a/veilid-flutter/lib/routing_context.dart +++ b/veilid-flutter/lib/routing_context.dart @@ -312,11 +312,13 @@ abstract class VeilidRoutingContext { // DHT Operations Future createDHTRecord(DHTSchema schema, {CryptoKind kind = 0}); - Future openDHTRecord(TypedKey key, KeyPair? writer); + Future openDHTRecord(TypedKey key, {KeyPair? writer}); Future closeDHTRecord(TypedKey key); Future deleteDHTRecord(TypedKey key); - Future getDHTValue(TypedKey key, int subkey, bool forceRefresh); - Future setDHTValue(TypedKey key, int subkey, Uint8List data); + Future getDHTValue(TypedKey key, int subkey, + {bool forceRefresh = false}); + Future setDHTValue(TypedKey key, int subkey, Uint8List data, + {KeyPair? writer}); Future watchDHTValues(TypedKey key, {List? subkeys, Timestamp? expiration, int? count}); Future cancelDHTWatch(TypedKey key, {List? subkeys}); diff --git a/veilid-flutter/lib/veilid_ffi.dart b/veilid-flutter/lib/veilid_ffi.dart index ecac809f..37a0bc61 100644 --- a/veilid-flutter/lib/veilid_ffi.dart +++ b/veilid-flutter/lib/veilid_ffi.dart @@ -81,9 +81,9 @@ typedef _RoutingContextDeleteDHTRecordDart = void Function( typedef _RoutingContextGetDHTValueDart = void Function( int, int, Pointer, int, bool); // 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( - int, int, Pointer, int, Pointer); + int, int, Pointer, int, Pointer, Pointer); // fn routing_context_watch_dht_values(port: i64, // id: u32, key: FfiStr, subkeys: FfiStr, expiration: FfiStr, count: u32) typedef _RoutingContextWatchDHTValuesDart = void Function( @@ -603,8 +603,8 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext { } @override - Future openDHTRecord( - TypedKey key, KeyPair? writer) async { + Future openDHTRecord(TypedKey key, + {KeyPair? writer}) async { _ctx.ensureValid(); final nativeKey = jsonEncode(key).toNativeUtf8(); final nativeWriter = @@ -641,8 +641,8 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext { } @override - Future getDHTValue( - TypedKey key, int subkey, bool forceRefresh) async { + Future getDHTValue(TypedKey key, int subkey, + {bool forceRefresh = false}) async { _ctx.ensureValid(); final nativeKey = jsonEncode(key).toNativeUtf8(); final recvPort = ReceivePort('routing_context_get_dht_value'); @@ -655,16 +655,18 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext { } @override - Future setDHTValue( - TypedKey key, int subkey, Uint8List data) async { + Future setDHTValue(TypedKey key, int subkey, Uint8List data, + {KeyPair? writer}) async { _ctx.ensureValid(); final nativeKey = jsonEncode(key).toNativeUtf8(); final nativeData = base64UrlNoPadEncode(data).toNativeUtf8(); + final nativeWriter = + writer != null ? jsonEncode(writer).toNativeUtf8() : nullptr; final recvPort = ReceivePort('routing_context_set_dht_value'); final sendPort = recvPort.sendPort; - _ctx.ffi._routingContextSetDHTValue( - sendPort.nativePort, _ctx.id!, nativeKey, subkey, nativeData); + _ctx.ffi._routingContextSetDHTValue(sendPort.nativePort, _ctx.id!, + nativeKey, subkey, nativeData, nativeWriter); final valueData = await processFutureOptJson(ValueData.fromJson, recvPort.first); return valueData; @@ -1236,7 +1238,8 @@ class VeilidFFI extends Veilid { Void Function(Int64, Uint32, Pointer, Uint32, Bool), _RoutingContextGetDHTValueDart>('routing_context_get_dht_value'), _routingContextSetDHTValue = dylib.lookupFunction< - Void Function(Int64, Uint32, Pointer, Uint32, Pointer), + Void Function(Int64, Uint32, Pointer, Uint32, Pointer, + Pointer), _RoutingContextSetDHTValueDart>('routing_context_set_dht_value'), _routingContextWatchDHTValues = dylib.lookupFunction< Void Function(Int64, Uint32, Pointer, Pointer, diff --git a/veilid-flutter/lib/veilid_js.dart b/veilid-flutter/lib/veilid_js.dart index 7cbd345b..2418d5e0 100644 --- a/veilid-flutter/lib/veilid_js.dart +++ b/veilid-flutter/lib/veilid_js.dart @@ -129,8 +129,8 @@ class VeilidRoutingContextJS extends VeilidRoutingContext { } @override - Future openDHTRecord( - TypedKey key, KeyPair? writer) async { + Future openDHTRecord(TypedKey key, + {KeyPair? writer}) async { final id = _ctx.requireId(); return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util .callMethod(wasm, 'routing_context_open_dht_record', [ @@ -155,8 +155,8 @@ class VeilidRoutingContextJS extends VeilidRoutingContext { } @override - Future getDHTValue( - TypedKey key, int subkey, bool forceRefresh) async { + Future getDHTValue(TypedKey key, int subkey, + {bool forceRefresh = false}) async { final id = _ctx.requireId(); final opt = await _wrapApiPromise(js_util.callMethod( wasm, @@ -170,13 +170,17 @@ class VeilidRoutingContextJS extends VeilidRoutingContext { } @override - Future setDHTValue( - TypedKey key, int subkey, Uint8List data) async { + Future setDHTValue(TypedKey key, int subkey, Uint8List data, + {KeyPair? writer}) async { final id = _ctx.requireId(); - final opt = await _wrapApiPromise(js_util.callMethod( - wasm, - 'routing_context_set_dht_value', - [id, jsonEncode(key), subkey, base64UrlNoPadEncode(data)])); + final opt = await _wrapApiPromise( + js_util.callMethod(wasm, 'routing_context_set_dht_value', [ + id, + jsonEncode(key), + subkey, + base64UrlNoPadEncode(data), + if (writer != null) jsonEncode(writer) else null + ])); if (opt == null) { return null; } diff --git a/veilid-flutter/rust/src/dart_ffi.rs b/veilid-flutter/rust/src/dart_ffi.rs index 350ec2f2..6d426ba4 100644 --- a/veilid-flutter/rust/src/dart_ffi.rs +++ b/veilid-flutter/rust/src/dart_ffi.rs @@ -667,12 +667,16 @@ pub extern "C" fn routing_context_set_dht_value( key: FfiStr, subkey: u32, data: FfiStr, + writer: FfiStr, ) { let key: veilid_core::TypedKey = veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap(); let data: Vec = data_encoding::BASE64URL_NOPAD .decode(data.into_opt_string().unwrap().as_bytes()) .unwrap(); + let writer: Option = writer + .into_opt_string() + .map(|s| veilid_core::deserialize_json(&s).unwrap()); DartIsolateWrapper::new(port).spawn_result_json(async move { let routing_context = { @@ -686,7 +690,9 @@ pub extern "C" fn routing_context_set_dht_value( }; 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) }); } diff --git a/veilid-python/veilid/api.py b/veilid-python/veilid/api.py index ea376119..8e6ab1cf 100644 --- a/veilid-python/veilid/api.py +++ b/veilid-python/veilid/api.py @@ -75,7 +75,7 @@ class RoutingContext(ABC): @abstractmethod 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]: pass diff --git a/veilid-python/veilid/json_api.py b/veilid-python/veilid/json_api.py index 748da356..e143a10f 100644 --- a/veilid-python/veilid/json_api.py +++ b/veilid-python/veilid/json_api.py @@ -626,7 +626,7 @@ class _JsonRoutingContext(RoutingContext): return None if ret is None else ValueData.from_json(ret) async def set_dht_value( - self, key: TypedKey, subkey: ValueSubkey, data: bytes + self, key: TypedKey, subkey: ValueSubkey, data: bytes, writer: Optional[KeyPair] ) -> Optional[ValueData]: ret = raise_api_result( await self.api.send_ndjson_request( @@ -637,6 +637,7 @@ class _JsonRoutingContext(RoutingContext): key=key, subkey=subkey, data=data, + writer=writer, ) ) return None if ret is None else ValueData.from_json(ret) diff --git a/veilid-python/veilid/schema/Request.json b/veilid-python/veilid/schema/Request.json index 4fe0b117..2e9ff5cb 100644 --- a/veilid-python/veilid/schema/Request.json +++ b/veilid-python/veilid/schema/Request.json @@ -451,6 +451,12 @@ "type": "integer", "format": "uint32", "minimum": 0.0 + }, + "writer": { + "type": [ + "string", + "null" + ] } } }, diff --git a/veilid-wasm/src/lib.rs b/veilid-wasm/src/lib.rs index 3e72be6c..4ebd2cff 100644 --- a/veilid-wasm/src/lib.rs +++ b/veilid-wasm/src/lib.rs @@ -581,11 +581,19 @@ pub fn routing_context_get_dht_value( } #[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, +) -> Promise { let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap(); let data: Vec = data_encoding::BASE64URL_NOPAD .decode(data.as_bytes()) .unwrap(); + let writer: Option = + writer.map(|s| veilid_core::deserialize_json(&s).unwrap()); wrap_api_future_json(async move { 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() }; - 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) }) } diff --git a/veilid-wasm/src/veilid_routing_context_js.rs b/veilid-wasm/src/veilid_routing_context_js.rs index 362fe65a..cd78b5ee 100644 --- a/veilid-wasm/src/veilid_routing_context_js.rs +++ b/veilid-wasm/src/veilid_routing_context_js.rs @@ -285,12 +285,18 @@ impl VeilidRoutingContext { key: String, subKey: u32, data: Box<[u8]>, + writer: Option, ) -> APIResult> { let key = TypedKey::from_str(&key)?; 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 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) } diff --git a/veilid-wasm/tests/package-lock.json b/veilid-wasm/tests/package-lock.json index 34ec1655..a0082466 100644 --- a/veilid-wasm/tests/package-lock.json +++ b/veilid-wasm/tests/package-lock.json @@ -4726,9 +4726,9 @@ } }, "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true }, "node_modules/is-arguments": { @@ -7836,9 +7836,9 @@ } }, "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", "dev": true }, "node_modules/source-map": { @@ -8489,9 +8489,9 @@ "link": true }, "node_modules/vite": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", - "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/veilid-wasm/tests/src/VeilidRoutingContext.test.ts b/veilid-wasm/tests/src/VeilidRoutingContext.test.ts index c7b7e55b..06418119 100644 --- a/veilid-wasm/tests/src/VeilidRoutingContext.test.ts +++ b/veilid-wasm/tests/src/VeilidRoutingContext.test.ts @@ -167,6 +167,31 @@ describe('VeilidRoutingContext', () => { ); 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(); + }); }); }); });