Made gateway mandatory during init (#331)
This commit is contained in:
committed by
GitHub
parent
82b0d7cbcf
commit
66eb1913ba
@@ -40,8 +40,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
.help("Id of the gateway we have preference to connect to. If left empty, a random gateway will be chosen.")
|
||||
.help("Id of the gateway we are going to connect to")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("directory")
|
||||
.long("directory")
|
||||
@@ -65,85 +66,40 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
}
|
||||
|
||||
async fn try_gateway_registration(
|
||||
gateways: &[gateway::Node],
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Option<(String, String, SharedKeys)> {
|
||||
) -> SharedKeys {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
for gateway in gateways {
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
if gateway_client.establish_connection().await.is_ok() {
|
||||
if let Ok(shared_key) = gateway_client.register().await {
|
||||
if let Err(err) = gateway_client.close_connection().await {
|
||||
eprintln!("Error while closing connection to the gateway! - {:?}", err);
|
||||
continue;
|
||||
} else {
|
||||
return Some((
|
||||
gateway.identity_key.to_base58_string(),
|
||||
gateway.client_listener.clone(),
|
||||
shared_key,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.register()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn choose_gateway(
|
||||
directory_server: String,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> (String, String, SharedKeys) {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.clone());
|
||||
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.to_string());
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
|
||||
|
||||
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
|
||||
// don't care about health of the networks as mixes can go up and down any time,
|
||||
// but DO care about gateways
|
||||
let gateways = version_filtered_topology.gateways();
|
||||
|
||||
// try to perform registration so that we wouldn't need to do it at startup
|
||||
// + at the same time we'll know if we can actually talk with that gateway
|
||||
let registration_result = try_gateway_registration(gateways, our_identity).await;
|
||||
match registration_result {
|
||||
None => {
|
||||
// while technically there's no issue client-side, it will be impossible to execute
|
||||
// `nym-client run` as no gateway is available so it might be best to not finalize
|
||||
// the init and rely on users trying to init another time?
|
||||
panic!(
|
||||
"Currently there are no valid gateways available on the network ({}). \
|
||||
Please try to run `init` again at later time or change your directory server",
|
||||
directory_server
|
||||
)
|
||||
}
|
||||
Some((gateway_id, gateway_listener, shared_key)) => {
|
||||
(gateway_id, gateway_listener, shared_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_gateway_listener(directory_server: String, gateway_identity: &str) -> Option<String> {
|
||||
let directory_client_config = directory_client::Config::new(directory_server);
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
|
||||
// technically we don't need to do conversion here, but let's be consistent
|
||||
let nym_topology: NymTopology = topology.try_into().ok()?;
|
||||
let gateways = nym_topology.gateways();
|
||||
|
||||
for gateway in gateways {
|
||||
if gateway.identity_key.to_base58_string() == gateway_identity {
|
||||
return Some(gateway.client_listener.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
version_filtered_topology
|
||||
.gateways()
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
@@ -161,38 +117,23 @@ pub fn execute(matches: &ArgMatches) {
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
// if there is no gateway chosen, get a random-ish one from the topology
|
||||
if config.get_base().get_gateway_id().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
|
||||
config.get_base().get_directory_server(),
|
||||
key_manager.identity_keypair(),
|
||||
));
|
||||
let gateway_id = matches.value_of("gateway").unwrap();
|
||||
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
let registration_fut = async {
|
||||
let gate_details =
|
||||
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
};
|
||||
|
||||
key_manager.insert_gateway_shared_key(shared_key)
|
||||
}
|
||||
|
||||
// we specified our gateway but don't know its physical address
|
||||
if config.get_base().get_gateway_listener().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let gateway_listener = rt
|
||||
.block_on(get_gateway_listener(
|
||||
config.get_base().get_directory_server(),
|
||||
&config.get_base().get_gateway_id(),
|
||||
))
|
||||
.expect("No gateway with provided id exists!");
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
}
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
|
||||
@@ -46,8 +46,9 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
.arg(Arg::with_name("gateway")
|
||||
.long("gateway")
|
||||
.help("Id of the gateway we have preference to connect to. If left empty, a random gateway will be chosen.")
|
||||
.help("Id of the gateway we are going to connect to")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
)
|
||||
.arg(Arg::with_name("directory")
|
||||
.long("directory")
|
||||
@@ -67,85 +68,40 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
)
|
||||
}
|
||||
|
||||
async fn try_gateway_registration(
|
||||
gateways: &[gateway::Node],
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Option<(String, String, SharedKeys)> {
|
||||
) -> SharedKeys {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
for gateway in gateways {
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
if gateway_client.establish_connection().await.is_ok() {
|
||||
if let Ok(shared_key) = gateway_client.register().await {
|
||||
if let Err(err) = gateway_client.close_connection().await {
|
||||
eprintln!("Error while closing connection to the gateway! - {:?}", err);
|
||||
continue;
|
||||
} else {
|
||||
return Some((
|
||||
gateway.identity_key.to_base58_string(),
|
||||
gateway.client_listener.clone(),
|
||||
shared_key,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
url::Url::parse(&gateway.client_listener).unwrap(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.register()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn choose_gateway(
|
||||
directory_server: String,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> (String, String, SharedKeys) {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.clone());
|
||||
async fn gateway_details(directory_server: &str, gateway_id: &str) -> gateway::Node {
|
||||
let directory_client_config = directory_client::Config::new(directory_server.to_string());
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
let nym_topology: NymTopology = topology.try_into().expect("Invalid topology data!");
|
||||
|
||||
let version_filtered_topology = nym_topology.filter_system_version(built_info::PKG_VERSION);
|
||||
// don't care about health of the networks as mixes can go up and down any time,
|
||||
// but DO care about gateways
|
||||
let gateways = version_filtered_topology.gateways();
|
||||
|
||||
// try to perform registration so that we wouldn't need to do it at startup
|
||||
// + at the same time we'll know if we can actually talk with that gateway
|
||||
let registration_result = try_gateway_registration(gateways, our_identity).await;
|
||||
match registration_result {
|
||||
None => {
|
||||
// while technically there's no issue client-side, it will be impossible to execute
|
||||
// `nym-client run` as no gateway is available so it might be best to not finalize
|
||||
// the init and rely on users trying to init another time?
|
||||
panic!(
|
||||
"Currently there are no valid gateways available on the network ({}). \
|
||||
Please try to run `init` again at later time or change your directory server",
|
||||
directory_server
|
||||
)
|
||||
}
|
||||
Some((gateway_id, gateway_listener, shared_key)) => {
|
||||
(gateway_id, gateway_listener, shared_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_gateway_listener(directory_server: String, gateway_identity: &str) -> Option<String> {
|
||||
let directory_client_config = directory_client::Config::new(directory_server);
|
||||
let directory_client = directory_client::Client::new(directory_client_config);
|
||||
let topology = directory_client.get_topology().await.unwrap();
|
||||
|
||||
// technically we don't need to do conversion here, but let's be consistent
|
||||
let nym_topology: NymTopology = topology.try_into().ok()?;
|
||||
let gateways = nym_topology.gateways();
|
||||
|
||||
for gateway in gateways {
|
||||
if gateway.identity_key.to_base58_string() == gateway_identity {
|
||||
return Some(gateway.client_listener.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
version_filtered_topology
|
||||
.gateways()
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
@@ -165,38 +121,23 @@ pub fn execute(matches: &ArgMatches) {
|
||||
// create identity, encryption and ack keys.
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
// if there is no gateway chosen, get a random-ish one from the topology
|
||||
if config.get_base().get_gateway_id().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (gateway_id, gateway_listener, shared_key) = rt.block_on(choose_gateway(
|
||||
config.get_base().get_directory_server(),
|
||||
key_manager.identity_keypair(),
|
||||
));
|
||||
let gateway_id = matches.value_of("gateway").unwrap();
|
||||
|
||||
config.get_base_mut().with_gateway_id(gateway_id);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
let registration_fut = async {
|
||||
let gate_details =
|
||||
gateway_details(&config.get_base().get_directory_server(), gateway_id).await;
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
};
|
||||
|
||||
key_manager.insert_gateway_shared_key(shared_key)
|
||||
}
|
||||
|
||||
// we specified our gateway but don't know its physical address
|
||||
if config.get_base().get_gateway_listener().is_empty() {
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let gateway_listener = rt
|
||||
.block_on(get_gateway_listener(
|
||||
config.get_base().get_directory_server(),
|
||||
&config.get_base().get_gateway_id(),
|
||||
))
|
||||
.expect("No gateway with provided id exists!");
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
}
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_listener(gateway_listener);
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
@@ -211,7 +152,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
|
||||
println!(
|
||||
"Unless overridden in all `nym-client run` we will be talking to the following gateway: {}...",
|
||||
"Unless overridden in all `nym-socks5-client run` we will be talking to the following gateway: {}...",
|
||||
config.get_base().get_gateway_id(),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user