mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-07-27 17:05:27 -04:00
allow_offline flag for set_dht_value
This commit is contained in:
parent
eda436f264
commit
b7d725ab12
36 changed files with 751 additions and 98 deletions
|
@ -1,5 +1,11 @@
|
|||
**UNRELEASED**
|
||||
|
||||
- _BREAKING API CHANGES_:
|
||||
- set_dht_value now accepts a new flag called `allow_offline`, which defaults to `true`.
|
||||
- The previous `writer: Option<KeyPair>` argument position is now `options: Option<SetDHTValueOptions>`
|
||||
- This will only be a breaking change for anyone utilizing the previous `writer` argument.
|
||||
- `writer` is now a member of `SetDHTValueOptions`, alongside the new `allow_offline` property.
|
||||
|
||||
- veilid-core:
|
||||
- Add private route example
|
||||
- Add `require_inbound_relay` option in VeilidConfig. Default is false, but if enabled, forces OutboundOnly/InboundRelay mode. Can be used as an extra layer of IP address obscurity for some threat models. (@neequ57)
|
||||
|
|
|
@ -145,11 +145,11 @@ impl StorageManager {
|
|||
};
|
||||
|
||||
// Validate with schema
|
||||
if !schema.check_subkey_value_data(
|
||||
if schema.check_subkey_value_data(
|
||||
descriptor.owner(),
|
||||
subkey,
|
||||
value.value_data(),
|
||||
) {
|
||||
).is_err() {
|
||||
// Validation failed, ignore this value
|
||||
// Move to the next node
|
||||
return Ok(FanoutCallOutput{peer_info_list: vec![], disposition: FanoutCallDisposition::Invalid});
|
||||
|
|
|
@ -727,7 +727,7 @@ impl StorageManager {
|
|||
record_key: TypedRecordKey,
|
||||
subkey: ValueSubkey,
|
||||
data: Vec<u8>,
|
||||
writer: Option<KeyPair>,
|
||||
options: Option<SetDHTValueOptions>,
|
||||
) -> VeilidAPIResult<Option<ValueData>> {
|
||||
let mut inner = self.inner.lock().await;
|
||||
|
||||
|
@ -748,7 +748,11 @@ 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);
|
||||
let opt_writer = options.as_ref().and_then(|o| o.writer).or(opt_writer);
|
||||
let allow_offline = options
|
||||
.unwrap_or_default()
|
||||
.allow_offline
|
||||
.unwrap_or_default();
|
||||
|
||||
// If we don't have a writer then we can't write
|
||||
let Some(writer) = opt_writer else {
|
||||
|
@ -781,9 +785,13 @@ impl StorageManager {
|
|||
};
|
||||
|
||||
// Validate with schema
|
||||
if !schema.check_subkey_value_data(descriptor.owner(), subkey, &value_data) {
|
||||
if let Err(e) = schema.check_subkey_value_data(descriptor.owner(), subkey, &value_data) {
|
||||
veilid_log!(self debug "schema validation error: {}", e);
|
||||
// Validation failed, ignore this value
|
||||
apibail_generic!("failed schema validation");
|
||||
apibail_generic!(format!(
|
||||
"failed schema validation: {}:{}",
|
||||
record_key, subkey
|
||||
));
|
||||
}
|
||||
|
||||
// Sign the new value data with the writer
|
||||
|
@ -821,10 +829,19 @@ impl StorageManager {
|
|||
};
|
||||
|
||||
if already_writing || !self.dht_is_online() {
|
||||
if allow_offline == AllowOffline(true) {
|
||||
veilid_log!(self debug "Writing subkey offline: {}:{} len={}", record_key, subkey, signed_value_data.value_data().data().len() );
|
||||
// Add to offline writes to flush
|
||||
Self::add_offline_subkey_write_inner(&mut inner, record_key, subkey, safety_selection);
|
||||
Self::add_offline_subkey_write_inner(
|
||||
&mut inner,
|
||||
record_key,
|
||||
subkey,
|
||||
safety_selection,
|
||||
);
|
||||
return Ok(None);
|
||||
} else {
|
||||
apibail_try_again!("offline, try again later");
|
||||
}
|
||||
};
|
||||
|
||||
// Drop the lock for network access
|
||||
|
@ -847,12 +864,17 @@ impl StorageManager {
|
|||
Err(e) => {
|
||||
// Failed to write, try again later
|
||||
let mut inner = self.inner.lock().await;
|
||||
|
||||
if allow_offline == AllowOffline(true) {
|
||||
Self::add_offline_subkey_write_inner(
|
||||
&mut inner,
|
||||
record_key,
|
||||
subkey,
|
||||
safety_selection,
|
||||
);
|
||||
} else {
|
||||
apibail_try_again!("offline, try again later");
|
||||
}
|
||||
|
||||
// Remove from active subkey writes
|
||||
let asw = inner.active_subkey_writes.get_mut(&record_key).unwrap();
|
||||
|
|
|
@ -142,11 +142,11 @@ impl StorageManager {
|
|||
veilid_log!(registry debug "SetValue got value back: len={} seq={}", value.value_data().data().len(), value.value_data().seq());
|
||||
|
||||
// Validate with schema
|
||||
if !ctx.schema.check_subkey_value_data(
|
||||
if ctx.schema.check_subkey_value_data(
|
||||
descriptor.owner(),
|
||||
subkey,
|
||||
value.value_data(),
|
||||
) {
|
||||
).is_err() {
|
||||
// Validation failed, ignore this value and pretend we never saw this node
|
||||
return Ok(FanoutCallOutput{peer_info_list: vec![], disposition: FanoutCallDisposition::Invalid});
|
||||
}
|
||||
|
@ -474,7 +474,10 @@ impl StorageManager {
|
|||
};
|
||||
|
||||
// Validate new value with schema
|
||||
if !schema.check_subkey_value_data(actual_descriptor.owner(), subkey, value.value_data()) {
|
||||
if schema
|
||||
.check_subkey_value_data(actual_descriptor.owner(), subkey, value.value_data())
|
||||
.is_err()
|
||||
{
|
||||
// Validation failed, ignore this value
|
||||
return Ok(NetworkResult::invalid_message("failed schema validation"));
|
||||
}
|
||||
|
|
|
@ -1179,11 +1179,10 @@ impl StorageManager {
|
|||
let schema = descriptor.schema()?;
|
||||
|
||||
// Validate with schema
|
||||
if !schema.check_subkey_value_data(
|
||||
descriptor.owner(),
|
||||
first_subkey,
|
||||
value.value_data(),
|
||||
) {
|
||||
if schema
|
||||
.check_subkey_value_data(descriptor.owner(), first_subkey, value.value_data())
|
||||
.is_err()
|
||||
{
|
||||
// Validation failed, ignore this value
|
||||
// Move to the next node
|
||||
return Ok(NetworkResult::invalid_message(format!(
|
||||
|
|
|
@ -319,7 +319,15 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||
|
||||
// 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))
|
||||
.set_dht_value(
|
||||
key,
|
||||
0,
|
||||
test_value_1.clone(),
|
||||
Some(SetDHTValueOptions {
|
||||
writer: Some(keypair),
|
||||
allow_offline: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
assert!(set_dht_test_value_0_result.is_ok());
|
||||
|
||||
|
@ -327,6 +335,69 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||
rc.delete_dht_record(key).await.unwrap();
|
||||
}
|
||||
|
||||
pub async fn test_set_dht_value_allow_offline(api: VeilidAPI) {
|
||||
let rc = api.routing_context().unwrap();
|
||||
|
||||
// Create a DHT record
|
||||
let rec = rc
|
||||
.create_dht_record(DHTSchema::dflt(1).unwrap(), None, Some(CRYPTO_KIND_VLD0))
|
||||
.await
|
||||
.unwrap();
|
||||
let dht_key = *rec.key();
|
||||
|
||||
let test_value = String::from("Test offline value").as_bytes().to_vec();
|
||||
|
||||
// Test 1: Default behavior (options = None) should allow offline writes
|
||||
let set_result = rc.set_dht_value(dht_key, 0, test_value.clone(), None).await;
|
||||
assert!(set_result.is_ok());
|
||||
|
||||
// Test 2: Default behavior (allow_offline = None) should allow offline writes
|
||||
let set_result = rc
|
||||
.set_dht_value(
|
||||
dht_key,
|
||||
0,
|
||||
test_value.clone(),
|
||||
Some(SetDHTValueOptions {
|
||||
writer: None,
|
||||
allow_offline: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
assert!(set_result.is_ok());
|
||||
|
||||
// Test 3: Explicitly allow offline writes
|
||||
let set_result = rc
|
||||
.set_dht_value(
|
||||
dht_key,
|
||||
1,
|
||||
test_value.clone(),
|
||||
Some(SetDHTValueOptions {
|
||||
writer: None,
|
||||
allow_offline: Some(AllowOffline(true)),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
assert!(set_result.is_ok());
|
||||
|
||||
// Test 4: Disallow offline writes
|
||||
let set_result = rc
|
||||
.set_dht_value(
|
||||
dht_key,
|
||||
2,
|
||||
test_value.clone(),
|
||||
Some(SetDHTValueOptions {
|
||||
writer: None,
|
||||
allow_offline: Some(AllowOffline(false)),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
assert!(set_result.is_err());
|
||||
assert!(set_result.unwrap_err().to_string().contains("offline"));
|
||||
|
||||
rc.close_dht_record(dht_key).await.unwrap();
|
||||
rc.delete_dht_record(dht_key).await.unwrap();
|
||||
}
|
||||
|
||||
// Network-related code to make sure veilid node is connetected to other peers
|
||||
|
||||
async fn wait_for_public_internet_ready(api: &VeilidAPI) {
|
||||
|
@ -364,6 +435,7 @@ pub async fn test_all() {
|
|||
test_create_dht_record_with_owner(api.clone()).await;
|
||||
test_set_get_dht_value(api.clone()).await;
|
||||
test_open_writer_dht_value(api.clone()).await;
|
||||
test_set_dht_value_allow_offline(api.clone()).await;
|
||||
|
||||
api.shutdown().await;
|
||||
}
|
||||
|
|
|
@ -1669,7 +1669,15 @@ impl VeilidAPI {
|
|||
|
||||
// Do a record set
|
||||
let value = match rc
|
||||
.set_dht_value(key, subkey as ValueSubkey, data, writer)
|
||||
.set_dht_value(
|
||||
key,
|
||||
subkey as ValueSubkey,
|
||||
data,
|
||||
Some(SetDHTValueOptions {
|
||||
writer,
|
||||
allow_offline: None,
|
||||
}),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Err(e) => {
|
||||
|
|
|
@ -435,15 +435,15 @@ impl RoutingContext {
|
|||
key: TypedRecordKey,
|
||||
subkey: ValueSubkey,
|
||||
data: Vec<u8>,
|
||||
writer: Option<KeyPair>,
|
||||
options: Option<SetDHTValueOptions>,
|
||||
) -> VeilidAPIResult<Option<ValueData>> {
|
||||
veilid_log!(self debug
|
||||
"RoutingContext::set_dht_value(self: {:?}, key: {:?}, subkey: {:?}, data: len={}, writer: {:?})", self, key, subkey, data.len(), writer);
|
||||
"RoutingContext::set_dht_value(self: {:?}, key: {:?}, subkey: {:?}, data: len={}, options: {:?})", self, key, subkey, data.len(), options);
|
||||
|
||||
Crypto::validate_crypto_kind(key.kind)?;
|
||||
|
||||
let storage_manager = self.api.core_context()?.storage_manager();
|
||||
Box::pin(storage_manager.set_value(key, subkey, data, writer)).await
|
||||
Box::pin(storage_manager.set_value(key, subkey, data, options)).await
|
||||
}
|
||||
|
||||
/// Add or update a watch to a DHT value that informs the user via an VeilidUpdate::ValueChange callback when the record has subkeys change.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mod dht_record_descriptor;
|
||||
mod dht_record_report;
|
||||
mod schema;
|
||||
mod set_dht_value_options;
|
||||
mod value_data;
|
||||
mod value_subkey_range_set;
|
||||
|
||||
|
@ -9,6 +10,7 @@ use super::*;
|
|||
pub use dht_record_descriptor::*;
|
||||
pub use dht_record_report::*;
|
||||
pub use schema::*;
|
||||
pub use set_dht_value_options::*;
|
||||
pub use value_data::*;
|
||||
pub use value_subkey_range_set::*;
|
||||
|
||||
|
|
|
@ -62,13 +62,12 @@ impl DHTSchemaDFLT {
|
|||
}
|
||||
|
||||
/// Check a subkey value data against the schema
|
||||
#[must_use]
|
||||
pub fn check_subkey_value_data(
|
||||
&self,
|
||||
owner: &PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
value_data: &ValueData,
|
||||
) -> bool {
|
||||
) -> VeilidAPIResult<()> {
|
||||
let subkey = subkey as usize;
|
||||
|
||||
// Check if subkey is in owner range
|
||||
|
@ -80,19 +79,27 @@ impl DHTSchemaDFLT {
|
|||
|
||||
// Ensure value size is within additional limit
|
||||
if value_data.data_size() <= max_value_len {
|
||||
return true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Value too big
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"value too big",
|
||||
"data",
|
||||
format!("{:?}", value_data.data())
|
||||
);
|
||||
}
|
||||
|
||||
// Wrong writer
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"wrong writer",
|
||||
"writer",
|
||||
format!("{:?}", value_data.writer())
|
||||
);
|
||||
}
|
||||
|
||||
// Subkey out of range
|
||||
false
|
||||
apibail_invalid_argument!("subkey out of range", "subkey", subkey);
|
||||
}
|
||||
|
||||
/// Check if a key is a schema member
|
||||
|
|
|
@ -64,13 +64,12 @@ impl DHTSchema {
|
|||
}
|
||||
|
||||
/// Check a subkey value data against the schema
|
||||
#[must_use]
|
||||
pub fn check_subkey_value_data(
|
||||
&self,
|
||||
owner: &PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
value_data: &ValueData,
|
||||
) -> bool {
|
||||
) -> VeilidAPIResult<()> {
|
||||
match self {
|
||||
DHTSchema::DFLT(d) => d.check_subkey_value_data(owner, subkey, value_data),
|
||||
DHTSchema::SMPL(s) => s.check_subkey_value_data(owner, subkey, value_data),
|
||||
|
|
|
@ -107,13 +107,12 @@ impl DHTSchemaSMPL {
|
|||
}
|
||||
|
||||
/// Check a subkey value data against the schema
|
||||
#[must_use]
|
||||
pub fn check_subkey_value_data(
|
||||
&self,
|
||||
owner: &PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
value_data: &ValueData,
|
||||
) -> bool {
|
||||
) -> VeilidAPIResult<()> {
|
||||
let mut cur_subkey = subkey as usize;
|
||||
|
||||
let max_value_len = usize::min(
|
||||
|
@ -127,14 +126,22 @@ impl DHTSchemaSMPL {
|
|||
if value_data.writer() == owner {
|
||||
// Ensure value size is within additional limit
|
||||
if value_data.data_size() <= max_value_len {
|
||||
return true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Value too big
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"value too big",
|
||||
"data",
|
||||
format!("{:?}", value_data.data())
|
||||
);
|
||||
}
|
||||
// Wrong writer
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"wrong writer",
|
||||
"writer",
|
||||
format!("{:?}", value_data.writer())
|
||||
);
|
||||
}
|
||||
cur_subkey -= self.o_cnt as usize;
|
||||
|
||||
|
@ -146,20 +153,28 @@ impl DHTSchemaSMPL {
|
|||
if value_data.writer() == &m.m_key {
|
||||
// Ensure value size is in allowed range
|
||||
if value_data.data_size() <= max_value_len {
|
||||
return true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Value too big
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"value too big",
|
||||
"data",
|
||||
format!("{:?}", value_data.data())
|
||||
);
|
||||
}
|
||||
// Wrong writer
|
||||
return false;
|
||||
apibail_invalid_argument!(
|
||||
"wrong writer",
|
||||
"writer",
|
||||
format!("{:?}", value_data.writer())
|
||||
);
|
||||
}
|
||||
cur_subkey -= m.m_cnt as usize;
|
||||
}
|
||||
|
||||
// Subkey out of range
|
||||
false
|
||||
apibail_invalid_argument!("subkey out of range", "subkey", subkey);
|
||||
}
|
||||
|
||||
/// Check if a key is a schema member
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
use crate::{Deserialize, JsonSchema, KeyPair, Serialize};
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||
use crate::Tsify;
|
||||
|
||||
#[derive(Debug, JsonSchema, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(
|
||||
all(target_arch = "wasm32", target_os = "unknown"),
|
||||
derive(Tsify),
|
||||
tsify(from_wasm_abi, into_wasm_abi)
|
||||
)]
|
||||
pub struct AllowOffline(pub bool);
|
||||
impl Default for AllowOffline {
|
||||
fn default() -> Self {
|
||||
Self(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(
|
||||
all(target_arch = "wasm32", target_os = "unknown"),
|
||||
derive(Tsify),
|
||||
tsify(from_wasm_abi, into_wasm_abi)
|
||||
)]
|
||||
pub struct SetDHTValueOptions {
|
||||
#[schemars(with = "Option<String>")]
|
||||
pub writer: Option<KeyPair>,
|
||||
/// Defaults to true. If false, the value will not be written if the node is offline,
|
||||
/// and a TryAgain error will be returned.
|
||||
pub allow_offline: Option<AllowOffline>,
|
||||
}
|
||||
|
||||
impl Default for SetDHTValueOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
writer: None,
|
||||
allow_offline: Some(AllowOffline(true)),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -244,7 +244,8 @@ Future<void> testOpenWriterDHTValue() async {
|
|||
// Should have prior sequence number as its returned value because it
|
||||
// exists online at seq 0
|
||||
vdtemp = await rc.setDHTValue(key, 0, va,
|
||||
writer: KeyPair(key: owner, secret: secret));
|
||||
options:
|
||||
SetDHTValueOptions(writer: KeyPair(key: owner, secret: secret)));
|
||||
expect(vdtemp, isNotNull);
|
||||
expect(vdtemp!.data, equals(vb));
|
||||
expect(vdtemp.seq, equals(0));
|
||||
|
@ -252,7 +253,8 @@ Future<void> testOpenWriterDHTValue() async {
|
|||
|
||||
// Should update the second time to seq 1
|
||||
vdtemp = await rc.setDHTValue(key, 0, va,
|
||||
writer: KeyPair(key: owner, secret: secret));
|
||||
options:
|
||||
SetDHTValueOptions(writer: KeyPair(key: owner, secret: secret)));
|
||||
expect(vdtemp, isNull);
|
||||
|
||||
// Clean up
|
||||
|
|
|
@ -13,10 +13,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
async_tools:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -101,10 +101,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -195,10 +195,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -450,7 +450,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.4.4"
|
||||
version: "0.4.7"
|
||||
veilid_test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -462,18 +462,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.0"
|
||||
webdriver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
|
||||
sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.4"
|
||||
version: "3.1.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -273,6 +273,25 @@ enum DHTReportScope {
|
|||
String toJson() => name.toPascalCase();
|
||||
}
|
||||
|
||||
/// SetDHTValueOptions
|
||||
|
||||
@freezed
|
||||
sealed class SetDHTValueOptions with _$SetDHTValueOptions {
|
||||
const factory SetDHTValueOptions({
|
||||
KeyPair? writer,
|
||||
bool? allowOffline,
|
||||
}) = _SetDHTValueOptions;
|
||||
|
||||
factory SetDHTValueOptions.fromJson(dynamic json) =>
|
||||
_$SetDHTValueOptionsFromJson(json as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => {
|
||||
'writer': writer,
|
||||
'allow_offline': allowOffline,
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
/// VeilidRoutingContext
|
||||
|
||||
|
@ -300,7 +319,7 @@ abstract class VeilidRoutingContext {
|
|||
Future<ValueData?> getDHTValue(TypedKey key, int subkey,
|
||||
{bool forceRefresh = false});
|
||||
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||
{KeyPair? writer});
|
||||
{SetDHTValueOptions? options});
|
||||
Future<bool> watchDHTValues(TypedKey key,
|
||||
{List<ValueSubkeyRange>? subkeys, Timestamp? expiration, int? count});
|
||||
Future<bool> cancelDHTWatch(TypedKey key, {List<ValueSubkeyRange>? subkeys});
|
||||
|
|
|
@ -1453,4 +1453,165 @@ class __$DHTRecordReportCopyWithImpl<$Res>
|
|||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SetDHTValueOptions {
|
||||
KeyPair? get writer;
|
||||
bool? get allowOffline;
|
||||
|
||||
/// Create a copy of SetDHTValueOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SetDHTValueOptionsCopyWith<SetDHTValueOptions> get copyWith =>
|
||||
_$SetDHTValueOptionsCopyWithImpl<SetDHTValueOptions>(
|
||||
this as SetDHTValueOptions, _$identity);
|
||||
|
||||
/// Serializes this SetDHTValueOptions to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is SetDHTValueOptions &&
|
||||
(identical(other.writer, writer) || other.writer == writer) &&
|
||||
(identical(other.allowOffline, allowOffline) ||
|
||||
other.allowOffline == allowOffline));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, writer, allowOffline);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SetDHTValueOptions(writer: $writer, allowOffline: $allowOffline)';
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SetDHTValueOptionsCopyWith<$Res> {
|
||||
factory $SetDHTValueOptionsCopyWith(
|
||||
SetDHTValueOptions value, $Res Function(SetDHTValueOptions) _then) =
|
||||
_$SetDHTValueOptionsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({KeyPair? writer, bool? allowOffline});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SetDHTValueOptionsCopyWithImpl<$Res>
|
||||
implements $SetDHTValueOptionsCopyWith<$Res> {
|
||||
_$SetDHTValueOptionsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SetDHTValueOptions _self;
|
||||
final $Res Function(SetDHTValueOptions) _then;
|
||||
|
||||
/// Create a copy of SetDHTValueOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? writer = freezed,
|
||||
Object? allowOffline = freezed,
|
||||
}) {
|
||||
return _then(_self.copyWith(
|
||||
writer: freezed == writer
|
||||
? _self.writer
|
||||
: writer // ignore: cast_nullable_to_non_nullable
|
||||
as KeyPair?,
|
||||
allowOffline: freezed == allowOffline
|
||||
? _self.allowOffline
|
||||
: allowOffline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _SetDHTValueOptions implements SetDHTValueOptions {
|
||||
const _SetDHTValueOptions({this.writer, this.allowOffline});
|
||||
factory _SetDHTValueOptions.fromJson(Map<String, dynamic> json) =>
|
||||
_$SetDHTValueOptionsFromJson(json);
|
||||
|
||||
@override
|
||||
final KeyPair? writer;
|
||||
@override
|
||||
final bool? allowOffline;
|
||||
|
||||
/// Create a copy of SetDHTValueOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SetDHTValueOptionsCopyWith<_SetDHTValueOptions> get copyWith =>
|
||||
__$SetDHTValueOptionsCopyWithImpl<_SetDHTValueOptions>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$SetDHTValueOptionsToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _SetDHTValueOptions &&
|
||||
(identical(other.writer, writer) || other.writer == writer) &&
|
||||
(identical(other.allowOffline, allowOffline) ||
|
||||
other.allowOffline == allowOffline));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, writer, allowOffline);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SetDHTValueOptions(writer: $writer, allowOffline: $allowOffline)';
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SetDHTValueOptionsCopyWith<$Res>
|
||||
implements $SetDHTValueOptionsCopyWith<$Res> {
|
||||
factory _$SetDHTValueOptionsCopyWith(
|
||||
_SetDHTValueOptions value, $Res Function(_SetDHTValueOptions) _then) =
|
||||
__$SetDHTValueOptionsCopyWithImpl;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({KeyPair? writer, bool? allowOffline});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$SetDHTValueOptionsCopyWithImpl<$Res>
|
||||
implements _$SetDHTValueOptionsCopyWith<$Res> {
|
||||
__$SetDHTValueOptionsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SetDHTValueOptions _self;
|
||||
final $Res Function(_SetDHTValueOptions) _then;
|
||||
|
||||
/// Create a copy of SetDHTValueOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call({
|
||||
Object? writer = freezed,
|
||||
Object? allowOffline = freezed,
|
||||
}) {
|
||||
return _then(_SetDHTValueOptions(
|
||||
writer: freezed == writer
|
||||
? _self.writer
|
||||
: writer // ignore: cast_nullable_to_non_nullable
|
||||
as KeyPair?,
|
||||
allowOffline: freezed == allowOffline
|
||||
? _self.allowOffline
|
||||
: allowOffline // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
|
|
@ -128,3 +128,15 @@ Map<String, dynamic> _$DHTRecordReportToJson(_DHTRecordReport instance) =>
|
|||
'local_seqs': instance.localSeqs,
|
||||
'network_seqs': instance.networkSeqs,
|
||||
};
|
||||
|
||||
_SetDHTValueOptions _$SetDHTValueOptionsFromJson(Map<String, dynamic> json) =>
|
||||
_SetDHTValueOptions(
|
||||
writer: json['writer'] == null ? null : KeyPair.fromJson(json['writer']),
|
||||
allowOffline: json['allow_offline'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SetDHTValueOptionsToJson(_SetDHTValueOptions instance) =>
|
||||
<String, dynamic>{
|
||||
'writer': instance.writer?.toJson(),
|
||||
'allow_offline': instance.allowOffline,
|
||||
};
|
||||
|
|
|
@ -266,6 +266,18 @@ sealed class VeilidConfigProtocol with _$VeilidConfigProtocol {
|
|||
|
||||
////////////
|
||||
|
||||
@freezed
|
||||
sealed class VeilidConfigPrivacy with _$VeilidConfigPrivacy {
|
||||
const factory VeilidConfigPrivacy({
|
||||
required bool requireInboundRelay,
|
||||
}) = _VeilidConfigPrivacy;
|
||||
|
||||
factory VeilidConfigPrivacy.fromJson(dynamic json) =>
|
||||
_$VeilidConfigPrivacyFromJson(json as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
////////////
|
||||
|
||||
@freezed
|
||||
sealed class VeilidConfigTLS with _$VeilidConfigTLS {
|
||||
const factory VeilidConfigTLS({
|
||||
|
@ -370,6 +382,7 @@ sealed class VeilidConfigNetwork with _$VeilidConfigNetwork {
|
|||
required VeilidConfigTLS tls,
|
||||
required VeilidConfigApplication application,
|
||||
required VeilidConfigProtocol protocol,
|
||||
required VeilidConfigPrivacy privacy,
|
||||
String? networkKeyPassword,
|
||||
}) = _VeilidConfigNetwork;
|
||||
|
||||
|
|
|
@ -4296,6 +4296,169 @@ class __$VeilidConfigProtocolCopyWithImpl<$Res>
|
|||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$VeilidConfigPrivacy implements DiagnosticableTreeMixin {
|
||||
bool get requireInboundRelay;
|
||||
|
||||
/// Create a copy of VeilidConfigPrivacy
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$VeilidConfigPrivacyCopyWith<VeilidConfigPrivacy> get copyWith =>
|
||||
_$VeilidConfigPrivacyCopyWithImpl<VeilidConfigPrivacy>(
|
||||
this as VeilidConfigPrivacy, _$identity);
|
||||
|
||||
/// Serializes this VeilidConfigPrivacy to a JSON map.
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'VeilidConfigPrivacy'))
|
||||
..add(DiagnosticsProperty('requireInboundRelay', requireInboundRelay));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is VeilidConfigPrivacy &&
|
||||
(identical(other.requireInboundRelay, requireInboundRelay) ||
|
||||
other.requireInboundRelay == requireInboundRelay));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, requireInboundRelay);
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VeilidConfigPrivacy(requireInboundRelay: $requireInboundRelay)';
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $VeilidConfigPrivacyCopyWith<$Res> {
|
||||
factory $VeilidConfigPrivacyCopyWith(
|
||||
VeilidConfigPrivacy value, $Res Function(VeilidConfigPrivacy) _then) =
|
||||
_$VeilidConfigPrivacyCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({bool requireInboundRelay});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$VeilidConfigPrivacyCopyWithImpl<$Res>
|
||||
implements $VeilidConfigPrivacyCopyWith<$Res> {
|
||||
_$VeilidConfigPrivacyCopyWithImpl(this._self, this._then);
|
||||
|
||||
final VeilidConfigPrivacy _self;
|
||||
final $Res Function(VeilidConfigPrivacy) _then;
|
||||
|
||||
/// Create a copy of VeilidConfigPrivacy
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? requireInboundRelay = null,
|
||||
}) {
|
||||
return _then(_self.copyWith(
|
||||
requireInboundRelay: null == requireInboundRelay
|
||||
? _self.requireInboundRelay
|
||||
: requireInboundRelay // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _VeilidConfigPrivacy
|
||||
with DiagnosticableTreeMixin
|
||||
implements VeilidConfigPrivacy {
|
||||
const _VeilidConfigPrivacy({required this.requireInboundRelay});
|
||||
factory _VeilidConfigPrivacy.fromJson(Map<String, dynamic> json) =>
|
||||
_$VeilidConfigPrivacyFromJson(json);
|
||||
|
||||
@override
|
||||
final bool requireInboundRelay;
|
||||
|
||||
/// Create a copy of VeilidConfigPrivacy
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$VeilidConfigPrivacyCopyWith<_VeilidConfigPrivacy> get copyWith =>
|
||||
__$VeilidConfigPrivacyCopyWithImpl<_VeilidConfigPrivacy>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$VeilidConfigPrivacyToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'VeilidConfigPrivacy'))
|
||||
..add(DiagnosticsProperty('requireInboundRelay', requireInboundRelay));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _VeilidConfigPrivacy &&
|
||||
(identical(other.requireInboundRelay, requireInboundRelay) ||
|
||||
other.requireInboundRelay == requireInboundRelay));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, requireInboundRelay);
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VeilidConfigPrivacy(requireInboundRelay: $requireInboundRelay)';
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$VeilidConfigPrivacyCopyWith<$Res>
|
||||
implements $VeilidConfigPrivacyCopyWith<$Res> {
|
||||
factory _$VeilidConfigPrivacyCopyWith(_VeilidConfigPrivacy value,
|
||||
$Res Function(_VeilidConfigPrivacy) _then) =
|
||||
__$VeilidConfigPrivacyCopyWithImpl;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({bool requireInboundRelay});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$VeilidConfigPrivacyCopyWithImpl<$Res>
|
||||
implements _$VeilidConfigPrivacyCopyWith<$Res> {
|
||||
__$VeilidConfigPrivacyCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _VeilidConfigPrivacy _self;
|
||||
final $Res Function(_VeilidConfigPrivacy) _then;
|
||||
|
||||
/// Create a copy of VeilidConfigPrivacy
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$Res call({
|
||||
Object? requireInboundRelay = null,
|
||||
}) {
|
||||
return _then(_VeilidConfigPrivacy(
|
||||
requireInboundRelay: null == requireInboundRelay
|
||||
? _self.requireInboundRelay
|
||||
: requireInboundRelay // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$VeilidConfigTLS implements DiagnosticableTreeMixin {
|
||||
String get certificatePath;
|
||||
|
@ -5922,6 +6085,7 @@ mixin _$VeilidConfigNetwork implements DiagnosticableTreeMixin {
|
|||
VeilidConfigTLS get tls;
|
||||
VeilidConfigApplication get application;
|
||||
VeilidConfigProtocol get protocol;
|
||||
VeilidConfigPrivacy get privacy;
|
||||
String? get networkKeyPassword;
|
||||
|
||||
/// Create a copy of VeilidConfigNetwork
|
||||
|
@ -5965,6 +6129,7 @@ mixin _$VeilidConfigNetwork implements DiagnosticableTreeMixin {
|
|||
..add(DiagnosticsProperty('tls', tls))
|
||||
..add(DiagnosticsProperty('application', application))
|
||||
..add(DiagnosticsProperty('protocol', protocol))
|
||||
..add(DiagnosticsProperty('privacy', privacy))
|
||||
..add(DiagnosticsProperty('networkKeyPassword', networkKeyPassword));
|
||||
}
|
||||
|
||||
|
@ -6012,6 +6177,7 @@ mixin _$VeilidConfigNetwork implements DiagnosticableTreeMixin {
|
|||
other.application == application) &&
|
||||
(identical(other.protocol, protocol) ||
|
||||
other.protocol == protocol) &&
|
||||
(identical(other.privacy, privacy) || other.privacy == privacy) &&
|
||||
(identical(other.networkKeyPassword, networkKeyPassword) ||
|
||||
other.networkKeyPassword == networkKeyPassword));
|
||||
}
|
||||
|
@ -6038,12 +6204,13 @@ mixin _$VeilidConfigNetwork implements DiagnosticableTreeMixin {
|
|||
tls,
|
||||
application,
|
||||
protocol,
|
||||
privacy,
|
||||
networkKeyPassword
|
||||
]);
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VeilidConfigNetwork(connectionInitialTimeoutMs: $connectionInitialTimeoutMs, connectionInactivityTimeoutMs: $connectionInactivityTimeoutMs, maxConnectionsPerIp4: $maxConnectionsPerIp4, maxConnectionsPerIp6Prefix: $maxConnectionsPerIp6Prefix, maxConnectionsPerIp6PrefixSize: $maxConnectionsPerIp6PrefixSize, maxConnectionFrequencyPerMin: $maxConnectionFrequencyPerMin, clientAllowlistTimeoutMs: $clientAllowlistTimeoutMs, reverseConnectionReceiptTimeMs: $reverseConnectionReceiptTimeMs, holePunchReceiptTimeMs: $holePunchReceiptTimeMs, routingTable: $routingTable, rpc: $rpc, dht: $dht, upnp: $upnp, detectAddressChanges: $detectAddressChanges, restrictedNatRetries: $restrictedNatRetries, tls: $tls, application: $application, protocol: $protocol, networkKeyPassword: $networkKeyPassword)';
|
||||
return 'VeilidConfigNetwork(connectionInitialTimeoutMs: $connectionInitialTimeoutMs, connectionInactivityTimeoutMs: $connectionInactivityTimeoutMs, maxConnectionsPerIp4: $maxConnectionsPerIp4, maxConnectionsPerIp6Prefix: $maxConnectionsPerIp6Prefix, maxConnectionsPerIp6PrefixSize: $maxConnectionsPerIp6PrefixSize, maxConnectionFrequencyPerMin: $maxConnectionFrequencyPerMin, clientAllowlistTimeoutMs: $clientAllowlistTimeoutMs, reverseConnectionReceiptTimeMs: $reverseConnectionReceiptTimeMs, holePunchReceiptTimeMs: $holePunchReceiptTimeMs, routingTable: $routingTable, rpc: $rpc, dht: $dht, upnp: $upnp, detectAddressChanges: $detectAddressChanges, restrictedNatRetries: $restrictedNatRetries, tls: $tls, application: $application, protocol: $protocol, privacy: $privacy, networkKeyPassword: $networkKeyPassword)';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6072,6 +6239,7 @@ abstract mixin class $VeilidConfigNetworkCopyWith<$Res> {
|
|||
VeilidConfigTLS tls,
|
||||
VeilidConfigApplication application,
|
||||
VeilidConfigProtocol protocol,
|
||||
VeilidConfigPrivacy privacy,
|
||||
String? networkKeyPassword});
|
||||
|
||||
$VeilidConfigRoutingTableCopyWith<$Res> get routingTable;
|
||||
|
@ -6080,6 +6248,7 @@ abstract mixin class $VeilidConfigNetworkCopyWith<$Res> {
|
|||
$VeilidConfigTLSCopyWith<$Res> get tls;
|
||||
$VeilidConfigApplicationCopyWith<$Res> get application;
|
||||
$VeilidConfigProtocolCopyWith<$Res> get protocol;
|
||||
$VeilidConfigPrivacyCopyWith<$Res> get privacy;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -6113,6 +6282,7 @@ class _$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
Object? tls = null,
|
||||
Object? application = null,
|
||||
Object? protocol = null,
|
||||
Object? privacy = null,
|
||||
Object? networkKeyPassword = freezed,
|
||||
}) {
|
||||
return _then(_self.copyWith(
|
||||
|
@ -6188,6 +6358,10 @@ class _$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
? _self.protocol
|
||||
: protocol // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidConfigProtocol,
|
||||
privacy: null == privacy
|
||||
? _self.privacy
|
||||
: privacy // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidConfigPrivacy,
|
||||
networkKeyPassword: freezed == networkKeyPassword
|
||||
? _self.networkKeyPassword
|
||||
: networkKeyPassword // ignore: cast_nullable_to_non_nullable
|
||||
|
@ -6254,6 +6428,16 @@ class _$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
return _then(_self.copyWith(protocol: value));
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of VeilidConfigNetwork
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VeilidConfigPrivacyCopyWith<$Res> get privacy {
|
||||
return $VeilidConfigPrivacyCopyWith<$Res>(_self.privacy, (value) {
|
||||
return _then(_self.copyWith(privacy: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -6280,6 +6464,7 @@ class _VeilidConfigNetwork
|
|||
required this.tls,
|
||||
required this.application,
|
||||
required this.protocol,
|
||||
required this.privacy,
|
||||
this.networkKeyPassword});
|
||||
factory _VeilidConfigNetwork.fromJson(Map<String, dynamic> json) =>
|
||||
_$VeilidConfigNetworkFromJson(json);
|
||||
|
@ -6321,6 +6506,8 @@ class _VeilidConfigNetwork
|
|||
@override
|
||||
final VeilidConfigProtocol protocol;
|
||||
@override
|
||||
final VeilidConfigPrivacy privacy;
|
||||
@override
|
||||
final String? networkKeyPassword;
|
||||
|
||||
/// Create a copy of VeilidConfigNetwork
|
||||
|
@ -6369,6 +6556,7 @@ class _VeilidConfigNetwork
|
|||
..add(DiagnosticsProperty('tls', tls))
|
||||
..add(DiagnosticsProperty('application', application))
|
||||
..add(DiagnosticsProperty('protocol', protocol))
|
||||
..add(DiagnosticsProperty('privacy', privacy))
|
||||
..add(DiagnosticsProperty('networkKeyPassword', networkKeyPassword));
|
||||
}
|
||||
|
||||
|
@ -6416,6 +6604,7 @@ class _VeilidConfigNetwork
|
|||
other.application == application) &&
|
||||
(identical(other.protocol, protocol) ||
|
||||
other.protocol == protocol) &&
|
||||
(identical(other.privacy, privacy) || other.privacy == privacy) &&
|
||||
(identical(other.networkKeyPassword, networkKeyPassword) ||
|
||||
other.networkKeyPassword == networkKeyPassword));
|
||||
}
|
||||
|
@ -6442,12 +6631,13 @@ class _VeilidConfigNetwork
|
|||
tls,
|
||||
application,
|
||||
protocol,
|
||||
privacy,
|
||||
networkKeyPassword
|
||||
]);
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'VeilidConfigNetwork(connectionInitialTimeoutMs: $connectionInitialTimeoutMs, connectionInactivityTimeoutMs: $connectionInactivityTimeoutMs, maxConnectionsPerIp4: $maxConnectionsPerIp4, maxConnectionsPerIp6Prefix: $maxConnectionsPerIp6Prefix, maxConnectionsPerIp6PrefixSize: $maxConnectionsPerIp6PrefixSize, maxConnectionFrequencyPerMin: $maxConnectionFrequencyPerMin, clientAllowlistTimeoutMs: $clientAllowlistTimeoutMs, reverseConnectionReceiptTimeMs: $reverseConnectionReceiptTimeMs, holePunchReceiptTimeMs: $holePunchReceiptTimeMs, routingTable: $routingTable, rpc: $rpc, dht: $dht, upnp: $upnp, detectAddressChanges: $detectAddressChanges, restrictedNatRetries: $restrictedNatRetries, tls: $tls, application: $application, protocol: $protocol, networkKeyPassword: $networkKeyPassword)';
|
||||
return 'VeilidConfigNetwork(connectionInitialTimeoutMs: $connectionInitialTimeoutMs, connectionInactivityTimeoutMs: $connectionInactivityTimeoutMs, maxConnectionsPerIp4: $maxConnectionsPerIp4, maxConnectionsPerIp6Prefix: $maxConnectionsPerIp6Prefix, maxConnectionsPerIp6PrefixSize: $maxConnectionsPerIp6PrefixSize, maxConnectionFrequencyPerMin: $maxConnectionFrequencyPerMin, clientAllowlistTimeoutMs: $clientAllowlistTimeoutMs, reverseConnectionReceiptTimeMs: $reverseConnectionReceiptTimeMs, holePunchReceiptTimeMs: $holePunchReceiptTimeMs, routingTable: $routingTable, rpc: $rpc, dht: $dht, upnp: $upnp, detectAddressChanges: $detectAddressChanges, restrictedNatRetries: $restrictedNatRetries, tls: $tls, application: $application, protocol: $protocol, privacy: $privacy, networkKeyPassword: $networkKeyPassword)';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6478,6 +6668,7 @@ abstract mixin class _$VeilidConfigNetworkCopyWith<$Res>
|
|||
VeilidConfigTLS tls,
|
||||
VeilidConfigApplication application,
|
||||
VeilidConfigProtocol protocol,
|
||||
VeilidConfigPrivacy privacy,
|
||||
String? networkKeyPassword});
|
||||
|
||||
@override
|
||||
|
@ -6492,6 +6683,8 @@ abstract mixin class _$VeilidConfigNetworkCopyWith<$Res>
|
|||
$VeilidConfigApplicationCopyWith<$Res> get application;
|
||||
@override
|
||||
$VeilidConfigProtocolCopyWith<$Res> get protocol;
|
||||
@override
|
||||
$VeilidConfigPrivacyCopyWith<$Res> get privacy;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
@ -6525,6 +6718,7 @@ class __$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
Object? tls = null,
|
||||
Object? application = null,
|
||||
Object? protocol = null,
|
||||
Object? privacy = null,
|
||||
Object? networkKeyPassword = freezed,
|
||||
}) {
|
||||
return _then(_VeilidConfigNetwork(
|
||||
|
@ -6600,6 +6794,10 @@ class __$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
? _self.protocol
|
||||
: protocol // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidConfigProtocol,
|
||||
privacy: null == privacy
|
||||
? _self.privacy
|
||||
: privacy // ignore: cast_nullable_to_non_nullable
|
||||
as VeilidConfigPrivacy,
|
||||
networkKeyPassword: freezed == networkKeyPassword
|
||||
? _self.networkKeyPassword
|
||||
: networkKeyPassword // ignore: cast_nullable_to_non_nullable
|
||||
|
@ -6666,6 +6864,16 @@ class __$VeilidConfigNetworkCopyWithImpl<$Res>
|
|||
return _then(_self.copyWith(protocol: value));
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of VeilidConfigNetwork
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VeilidConfigPrivacyCopyWith<$Res> get privacy {
|
||||
return $VeilidConfigPrivacyCopyWith<$Res>(_self.privacy, (value) {
|
||||
return _then(_self.copyWith(privacy: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
|
|
@ -314,6 +314,17 @@ Map<String, dynamic> _$VeilidConfigProtocolToJson(
|
|||
'wss': instance.wss.toJson(),
|
||||
};
|
||||
|
||||
_VeilidConfigPrivacy _$VeilidConfigPrivacyFromJson(Map<String, dynamic> json) =>
|
||||
_VeilidConfigPrivacy(
|
||||
requireInboundRelay: json['require_inbound_relay'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$VeilidConfigPrivacyToJson(
|
||||
_VeilidConfigPrivacy instance) =>
|
||||
<String, dynamic>{
|
||||
'require_inbound_relay': instance.requireInboundRelay,
|
||||
};
|
||||
|
||||
_VeilidConfigTLS _$VeilidConfigTLSFromJson(Map<String, dynamic> json) =>
|
||||
_VeilidConfigTLS(
|
||||
certificatePath: json['certificate_path'] as String,
|
||||
|
@ -472,6 +483,7 @@ _VeilidConfigNetwork _$VeilidConfigNetworkFromJson(Map<String, dynamic> json) =>
|
|||
tls: VeilidConfigTLS.fromJson(json['tls']),
|
||||
application: VeilidConfigApplication.fromJson(json['application']),
|
||||
protocol: VeilidConfigProtocol.fromJson(json['protocol']),
|
||||
privacy: VeilidConfigPrivacy.fromJson(json['privacy']),
|
||||
networkKeyPassword: json['network_key_password'] as String?,
|
||||
);
|
||||
|
||||
|
@ -499,6 +511,7 @@ Map<String, dynamic> _$VeilidConfigNetworkToJson(
|
|||
'tls': instance.tls.toJson(),
|
||||
'application': instance.application.toJson(),
|
||||
'protocol': instance.protocol.toJson(),
|
||||
'privacy': instance.privacy.toJson(),
|
||||
'network_key_password': instance.networkKeyPassword,
|
||||
};
|
||||
|
||||
|
|
|
@ -696,17 +696,17 @@ class VeilidRoutingContextFFI extends VeilidRoutingContext {
|
|||
|
||||
@override
|
||||
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||
{KeyPair? writer}) async {
|
||||
{SetDHTValueOptions? options}) async {
|
||||
_ctx.ensureValid();
|
||||
final nativeKey = jsonEncode(key).toNativeUtf8();
|
||||
final nativeData = base64UrlNoPadEncode(data).toNativeUtf8();
|
||||
final nativeWriter =
|
||||
writer != null ? jsonEncode(writer).toNativeUtf8() : nullptr;
|
||||
final nativeOptions =
|
||||
options != null ? jsonEncode(options).toNativeUtf8() : nullptr;
|
||||
|
||||
final recvPort = ReceivePort('routing_context_set_dht_value');
|
||||
final sendPort = recvPort.sendPort;
|
||||
_ctx.ffi._routingContextSetDHTValue(sendPort.nativePort, _ctx.id!,
|
||||
nativeKey, subkey, nativeData, nativeWriter);
|
||||
nativeKey, subkey, nativeData, nativeOptions);
|
||||
final valueData =
|
||||
await processFutureOptJson(ValueData.fromJson, recvPort.first);
|
||||
return valueData;
|
||||
|
|
|
@ -193,7 +193,7 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
|
|||
|
||||
@override
|
||||
Future<ValueData?> setDHTValue(TypedKey key, int subkey, Uint8List data,
|
||||
{KeyPair? writer}) async {
|
||||
{SetDHTValueOptions? options}) async {
|
||||
final id = _ctx.requireId();
|
||||
final opt = await _wrapApiPromise<String?>(
|
||||
js_util.callMethod(wasm, 'routing_context_set_dht_value', [
|
||||
|
@ -201,7 +201,7 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
|
|||
jsonEncode(key),
|
||||
subkey,
|
||||
base64UrlNoPadEncode(data),
|
||||
if (writer != null) jsonEncode(writer) else null
|
||||
if (options != null) jsonEncode(options) else null
|
||||
]));
|
||||
if (opt == null) {
|
||||
return null;
|
||||
|
|
|
@ -793,14 +793,14 @@ pub extern "C" fn routing_context_set_dht_value(
|
|||
key: FfiStr,
|
||||
subkey: u32,
|
||||
data: FfiStr,
|
||||
writer: FfiStr,
|
||||
options: FfiStr,
|
||||
) {
|
||||
let key: veilid_core::TypedRecordKey =
|
||||
veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap();
|
||||
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||
.decode(data.into_opt_string().unwrap().as_bytes())
|
||||
.unwrap();
|
||||
let writer: Option<veilid_core::KeyPair> = writer
|
||||
let options: Option<veilid_core::SetDHTValueOptions> = options
|
||||
.into_opt_string()
|
||||
.map(|s| veilid_core::deserialize_json(&s).unwrap());
|
||||
|
||||
|
@ -809,7 +809,7 @@ pub extern "C" fn routing_context_set_dht_value(
|
|||
let routing_context = get_routing_context(id, "routing_context_set_dht_value")?;
|
||||
|
||||
let res = routing_context
|
||||
.set_dht_value(key, subkey, data, writer)
|
||||
.set_dht_value(key, subkey, data, options)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
|
|
|
@ -238,14 +238,14 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
|
|||
|
||||
# Verify subkey 0 can be set because override with the right writer
|
||||
# Should have prior sequence number as its returned value because it exists online at seq 0
|
||||
vdtemp = await rc.set_dht_value(key, ValueSubkey(0), va, veilid.KeyPair.from_parts(owner, secret))
|
||||
vdtemp = await rc.set_dht_value(key, ValueSubkey(0), va, veilid.SetDHTValueOptions(veilid.KeyPair.from_parts(owner, secret)))
|
||||
assert vdtemp is not None
|
||||
assert vdtemp.data == vb
|
||||
assert vdtemp.seq == 0
|
||||
assert vdtemp.writer == owner
|
||||
|
||||
# Should update the second time to seq 1
|
||||
vdtemp = await rc.set_dht_value(key, ValueSubkey(0), va, veilid.KeyPair.from_parts(owner, secret))
|
||||
vdtemp = await rc.set_dht_value(key, ValueSubkey(0), va, veilid.SetDHTValueOptions(veilid.KeyPair.from_parts(owner, secret)))
|
||||
assert vdtemp is None
|
||||
|
||||
# Clean up
|
||||
|
|
|
@ -84,7 +84,7 @@ class RoutingContext(ABC):
|
|||
|
||||
@abstractmethod
|
||||
async def set_dht_value(
|
||||
self, key: types.TypedKey, subkey: types.ValueSubkey, data: bytes, writer: Optional[types.KeyPair] = None
|
||||
self, key: types.TypedKey, subkey: types.ValueSubkey, data: bytes, options: Optional[types.SetDHTValueOptions] = None
|
||||
) -> Optional[types.ValueData]:
|
||||
pass
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ from .types import (
|
|||
SafetySelection,
|
||||
SecretKey,
|
||||
Sequencing,
|
||||
SetDHTValueOptions,
|
||||
SharedSecret,
|
||||
Signature,
|
||||
Stability,
|
||||
|
@ -721,12 +722,12 @@ 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, writer: Optional[KeyPair] = None
|
||||
self, key: TypedKey, subkey: ValueSubkey, data: bytes, options: Optional[SetDHTValueOptions] = None
|
||||
) -> Optional[ValueData]:
|
||||
assert isinstance(key, TypedKey)
|
||||
assert isinstance(subkey, ValueSubkey)
|
||||
assert isinstance(data, bytes)
|
||||
assert writer is None or isinstance(writer, KeyPair)
|
||||
assert options is None or isinstance(options, SetDHTValueOptions)
|
||||
|
||||
ret = raise_api_result(
|
||||
await self.api.send_ndjson_request(
|
||||
|
@ -737,7 +738,7 @@ class _JsonRoutingContext(RoutingContext):
|
|||
key=key,
|
||||
subkey=subkey,
|
||||
data=data,
|
||||
writer=writer,
|
||||
options=options,
|
||||
)
|
||||
)
|
||||
return None if ret is None else ValueData.from_json(ret)
|
||||
|
|
|
@ -3944,6 +3944,7 @@
|
|||
]
|
||||
},
|
||||
"VeilidCapability": {
|
||||
"description": "A four-character code",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
|
|
|
@ -461,6 +461,16 @@
|
|||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/SetDHTValueOptions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rc_op": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -471,12 +481,6 @@
|
|||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"writer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1656,6 +1660,9 @@
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"AllowOffline": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"DHTReportScope": {
|
||||
"description": "DHT Record Report Scope",
|
||||
"oneOf": [
|
||||
|
@ -1852,6 +1859,28 @@
|
|||
"EnsureOrdered"
|
||||
]
|
||||
},
|
||||
"SetDHTValueOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_offline": {
|
||||
"description": "Defaults to true. If false, the value will not be written if the node is offline, and a TryAgain error will be returned.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/AllowOffline"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"writer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Stability": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
|
@ -431,6 +431,27 @@ class DHTRecordReport:
|
|||
return self.__dict__
|
||||
|
||||
|
||||
class SetDHTValueOptions:
|
||||
writer: Optional[KeyPair]
|
||||
allow_offline: Optional[bool]
|
||||
|
||||
def __init__(self, writer: Optional[KeyPair], allow_offline: Optional[bool] = None):
|
||||
self.writer = writer
|
||||
self.allow_offline = allow_offline
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.__class__.__name__}(writer={self.writer!r}, allow_offline={self.allow_offline!r})>"
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, j: dict) -> Self:
|
||||
return cls(
|
||||
KeyPair(j["writer"]) if "writer" in j else None,
|
||||
j["allow_offline"] if "allow_offline" in j else None,
|
||||
)
|
||||
|
||||
def to_json(self) -> dict:
|
||||
return self.__dict__
|
||||
|
||||
@total_ordering
|
||||
class ValueData:
|
||||
seq: ValueSeqNum
|
||||
|
|
|
@ -324,11 +324,11 @@ impl JsonRequestProcessor {
|
|||
key,
|
||||
subkey,
|
||||
data,
|
||||
writer,
|
||||
options,
|
||||
} => RoutingContextResponseOp::SetDhtValue {
|
||||
result: to_json_api_result(
|
||||
routing_context
|
||||
.set_dht_value(key, subkey, data, writer)
|
||||
.set_dht_value(key, subkey, data, options)
|
||||
.await,
|
||||
),
|
||||
},
|
||||
|
|
|
@ -72,8 +72,7 @@ pub enum RoutingContextRequestOp {
|
|||
#[serde(with = "as_human_base64")]
|
||||
#[schemars(with = "String")]
|
||||
data: Vec<u8>,
|
||||
#[schemars(with = "Option<String>")]
|
||||
writer: Option<KeyPair>,
|
||||
options: Option<SetDHTValueOptions>,
|
||||
},
|
||||
WatchDhtValues {
|
||||
#[schemars(with = "String")]
|
||||
|
|
|
@ -593,7 +593,7 @@ pub fn routing_context_set_dht_value(
|
|||
key: String,
|
||||
subkey: u32,
|
||||
data: String,
|
||||
writer: Option<String>,
|
||||
options: Option<String>,
|
||||
) -> Promise {
|
||||
wrap_api_future_json(async move {
|
||||
let key: veilid_core::TypedRecordKey =
|
||||
|
@ -601,15 +601,16 @@ pub fn routing_context_set_dht_value(
|
|||
let data: Vec<u8> = data_encoding::BASE64URL_NOPAD
|
||||
.decode(data.as_bytes())
|
||||
.map_err(VeilidAPIError::generic)?;
|
||||
let writer: Option<veilid_core::KeyPair> = match writer {
|
||||
Some(s) => veilid_core::deserialize_json(&s).map_err(VeilidAPIError::generic)?,
|
||||
|
||||
let options: Option<veilid_core::SetDHTValueOptions> = match options {
|
||||
Some(s) => Some(veilid_core::deserialize_json(&s).map_err(VeilidAPIError::generic)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let routing_context = get_routing_context(id, "routing_context_set_dht_value")?;
|
||||
|
||||
let res = routing_context
|
||||
.set_dht_value(key, subkey, data, writer)
|
||||
.set_dht_value(key, subkey, data, options)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
})
|
||||
|
|
|
@ -322,17 +322,14 @@ impl VeilidRoutingContext {
|
|||
key: String,
|
||||
subkey: u32,
|
||||
data: Box<[u8]>,
|
||||
writer: Option<String>,
|
||||
options: Option<SetDHTValueOptions>,
|
||||
) -> APIResult<Option<ValueData>> {
|
||||
let key = TypedRecordKey::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, writer)
|
||||
.set_dht_value(key, subkey, data, options)
|
||||
.await?;
|
||||
APIResult::Ok(res)
|
||||
}
|
||||
|
|
2
veilid-wasm/tests/package-lock.json
generated
2
veilid-wasm/tests/package-lock.json
generated
|
@ -21,7 +21,7 @@
|
|||
},
|
||||
"../pkg": {
|
||||
"name": "veilid-wasm",
|
||||
"version": "0.4.6",
|
||||
"version": "0.4.7",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0"
|
||||
},
|
||||
|
|
|
@ -225,7 +225,10 @@ describe('VeilidRoutingContext', () => {
|
|||
dhtRecord.key,
|
||||
0,
|
||||
textEncoder.encode(`${data}👋`),
|
||||
`${dhtRecord.owner}:${dhtRecord.owner_secret}`
|
||||
{
|
||||
writer: `${dhtRecord.owner}:${dhtRecord.owner_secret}`,
|
||||
allow_offline: undefined
|
||||
}
|
||||
);
|
||||
expect(setValueRes).toBeUndefined();
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue