adjusting the trait

This commit is contained in:
Jędrzej Stuczyński
2024-03-05 15:39:56 +00:00
parent 84a36c00b4
commit fe2edd56a8
11 changed files with 300 additions and 26 deletions
@@ -12,6 +12,7 @@ log.workspace = true
serde = { workspace = true, features = ["derive"] }
thiserror.workspace = true
time.workspace = true
tokio = { workspace = true, features = ["sync"] }
url.workspace = true
zeroize = { workspace = true, features = ["zeroize_derive"] }
@@ -0,0 +1,38 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::io;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum StorageError {
#[error("the provided database path doesn't have a filename defined")]
DatabasePathWithoutFilename { provided_path: PathBuf },
#[error("unable to create the directory for the database at {}: {source}", provided_path.display())]
DatabasePathUnableToCreateParentDirectory {
provided_path: PathBuf,
source: io::Error,
},
#[error("failed to perform sqlx migration: {source}")]
MigrationError {
#[source]
#[from]
source: sqlx::migrate::MigrateError,
},
#[error("failed to connect to the underlying connection pool: {source}")]
DatabaseConnectionError {
#[source]
source: sqlx::error::Error,
},
#[error("failed to run the SQL query: {source}")]
QueryError {
#[source]
#[from]
source: sqlx::error::Error,
},
}
@@ -0,0 +1,53 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::backend::fs_backend::error::StorageError;
use crate::backend::fs_backend::models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
};
use log::{error, info};
use sqlx::ConnectOptions;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct StorageManager {
pub connection_pool: sqlx::SqlitePool,
}
// all SQL goes here
impl StorageManager {
pub async fn init<P: AsRef<Path>>(database_path: P, fresh: bool) -> Result<Self, StorageError> {
// ensure the whole directory structure exists
if let Some(parent_dir) = database_path.as_ref().parent() {
std::fs::create_dir_all(parent_dir).map_err(|source| {
StorageError::DatabasePathUnableToCreateParentDirectory {
provided_path: database_path.as_ref().to_path_buf(),
source,
}
})?;
}
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(fresh);
opts.disable_statement_logging();
let connection_pool = sqlx::SqlitePool::connect_with(opts)
.await
.map_err(|source| {
error!("Failed to connect to SQLx database: {err}");
StorageError::DatabaseConnectionError { source }
})?;
sqlx::migrate!("./fs_gateways_migrations")
.run(&connection_pool)
.await
.inspect_err(|err| {
error!("Failed to initialize SQLx database: {err}");
})?;
info!("Database migration finished!");
Ok(StorageManager { connection_pool })
}
}
@@ -0,0 +1,46 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::GatewayDetails;
use crate::GatewayDetailsStore;
use async_trait::async_trait;
use manager::StorageManager;
mod error;
mod manager;
mod models;
pub struct OnDiskGatewayDetails {
manager: StorageManager,
}
#[async_trait]
impl GatewayDetailsStore for OnDiskGatewayDetails {
type StorageError = error::StorageError;
async fn active_gateway(&self) -> Result<Option<GatewayDetails>, Self::StorageError> {
todo!()
}
async fn all_gateways(&self) -> Result<Vec<GatewayDetails>, Self::StorageError> {
todo!()
}
async fn load_gateway_details(
&self,
gateway_id: &str,
) -> Result<GatewayDetails, Self::StorageError> {
todo!()
}
async fn store_gateway_details(
&self,
details: GatewayDetails,
) -> Result<(), Self::StorageError> {
todo!()
}
async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> {
todo!()
}
}
@@ -0,0 +1,2 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,69 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::GatewayDetails;
use crate::{BadGateway, GatewayDetailsStore};
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;
use tokio::sync::RwLock;
#[derive(Debug, Error)]
pub enum InMemStorageError {
#[error("gateway {gateway_id} does not exist")]
GatewayDoesNotExist { gateway_id: String },
#[error(transparent)]
MalformedGateway(#[from] BadGateway),
}
pub struct InMemStorage {
inner: Arc<RwLock<InMemStorageInner>>,
}
struct InMemStorageInner {
active_gateway: Option<String>,
gateways: HashMap<String, GatewayDetails>,
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl GatewayDetailsStore for InMemStorage {
type StorageError = InMemStorageError;
async fn active_gateway(&self) -> Result<Option<GatewayDetails>, Self::StorageError> {
// let guard = self.inner.read().await;
//
// let foo = guard.active_gateway.map(|id| {
// // SAFETY: if particular gateway is set as active, its details MUST exist
// #[allow(clippy::unwrap_used)]
// guard.gateways.get(&id).unwrap()
// });
todo!()
// foo.cloned()
}
async fn all_gateways(&self) -> Result<Vec<GatewayDetails>, Self::StorageError> {
todo!()
}
async fn load_gateway_details(
&self,
gateway_id: &str,
) -> Result<GatewayDetails, Self::StorageError> {
todo!()
}
async fn store_gateway_details(
&self,
details: GatewayDetails,
) -> Result<(), Self::StorageError> {
todo!()
}
async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> {
todo!()
}
}
@@ -0,0 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))]
pub mod fs_backend;
pub mod mem_backend;
@@ -6,7 +6,7 @@ use nym_gateway_requests::registration::handshake::shared_key::SharedKeyConversi
use thiserror::Error;
#[derive(Debug, Error)]
pub enum GatewaysStorageError {
pub enum BadGateway {
#[error("{typ} is not a valid gateway type")]
InvalidGatewayType { typ: String },
+21 -7
View File
@@ -1,28 +1,42 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
use async_trait::async_trait;
use std::error::Error;
mod backend;
pub mod error;
pub mod models;
pub mod types;
pub use error::GatewaysStorageError;
use crate::types::GatewayDetails;
pub use error::BadGateway;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait GatewayDetailsStore {
type StorageError: Error;
type StorageError: Error + From<error::BadGateway>;
/// Returns details of the currently active gateway, if available.
async fn active_gateway(&self) -> Result<Option<()>, Self::StorageError>;
async fn active_gateway(&self) -> Result<Option<GatewayDetails>, Self::StorageError>;
/// Returns details of all registered gateways.
async fn all_gateways(&self) -> Result<Vec<()>, Self::StorageError>;
async fn all_gateways(&self) -> Result<Vec<GatewayDetails>, Self::StorageError>;
/// Returns details of the particular gateway.
async fn load_gateway_details(&self) -> Result<(), Self::StorageError>;
async fn load_gateway_details(
&self,
gateway_id: &str,
) -> Result<GatewayDetails, Self::StorageError>;
/// Store the provided gateway details.
async fn store_gateway_details(&self) -> Result<(), Self::StorageError>;
async fn store_gateway_details(
&self,
details: GatewayDetails,
) -> Result<(), Self::StorageError>;
/// Remove given gateway details from the underlying store.
async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError>;
}
@@ -1,13 +1,14 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::GatewaysStorageError;
use crate::BadGateway;
use cosmrs::AccountId;
use nym_crypto::asymmetric::identity;
use nym_gateway_requests::registration::handshake::SharedKeys;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use std::sync::Arc;
use time::OffsetDateTime;
use url::Url;
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -15,6 +16,37 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
pub const REMOTE_GATEWAY_TYPE: &str = "remote";
pub const CUSTOM_GATEWAY_TYPE: &str = "custom";
#[derive(Debug)]
pub struct GatewayRegistration {
pub details: GatewayDetails,
pub registration_timestamp: OffsetDateTime,
}
#[derive(Debug)]
pub enum GatewayDetails {
/// Standard details of a remote gateway
Remote(RemoteGatewayDetails),
/// Custom gateway setup, such as for a client embedded inside gateway itself
Custom(CustomGatewayDetails),
}
impl GatewayDetails {
pub fn gateway_id(&self) -> identity::PublicKey {
match self {
GatewayDetails::Remote(details) => details.gateway_id,
GatewayDetails::Custom(details) => details.gateway_id,
}
}
pub fn shared_key(&self) -> Option<&SharedKeys> {
match self {
GatewayDetails::Remote(details) => Some(&details.derived_aes128_ctr_blake3_hmac_keys),
GatewayDetails::Custom(_) => None,
}
}
}
#[derive(Debug, Copy, Clone, Default)]
pub enum GatewayType {
#[default]
@@ -24,13 +56,13 @@ pub enum GatewayType {
}
impl FromStr for GatewayType {
type Err = GatewaysStorageError;
type Err = BadGateway;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
REMOTE_GATEWAY_TYPE => Ok(GatewayType::Remote),
CUSTOM_GATEWAY_TYPE => Ok(GatewayType::Custom),
other => Err(GatewaysStorageError::InvalidGatewayType {
other => Err(BadGateway::InvalidGatewayType {
typ: other.to_string(),
}),
}
@@ -57,6 +89,15 @@ pub struct RawRegisteredGateway {
pub gateway_type: String,
}
#[derive(Debug, Clone, Copy)]
pub struct RegisteredGateway {
pub gateway_id: identity::PublicKey,
pub registration_timestamp: OffsetDateTime,
pub gateway_type: GatewayType,
}
#[derive(Debug, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct RawRemoteGatewayDetails {
@@ -67,27 +108,28 @@ pub struct RawRemoteGatewayDetails {
}
impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
type Error = GatewaysStorageError;
type Error = BadGateway;
fn try_from(value: RawRemoteGatewayDetails) -> Result<Self, Self::Error> {
let gateway_id =
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
GatewaysStorageError::MalformedGatewayIdentity {
BadGateway::MalformedGatewayIdentity {
gateway_id: value.gateway_id_bs58.clone(),
source,
}
})?;
let derived_aes128_ctr_blake3_hmac_keys =
let derived_aes128_ctr_blake3_hmac_keys = Arc::new(
SharedKeys::try_from_base58_string(&value.derived_aes128_ctr_blake3_hmac_keys_bs58)
.map_err(|source| GatewaysStorageError::MalformedSharedKeys {
.map_err(|source| BadGateway::MalformedSharedKeys {
gateway_id: value.gateway_id_bs58.clone(),
source,
})?;
})?,
);
let gateway_owner_address =
AccountId::from_str(&value.gateway_owner_address).map_err(|source| {
GatewaysStorageError::MalformedGatewayOwnerAccountAddress {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: value.gateway_owner_address.clone(),
source,
@@ -95,7 +137,7 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
})?;
let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| {
GatewaysStorageError::MalformedListener {
BadGateway::MalformedListener {
gateway_id: value.gateway_id_bs58.clone(),
raw_listener: value.gateway_listener.clone(),
source,
@@ -124,14 +166,16 @@ impl From<RemoteGatewayDetails> for RawRemoteGatewayDetails {
}
}
#[derive(Debug, Zeroize, ZeroizeOnDrop)]
#[derive(Debug)]
pub struct RemoteGatewayDetails {
#[zeroize(skip)]
pub gateway_id: identity::PublicKey,
pub derived_aes128_ctr_blake3_hmac_keys: SharedKeys,
#[zeroize(skip)]
// note: `SharedKeys` implement ZeroizeOnDrop, meaning when `RemoteGatewayDetails` is dropped,
// the keys will be zeroized
pub derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
pub gateway_owner_address: AccountId,
#[zeroize(skip)]
pub gateway_listener: Url,
}
@@ -143,12 +187,12 @@ pub struct RawCustomGatewayDetails {
}
impl TryFrom<RawCustomGatewayDetails> for CustomGatewayDetails {
type Error = GatewaysStorageError;
type Error = BadGateway;
fn try_from(value: RawCustomGatewayDetails) -> Result<Self, Self::Error> {
let gateway_id =
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
GatewaysStorageError::MalformedGatewayIdentity {
BadGateway::MalformedGatewayIdentity {
gateway_id: value.gateway_id_bs58.clone(),
source,
}
@@ -10,7 +10,7 @@ pub enum StorageError {
#[error("the provided database path doesn't have a filename defined")]
DatabasePathWithoutFilename { provided_path: PathBuf },
#[error("unable to create the directory for the database")]
#[error("unable to create the directory for the database at {}: {source}", provided_path.display())]
DatabasePathUnableToCreateParentDirectory {
provided_path: PathBuf,
source: io::Error,