forked from StellarRouter/StellarRouter
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.rs
More file actions
139 lines (118 loc) · 3.89 KB
/
Copy pathmain.rs
File metadata and controls
139 lines (118 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
mod auth;
mod handlers;
mod openapi;
mod rate_limit;
mod rpc;
mod state;
mod types;
mod websocket;
mod xdr;
#[cfg(test)]
mod tests;
use anyhow::{Context, Result};
use axum::{
extract::DefaultBodyLimit,
middleware::from_fn_with_state,
routing::{get, post},
Json, Router,
};
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
use clap::Parser;
use std::net::SocketAddr;
use tracing::info;
use crate::{
auth::AuthConfig,
rate_limit::{rate_limit_middleware, RateLimitConfig, RateLimiter},
rpc::FeeConfig,
state::AppState,
};
#[derive(Parser, Debug)]
#[command(name = "router-api-server")]
#[command(
about = "API server for stellar-router with transaction simulation and WebSocket tracking"
)]
struct Args {
/// Listen address (default: 127.0.0.1:8080)
#[arg(long, env = "LISTEN_ADDR", default_value = "127.0.0.1:8080")]
listen: String,
/// Soroban RPC endpoint URL
#[arg(long, env = "SOROBAN_RPC_URL")]
rpc_url: String,
/// Router execution contract ID
#[arg(long, env = "ROUTER_EXECUTION_CONTRACT_ID")]
execution_contract_id: String,
/// Router core contract ID (for GET /routes)
#[arg(long, env = "ROUTER_CORE_CONTRACT_ID", default_value = "")]
router_core_contract_id: String,
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive(tracing::Level::INFO.into()),
)
.init();
let args = Args::parse();
info!("Starting router-api-server");
info!("Listen address: {}", args.listen);
info!("RPC URL: {}", args.rpc_url);
let auth_config = AuthConfig::from_env();
info!("Router auth enabled: {}", auth_config.enabled);
let rate_limit_config = RateLimitConfig::from_env()?;
info!(
max_requests = rate_limit_config.max_requests,
window_secs = rate_limit_config.window.as_secs(),
"Router API rate limiting enabled"
);
let rate_limiter = RateLimiter::new(rate_limit_config);
let fee_config = FeeConfig::from_env();
info!(
base_fee = fee_config.base_fee,
resource_fee_floor = fee_config.resource_fee_floor,
resource_fee_divisor = fee_config.resource_fee_divisor,
surge_load_threshold_bps = fee_config.surge_load_threshold_bps,
surge_multiplier = fee_config.surge_multiplier,
normal_multiplier = fee_config.normal_multiplier,
"Router fee-estimation config loaded"
);
let state = AppState::new(
args.rpc_url,
args.execution_contract_id,
args.router_core_contract_id,
auth_config.clone(),
fee_config,
);
let protected_routes = Router::new()
.route("/simulate", post(handlers::simulate))
.route("/routes", get(handlers::list_routes))
.route("/routes/:name", get(handlers::get_route))
.route("/ws", get(websocket::ws_handler))
.route_layer(from_fn_with_state(rate_limiter, rate_limit_middleware))
.route_layer(from_fn_with_state(auth_config, auth::auth_middleware));
let app = Router::new()
.route(
"/api-docs/openapi.json",
get(|| async { Json(openapi::ApiDoc::openapi()) }),
)
.merge(
SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", openapi::ApiDoc::openapi()),
)
.route("/health", get(handlers::health))
.nest("/", protected_routes)
.layer(DefaultBodyLimit::max(1024 * 1024))
.with_state(state);
let addr: SocketAddr = args
.listen
.parse()
.with_context(|| format!("invalid listen address: {}", args.listen))?;
info!("Server listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await?;
Ok(())
}