rust implementation

This commit is contained in:
2025-11-23 12:12:20 +08:00
parent f40ace4058
commit 226e8cbf4f
19 changed files with 2358 additions and 364 deletions

81
src/main.rs Normal file
View File

@@ -0,0 +1,81 @@
use std::{net::SocketAddr, sync::Arc};
use anyhow::Context;
use axum::{routing::any, Router};
use dotenvy::dotenv;
use tracing::{error, info, level_filters::LevelFilter};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
mod crypto;
mod proxy;
#[derive(Clone)]
pub struct AppState {
pub client: reqwest::Client,
pub target_url: reqwest::Url,
pub key: String,
pub iv: String,
}
const DEFAULT_TARGET_URL: &str = "https://cloud.linspirer.com:883";
const DEFAULT_HOST: &str = "0.0.0.0";
const DEFAULT_PORT: &str = "8080";
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Load environment variables from .env file
dotenv().ok();
// Set up logging
tracing_subscriber::registry()
.with(fmt::layer())
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.init();
// Load configuration from environment
let key = std::env::var("LINSPIRER_KEY").context("LINSPIRER_KEY must be set")?;
let iv = std::env::var("LINSPIRER_IV").context("LINSPIRER_IV must be set")?;
let target_url_str = std::env::var("LINSPIRER_TARGET_URL");
let target_url_str = target_url_str.as_deref().unwrap_or(DEFAULT_TARGET_URL);
let target_url = reqwest::Url::parse(target_url_str)?;
let host_str = std::env::var("LINSPIRER_HOST");
let host = host_str.as_deref().unwrap_or(DEFAULT_HOST);
let port_str = std::env::var("LINSPIRER_PORT");
let port = port_str.as_deref().unwrap_or(DEFAULT_PORT);
let addr_str = format!("{}:{}", host, port);
let addr: SocketAddr = addr_str
.parse()
.context(format!("Invalid address format: {}", addr_str))?;
// Create a reqwest client that ignores SSL certificate verification
let client = reqwest::Client::builder()
.danger_accept_invalid_certs(true)
.build()?;
// Create shared state
let state = Arc::new(AppState {
client,
target_url,
key,
iv,
});
// Build our application with a single route
let app = Router::new()
.route("/{*path}", any(proxy::proxy_handler))
.with_state(state);
// Run the server
info!("Proxy started on {} => {}", addr_str, target_url_str);
let listener = tokio::net::TcpListener::bind(&addr).await?;
if let Err(e) = axum::serve(listener, app.into_make_service()).await {
error!("Server error: {}", e);
}
Ok(())
}