|
| 1 | +// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +use crate::{ |
| 5 | + cli::{override_config, OverrideConfig}, |
| 6 | + config::Config, |
| 7 | + error::NetworkRequesterError, |
| 8 | +}; |
| 9 | +use clap::Args; |
| 10 | +use config::NymConfig; |
| 11 | +use crypto::asymmetric::identity; |
| 12 | +use nymsphinx::addressing::clients::Recipient; |
| 13 | +use serde::Serialize; |
| 14 | +use std::fmt::Display; |
| 15 | +use tap::TapFallible; |
| 16 | + |
| 17 | +#[derive(Args, Clone)] |
| 18 | +pub(crate) struct Init { |
| 19 | + /// Id of the nym-mixnet-client we want to create config for. |
| 20 | + #[clap(long)] |
| 21 | + id: String, |
| 22 | + |
| 23 | + /// Id of the gateway we are going to connect to. |
| 24 | + #[clap(long)] |
| 25 | + gateway: Option<identity::PublicKey>, |
| 26 | + |
| 27 | + /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, |
| 28 | + /// potentially causing loss of access. |
| 29 | + #[clap(long)] |
| 30 | + force_register_gateway: bool, |
| 31 | + |
| 32 | + /// Comma separated list of rest endpoints of the nyxd validators |
| 33 | + #[clap(long, alias = "nymd_validators", value_delimiter = ',')] |
| 34 | + nyxd_urls: Option<Vec<url::Url>>, |
| 35 | + |
| 36 | + /// Comma separated list of rest endpoints of the API validators |
| 37 | + #[clap(long, alias = "api_validators", value_delimiter = ',')] |
| 38 | + // the alias here is included for backwards compatibility (1.1.4 and before) |
| 39 | + nym_apis: Option<Vec<url::Url>>, |
| 40 | + |
| 41 | + /// Set this client to work in a enabled credentials mode that would attempt to use gateway |
| 42 | + /// with bandwidth credential requirement. |
| 43 | + #[clap(long)] |
| 44 | + enabled_credentials_mode: Option<bool>, |
| 45 | + |
| 46 | + /// Save a summary of the initialization to a json file |
| 47 | + #[clap(long)] |
| 48 | + output_json: bool, |
| 49 | +} |
| 50 | + |
| 51 | +impl From<Init> for OverrideConfig { |
| 52 | + fn from(init_config: Init) -> Self { |
| 53 | + OverrideConfig { |
| 54 | + nym_apis: init_config.nym_apis, |
| 55 | + fastmode: false, |
| 56 | + no_cover: false, |
| 57 | + |
| 58 | + nyxd_urls: init_config.nyxd_urls, |
| 59 | + enabled_credentials_mode: init_config.enabled_credentials_mode, |
| 60 | + } |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +#[derive(Debug, Serialize)] |
| 65 | +pub struct InitResults { |
| 66 | + #[serde(flatten)] |
| 67 | + client_core: client_core::init::InitResults, |
| 68 | +} |
| 69 | + |
| 70 | +impl InitResults { |
| 71 | + fn new(config: &Config, address: &Recipient) -> Self { |
| 72 | + Self { |
| 73 | + client_core: client_core::init::InitResults::new(config.get_base(), address), |
| 74 | + } |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +impl Display for InitResults { |
| 79 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 80 | + write!(f, "{}", self.client_core) |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +pub(crate) async fn execute(args: &Init) -> Result<(), NetworkRequesterError> { |
| 85 | + println!("Initialising client..."); |
| 86 | + |
| 87 | + let id = &args.id; |
| 88 | + |
| 89 | + let already_init = Config::default_config_file_path(id).exists(); |
| 90 | + if already_init { |
| 91 | + println!("Client \"{id}\" was already initialised before"); |
| 92 | + } |
| 93 | + |
| 94 | + // Usually you only register with the gateway on the first init, however you can force |
| 95 | + // re-registering if wanted. |
| 96 | + let user_wants_force_register = args.force_register_gateway; |
| 97 | + if user_wants_force_register { |
| 98 | + println!("Instructed to force registering gateway. This might overwrite keys!"); |
| 99 | + } |
| 100 | + |
| 101 | + // If the client was already initialized, don't generate new keys and don't re-register with |
| 102 | + // the gateway (because this would create a new shared key). |
| 103 | + // Unless the user really wants to. |
| 104 | + let register_gateway = !already_init || user_wants_force_register; |
| 105 | + |
| 106 | + // Attempt to use a user-provided gateway, if possible |
| 107 | + let user_chosen_gateway_id = args.gateway; |
| 108 | + |
| 109 | + // Load and potentially override config |
| 110 | + let mut config = override_config(Config::new(id), OverrideConfig::from(args.clone())); |
| 111 | + |
| 112 | + // Setup gateway by either registering a new one, or creating a new config from the selected |
| 113 | + // one but with keys kept, or reusing the gateway configuration. |
| 114 | + let gateway = client_core::init::setup_gateway_from_config::<Config, _>( |
| 115 | + register_gateway, |
| 116 | + user_chosen_gateway_id, |
| 117 | + config.get_base(), |
| 118 | + ) |
| 119 | + .await |
| 120 | + .map_err(|source| { |
| 121 | + eprintln!("Failed to setup gateway\nError: {source}"); |
| 122 | + NetworkRequesterError::FailedToSetupGateway { source } |
| 123 | + })?; |
| 124 | + |
| 125 | + config.get_base_mut().set_gateway_endpoint(gateway); |
| 126 | + |
| 127 | + config.save_to_file(None).tap_err(|_| { |
| 128 | + log::error!("Failed to save the config file"); |
| 129 | + })?; |
| 130 | + |
| 131 | + print_saved_config(&config); |
| 132 | + |
| 133 | + let address = client_core::init::get_client_address_from_stored_keys(config.get_base())?; |
| 134 | + let init_results = InitResults::new(&config, &address); |
| 135 | + println!("{init_results}"); |
| 136 | + |
| 137 | + // Output summary to a json file, if specified |
| 138 | + if args.output_json { |
| 139 | + client_core::init::output_to_json(&init_results, "client_init_results.json"); |
| 140 | + } |
| 141 | + |
| 142 | + println!("\nThe address of this client is: {address}\n"); |
| 143 | + Ok(()) |
| 144 | +} |
| 145 | + |
| 146 | +fn print_saved_config(config: &Config) { |
| 147 | + let config_save_location = config.get_config_file_save_location(); |
| 148 | + println!("Saved configuration file to {config_save_location:?}"); |
| 149 | + println!("Using gateway: {}", config.get_base().get_gateway_id()); |
| 150 | + log::debug!("Gateway id: {}", config.get_base().get_gateway_id()); |
| 151 | + log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner()); |
| 152 | + log::debug!( |
| 153 | + "Gateway listener: {}", |
| 154 | + config.get_base().get_gateway_listener() |
| 155 | + ); |
| 156 | + println!("Client configuration completed.\n"); |
| 157 | +} |
0 commit comments