running the api as a proper task in gateway 'run'
This commit is contained in:
@@ -51,7 +51,11 @@ where
|
||||
if T::pem_type() != key_pem.tag {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unexpected key pem tag",
|
||||
format!(
|
||||
"unexpected key pem tag. Got '{}', expected: '{}'",
|
||||
key_pem.tag,
|
||||
T::pem_type()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::config::old_config_v1_1_28::ConfigV1_1_28;
|
||||
use crate::config::old_config_v1_1_29::ConfigV1_1_29;
|
||||
use crate::config::{default_config_filepath, Config};
|
||||
use crate::error::GatewayError;
|
||||
use log::info;
|
||||
@@ -20,7 +21,8 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, GatewayError> {
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_28 = old_config.into();
|
||||
let updated: Config = updated_step1.into();
|
||||
let updated_step2: ConfigV1_1_29 = updated_step1.into();
|
||||
let updated: Config = updated_step2.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
.map_err(|err| GatewayError::ConfigSaveFailure {
|
||||
@@ -42,6 +44,29 @@ fn try_upgrade_v1_1_28_config(id: &str) -> Result<bool, GatewayError> {
|
||||
info!("It seems the gateway is using <= v1.1.28 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_29 = old_config.into();
|
||||
let updated: Config = updated_step1.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
.map_err(|err| GatewayError::ConfigSaveFailure {
|
||||
path: default_config_filepath(id),
|
||||
id: id.to_string(),
|
||||
source: err,
|
||||
})?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_29_config(id: &str) -> Result<bool, GatewayError> {
|
||||
// explicitly load it as v1.1.29 (which is incompatible with the current, i.e. 1.1.30+)
|
||||
let Ok(old_config) = ConfigV1_1_29::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the gateway is using <= v1.1.29 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
@@ -61,6 +86,9 @@ pub(crate) fn try_upgrade_config(id: &str) -> Result<(), GatewayError> {
|
||||
if try_upgrade_v1_1_28_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_29_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use nym_config::{
|
||||
use nym_network_defaults::mainnet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -22,6 +22,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
pub(crate) mod old_config_v1_1_20;
|
||||
pub(crate) mod old_config_v1_1_28;
|
||||
pub(crate) mod old_config_v1_1_29;
|
||||
pub mod persistence;
|
||||
mod template;
|
||||
|
||||
@@ -71,6 +72,9 @@ pub struct Config {
|
||||
#[serde(skip)]
|
||||
pub(crate) save_path: Option<PathBuf>,
|
||||
|
||||
#[serde(default)]
|
||||
pub http: Http,
|
||||
|
||||
pub gateway: Gateway,
|
||||
|
||||
pub storage_paths: GatewayPaths,
|
||||
@@ -94,6 +98,7 @@ impl Config {
|
||||
pub fn new<S: AsRef<str>>(id: S) -> Self {
|
||||
Config {
|
||||
save_path: None,
|
||||
http: Default::default(),
|
||||
gateway: Gateway::new_default(id.as_ref()),
|
||||
storage_paths: GatewayPaths::new_default(id.as_ref()),
|
||||
network_requester: Default::default(),
|
||||
@@ -219,6 +224,22 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct Http {
|
||||
/// Socket address this node will use for binding its http API.
|
||||
/// default: `0.0.0.0:80`
|
||||
pub bind_address: SocketAddr,
|
||||
}
|
||||
|
||||
impl Default for Http {
|
||||
fn default() -> Self {
|
||||
Http {
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 80),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we only really care about the mnemonic being zeroized
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct Gateway {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::paths::{GatewayPaths, KeysPaths};
|
||||
use crate::config::{Config, Debug, Gateway};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use crate::config::old_config_v1_1_29::{
|
||||
ConfigV1_1_29, DebugV1_1_29, GatewayPathsV1_1_29, GatewayV1_1_29, KeysPathsV1_1_29,
|
||||
LoggingSettingsV1_1_29,
|
||||
};
|
||||
use nym_config::{
|
||||
must_get_home, read_config_from_toml_file, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, NYM_DIR,
|
||||
};
|
||||
@@ -84,11 +85,13 @@ impl ConfigV1_1_28 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_28> for Config {
|
||||
impl From<ConfigV1_1_28> for ConfigV1_1_29 {
|
||||
fn from(value: ConfigV1_1_28) -> Self {
|
||||
Config {
|
||||
ConfigV1_1_29 {
|
||||
// \/ ADDED
|
||||
save_path: None,
|
||||
gateway: Gateway {
|
||||
// /\ ADDED
|
||||
gateway: GatewayV1_1_29 {
|
||||
version: value.gateway.version,
|
||||
id: value.gateway.id,
|
||||
only_coconut_credentials: value.gateway.only_coconut_credentials,
|
||||
@@ -101,19 +104,25 @@ impl From<ConfigV1_1_28> for Config {
|
||||
statistics_service_url: value.gateway.statistics_service_url,
|
||||
cosmos_mnemonic: value.gateway.cosmos_mnemonic,
|
||||
},
|
||||
storage_paths: GatewayPaths {
|
||||
keys: KeysPaths {
|
||||
storage_paths: GatewayPathsV1_1_29 {
|
||||
keys: KeysPathsV1_1_29 {
|
||||
private_identity_key_file: value.storage_paths.keys.private_identity_key_file,
|
||||
public_identity_key_file: value.storage_paths.keys.public_identity_key_file,
|
||||
private_sphinx_key_file: value.storage_paths.keys.private_sphinx_key_file,
|
||||
public_sphinx_key_file: value.storage_paths.keys.public_sphinx_key_file,
|
||||
},
|
||||
clients_storage: value.storage_paths.clients_storage,
|
||||
|
||||
// \/ ADDED
|
||||
network_requester_config: None,
|
||||
// /\ ADDED
|
||||
},
|
||||
|
||||
// \/ ADDED
|
||||
network_requester: Default::default(),
|
||||
logging: LoggingSettings {},
|
||||
debug: Debug {
|
||||
// /\ ADDED
|
||||
logging: LoggingSettingsV1_1_29 {},
|
||||
debug: DebugV1_1_29 {
|
||||
packet_forwarding_initial_backoff: value.debug.packet_forwarding_initial_backoff,
|
||||
packet_forwarding_maximum_backoff: value.debug.packet_forwarding_maximum_backoff,
|
||||
initial_connection_timeout: value.debug.initial_connection_timeout,
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::paths::{GatewayPaths, KeysPaths};
|
||||
use crate::config::{Config, Debug, Gateway, NetworkRequester};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_config::{
|
||||
must_get_home, read_config_from_toml_file, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, NYM_DIR,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
const DEFAULT_GATEWAYS_DIR: &str = "gateways";
|
||||
|
||||
// 'DEBUG'
|
||||
// where applicable, the below are defined in milliseconds
|
||||
const DEFAULT_PRESENCE_SENDING_DELAY: Duration = Duration::from_millis(10_000);
|
||||
const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000);
|
||||
const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000);
|
||||
const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500);
|
||||
const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000;
|
||||
|
||||
const DEFAULT_STORED_MESSAGE_FILENAME_LENGTH: u16 = 16;
|
||||
const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
|
||||
|
||||
/// Derive default path to gateway's config directory.
|
||||
/// It should get resolved to `$HOME/.nym/gateways/<id>/config`
|
||||
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_GATEWAYS_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_CONFIG_DIR)
|
||||
}
|
||||
|
||||
/// Derive default path to gateways's config file.
|
||||
/// It should get resolved to `$HOME/.nym/gateways/<id>/config/config.toml`
|
||||
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct KeysPathsV1_1_29 {
|
||||
pub private_identity_key_file: PathBuf,
|
||||
pub public_identity_key_file: PathBuf,
|
||||
pub private_sphinx_key_file: PathBuf,
|
||||
pub public_sphinx_key_file: PathBuf,
|
||||
}
|
||||
|
||||
fn de_maybe_path<'de, D>(deserializer: D) -> Result<Option<PathBuf>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let path = PathBuf::deserialize(deserializer)?;
|
||||
if path.as_os_str().is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(path))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct GatewayPathsV1_1_29 {
|
||||
pub keys: KeysPathsV1_1_29,
|
||||
|
||||
#[serde(alias = "persistent_storage")]
|
||||
pub clients_storage: PathBuf,
|
||||
|
||||
#[serde(deserialize_with = "de_maybe_path")]
|
||||
pub network_requester_config: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LoggingSettingsV1_1_29 {}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_29 {
|
||||
#[serde(skip)]
|
||||
pub save_path: Option<PathBuf>,
|
||||
|
||||
pub gateway: GatewayV1_1_29,
|
||||
|
||||
pub storage_paths: GatewayPathsV1_1_29,
|
||||
|
||||
pub network_requester: NetworkRequesterV1_1_29,
|
||||
|
||||
#[serde(default)]
|
||||
pub logging: LoggingSettingsV1_1_29,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: DebugV1_1_29,
|
||||
}
|
||||
|
||||
impl ConfigV1_1_29 {
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_29> for Config {
|
||||
fn from(value: ConfigV1_1_29) -> Self {
|
||||
Config {
|
||||
save_path: value.save_path,
|
||||
|
||||
// \/ ADDED
|
||||
http: Default::default(),
|
||||
// /\ ADDED
|
||||
gateway: Gateway {
|
||||
version: value.gateway.version,
|
||||
id: value.gateway.id,
|
||||
only_coconut_credentials: value.gateway.only_coconut_credentials,
|
||||
listening_address: value.gateway.listening_address,
|
||||
mix_port: value.gateway.mix_port,
|
||||
clients_port: value.gateway.clients_port,
|
||||
enabled_statistics: value.gateway.enabled_statistics,
|
||||
nym_api_urls: value.gateway.nym_api_urls,
|
||||
nyxd_urls: value.gateway.nyxd_urls,
|
||||
statistics_service_url: value.gateway.statistics_service_url,
|
||||
cosmos_mnemonic: value.gateway.cosmos_mnemonic,
|
||||
},
|
||||
storage_paths: GatewayPaths {
|
||||
keys: KeysPaths {
|
||||
private_identity_key_file: value.storage_paths.keys.private_identity_key_file,
|
||||
public_identity_key_file: value.storage_paths.keys.public_identity_key_file,
|
||||
private_sphinx_key_file: value.storage_paths.keys.private_sphinx_key_file,
|
||||
public_sphinx_key_file: value.storage_paths.keys.public_sphinx_key_file,
|
||||
},
|
||||
clients_storage: value.storage_paths.clients_storage,
|
||||
network_requester_config: value.storage_paths.network_requester_config,
|
||||
},
|
||||
network_requester: NetworkRequester {
|
||||
enabled: value.network_requester.enabled,
|
||||
},
|
||||
logging: LoggingSettings {},
|
||||
debug: Debug {
|
||||
packet_forwarding_initial_backoff: value.debug.packet_forwarding_initial_backoff,
|
||||
packet_forwarding_maximum_backoff: value.debug.packet_forwarding_maximum_backoff,
|
||||
initial_connection_timeout: value.debug.initial_connection_timeout,
|
||||
maximum_connection_buffer_size: value.debug.maximum_connection_buffer_size,
|
||||
presence_sending_delay: value.debug.presence_sending_delay,
|
||||
stored_messages_filename_length: value.debug.stored_messages_filename_length,
|
||||
message_retrieval_limit: value.debug.message_retrieval_limit,
|
||||
use_legacy_framed_packet_version: value.debug.use_legacy_framed_packet_version,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct GatewayV1_1_29 {
|
||||
/// Version of the gateway for which this configuration was created.
|
||||
pub version: String,
|
||||
|
||||
/// ID specifies the human readable ID of this particular gateway.
|
||||
pub id: String,
|
||||
|
||||
/// Indicates whether this gateway is accepting only coconut credentials for accessing the
|
||||
/// the mixnet, or if it also accepts non-paying clients
|
||||
#[serde(default)]
|
||||
pub only_coconut_credentials: bool,
|
||||
|
||||
/// Address to which this mixnode will bind to and will be listening for packets.
|
||||
pub listening_address: IpAddr,
|
||||
|
||||
/// Port used for listening for all mixnet traffic.
|
||||
/// (default: 1789)
|
||||
pub mix_port: u16,
|
||||
|
||||
/// Port used for listening for all client-related traffic.
|
||||
/// (default: 9000)
|
||||
pub clients_port: u16,
|
||||
|
||||
/// Whether gateway collects and sends anonymized statistics
|
||||
pub enabled_statistics: bool,
|
||||
|
||||
/// Domain address of the statistics service
|
||||
pub statistics_service_url: Url,
|
||||
|
||||
/// Addresses to APIs from which the node gets the view of the network.
|
||||
#[serde(alias = "validator_api_urls")]
|
||||
pub nym_api_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to validators which the node uses to check for double spending of ERC20 tokens.
|
||||
#[serde(alias = "validator_nymd_urls")]
|
||||
pub nyxd_urls: Vec<Url>,
|
||||
|
||||
/// Mnemonic of a cosmos wallet used in checking for double spending.
|
||||
// #[deprecated(note = "move to storage")]
|
||||
// TODO: I don't think this should be stored directly in the config...
|
||||
pub cosmos_mnemonic: bip39::Mnemonic,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct NetworkRequesterV1_1_29 {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for NetworkRequesterV1_1_29 {
|
||||
fn default() -> Self {
|
||||
NetworkRequesterV1_1_29 { enabled: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct DebugV1_1_29 {
|
||||
/// Initial value of an exponential backoff to reconnect to dropped TCP connection when
|
||||
/// forwarding sphinx packets.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub packet_forwarding_initial_backoff: Duration,
|
||||
|
||||
/// Maximum value of an exponential backoff to reconnect to dropped TCP connection when
|
||||
/// forwarding sphinx packets.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub packet_forwarding_maximum_backoff: Duration,
|
||||
|
||||
/// Timeout for establishing initial connection when trying to forward a sphinx packet.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub initial_connection_timeout: Duration,
|
||||
|
||||
/// Maximum number of packets that can be stored waiting to get sent to a particular connection.
|
||||
pub maximum_connection_buffer_size: usize,
|
||||
|
||||
/// Delay between each subsequent presence data being sent.
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub presence_sending_delay: Duration,
|
||||
|
||||
/// Length of filenames for new client messages.
|
||||
pub stored_messages_filename_length: u16,
|
||||
|
||||
/// Number of messages from offline client that can be pulled at once from the storage.
|
||||
pub message_retrieval_limit: i64,
|
||||
|
||||
/// Specifies whether the mixnode should be using the legacy framing for the sphinx packets.
|
||||
// it's set to true by default. The reason for that decision is to preserve compatibility with the
|
||||
// existing nodes whilst everyone else is upgrading and getting the code for handling the new field.
|
||||
// It shall be disabled in the subsequent releases.
|
||||
pub use_legacy_framed_packet_version: bool,
|
||||
}
|
||||
|
||||
impl Default for DebugV1_1_29 {
|
||||
fn default() -> Self {
|
||||
DebugV1_1_29 {
|
||||
packet_forwarding_initial_backoff: DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF,
|
||||
packet_forwarding_maximum_backoff: DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF,
|
||||
initial_connection_timeout: DEFAULT_INITIAL_CONNECTION_TIMEOUT,
|
||||
presence_sending_delay: DEFAULT_PRESENCE_SENDING_DELAY,
|
||||
maximum_connection_buffer_size: DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE,
|
||||
stored_messages_filename_length: DEFAULT_STORED_MESSAGE_FILENAME_LENGTH,
|
||||
message_retrieval_limit: DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
|
||||
use_legacy_framed_packet_version: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,11 @@ nyxd_urls = [
|
||||
|
||||
cosmos_mnemonic = '{{ gateway.cosmos_mnemonic }}'
|
||||
|
||||
[http]
|
||||
# Socket address this node will use for binding its http API.
|
||||
# default: `0.0.0.0:80`
|
||||
bind_address = '{{ http.bind_address }}'
|
||||
|
||||
[network_requester]
|
||||
# Specifies whether network requester service is enabled in this process.
|
||||
enabled = {{ network_requester.enabled }}
|
||||
|
||||
@@ -106,6 +106,11 @@ pub(crate) enum GatewayError {
|
||||
#[from]
|
||||
source: NyxdError,
|
||||
},
|
||||
|
||||
// TODO: in the future this should work the other way, i.e. NymNode depending on Gateway errors
|
||||
#[error(transparent)]
|
||||
NymNodeError(#[from] nym_node::error::NymNodeError),
|
||||
|
||||
#[error("Error verifying hmac digest")]
|
||||
HmacDigestError {
|
||||
#[from]
|
||||
|
||||
@@ -1,2 +1,98 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::error::GatewayError;
|
||||
use crate::node::helpers::load_public_key;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_node::http;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_task::TaskClient;
|
||||
|
||||
fn load_gateway_details(
|
||||
config: &Config,
|
||||
) -> Result<http::api::v1::gateway::types::Gateway, GatewayError> {
|
||||
let identity_public_key: identity::PublicKey = load_public_key(
|
||||
&config.storage_paths.keys.public_identity_key_file,
|
||||
"gateway identity",
|
||||
)?;
|
||||
|
||||
let sphinx_public_key: encryption::PublicKey = load_public_key(
|
||||
&config.storage_paths.keys.public_sphinx_key_file,
|
||||
"gateway sphinx",
|
||||
)?;
|
||||
|
||||
Ok(http::api::v1::gateway::types::Gateway {
|
||||
encoded_identity_key: identity_public_key.to_base58_string(),
|
||||
encoded_sphinx_key: sphinx_public_key.to_base58_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn load_network_requester_details(
|
||||
config: &Config,
|
||||
network_requester_config: &nym_network_requester::Config,
|
||||
) -> Result<http::api::v1::network_requester::types::NetworkRequester, GatewayError> {
|
||||
let identity_public_key: identity::PublicKey = load_public_key(
|
||||
&network_requester_config
|
||||
.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.public_identity_key_file,
|
||||
"network requester identity",
|
||||
)?;
|
||||
|
||||
let dh_public_key: encryption::PublicKey = load_public_key(
|
||||
&network_requester_config
|
||||
.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.public_encryption_key_file,
|
||||
"network requester diffie hellman",
|
||||
)?;
|
||||
|
||||
let gateway_identity_public_key: identity::PublicKey = load_public_key(
|
||||
&config.storage_paths.keys.public_identity_key_file,
|
||||
"gateway identity",
|
||||
)?;
|
||||
|
||||
Ok(http::api::v1::network_requester::types::NetworkRequester {
|
||||
encoded_identity_key: identity_public_key.to_base58_string(),
|
||||
encoded_sphinx_key: dh_public_key.to_base58_string(),
|
||||
address: Recipient::new(
|
||||
identity_public_key,
|
||||
dh_public_key,
|
||||
gateway_identity_public_key,
|
||||
)
|
||||
.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn start_http_api(
|
||||
gateway_config: &Config,
|
||||
network_requester_config: Option<&nym_network_requester::Config>,
|
||||
task_client: TaskClient,
|
||||
) -> Result<(), GatewayError> {
|
||||
// is it suboptimal to load all the keys, etc for the second time after they've already been
|
||||
// retrieved during startup of the rest of the components?
|
||||
// yes, a bit.
|
||||
// but in the grand scheme of things performance penalty is negligible since it's only happening on startup
|
||||
// and makes the code a bit nicer to manage. on top of it, all of it will refactored anyway at some point
|
||||
// (famous last words, eh? - 22.09.23)
|
||||
|
||||
let mut config = nym_node::http::Config::new(bin_info_owned!())
|
||||
.with_gateway(load_gateway_details(gateway_config)?);
|
||||
|
||||
if let Some(nr_config) = network_requester_config {
|
||||
config = config
|
||||
.with_network_requester(load_network_requester_details(gateway_config, nr_config)?)
|
||||
}
|
||||
|
||||
let router = nym_node::http::NymNodeRouter::new(config);
|
||||
|
||||
let server = router
|
||||
.build_server(&gateway_config.http.bind_address)?
|
||||
.with_task_client(task_client);
|
||||
tokio::spawn(async move { server.run().await });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+14
-49
@@ -8,13 +8,11 @@ use clap::{crate_name, crate_version, Parser};
|
||||
use colored::Colorize;
|
||||
use lazy_static::lazy_static;
|
||||
use log::error;
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_bin_common::{bin_info, bin_info_owned};
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_node::http::api::v1::roles::NodeRoles;
|
||||
use std::error::Error;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
mod commands;
|
||||
mod config;
|
||||
@@ -51,54 +49,21 @@ struct Cli {
|
||||
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
setup_logging();
|
||||
|
||||
let config = nym_node::http::Config {
|
||||
landing: Default::default(),
|
||||
policy: Default::default(),
|
||||
api: nym_node::http::api::Config {
|
||||
v1_config: nym_node::http::api::v1::Config {
|
||||
build_information: bin_info_owned!(),
|
||||
roles: NodeRoles {
|
||||
mixnode_enabled: false,
|
||||
gateway_enabled: false,
|
||||
network_requester_enabled: false,
|
||||
},
|
||||
gateway: nym_node::http::api::v1::gateway::Config {
|
||||
details: Some(nym_node::http::api::v1::gateway::types::Gateway {
|
||||
encoded_identity_key: "aaa".to_string(),
|
||||
encoded_sphinx_key: "bbb".to_string(),
|
||||
}),
|
||||
},
|
||||
mixnode: Default::default(),
|
||||
network_requester: Default::default(),
|
||||
},
|
||||
},
|
||||
};
|
||||
let mut router = nym_node::http::NymNodeRouter::new(config);
|
||||
let args = Cli::parse();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
|
||||
let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 12345);
|
||||
let server = router.build_server(&address)?;
|
||||
server.await?;
|
||||
if !args.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
//
|
||||
//
|
||||
// let args = Cli::parse();
|
||||
// setup_env(args.config_env_file.as_ref());
|
||||
//
|
||||
// if !args.no_banner {
|
||||
// maybe_print_banner(crate_name!(), crate_version!());
|
||||
// }
|
||||
// setup_logging();
|
||||
//
|
||||
// commands::execute(args).await.map_err(|err| {
|
||||
// if atty::is(atty::Stream::Stdout) {
|
||||
// let error_message = format!("{err}").red();
|
||||
// error!("{error_message}");
|
||||
// error!("Exiting...");
|
||||
// }
|
||||
// err
|
||||
// })
|
||||
commands::execute(args).await.map_err(|err| {
|
||||
if atty::is(atty::Stream::Stdout) {
|
||||
let error_message = format!("{err}").red();
|
||||
error!("{error_message}");
|
||||
error!("Exiting...");
|
||||
}
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -6,6 +6,7 @@ use self::storage::PersistentStorage;
|
||||
use crate::commands::helpers::{override_network_requester_config, OverrideNetworkRequesterConfig};
|
||||
use crate::config::Config;
|
||||
use crate::error::GatewayError;
|
||||
use crate::http::start_http_api;
|
||||
use crate::node::client_handling::active_clients::ActiveClientsStore;
|
||||
use crate::node::client_handling::embedded_network_requester::{
|
||||
LocalNetworkRequesterHandle, MessageRouter,
|
||||
@@ -333,6 +334,12 @@ impl<St> Gateway<St> {
|
||||
CoconutVerifier::new(nyxd_client)
|
||||
};
|
||||
|
||||
start_http_api(
|
||||
&self.config,
|
||||
self.network_requester_opts.as_ref().map(|o| &o.config),
|
||||
shutdown.subscribe().named("http-api"),
|
||||
)?;
|
||||
|
||||
let mix_forwarding_channel =
|
||||
self.start_packet_forwarder(shutdown.subscribe().named("PacketForwarder"));
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ serde_yaml = "0.9.25"
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros"] }
|
||||
|
||||
# HTTP API:
|
||||
axum = { workspace = true }
|
||||
@@ -38,3 +39,4 @@ utoipa-swagger-ui = { version = "3.1.5", features = ["axum"] }
|
||||
|
||||
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["openapi"] }
|
||||
nym-task = { path = "../common/task" }
|
||||
|
||||
+51
-11
@@ -1,19 +1,59 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::routing::IntoMakeService;
|
||||
use axum::Router;
|
||||
use hyper::server::conn::AddrIncoming;
|
||||
use hyper::Server;
|
||||
use nym_task::TaskClient;
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
pub mod middleware;
|
||||
pub mod router;
|
||||
pub mod state;
|
||||
|
||||
pub use router::{Config, NymNodeRouter, api, landing_page, policy};
|
||||
pub use router::{api, landing_page, policy, Config, NymNodeRouter};
|
||||
|
||||
// pub struct Config {
|
||||
// router_config: router::Config,
|
||||
// bind_address: SocketAddr,
|
||||
// }
|
||||
//
|
||||
// async fn run(config: Config) -> Result<(), NymNodeError> {
|
||||
// NymNodeRouter::new(config.router_config)
|
||||
// .start_server(&config.bind_address)
|
||||
// .await
|
||||
// }
|
||||
pub struct NymNodeHTTPServer {
|
||||
task_client: Option<TaskClient>,
|
||||
inner: Server<AddrIncoming, IntoMakeService<Router>>,
|
||||
}
|
||||
|
||||
impl NymNodeHTTPServer {
|
||||
pub(crate) fn new(inner: Server<AddrIncoming, IntoMakeService<Router>>) -> Self {
|
||||
NymNodeHTTPServer {
|
||||
task_client: None,
|
||||
inner,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_task_client(mut self, task_client: TaskClient) -> Self {
|
||||
self.task_client = Some(task_client);
|
||||
self
|
||||
}
|
||||
|
||||
async fn run_server_forever(server: Server<AddrIncoming, IntoMakeService<Router>>) {
|
||||
if let Err(err) = server.await {
|
||||
error!("the HTTP server has terminated with the error: {err}");
|
||||
} else {
|
||||
error!("the HTTP server has terminated with producing any errors");
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(self) {
|
||||
info!("Started NymNodeHTTPServer on {}", self.inner.local_addr());
|
||||
if let Some(mut task_client) = self.task_client {
|
||||
tokio::select! {
|
||||
_ = task_client.recv_with_delay() => {
|
||||
debug!("NymNodeHTTPServer: Received shutdown");
|
||||
}
|
||||
_ = Self::run_server_forever(self.inner) => { }
|
||||
}
|
||||
} else {
|
||||
Self::run_server_forever(self.inner).await
|
||||
}
|
||||
|
||||
debug!("NymNodeHTTPServer: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
// .nest(routes::SWAGGER, openapi::route())
|
||||
}
|
||||
|
||||
// #[derive(Debug, Clone, ToSchema)]
|
||||
// pub struct SignedResponse<T>{
|
||||
// encoded_signature: String,
|
||||
// data: T,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, ToSchema)]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
|
||||
@@ -11,4 +11,7 @@ pub struct NetworkRequester {
|
||||
|
||||
/// Base58-encoded x25519 public key used for performing key exchange with remote clients.
|
||||
pub encoded_sphinx_key: String,
|
||||
|
||||
/// Nym address of this network requester.
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use axum::extract::Query;
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Debug, Copy, ToSchema, Serialize)]
|
||||
#[derive(Clone, Default, Debug, Copy, ToSchema, Serialize)]
|
||||
pub struct NodeRoles {
|
||||
pub mixnode_enabled: bool,
|
||||
pub gateway_enabled: bool,
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::NymNodeError;
|
||||
use crate::http::api::v1::gateway::types::Gateway;
|
||||
use crate::http::api::v1::mixnode::types::Mixnode;
|
||||
use crate::http::api::v1::network_requester::types::NetworkRequester;
|
||||
use crate::http::middleware::logging;
|
||||
use crate::http::state::AppState;
|
||||
use axum::routing::IntoMakeService;
|
||||
use crate::http::NymNodeHTTPServer;
|
||||
use axum::Router;
|
||||
use hyper::server::conn::AddrIncoming;
|
||||
use hyper::Server;
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub mod api;
|
||||
@@ -21,9 +23,6 @@ pub(crate) mod routes {
|
||||
pub(crate) const API: &str = "/api";
|
||||
}
|
||||
|
||||
// TODO: can it be made nicer?
|
||||
pub type NymNodeHTTPServer = Server<AddrIncoming, IntoMakeService<Router>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub landing: landing_page::Config,
|
||||
@@ -31,6 +30,45 @@ pub struct Config {
|
||||
pub api: api::Config,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(binary_info: BinaryBuildInformationOwned) -> Self {
|
||||
Config {
|
||||
landing: Default::default(),
|
||||
policy: Default::default(),
|
||||
api: api::Config {
|
||||
v1_config: api::v1::Config {
|
||||
build_information: binary_info,
|
||||
roles: Default::default(),
|
||||
gateway: Default::default(),
|
||||
mixnode: Default::default(),
|
||||
network_requester: Default::default(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_gateway(mut self, gateway: Gateway) -> Self {
|
||||
self.api.v1_config.roles.gateway_enabled = true;
|
||||
self.api.v1_config.gateway.details = Some(gateway);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_mixnode(mut self, mixnode: Mixnode) -> Self {
|
||||
self.api.v1_config.roles.mixnode_enabled = true;
|
||||
self.api.v1_config.mixnode.details = Some(mixnode);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_network_requester(mut self, network_requester: NetworkRequester) -> Self {
|
||||
self.api.v1_config.roles.network_requester_enabled = true;
|
||||
self.api.v1_config.network_requester.details = Some(network_requester);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NymNodeRouter {
|
||||
inner: Router,
|
||||
}
|
||||
@@ -60,11 +98,13 @@ impl NymNodeRouter {
|
||||
self,
|
||||
bind_address: &SocketAddr,
|
||||
) -> Result<NymNodeHTTPServer, NymNodeError> {
|
||||
Ok(axum::Server::try_bind(bind_address)
|
||||
let axum_server = axum::Server::try_bind(bind_address)
|
||||
.map_err(|source| NymNodeError::HttpBindFailure {
|
||||
bind_address: *bind_address,
|
||||
source,
|
||||
})?
|
||||
.serve(self.inner.into_make_service()))
|
||||
.serve(self.inner.into_make_service());
|
||||
|
||||
Ok(NymNodeHTTPServer::new(axum_server))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user