temp before big mod
This commit is contained in:
Generated
+409
-953
File diff suppressed because it is too large
Load Diff
@@ -16,10 +16,11 @@ nym-http-api-client = { path = "../common/http-api-client" }
|
||||
nym-sphinx = { path = "../common/nymsphinx" } # replaces the types pulled in from nym-sdk in nym-vpn-client repo
|
||||
nym-topology = { path = "../common/topology" } # replaces the types pulled in from nym-sdk in nym-vpn-client repo
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
nym-vpn-api-client = { git = "https://github.com/nymtech/nym-vpn-client/", rev = "5ab01ba06057449614dd6a8450d04358c5ec33d1" }
|
||||
# nym-vpn-api-client = { git = "https://github.com/nymtech/nym-vpn-client/", rev = "5ab01ba06057449614dd6a8450d04358c5ec33d1" }
|
||||
nym-crypto = { path = "../common/crypto" }
|
||||
nym-sphinx-addressing = { path = "../common/nymsphinx/addressing" }
|
||||
nym-network-defaults = { path = "../common/network-defaults" }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
|
||||
rand.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::Location;
|
||||
use crate::{Location, NymDirectoryCountry};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Country {
|
||||
@@ -14,8 +14,8 @@ impl Country {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::NymDirectoryCountry> for Country {
|
||||
fn from(country: nym_vpn_api_client::response::NymDirectoryCountry) -> Self {
|
||||
impl From<NymDirectoryCountry> for Country {
|
||||
fn from(country: NymDirectoryCountry) -> Self {
|
||||
Self {
|
||||
iso_code: country.iso_code().to_string(),
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use itertools::Itertools;
|
||||
use nym_contracts_common::Percent;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_topology::{NodeId, RoutingNode};
|
||||
use nym_validator_client::models::{KeyRotationId, NymNodeDescription};
|
||||
use nym_vpn_api_client::{
|
||||
response::{BridgeInformation, BridgeParameters},
|
||||
types::{Percent, ScoreThresholds},
|
||||
};
|
||||
use rand::seq::IteratorRandom;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||
@@ -18,14 +15,13 @@ use std::{
|
||||
use tracing::error;
|
||||
|
||||
use crate::{
|
||||
AuthAddress, Country, Error, IpPacketRouterAddress,
|
||||
AuthAddress, BridgeInformation, BridgeParameters, Country, Error, IpPacketRouterAddress,
|
||||
ScoreThresholds,
|
||||
entries::score::{HIGH_SCORE_THRESHOLD, LOW_SCORE_THRESHOLD, MEDIUM_SCORE_THRESHOLD, Score},
|
||||
error::Result,
|
||||
helpers,
|
||||
};
|
||||
|
||||
// pub type NymNode = Gateway;
|
||||
|
||||
pub const COUNTRY_WITH_REGION_SELECTOR: &str = "US";
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -286,7 +282,7 @@ pub struct Location {
|
||||
pub asn: Option<Asn>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ScoreValue {
|
||||
Offline,
|
||||
Low,
|
||||
@@ -391,17 +387,17 @@ pub struct WgProbeResults {
|
||||
pub ping_ips_performance: f32,
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::AsnKind> for AsnKind {
|
||||
fn from(value: nym_vpn_api_client::response::AsnKind) -> Self {
|
||||
impl From<helpers::AsnKind> for AsnKind {
|
||||
fn from(value: helpers::AsnKind) -> Self {
|
||||
match value {
|
||||
nym_vpn_api_client::response::AsnKind::Residential => AsnKind::Residential,
|
||||
nym_vpn_api_client::response::AsnKind::Other => AsnKind::Other,
|
||||
helpers::AsnKind::Residential => AsnKind::Residential,
|
||||
helpers::AsnKind::Other => AsnKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::Asn> for Asn {
|
||||
fn from(location: nym_vpn_api_client::response::Asn) -> Self {
|
||||
impl From<helpers::Asn> for Asn {
|
||||
fn from(location: helpers::Asn) -> Self {
|
||||
Asn {
|
||||
asn: location.asn,
|
||||
name: location.name,
|
||||
@@ -410,8 +406,8 @@ impl From<nym_vpn_api_client::response::Asn> for Asn {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::Location> for Location {
|
||||
fn from(location: nym_vpn_api_client::response::Location) -> Self {
|
||||
impl From<helpers::Location> for Location {
|
||||
fn from(location: helpers::Location) -> Self {
|
||||
Location {
|
||||
two_letter_iso_country_code: location.two_letter_iso_country_code,
|
||||
latitude: location.latitude,
|
||||
@@ -423,36 +419,36 @@ impl From<nym_vpn_api_client::response::Location> for Location {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::ScoreValue> for ScoreValue {
|
||||
fn from(value: nym_vpn_api_client::response::ScoreValue) -> Self {
|
||||
match value {
|
||||
nym_vpn_api_client::response::ScoreValue::Offline => ScoreValue::Offline,
|
||||
nym_vpn_api_client::response::ScoreValue::Low => ScoreValue::Low,
|
||||
nym_vpn_api_client::response::ScoreValue::Medium => ScoreValue::Medium,
|
||||
nym_vpn_api_client::response::ScoreValue::High => ScoreValue::High,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::ScoreValue> for ScoreValue {
|
||||
// fn from(value: nym_vpn_api_client::response::ScoreValue) -> Self {
|
||||
// match value {
|
||||
// nym_vpn_api_client::response::ScoreValue::Offline => ScoreValue::Offline,
|
||||
// nym_vpn_api_client::response::ScoreValue::Low => ScoreValue::Low,
|
||||
// nym_vpn_api_client::response::ScoreValue::Medium => ScoreValue::Medium,
|
||||
// nym_vpn_api_client::response::ScoreValue::High => ScoreValue::High,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<nym_vpn_api_client::response::DVpnGatewayPerformance> for Performance {
|
||||
fn from(value: nym_vpn_api_client::response::DVpnGatewayPerformance) -> Self {
|
||||
Performance {
|
||||
last_updated_utc: value.last_updated_utc,
|
||||
score: value.score.into(),
|
||||
load: value.load.into(),
|
||||
uptime_percentage_last_24_hours: value.uptime_percentage_last_24_hours,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::DVpnGatewayPerformance> for Performance {
|
||||
// fn from(value: nym_vpn_api_client::response::DVpnGatewayPerformance) -> Self {
|
||||
// Performance {
|
||||
// last_updated_utc: value.last_updated_utc,
|
||||
// score: value.score.into(),
|
||||
// load: value.load.into(),
|
||||
// uptime_percentage_last_24_hours: value.uptime_percentage_last_24_hours,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<nym_vpn_api_client::response::Probe> for Probe {
|
||||
fn from(probe: nym_vpn_api_client::response::Probe) -> Self {
|
||||
Probe {
|
||||
last_updated_utc: probe.last_updated_utc,
|
||||
outcome: ProbeOutcome::from(probe.outcome),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::Probe> for Probe {
|
||||
// fn from(probe: nym_vpn_api_client::response::Probe) -> Self {
|
||||
// Probe {
|
||||
// last_updated_utc: probe.last_updated_utc,
|
||||
// outcome: ProbeOutcome::from(probe.outcome),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<Percent> for Score {
|
||||
fn from(percent: Percent) -> Self {
|
||||
@@ -469,96 +465,96 @@ impl From<Percent> for Score {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::response::ProbeOutcome> for ProbeOutcome {
|
||||
fn from(outcome: nym_vpn_api_client::response::ProbeOutcome) -> Self {
|
||||
ProbeOutcome {
|
||||
as_entry: Entry::from(outcome.as_entry),
|
||||
as_exit: outcome.as_exit.map(Exit::from),
|
||||
wg: outcome.wg.map(WgProbeResults::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::ProbeOutcome> for ProbeOutcome {
|
||||
// fn from(outcome: nym_vpn_api_client::response::ProbeOutcome) -> Self {
|
||||
// ProbeOutcome {
|
||||
// as_entry: Entry::from(outcome.as_entry),
|
||||
// as_exit: outcome.as_exit.map(Exit::from),
|
||||
// wg: outcome.wg.map(WgProbeResults::from),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<nym_vpn_api_client::response::Entry> for Entry {
|
||||
fn from(entry: nym_vpn_api_client::response::Entry) -> Self {
|
||||
Entry {
|
||||
can_connect: entry.can_connect,
|
||||
can_route: entry.can_route,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::Entry> for Entry {
|
||||
// fn from(entry: nym_vpn_api_client::response::Entry) -> Self {
|
||||
// Entry {
|
||||
// can_connect: entry.can_connect,
|
||||
// can_route: entry.can_route,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<nym_vpn_api_client::response::Exit> for Exit {
|
||||
fn from(exit: nym_vpn_api_client::response::Exit) -> Self {
|
||||
Exit {
|
||||
can_connect: exit.can_connect,
|
||||
can_route_ip_v4: exit.can_route_ip_v4,
|
||||
can_route_ip_external_v4: exit.can_route_ip_external_v4,
|
||||
can_route_ip_v6: exit.can_route_ip_v6,
|
||||
can_route_ip_external_v6: exit.can_route_ip_external_v6,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::Exit> for Exit {
|
||||
// fn from(exit: nym_vpn_api_client::response::Exit) -> Self {
|
||||
// Exit {
|
||||
// can_connect: exit.can_connect,
|
||||
// can_route_ip_v4: exit.can_route_ip_v4,
|
||||
// can_route_ip_external_v4: exit.can_route_ip_external_v4,
|
||||
// can_route_ip_v6: exit.can_route_ip_v6,
|
||||
// can_route_ip_external_v6: exit.can_route_ip_external_v6,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<nym_vpn_api_client::response::WgProbeResults> for WgProbeResults {
|
||||
fn from(results: nym_vpn_api_client::response::WgProbeResults) -> Self {
|
||||
WgProbeResults {
|
||||
can_register: results.can_register,
|
||||
can_handshake: results.can_handshake,
|
||||
can_resolve_dns: results.can_resolve_dns,
|
||||
ping_hosts_performance: results.ping_hosts_performance,
|
||||
ping_ips_performance: results.ping_ips_performance,
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl From<nym_vpn_api_client::response::WgProbeResults> for WgProbeResults {
|
||||
// fn from(results: nym_vpn_api_client::response::WgProbeResults) -> Self {
|
||||
// WgProbeResults {
|
||||
// can_register: results.can_register,
|
||||
// can_handshake: results.can_handshake,
|
||||
// can_resolve_dns: results.can_resolve_dns,
|
||||
// ping_hosts_performance: results.ping_hosts_performance,
|
||||
// ping_ips_performance: results.ping_ips_performance,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl TryFrom<nym_vpn_api_client::response::NymDirectoryGateway> for Gateway {
|
||||
type Error = Error;
|
||||
// impl TryFrom<nym_vpn_api_client::response::NymDirectoryGateway> for Gateway {
|
||||
// type Error = Error;
|
||||
|
||||
fn try_from(gateway: nym_vpn_api_client::response::NymDirectoryGateway) -> Result<Self> {
|
||||
let identity =
|
||||
NodeIdentity::from_base58_string(&gateway.identity_key).map_err(|source| {
|
||||
Error::NodeIdentityFormattingError {
|
||||
identity: gateway.identity_key,
|
||||
source,
|
||||
}
|
||||
})?;
|
||||
// fn try_from(gateway: nym_vpn_api_client::response::NymDirectoryGateway) -> Result<Self> {
|
||||
// let identity =
|
||||
// NodeIdentity::from_base58_string(&gateway.identity_key).map_err(|source| {
|
||||
// Error::NodeIdentityFormattingError {
|
||||
// identity: gateway.identity_key,
|
||||
// source,
|
||||
// }
|
||||
// })?;
|
||||
|
||||
let ipr_address = gateway
|
||||
.ip_packet_router
|
||||
.and_then(|ipr| IpPacketRouterAddress::try_from_base58_string(&ipr.address).ok());
|
||||
// let ipr_address = gateway
|
||||
// .ip_packet_router
|
||||
// .and_then(|ipr| IpPacketRouterAddress::try_from_base58_string(&ipr.address).ok());
|
||||
|
||||
let authenticator_address = gateway
|
||||
.authenticator
|
||||
.and_then(|auth| AuthAddress::try_from_base58_string(&auth.address).ok());
|
||||
// let authenticator_address = gateway
|
||||
// .authenticator
|
||||
// .and_then(|auth| AuthAddress::try_from_base58_string(&auth.address).ok());
|
||||
|
||||
let hostname = gateway.entry.hostname;
|
||||
let first_ip_address = gateway
|
||||
.ip_addresses
|
||||
.first()
|
||||
.cloned()
|
||||
.map(|ip| ip.to_string());
|
||||
let host = hostname.or(first_ip_address);
|
||||
// let hostname = gateway.entry.hostname;
|
||||
// let first_ip_address = gateway
|
||||
// .ip_addresses
|
||||
// .first()
|
||||
// .cloned()
|
||||
// .map(|ip| ip.to_string());
|
||||
// let host = hostname.or(first_ip_address);
|
||||
|
||||
Ok(Gateway {
|
||||
identity,
|
||||
moniker: gateway.name,
|
||||
location: Some(gateway.location.into()),
|
||||
ipr_address,
|
||||
authenticator_address,
|
||||
bridge_params: gateway.bridges,
|
||||
last_probe: gateway.last_probe.map(Probe::from),
|
||||
ips: gateway.ip_addresses,
|
||||
host,
|
||||
clients_ws_port: Some(gateway.entry.ws_port),
|
||||
clients_wss_port: gateway.entry.wss_port,
|
||||
mixnet_performance: Some(gateway.performance),
|
||||
mixnet_score: Some(Score::from(gateway.performance)),
|
||||
wg_performance: gateway.performance_v2.map(Performance::from),
|
||||
version: gateway.build_information.map(|info| info.build_version),
|
||||
})
|
||||
}
|
||||
}
|
||||
// Ok(Gateway {
|
||||
// identity,
|
||||
// moniker: gateway.name,
|
||||
// location: Some(gateway.location.into()),
|
||||
// ipr_address,
|
||||
// authenticator_address,
|
||||
// bridge_params: gateway.bridges,
|
||||
// last_probe: gateway.last_probe.map(Probe::from),
|
||||
// ips: gateway.ip_addresses,
|
||||
// host,
|
||||
// clients_ws_port: Some(gateway.entry.ws_port),
|
||||
// clients_wss_port: gateway.entry.wss_port,
|
||||
// mixnet_performance: Some(gateway.performance),
|
||||
// mixnet_score: Some(Score::from(gateway.performance)),
|
||||
// wg_performance: gateway.performance_v2.map(Performance::from),
|
||||
// version: gateway.build_information.map(|info| info.build_version),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
pub type NymNodeList = GatewayList;
|
||||
|
||||
@@ -702,22 +698,22 @@ impl fmt::Display for GatewayType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_vpn_api_client::types::GatewayType> for GatewayType {
|
||||
fn from(gateway_type: nym_vpn_api_client::types::GatewayType) -> Self {
|
||||
impl From<helpers::GatewayType> for GatewayType {
|
||||
fn from(gateway_type: helpers::GatewayType) -> Self {
|
||||
match gateway_type {
|
||||
nym_vpn_api_client::types::GatewayType::MixnetEntry => GatewayType::MixnetEntry,
|
||||
nym_vpn_api_client::types::GatewayType::MixnetExit => GatewayType::MixnetExit,
|
||||
nym_vpn_api_client::types::GatewayType::Wg => GatewayType::Wg,
|
||||
helpers::GatewayType::MixnetEntry => GatewayType::MixnetEntry,
|
||||
helpers::GatewayType::MixnetExit => GatewayType::MixnetExit,
|
||||
helpers::GatewayType::Wg => GatewayType::Wg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GatewayType> for nym_vpn_api_client::types::GatewayType {
|
||||
impl From<GatewayType> for helpers::GatewayType {
|
||||
fn from(gateway_type: GatewayType) -> Self {
|
||||
match gateway_type {
|
||||
GatewayType::MixnetEntry => nym_vpn_api_client::types::GatewayType::MixnetEntry,
|
||||
GatewayType::MixnetExit => nym_vpn_api_client::types::GatewayType::MixnetExit,
|
||||
GatewayType::Wg => nym_vpn_api_client::types::GatewayType::Wg,
|
||||
GatewayType::MixnetEntry => helpers::GatewayType::MixnetEntry,
|
||||
GatewayType::MixnetExit => helpers::GatewayType::MixnetExit,
|
||||
GatewayType::Wg => helpers::GatewayType::Wg,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -731,189 +727,3 @@ pub enum GatewayFilter {
|
||||
Exit, // Has an IPR address
|
||||
Vpn, // Has an authenticator address
|
||||
}
|
||||
|
||||
// #[derive(Debug, Clone, PartialEq)]
|
||||
// pub struct GatewayFilters {
|
||||
// pub gw_type: GatewayType,
|
||||
// pub filters: Vec<GatewayFilter>,
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Create a list of Gateways with different properties set for testing
|
||||
fn sample_gateway_list(gw_type: GatewayType) -> GatewayList {
|
||||
let asn = Asn {
|
||||
asn: "AS12345".to_string(),
|
||||
name: "Test ASN".to_string(),
|
||||
kind: AsnKind::Residential,
|
||||
};
|
||||
let addr = "MNrmKzuKjNdbEhfPUzVNfjw63oBQNSayqoQKGL4JjAV.6fDcSN6faGpvA3pd3riCwjpzXc7RQfWmGMa82UVoEwKE@d5adfJNtcdZW2XwK85JAAU8nXAs9JCPYn2RNvDLZn4e";
|
||||
let ipr = IpPacketRouterAddress::try_from_base58_string(addr).unwrap();
|
||||
let aa = AuthAddress::try_from_base58_string(addr).unwrap();
|
||||
let variables = [
|
||||
("US", "CA", None, Some(ipr), Some(aa)), // Gateway 1
|
||||
("US", "NY", Some(asn.clone()), None, None), // Gateway 2
|
||||
("DE", "BE", None, None, Some(aa)), // Gateway 3
|
||||
("FR", "Aquitaine", Some(asn.clone()), None, Some(aa)), // Gateway 4
|
||||
("US", "TX", Some(asn.clone()), Some(ipr), None), // Gateway 5
|
||||
("GB", "Hampshire", None, None, None), // Gateway 6
|
||||
];
|
||||
|
||||
let mut instance = 0;
|
||||
let gateways: Vec<Gateway> = variables
|
||||
.into_iter()
|
||||
.map(|(country, region, asn, ipr, aa)| {
|
||||
instance += 1;
|
||||
Gateway {
|
||||
identity: NodeIdentity::from_base58_string(
|
||||
"7CWjY3QFoA9dgE535u9bQiXCfzgMZvSpJu842GA1Wn42",
|
||||
)
|
||||
.unwrap(),
|
||||
moniker: format!("Gateway {instance}"),
|
||||
location: Some(Location {
|
||||
two_letter_iso_country_code: country.to_string(),
|
||||
region: region.to_string(),
|
||||
asn,
|
||||
..Default::default()
|
||||
}),
|
||||
ipr_address: ipr,
|
||||
authenticator_address: aa,
|
||||
bridge_params: None,
|
||||
last_probe: None,
|
||||
ips: Vec::new(),
|
||||
host: None,
|
||||
clients_ws_port: None,
|
||||
clients_wss_port: None,
|
||||
mixnet_performance: Some(Percent::from_percentage_value(75).unwrap()),
|
||||
mixnet_score: None,
|
||||
wg_performance: Some(Performance {
|
||||
last_updated_utc: "2024-01-01T00:00:00Z".to_string(),
|
||||
score: ScoreValue::High,
|
||||
load: ScoreValue::Low,
|
||||
uptime_percentage_last_24_hours: 0.75,
|
||||
}),
|
||||
version: None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
GatewayList::new(Some(gw_type), gateways)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_filter_score() {
|
||||
let wg_list = sample_gateway_list(GatewayType::Wg);
|
||||
let mixnet_entry_list = sample_gateway_list(GatewayType::MixnetEntry);
|
||||
let mixnet_exit_list = sample_gateway_list(GatewayType::MixnetExit);
|
||||
|
||||
let gws = wg_list.filter(&[GatewayFilter::MinScore(ScoreValue::High)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
let gws = wg_list.filter(&[GatewayFilter::MinScore(ScoreValue::Medium)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
let gws = wg_list.filter(&[GatewayFilter::MinScore(ScoreValue::Low)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
|
||||
let gws = mixnet_entry_list.filter(&[GatewayFilter::MinScore(ScoreValue::High)]);
|
||||
assert_eq!(gws.len(), 0);
|
||||
let gws = mixnet_entry_list.filter(&[GatewayFilter::MinScore(ScoreValue::Medium)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
let gws = mixnet_entry_list.filter(&[GatewayFilter::MinScore(ScoreValue::Low)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
|
||||
let gws = mixnet_exit_list.filter(&[GatewayFilter::MinScore(ScoreValue::High)]);
|
||||
assert_eq!(gws.len(), 0);
|
||||
let gws = mixnet_exit_list.filter(&[GatewayFilter::MinScore(ScoreValue::Medium)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
let gws = mixnet_exit_list.filter(&[GatewayFilter::MinScore(ScoreValue::Low)]);
|
||||
assert_eq!(gws.len(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_filter_exit_nodes() {
|
||||
let gateway_list = sample_gateway_list(GatewayType::MixnetEntry);
|
||||
let exit_gws = gateway_list.filter(&[GatewayFilter::Exit]);
|
||||
assert_eq!(exit_gws.len(), 2);
|
||||
assert_eq!(exit_gws[0].moniker, "Gateway 1");
|
||||
assert_eq!(exit_gws[1].moniker, "Gateway 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_filter_vpn_nodes() {
|
||||
let gateway_list = sample_gateway_list(GatewayType::MixnetExit);
|
||||
let vpn_gws = gateway_list.filter(&[GatewayFilter::Vpn]);
|
||||
assert_eq!(vpn_gws.len(), 3);
|
||||
assert_eq!(vpn_gws[0].moniker, "Gateway 1");
|
||||
assert_eq!(vpn_gws[1].moniker, "Gateway 3");
|
||||
assert_eq!(vpn_gws[2].moniker, "Gateway 4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_filter_residential() {
|
||||
let gateway_list = sample_gateway_list(GatewayType::Wg);
|
||||
let residential_gws = gateway_list.filter(&[GatewayFilter::Residential]);
|
||||
assert_eq!(residential_gws.len(), 3);
|
||||
assert_eq!(residential_gws[0].moniker, "Gateway 2");
|
||||
assert_eq!(residential_gws[1].moniker, "Gateway 4");
|
||||
assert_eq!(residential_gws[2].moniker, "Gateway 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_random_country() {
|
||||
let gateway_list = sample_gateway_list(GatewayType::MixnetEntry);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[GatewayFilter::Country("US".into())])
|
||||
.unwrap()
|
||||
.is_in_country("US")
|
||||
);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[GatewayFilter::Country("DE".into())])
|
||||
.unwrap()
|
||||
.is_in_country("DE")
|
||||
);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[GatewayFilter::Country("BE".into())])
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gateway_random_region() {
|
||||
let gateway_list = sample_gateway_list(GatewayType::MixnetExit);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[
|
||||
GatewayFilter::Country("US".into()),
|
||||
GatewayFilter::Region("CA".into())
|
||||
])
|
||||
.unwrap()
|
||||
.is_in_region("CA")
|
||||
);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[
|
||||
GatewayFilter::Country("GB".into()),
|
||||
GatewayFilter::Region("Hampshire".into())
|
||||
])
|
||||
.unwrap()
|
||||
.is_in_region("Hampshire")
|
||||
);
|
||||
|
||||
assert!(
|
||||
gateway_list
|
||||
.choose_random(&[
|
||||
GatewayFilter::Country("DE".into()),
|
||||
GatewayFilter::Region("XZ".into())
|
||||
])
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
// use nym_sdk::mixnet::{NodeIdentity, Recipient};
|
||||
use nym_validator_client::models::NymNodeData;
|
||||
|
||||
use crate::{Error, error::Result};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use nym_vpn_api_client::types::ScoreThresholds;
|
||||
use crate::helpers::ScoreThresholds;
|
||||
|
||||
pub(crate) const HIGH_SCORE_THRESHOLD: u8 = 80;
|
||||
pub(crate) const MEDIUM_SCORE_THRESHOLD: u8 = 60;
|
||||
|
||||
@@ -6,21 +6,20 @@ use std::{
|
||||
net::{IpAddr, SocketAddr},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Error, GatewayMinPerformance, ScoreThresholds,
|
||||
entries::gateway::{Gateway, GatewayList, GatewayType, NymNodeList},
|
||||
error::Result,
|
||||
};
|
||||
use nym_contracts_common::Percent;
|
||||
use nym_http_api_client::UserAgent;
|
||||
use nym_validator_client::{
|
||||
models::NymNodeDescription, nym_api::NymApiClientExt, nym_nodes::SkimmedNodesWithMetadata,
|
||||
};
|
||||
use nym_vpn_api_client::types::{GatewayMinPerformance, Percent, ScoreThresholds};
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use tracing::{debug, error, warn};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
Error,
|
||||
entries::gateway::{Gateway, GatewayList, GatewayType, NymNodeList},
|
||||
error::Result,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub nyxd_url: Url,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::ScoreValue;
|
||||
use nym_contracts_common::Percent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
pub fn split_ips(ips: Vec<IpAddr>) -> (Vec<Ipv4Addr>, Vec<Ipv6Addr>) {
|
||||
@@ -13,3 +16,119 @@ pub fn split_ips(ips: Vec<IpAddr>) -> (Vec<Ipv4Addr>, Vec<Ipv6Addr>) {
|
||||
(v4, v6)
|
||||
})
|
||||
}
|
||||
|
||||
// Types copied in from nym-vpn-client/nym-vpn-core/crates/nym-vpn-api-client
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NymDirectoryCountry(String);
|
||||
|
||||
impl NymDirectoryCountry {
|
||||
pub fn iso_code(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
pub fn into_string(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for NymDirectoryCountry {
|
||||
fn from(s: String) -> Self {
|
||||
Self(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct ScoreThresholds {
|
||||
pub high: u8,
|
||||
pub medium: u8,
|
||||
pub low: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GatewayType {
|
||||
MixnetEntry,
|
||||
MixnetExit,
|
||||
Wg,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug, Eq, PartialEq)]
|
||||
pub struct GatewayMinPerformance {
|
||||
pub mixnet_min_performance: Option<Percent>,
|
||||
pub vpn_min_performance: Option<Percent>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BridgeInformation {
|
||||
pub version: String,
|
||||
pub transports: Vec<BridgeParameters>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(tag = "transport_type", content = "args")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum BridgeParameters {
|
||||
QuicPlain(QuicClientOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct QuicClientOptions {
|
||||
/// Address describing the remote transport server. This is a vec to support multiple addresses
|
||||
/// so as to support both IPv4 and IPv6. These addresses are meant to describe a single bridge
|
||||
/// as the key material should not be used across multiple instances.
|
||||
pub addresses: Vec<std::net::SocketAddr>,
|
||||
|
||||
/// Override hostname used for certificate verification
|
||||
pub host: Option<String>,
|
||||
|
||||
/// Use identity public key to verify server self signed certificate
|
||||
pub id_pubkey: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AsnKind {
|
||||
Residential,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Asn {
|
||||
pub asn: String,
|
||||
pub name: String,
|
||||
pub kind: AsnKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Entry {
|
||||
pub can_connect: bool,
|
||||
pub can_route: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Exit {
|
||||
pub can_connect: bool,
|
||||
pub can_route_ip_v4: bool,
|
||||
pub can_route_ip_external_v4: bool,
|
||||
pub can_route_ip_v6: bool,
|
||||
pub can_route_ip_external_v6: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Location {
|
||||
pub two_letter_iso_country_code: String,
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
|
||||
pub city: String,
|
||||
pub region: String,
|
||||
|
||||
pub asn: Option<Asn>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct DVpnGatewayPerformance {
|
||||
pub last_updated_utc: String,
|
||||
pub score: ScoreValue,
|
||||
pub load: ScoreValue,
|
||||
pub uptime_percentage_last_24_hours: f32,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ mod entries;
|
||||
mod error;
|
||||
mod gateway_client;
|
||||
mod helpers;
|
||||
pub use nym_vpn_api_client::types::{GatewayMinPerformance, NaiveFloat, Percent};
|
||||
|
||||
pub use crate::{
|
||||
entries::{
|
||||
@@ -22,5 +21,8 @@ pub use crate::{
|
||||
},
|
||||
error::Error,
|
||||
gateway_client::{Config, GatewayClient},
|
||||
helpers::split_ips,
|
||||
helpers::{
|
||||
BridgeInformation, BridgeParameters, GatewayMinPerformance, NymDirectoryCountry,
|
||||
QuicClientOptions, ScoreThresholds, split_ips,
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user