Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ lazy_static = "1.5.0"
prometheus = {version = "0.14.0", features = ["process"]}
subxt = "0.43.0"
tiny-keccak = {version = "2.0.2", features = ["keccak"]}
notify = "8.2.0"

[dev-dependencies]
mockall = "0.13"
Expand Down
5 changes: 4 additions & 1 deletion config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,7 @@ sync_interval_in_hours = 24
tweets_req_interval_in_secs = 60

[alert]
webhook_url = "https://www.webhook_url.com"
webhook_url = "https://www.webhook_url.com"

[feature_flags]
wallet_feature_flags_config_file = "../wallet_feature_flags/default_feature_flags.json"
3 changes: 3 additions & 0 deletions config/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ tweets_req_interval_in_secs = 60
[alert]
webhook_url = "https://www.webhook_url.com"

[feature_flags]
wallet_feature_flags_config_file = "../wallet_feature_flags/default_feature_flags.json"

# Example environment variable overrides:
# TASKMASTER_BLOCKCHAIN__NODE_URL="ws://remote-node:9944"
# TASKMASTER_BLOCKCHAIN__WALLET_PASSWORD="super_secure_password"
Expand Down
5 changes: 4 additions & 1 deletion config/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,7 @@ sync_interval_in_hours = 24
tweets_req_interval_in_secs = 1

[alert]
webhook_url = "https://www.webhook_url.com"
webhook_url = "https://www.webhook_url.com"

[feature_flags]
wallet_feature_flags_config_file = "../wallet_feature_flags/test_feature_flags.json"
32 changes: 29 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::Path;

use rusx::config::OauthConfig;
use serde::{Deserialize, Serialize};
use tokio::time;
Expand All @@ -16,6 +18,12 @@ pub struct Config {
pub raid_leaderboard: RaidLeaderboardConfig,
pub alert: AlertConfig,
pub x_association: XAssociationConfig,
pub feature_flags: FeatureFlagsConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeatureFlagsConfig {
pub wallet_feature_flags_config_file: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -98,20 +106,25 @@ impl Config {
.add_source(config::Environment::with_prefix("TASKMASTER"))
.build()?;

settings.try_deserialize()
let mut config: Self = settings.try_deserialize()?;
config.resolve_relative_paths(config_path);
Ok(config)
}

#[cfg(test)]
pub fn load_test_env() -> Result<Self, config::ConfigError> {
println!("Loading TEST configuration..."); // For demonstration
let test_config_path = "config/test.toml";
let settings = config::Config::builder()
// Load the test-specific configuration file
.add_source(config::File::with_name("config/test"))
.add_source(config::File::new(test_config_path, config::FileFormat::Toml))
// You can still layer environment variables for testing if you need to
.add_source(config::Environment::with_prefix("TASKMASTER"))
.build()?;

settings.try_deserialize()
let mut config: Self = settings.try_deserialize()?;
config.resolve_relative_paths(test_config_path);
Ok(config)
}

pub fn get_database_url(&self) -> &str {
Expand Down Expand Up @@ -145,6 +158,16 @@ impl Config {
pub fn get_x_association_keywords(&self) -> &str {
&self.x_association.keywords
}

fn resolve_relative_paths(&mut self, config_path: &str) {
let feature_flags_path = Path::new(&self.feature_flags.wallet_feature_flags_config_file);
if feature_flags_path.is_absolute() {
return;
}
let base_dir = Path::new(config_path).parent().expect("Failed to get base directory");
self.feature_flags.wallet_feature_flags_config_file =
base_dir.join(feature_flags_path).to_string_lossy().to_string();
}
}

impl Default for Config {
Expand Down Expand Up @@ -206,6 +229,9 @@ impl Default for Config {
x_association: XAssociationConfig {
keywords: "quantus".to_string(),
},
feature_flags: FeatureFlagsConfig {
wallet_feature_flags_config_file: "wallet_feature_flags/default_feature_flags.json".to_string(),
},
}
}
}
11 changes: 10 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
db_persistence::DbError,
handlers::{address::AddressHandlerError, auth::AuthHandlerError, referral::ReferralHandlerError, HandlerError},
models::ModelError,
services::graphql_client::GraphqlError,
services::{graphql_client::GraphqlError, wallet_feature_flags_service::WalletFeatureFlagsError},
};

#[derive(Debug, thiserror::Error)]
Expand All @@ -26,6 +26,8 @@ pub enum AppError {
Database(#[from] DbError),
#[error("Server error: {0}")]
Server(String),
#[error("Wallet feature flags error: {0}")]
WalletFeatureFlags(#[from] WalletFeatureFlagsError),
#[error("Join error: {0}")]
Join(#[from] tokio::task::JoinError),
#[error("GraphQL error: {0}")]
Expand All @@ -49,6 +51,9 @@ impl IntoResponse for AppError {
err,
),

// --- Wallet Feature Flags ---
AppError::WalletFeatureFlags(err) => map_wallet_feature_flags_error(err),

// --- Model ---
AppError::Model(err) => (StatusCode::BAD_REQUEST, err.to_string()),

Expand Down Expand Up @@ -166,3 +171,7 @@ fn map_db_error(err: DbError) -> (StatusCode, String) {
),
}
}

fn map_wallet_feature_flags_error(err: WalletFeatureFlagsError) -> (StatusCode, String) {
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
1 change: 1 addition & 0 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod raid_quest;
pub mod referral;
pub mod relevant_tweet;
pub mod tweet_author;
pub mod wallet_feature_flags;

#[derive(Debug, thiserror::Error)]
pub enum HandlerError {
Expand Down
12 changes: 12 additions & 0 deletions src/handlers/wallet_feature_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use axum::{extract::State, Json};
use serde_json::Value;

use crate::{handlers::SuccessResponse, http_server::AppState, AppError};

pub async fn handle_get_wallet_feature_flags(
State(state): State<AppState>,
) -> Result<Json<SuccessResponse<Value>>, AppError> {
let flags = state.wallet_feature_flags_service.get_wallet_feature_flags()?;

Ok(SuccessResponse::new(flags))
}
5 changes: 5 additions & 0 deletions src/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
db_persistence::DbPersistence,
metrics::{metrics_handler, track_metrics, Metrics},
routes::api_routes,
services::wallet_feature_flags_service::WalletFeatureFlagsService,
Config, GraphqlClient,
};
use chrono::{DateTime, Utc};
Expand All @@ -23,6 +24,7 @@ pub struct AppState {
pub db: Arc<DbPersistence>,
pub metrics: Arc<Metrics>,
pub graphql_client: Arc<GraphqlClient>,
pub wallet_feature_flags_service: Arc<WalletFeatureFlagsService>,
pub config: Arc<Config>,
pub challenges: Arc<RwLock<HashMap<String, Challenge>>>,
pub oauth_sessions: Arc<Mutex<HashMap<String, PkceCodeVerifier>>>,
Expand Down Expand Up @@ -83,6 +85,9 @@ pub async fn start_server(
db,
metrics: Arc::new(Metrics::new()),
graphql_client,
wallet_feature_flags_service: Arc::new(WalletFeatureFlagsService::new(
config.feature_flags.wallet_feature_flags_config_file.clone(),
)?),
config,
twitter_gateway,
challenges: Arc::new(RwLock::new(HashMap::new())),
Expand Down
3 changes: 3 additions & 0 deletions src/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use auth::auth_routes;
use axum::Router;
use referral::referral_routes;
use wallet_feature_flags::wallet_feature_flags_routes;

use crate::{
http_server::AppState,
Expand All @@ -16,6 +17,7 @@ pub mod raid_quest;
pub mod referral;
pub mod relevant_tweet;
pub mod tweet_author;
pub mod wallet_feature_flags;

pub fn api_routes(state: AppState) -> Router<AppState> {
Router::new()
Expand All @@ -24,5 +26,6 @@ pub fn api_routes(state: AppState) -> Router<AppState> {
.merge(auth_routes(state.clone()))
.merge(relevant_tweet_routes(state.clone()))
.merge(tweet_author_routes(state.clone()))
.merge(wallet_feature_flags_routes())
.merge(raid_quest_routes(state))
}
7 changes: 7 additions & 0 deletions src/routes/wallet_feature_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use axum::{routing::get, Router};

use crate::{handlers::wallet_feature_flags::handle_get_wallet_feature_flags, http_server::AppState};

pub fn wallet_feature_flags_routes() -> Router<AppState> {
Router::new().route("/feature-flags/wallet", get(handle_get_wallet_feature_flags))
}
1 change: 1 addition & 0 deletions src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub mod raid_leaderboard_service;
pub mod signature_service;
pub mod telegram_service;
pub mod tweet_synchronizer_service;
pub mod wallet_feature_flags_service;
Loading
Loading