#![allow(clippy::drop_non_drop)]
use crate::error::WasmCoreError;
use nym_client_core::config::{ForgetMe, RememberMe};
use nym_config::helpers::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType};
use nym_statistics_common::types::SessionType;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use wasm_bindgen::prelude::*;
pub mod r#override;
pub use nym_client_core::config::{
Acknowledgements as ConfigAcknowledgements, Config as BaseClientConfig,
CoverTraffic as ConfigCoverTraffic, DebugConfig as ConfigDebug,
GatewayConnection as ConfigGatewayConnection, ReplySurbs as ConfigReplySurbs,
StatsReporting as ConfigStatsReporting, Topology as ConfigTopology, Traffic as ConfigTraffic,
};
pub fn new_base_client_config(
id: String,
version: String,
nym_api: Option<String>,
nyxd: Option<String>,
debug: Option<DebugWasm>,
) -> Result<BaseClientConfig, WasmCoreError> {
let nym_api_url = match nym_api {
Some(raw) => Some(
raw.parse()
.map_err(|source| WasmCoreError::MalformedUrl { raw, source })?,
),
None => None,
};
let nyxd_url = match nyxd {
Some(raw) => Some(
raw.parse()
.map_err(|source| WasmCoreError::MalformedUrl { raw, source })?,
),
None => None,
};
Ok(BaseClientConfig::new(id, version)
.with_optional(
BaseClientConfig::with_custom_nym_apis,
nym_api_url.map(|u| vec![u]),
)
.with_optional(
BaseClientConfig::with_custom_nyxd,
nyxd_url.map(|u| vec![u]),
)
.with_debug_config(debug.map(Into::into).unwrap_or_default()))
}
#[wasm_bindgen]
pub fn default_debug() -> DebugWasm {
ConfigDebug::default().into()
}
#[wasm_bindgen(js_name = defaultDebug)]
pub fn default_debug_obj() -> JsValue {
let dbg = default_debug();
serde_wasm_bindgen::to_value(&dbg)
.expect("our 'DebugWasm' struct should have had a correctly defined serde implementation")
}
#[wasm_bindgen]
pub fn no_cover_debug() -> DebugWasm {
let mut cfg = ConfigDebug::default();
cfg.traffic.disable_main_poisson_packet_distribution = true;
cfg.cover_traffic.disable_loop_cover_traffic_stream = true;
cfg.into()
}
#[wasm_bindgen(js_name = noCoverDebug)]
pub fn no_cover_debug_obj() -> JsValue {
let dbg = no_cover_debug();
serde_wasm_bindgen::to_value(&dbg)
.expect("our 'DebugWasm' struct should have had a correctly defined serde implementation")
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DebugWasm {
pub traffic: TrafficWasm,
pub cover_traffic: CoverTrafficWasm,
pub gateway_connection: GatewayConnectionWasm,
pub acknowledgements: AcknowledgementsWasm,
pub topology: TopologyWasm,
pub reply_surbs: ReplySurbsWasm,
#[wasm_bindgen(getter_with_clone)]
pub stats_reporting: StatsReportingWasm,
pub forget_me: ForgetMeWasm,
pub remember_me: RememberMeWasm,
}
impl Default for DebugWasm {
fn default() -> Self {
ConfigDebug::default().into()
}
}
impl From<DebugWasm> for ConfigDebug {
fn from(debug: DebugWasm) -> Self {
ConfigDebug {
traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(),
gateway_connection: debug.gateway_connection.into(),
acknowledgements: debug.acknowledgements.into(),
topology: debug.topology.into(),
reply_surbs: debug.reply_surbs.into(),
stats_reporting: debug.stats_reporting.into(),
forget_me: debug.forget_me.into(),
remember_me: debug.remember_me.into(),
}
}
}
impl From<ConfigDebug> for DebugWasm {
fn from(debug: ConfigDebug) -> Self {
DebugWasm {
traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(),
gateway_connection: debug.gateway_connection.into(),
acknowledgements: debug.acknowledgements.into(),
topology: debug.topology.into(),
reply_surbs: debug.reply_surbs.into(),
stats_reporting: debug.stats_reporting.into(),
forget_me: ForgetMeWasm::from(debug.forget_me),
remember_me: RememberMeWasm::from(debug.remember_me),
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TrafficWasm {
pub average_packet_delay_ms: u32,
pub message_sending_average_delay_ms: u32,
pub maximum_number_of_retransmissions: Option<u32>,
pub deterministic_route_selection: bool,
pub disable_main_poisson_packet_distribution: bool,
pub use_extended_packet_size: bool,
pub use_legacy_sphinx_format: bool,
pub use_outfox: bool,
pub disable_mix_hops: bool,
}
impl Default for TrafficWasm {
fn default() -> Self {
ConfigTraffic::default().into()
}
}
impl From<TrafficWasm> for ConfigTraffic {
fn from(traffic: TrafficWasm) -> Self {
let use_extended_packet_size = traffic
.use_extended_packet_size
.then_some(PacketSize::ExtendedPacket32);
let packet_type = if traffic.use_outfox {
PacketType::Outfox
} else {
PacketType::Mix
};
ConfigTraffic {
average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms as u64),
message_sending_average_delay: Duration::from_millis(
traffic.message_sending_average_delay_ms as u64,
),
deterministic_route_selection: traffic.deterministic_route_selection,
maximum_number_of_retransmissions: traffic.maximum_number_of_retransmissions,
disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution,
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: use_extended_packet_size,
use_legacy_sphinx_format: traffic.use_legacy_sphinx_format,
packet_type,
disable_mix_hops: traffic.disable_mix_hops,
}
}
}
impl From<ConfigTraffic> for TrafficWasm {
fn from(traffic: ConfigTraffic) -> Self {
TrafficWasm {
average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u32,
message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis()
as u32,
deterministic_route_selection: traffic.deterministic_route_selection,
maximum_number_of_retransmissions: traffic.maximum_number_of_retransmissions,
disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution,
use_legacy_sphinx_format: traffic.use_legacy_sphinx_format,
use_extended_packet_size: traffic.secondary_packet_size.is_some(),
use_outfox: traffic.packet_type == PacketType::Outfox,
disable_mix_hops: traffic.disable_mix_hops,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CoverTrafficWasm {
pub loop_cover_traffic_average_delay_ms: u32,
pub cover_traffic_primary_size_ratio: f64,
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTrafficWasm {
fn default() -> Self {
ConfigCoverTraffic::default().into()
}
}
impl From<CoverTrafficWasm> for ConfigCoverTraffic {
fn from(cover_traffic: CoverTrafficWasm) -> Self {
ConfigCoverTraffic {
loop_cover_traffic_average_delay: Duration::from_millis(
cover_traffic.loop_cover_traffic_average_delay_ms as u64,
),
cover_traffic_primary_size_ratio: cover_traffic.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
}
}
}
impl From<ConfigCoverTraffic> for CoverTrafficWasm {
fn from(cover_traffic: ConfigCoverTraffic) -> Self {
CoverTrafficWasm {
loop_cover_traffic_average_delay_ms: cover_traffic
.loop_cover_traffic_average_delay
.as_millis() as u32,
cover_traffic_primary_size_ratio: cover_traffic.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct GatewayConnectionWasm {
pub gateway_response_timeout_ms: u32,
}
impl Default for GatewayConnectionWasm {
fn default() -> Self {
ConfigGatewayConnection::default().into()
}
}
impl From<GatewayConnectionWasm> for ConfigGatewayConnection {
fn from(gateway_connection: GatewayConnectionWasm) -> Self {
ConfigGatewayConnection {
gateway_response_timeout: Duration::from_millis(
gateway_connection.gateway_response_timeout_ms as u64,
),
}
}
}
impl From<ConfigGatewayConnection> for GatewayConnectionWasm {
fn from(gateway_connection: ConfigGatewayConnection) -> Self {
GatewayConnectionWasm {
gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis()
as u32,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AcknowledgementsWasm {
pub average_ack_delay_ms: u32,
pub ack_wait_multiplier: f64,
pub ack_wait_addition_ms: u32,
}
impl Default for AcknowledgementsWasm {
fn default() -> Self {
ConfigAcknowledgements::default().into()
}
}
impl From<AcknowledgementsWasm> for ConfigAcknowledgements {
fn from(acknowledgements: AcknowledgementsWasm) -> Self {
ConfigAcknowledgements {
average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms as u64),
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
ack_wait_addition: Duration::from_millis(acknowledgements.ack_wait_addition_ms as u64),
}
}
}
impl From<ConfigAcknowledgements> for AcknowledgementsWasm {
fn from(acknowledgements: ConfigAcknowledgements) -> Self {
AcknowledgementsWasm {
average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u32,
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u32,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TopologyWasm {
pub topology_refresh_rate_ms: u32,
pub topology_resolution_timeout_ms: u32,
pub max_startup_gateway_waiting_period_ms: u32,
pub disable_refreshing: bool,
pub minimum_mixnode_performance: u8,
pub minimum_gateway_performance: u8,
pub use_extended_topology: bool,
pub ignore_egress_epoch_role: bool,
pub ignore_ingress_epoch_role: bool,
}
impl Default for TopologyWasm {
fn default() -> Self {
ConfigTopology::default().into()
}
}
impl From<TopologyWasm> for ConfigTopology {
fn from(topology: TopologyWasm) -> Self {
ConfigTopology {
topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms as u64),
topology_resolution_timeout: Duration::from_millis(
topology.topology_resolution_timeout_ms as u64,
),
disable_refreshing: topology.disable_refreshing,
max_startup_gateway_waiting_period: Duration::from_millis(
topology.max_startup_gateway_waiting_period_ms as u64,
),
minimum_mixnode_performance: topology.minimum_mixnode_performance,
minimum_gateway_performance: topology.minimum_gateway_performance,
use_extended_topology: topology.use_extended_topology,
ignore_egress_epoch_role: topology.ignore_egress_epoch_role,
ignore_ingress_epoch_role: topology.ignore_ingress_epoch_role,
}
}
}
impl From<ConfigTopology> for TopologyWasm {
fn from(topology: ConfigTopology) -> Self {
TopologyWasm {
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u32,
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u32,
max_startup_gateway_waiting_period_ms: topology
.max_startup_gateway_waiting_period
.as_millis() as u32,
disable_refreshing: topology.disable_refreshing,
minimum_mixnode_performance: topology.minimum_mixnode_performance,
minimum_gateway_performance: topology.minimum_gateway_performance,
use_extended_topology: topology.use_extended_topology,
ignore_egress_epoch_role: topology.ignore_egress_epoch_role,
ignore_ingress_epoch_role: topology.ignore_ingress_epoch_role,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReplySurbsWasm {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
pub minimum_reply_surb_threshold_buffer: usize,
pub minimum_reply_surb_request_size: u32,
pub maximum_reply_surb_request_size: u32,
pub maximum_allowed_reply_surb_request_size: u32,
pub maximum_reply_surb_rerequest_waiting_period_ms: u32,
pub maximum_reply_surb_drop_waiting_period_ms: u32,
pub maximum_reply_surbs_rerequests: usize,
pub maximum_reply_key_age_ms: u32,
pub surb_mix_hops: Option<u8>,
}
impl Default for ReplySurbsWasm {
fn default() -> Self {
ConfigReplySurbs::default().into()
}
}
impl From<ReplySurbsWasm> for ConfigReplySurbs {
fn from(reply_surbs: ReplySurbsWasm) -> Self {
ConfigReplySurbs {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
minimum_reply_surb_threshold_buffer: reply_surbs.minimum_reply_surb_threshold_buffer,
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: reply_surbs
.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period: Duration::from_millis(
reply_surbs.maximum_reply_surb_rerequest_waiting_period_ms as u64,
),
maximum_reply_surb_drop_waiting_period: Duration::from_millis(
reply_surbs.maximum_reply_surb_drop_waiting_period_ms as u64,
),
maximum_reply_surbs_rerequests: reply_surbs.maximum_reply_surbs_rerequests,
maximum_reply_key_age: Duration::from_millis(
reply_surbs.maximum_reply_key_age_ms as u64,
),
surb_mix_hops: reply_surbs.surb_mix_hops,
}
}
}
impl From<ConfigReplySurbs> for ReplySurbsWasm {
fn from(reply_surbs: ConfigReplySurbs) -> Self {
ReplySurbsWasm {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
minimum_reply_surb_threshold_buffer: reply_surbs.minimum_reply_surb_threshold_buffer,
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: reply_surbs
.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period_ms: reply_surbs
.maximum_reply_surb_rerequest_waiting_period
.as_millis() as u32,
maximum_reply_surb_drop_waiting_period_ms: reply_surbs
.maximum_reply_surb_drop_waiting_period
.as_millis() as u32,
maximum_reply_surbs_rerequests: reply_surbs.maximum_reply_surbs_rerequests,
maximum_reply_key_age_ms: reply_surbs.maximum_reply_key_age.as_millis() as u32,
surb_mix_hops: reply_surbs.surb_mix_hops,
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize, Copy, Default)]
#[serde(deny_unknown_fields)]
pub struct ForgetMeWasm {
pub client: bool,
pub stats: bool,
}
impl From<ForgetMeWasm> for ForgetMe {
fn from(value: ForgetMeWasm) -> Self {
ForgetMe::new(value.client, value.stats)
}
}
impl From<ForgetMe> for ForgetMeWasm {
fn from(value: ForgetMe) -> Self {
Self {
client: value.client(),
stats: value.stats(),
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Copy, Clone, Deserialize, PartialEq, Serialize, Default)]
#[serde(deny_unknown_fields)]
pub struct RememberMeWasm {
pub stats: bool,
}
impl From<RememberMeWasm> for RememberMe {
fn from(value: RememberMeWasm) -> Self {
RememberMe::new(value.stats, SessionType::Wasm)
}
}
impl From<RememberMe> for RememberMeWasm {
fn from(value: RememberMe) -> Self {
Self {
stats: value.stats(),
}
}
}
#[wasm_bindgen(inspectable)]
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct StatsReportingWasm {
pub enabled: bool,
#[wasm_bindgen(getter_with_clone)]
pub provider_address: Option<String>,
pub reporting_interval_ms: u32,
}
impl Default for StatsReportingWasm {
fn default() -> Self {
ConfigStatsReporting::default().into()
}
}
impl From<StatsReportingWasm> for ConfigStatsReporting {
fn from(stats_reporting: StatsReportingWasm) -> Self {
ConfigStatsReporting {
enabled: stats_reporting.enabled,
provider_address: stats_reporting
.provider_address
.map(|address| address.parse().expect("Invalid provider address")),
reporting_interval: Duration::from_millis(stats_reporting.reporting_interval_ms as u64),
}
}
}
impl From<ConfigStatsReporting> for StatsReportingWasm {
fn from(stats_reporting: ConfigStatsReporting) -> Self {
StatsReportingWasm {
enabled: stats_reporting.enabled,
provider_address: stats_reporting.provider_address.map(|r| r.to_string()),
reporting_interval_ms: stats_reporting.reporting_interval.as_millis() as u32,
}
}
}