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
18 changes: 0 additions & 18 deletions config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,6 @@ callback_url = "http://localhost:3000/api/auth/x/callback"
client_id = "WlVrcm4xSEpXQ2l3TURFM3lLZnE6MTpjaQ"
client_secret = "lfXc45dZLqYTzP62Ms32EhXinGQzxcIP9TvjJml2B-h0T1nIJK"

[tweet_sync]
api_key = "some-key"
interval_in_hours = 24
keywords = "quantum"
monthly_limit = 15000
alert_threshold = 13500
reset_day = 22

[tg_bot]
base_url = "https://api.telegram.org"
chat_id = "-1"
# This is optional, if you don't need message thread just remove it
message_thread_id = "1"
token = "token"

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

[remote_configs]
wallet_configs_file = "../wallet_configs/default_configs.json"

Expand Down
18 changes: 0 additions & 18 deletions config/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,6 @@ callback_url = "http://localhost:12345/example/callback"
client_id = "example-id"
client_secret = "example-secret"

[tweet_sync]
api_key = "some-key"
interval_in_hours = 24
keywords = "example"
monthly_limit = 15000
alert_threshold = 13500
reset_day = 22

[tg_bot]
base_url = "https://api.telegram.org"
chat_id = '-1'
# This is optional, if you don't need message thread just remove it
message_thread_id = '1'
token = "token"

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

[remote_configs]
wallet_configs_file = "../wallet_configs/default_configs.json"

Expand Down
18 changes: 0 additions & 18 deletions config/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,6 @@ callback_url = "http://localhost:12345/api/auth/x/callback"
client_id = "test-id"
client_secret = "test-secret"

[tweet_sync]
api_key = "some-key"
interval_in_hours = 24
keywords = "test"
monthly_limit = 15000
alert_threshold = 13500
reset_day = 22

[tg_bot]
base_url = "https://api.telegram.org"
chat_id = '-1'
# This is optional, if you don't need message thread just remove it
message_thread_id = '1'
token = "token"

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

[remote_configs]
wallet_configs_file = "../wallet_configs/test_configs.json"

Expand Down
31 changes: 0 additions & 31 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::path::Path;
use axum::http::HeaderValue;
use rusx::config::OauthConfig;
use serde::{Deserialize, Serialize};
use tokio::time;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
Expand All @@ -13,9 +12,6 @@ pub struct Config {
pub logging: LoggingConfig,
pub jwt: JwtConfig,
pub x_oauth: OauthConfig,
pub tweet_sync: TweetSyncConfig,
pub tg_bot: TelegramBotConfig,
pub alert: AlertConfig,
pub remote_configs: RemoteConfigsConfig,
pub risk_checker: RiskCheckerConfig,
pub exchange_rate: ExchangeRateConfig,
Expand Down Expand Up @@ -55,29 +51,6 @@ pub struct JwtConfig {
pub exp_in_hours: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TweetSyncConfig {
pub interval_in_hours: u64,
pub keywords: String,
pub api_key: String,
pub monthly_limit: u32,
pub alert_threshold: u32,
pub reset_day: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TelegramBotConfig {
pub base_url: String,
pub token: String,
pub chat_id: String,
pub message_thread_id: Option<String>,
}

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiskCheckerConfig {
pub etherscan_api_key: String,
Expand Down Expand Up @@ -133,10 +106,6 @@ impl Config {
chrono::Duration::hours(self.jwt.exp_in_hours)
}

pub fn get_tweet_sync_interval(&self) -> time::Duration {
time::Duration::from_secs(self.tweet_sync.interval_in_hours * 3600)
}

pub fn get_cors_allowed_origins(&self) -> Vec<HeaderValue> {
self.server
.cors_allowed_origins
Expand Down
4 changes: 0 additions & 4 deletions src/db_persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::repositories::admin::AdminRepository;
use crate::repositories::raid_quest::RaidQuestRepository;
use crate::repositories::relevant_tweet::RelevantTweetRepository;
use crate::repositories::tweet_author::TweetAuthorRepository;
use crate::repositories::tweet_pull_usage::TweetPullUsageRepository;
use crate::repositories::DbResult;
use crate::repositories::{address::AddressRepository, referral::ReferralRepository};

Expand All @@ -30,7 +29,6 @@ pub struct DbPersistence {
pub relevant_tweets: RelevantTweetRepository,
pub tweet_authors: TweetAuthorRepository,
pub raid_quests: RaidQuestRepository,
pub tweet_pull_usage: TweetPullUsageRepository,

/// Used by the `create_admin` binary and integration tests (not the main server binary).
#[allow(dead_code)]
Expand All @@ -49,7 +47,6 @@ impl DbPersistence {
let relevant_tweets = RelevantTweetRepository::new(&pool);
let tweet_authors = TweetAuthorRepository::new(&pool);
let raid_quests = RaidQuestRepository::new(&pool);
let tweet_pull_usage = TweetPullUsageRepository::new(pool.clone());

Ok(Self {
pool,
Expand All @@ -59,7 +56,6 @@ impl DbPersistence {
relevant_tweets,
tweet_authors,
raid_quests,
tweet_pull_usage,
})
}
}
8 changes: 0 additions & 8 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ pub enum AppError {
Http(#[from] axum::http::Error),
#[error("Rusx error: {0}")]
Rusx(#[from] SdkError),
#[error("Telegram API error: {1}")]
Telegram(u16, String),
#[error("Risk checker error: {0}")]
RiskChecker(#[from] RiskCheckerError),
#[error("Exchange rate error: {0}")]
Expand All @@ -52,12 +50,6 @@ pub type AppResult<T> = Result<T, AppError>;
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
// --- Telegram ---
AppError::Telegram(code, err) => (
StatusCode::from_u16(code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
err,
),

// --- Wallet Feature Flags ---
AppError::WalletConfigs(err) => map_wallet_configs_error(err),

Expand Down
25 changes: 2 additions & 23 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ use crate::{
args::Args,
db_persistence::DbPersistence,
errors::{AppError, AppResult},
services::{
alert_service::AlertService, graphql_client::GraphqlClient, telegram_service::TelegramService,
tweet_synchronizer_service::TweetSynchronizerService,
},
services::graphql_client::GraphqlClient,
};

use clap::Parser;
Expand Down Expand Up @@ -68,12 +65,7 @@ async fn main() -> AppResult<()> {
let server_address = config.get_server_address();
info!("Starting HTTP server on {}", server_address);

let twitter_gateway = Arc::new(RusxGateway::new(
config.x_oauth.clone(),
Some(config.tweet_sync.api_key.clone()),
)?);
let telegram_service = Arc::new(TelegramService::new(config.tg_bot.clone()));
let alert_service = Arc::new(AlertService::new(config.clone(), db.tweet_pull_usage.clone()));
let twitter_gateway = Arc::new(RusxGateway::new(config.x_oauth.clone(), None)?);
let server_db = db.clone();
let server_addr_clone = server_address.clone();
let server_config = Arc::new(config.clone());
Expand All @@ -87,25 +79,12 @@ async fn main() -> AppResult<()> {
info!("🎯 TaskMaster is now running!");
info!("HTTP API available at: http://{}", server_address);

// Initialize tweet sync service
let tweet_synchronizer = TweetSynchronizerService::new(
db.clone(),
twitter_gateway.clone(),
telegram_service,
alert_service.clone(),
Arc::new(config.clone()),
);

// Wait for any task to complete (they should run forever unless there's an error)
tokio::select! {
result = server_task => {
error!("HTTP server exited: {:?}", result);
result??;
}
result = tweet_synchronizer.spawn_tweet_synchronizer() => {
error!("Tweet synchronizer exited: {:?}", result);
result??;
}
}

Ok(())
Expand Down
118 changes: 0 additions & 118 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use std::sync::Arc;
use std::time::Instant;

use crate::http_server::AppState;
use rusx::error::SdkError;

// Define comprehensive metrics for REST API monitoring
lazy_static! {
Expand Down Expand Up @@ -50,35 +49,6 @@ lazy_static! {
&["method", "endpoint", "status"]
)
.unwrap();

// Twitter API metrics
pub static ref TWITTER_API_CALLS_TOTAL: IntCounterVec = IntCounterVec::new(
Opts::new("twitter_api_calls_total", "Total number of Twitter API calls"),
&["operation"]
)
.unwrap();
pub static ref TWITTER_API_CALL_DURATION: HistogramVec = HistogramVec::new(
HistogramOpts::new("twitter_api_call_duration_seconds", "Twitter API call duration in seconds")
.buckets(vec![0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0]),
&["operation"]
)
.unwrap();
pub static ref TWITTER_TWEETS_PULLED_TOTAL: IntCounterVec = IntCounterVec::new(
Opts::new("twitter_tweets_pulled_total", "Total number of tweets pulled from Twitter API"),
&["operation"]
)
.unwrap();
pub static ref TWITTER_API_ERRORS_TOTAL: IntCounterVec = IntCounterVec::new(
Opts::new("twitter_api_errors_total", "Total number of Twitter API errors"),
&["operation", "error_type"]
)
.unwrap();
pub static ref TWITTER_TWEETS_PER_CALL: HistogramVec = HistogramVec::new(
HistogramOpts::new("twitter_tweets_per_call", "Number of tweets returned per API call")
.buckets(vec![0.0, 1.0, 5.0, 10.0, 25.0, 50.0, 100.0]),
&["operation"]
)
.unwrap();
}

impl Default for Metrics {
Expand Down Expand Up @@ -111,15 +81,6 @@ impl Metrics {
registry.register(Box::new(HTTP_RESPONSE_SIZE_BYTES.clone())).unwrap();
registry.register(Box::new(HTTP_ERRORS_TOTAL.clone())).unwrap();

// Register Twitter API metrics
registry.register(Box::new(TWITTER_API_CALLS_TOTAL.clone())).unwrap();
registry.register(Box::new(TWITTER_API_CALL_DURATION.clone())).unwrap();
registry
.register(Box::new(TWITTER_TWEETS_PULLED_TOTAL.clone()))
.unwrap();
registry.register(Box::new(TWITTER_API_ERRORS_TOTAL.clone())).unwrap();
registry.register(Box::new(TWITTER_TWEETS_PER_CALL.clone())).unwrap();

Self {
registry: Arc::new(registry),
}
Expand Down Expand Up @@ -217,85 +178,6 @@ pub async fn track_metrics(req: Request, next: Next) -> Response {
response
}

fn extract_sdk_error_type(err: &SdkError) -> &'static str {
match err {
SdkError::Api { status, .. } => {
// Categorize based on HTTP status code
// Match specific status codes first, then ranges
match *status {
400 => "bad_request",
401 => "unauthorized",
403 => "forbidden",
404 => "not_found",
429 => "rate_limit",
500..=599 => "server_error",
402 | 405..=428 | 430..=499 => "client_error",
_ => "twitter_api_error",
}
}
_ => "sdk_error",
}
}

/// Track Twitter API call metrics with error type detection
///
/// This function should be called around Twitter API calls to track:
/// - API call duration
/// - Number of tweets pulled
/// - Errors with specific error types extracted from SdkError
///
/// # Arguments
/// * `operation` - The type of operation (e.g., "search_recent", "tweets_get_many")
/// * `f` - The async function that makes the Twitter API call
///
/// # Returns
/// The result of the API call, with metrics automatically tracked
pub async fn track_twitter_api_call<T, F>(operation: &str, f: F) -> Result<T, SdkError>
where
F: std::future::Future<Output = Result<T, SdkError>>,
{
let start = Instant::now();

// Track API call attempt
TWITTER_API_CALLS_TOTAL.with_label_values(&[operation]).inc();

let result = f.await;

// Record duration
let duration = start.elapsed().as_secs_f64();
TWITTER_API_CALL_DURATION
.with_label_values(&[operation])
.observe(duration);

// Track errors with specific error types
if let Err(ref err) = result {
let error_type = extract_sdk_error_type(err);
TWITTER_API_ERRORS_TOTAL
.with_label_values(&[operation, error_type])
.inc();
}

result
}

/// Track tweets pulled from a Twitter API call
///
/// Call this after successfully getting tweets from the API to track:
/// - Total tweets pulled
/// - Tweets per call distribution
///
/// # Arguments
/// * `operation` - The type of operation (e.g., "search_recent", "tweets_get_many")
/// * `tweet_count` - Number of tweets returned by the API call
pub fn track_tweets_pulled(operation: &str, tweet_count: usize) {
TWITTER_TWEETS_PULLED_TOTAL
.with_label_values(&[operation])
.inc_by(tweet_count as u64);
TWITTER_TWEETS_PER_CALL
.with_label_values(&[operation])
.observe(tweet_count as f64);
}

pub async fn metrics_handler(State(state): State<AppState>) -> impl IntoResponse {
let encoder = TextEncoder::new();
let metric_families = state.metrics.registry.gather();
Expand Down
1 change: 0 additions & 1 deletion src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ pub mod raid_quest;
pub mod referrals;
pub mod relevant_tweet;
pub mod tweet_author;
pub mod tweet_pull_usage;
Loading
Loading