portal, platform, and server fixes
This commit is contained in:
259
portal-server/cmd/main.rs
Normal file
259
portal-server/cmd/main.rs
Normal file
@@ -0,0 +1,259 @@
|
||||
//! Portal Server CLI
|
||||
//!
|
||||
//! Command-line interface for running the portal server with configurable options.
|
||||
|
||||
use clap::Parser;
|
||||
use portal_server::{PortalServerBuilder, ServerConfig};
|
||||
use tracing::{info, error};
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "portal-server")]
|
||||
#[command(about = "Portal Server for KYC verification and payment processing")]
|
||||
#[command(version = "0.1.0")]
|
||||
struct Cli {
|
||||
/// Server host address
|
||||
#[arg(long, default_value = "127.0.0.1")]
|
||||
host: String,
|
||||
|
||||
/// Server port
|
||||
#[arg(short, long, default_value = "3001")]
|
||||
port: u16,
|
||||
|
||||
/// Stripe secret key
|
||||
#[arg(long, env)]
|
||||
stripe_secret_key: Option<String>,
|
||||
|
||||
/// Stripe publishable key
|
||||
#[arg(long, env)]
|
||||
stripe_publishable_key: Option<String>,
|
||||
|
||||
/// Stripe webhook secret
|
||||
#[arg(long, env)]
|
||||
stripe_webhook_secret: Option<String>,
|
||||
|
||||
/// Identify API key for KYC verification
|
||||
#[arg(long, env)]
|
||||
identify_api_key: Option<String>,
|
||||
|
||||
/// Identify webhook secret for signature verification
|
||||
#[arg(long, env)]
|
||||
identify_webhook_secret: Option<String>,
|
||||
|
||||
/// API keys for authentication (comma-separated)
|
||||
#[arg(long, env)]
|
||||
api_keys: Option<String>,
|
||||
|
||||
/// Identify API URL
|
||||
#[arg(long, env, default_value = "https://api.identify.com")]
|
||||
identify_api_url: String,
|
||||
|
||||
/// CORS allowed origins (comma-separated)
|
||||
#[arg(long, env, default_value = "*")]
|
||||
cors_origins: String,
|
||||
|
||||
/// Directory to serve static files from
|
||||
#[arg(long)]
|
||||
static_dir: Option<String>,
|
||||
|
||||
/// Load configuration from environment variables
|
||||
#[arg(long)]
|
||||
from_env: bool,
|
||||
|
||||
/// Path to .env file (defaults to .env in current directory)
|
||||
#[arg(long)]
|
||||
env_file: Option<String>,
|
||||
|
||||
/// Enable verbose logging
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
}
|
||||
|
||||
fn load_env_file(cli: &Cli) -> Result<()> {
|
||||
use std::path::Path;
|
||||
|
||||
if let Some(env_file_path) = &cli.env_file {
|
||||
// Use the specified .env file path
|
||||
info!("Loading .env file from: {}", env_file_path);
|
||||
if Path::new(env_file_path).exists() {
|
||||
dotenv::from_path(env_file_path)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to load .env file from {}: {}", env_file_path, e))?;
|
||||
info!("Successfully loaded .env file from: {}", env_file_path);
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Specified .env file not found: {}", env_file_path));
|
||||
}
|
||||
} else {
|
||||
// Try default locations in order of preference
|
||||
let default_paths = [
|
||||
".env", // Current directory
|
||||
"portal-server/.env", // portal-server subdirectory
|
||||
];
|
||||
|
||||
let mut loaded = false;
|
||||
for path in &default_paths {
|
||||
if Path::new(path).exists() {
|
||||
info!("Loading .env file from: {}", path);
|
||||
dotenv::from_path(path)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to load .env file from {}: {}", path, e))?;
|
||||
info!("Successfully loaded .env file from: {}", path);
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !loaded {
|
||||
info!("No .env file found in default locations. Using environment variables and CLI arguments only.");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
// Initialize tracing
|
||||
if cli.verbose {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(tracing::Level::DEBUG)
|
||||
.init();
|
||||
} else {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(tracing::Level::INFO)
|
||||
.init();
|
||||
}
|
||||
|
||||
info!("Starting Portal Server...");
|
||||
|
||||
// Load .env file if specified or use default locations
|
||||
load_env_file(&cli)?;
|
||||
|
||||
// Build configuration
|
||||
let config = if cli.from_env {
|
||||
info!("Loading configuration from environment variables");
|
||||
ServerConfig::from_env()?
|
||||
} else {
|
||||
info!("Using configuration from command line arguments");
|
||||
build_config_from_cli(&cli)?
|
||||
};
|
||||
|
||||
// Log configuration (without sensitive data)
|
||||
info!("Server configuration:");
|
||||
info!(" Host: {}", config.host);
|
||||
info!(" Port: {}", config.port);
|
||||
info!(" Identify API URL: {}", config.identify_api_url);
|
||||
info!(" CORS Origins: {:?}", config.cors_origins);
|
||||
info!(" Stripe configured: {}", !config.stripe_secret_key.is_empty());
|
||||
info!(" Identify configured: {}", !config.identify_api_key.is_empty());
|
||||
|
||||
// Build server
|
||||
let mut builder = PortalServerBuilder::new(config);
|
||||
|
||||
// Add static file serving if specified
|
||||
if let Some(static_dir) = cli.static_dir {
|
||||
builder = builder.with_static_dir(static_dir);
|
||||
}
|
||||
|
||||
let server = builder.build().await?;
|
||||
|
||||
// Run server
|
||||
if let Err(e) = server.run().await {
|
||||
error!("Server error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_config_from_cli(cli: &Cli) -> Result<ServerConfig> {
|
||||
let stripe_secret_key = cli.stripe_secret_key
|
||||
.clone()
|
||||
.or_else(|| std::env::var("STRIPE_SECRET_KEY").ok())
|
||||
.ok_or_else(|| anyhow::anyhow!("Stripe secret key is required. Use --stripe-secret-key or set STRIPE_SECRET_KEY environment variable"))?;
|
||||
|
||||
let stripe_publishable_key = cli.stripe_publishable_key
|
||||
.clone()
|
||||
.or_else(|| std::env::var("STRIPE_PUBLISHABLE_KEY").ok())
|
||||
.ok_or_else(|| anyhow::anyhow!("Stripe publishable key is required. Use --stripe-publishable-key or set STRIPE_PUBLISHABLE_KEY environment variable"))?;
|
||||
|
||||
let identify_api_key = cli.identify_api_key
|
||||
.clone()
|
||||
.or_else(|| std::env::var("IDENTIFY_API_KEY").ok())
|
||||
.ok_or_else(|| anyhow::anyhow!("Identify API key is required. Use --identify-api-key or set IDENTIFY_API_KEY environment variable"))?;
|
||||
|
||||
let cors_origins = cli.cors_origins
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.collect();
|
||||
|
||||
let api_keys = cli.api_keys
|
||||
.clone()
|
||||
.or_else(|| std::env::var("API_KEYS").ok())
|
||||
.map(|keys| keys.split(',').map(|s| s.trim().to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(ServerConfig {
|
||||
host: cli.host.clone(),
|
||||
port: cli.port,
|
||||
stripe_secret_key,
|
||||
stripe_publishable_key,
|
||||
stripe_webhook_secret: cli.stripe_webhook_secret.clone(),
|
||||
identify_api_key,
|
||||
identify_webhook_secret: cli.identify_webhook_secret.clone(),
|
||||
identify_api_url: cli.identify_api_url.clone(),
|
||||
cors_origins,
|
||||
api_keys,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cli_parsing() {
|
||||
let cli = Cli::parse_from(&[
|
||||
"portal-server",
|
||||
"--host", "0.0.0.0",
|
||||
"--port", "8080",
|
||||
"--stripe-secret-key", "sk_test_123",
|
||||
"--stripe-publishable-key", "pk_test_123",
|
||||
"--identify-api-key", "identify_123",
|
||||
"--verbose",
|
||||
]);
|
||||
|
||||
assert_eq!(cli.host, "0.0.0.0");
|
||||
assert_eq!(cli.port, 8080);
|
||||
assert_eq!(cli.stripe_secret_key, Some("sk_test_123".to_string()));
|
||||
assert_eq!(cli.stripe_publishable_key, Some("pk_test_123".to_string()));
|
||||
assert_eq!(cli.identify_api_key, Some("identify_123".to_string()));
|
||||
assert!(cli.verbose);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_from_cli() {
|
||||
let cli = Cli {
|
||||
host: "localhost".to_string(),
|
||||
port: 3000,
|
||||
stripe_secret_key: Some("sk_test_123".to_string()),
|
||||
stripe_publishable_key: Some("pk_test_123".to_string()),
|
||||
stripe_webhook_secret: None,
|
||||
identify_api_key: Some("identify_123".to_string()),
|
||||
identify_webhook_secret: None,
|
||||
api_keys: None,
|
||||
identify_api_url: "https://api.identify.com".to_string(),
|
||||
cors_origins: "*".to_string(),
|
||||
static_dir: None,
|
||||
from_env: false,
|
||||
env_file: None,
|
||||
verbose: false,
|
||||
};
|
||||
|
||||
let config = build_config_from_cli(&cli).unwrap();
|
||||
assert_eq!(config.host, "localhost");
|
||||
assert_eq!(config.port, 3000);
|
||||
assert_eq!(config.stripe_secret_key, "sk_test_123");
|
||||
assert_eq!(config.identify_api_key, "identify_123");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user