use clap::Parser;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Parser, Debug, Clone)]
#[command(name = "maple-proxy")]
#[command(about = "Lightweight OpenAI-compatible proxy server for Maple/OpenSecret")]
pub struct Config {
#[arg(long, env = "MAPLE_HOST", default_value = "127.0.0.1")]
pub host: String,
#[arg(short, long, env = "MAPLE_PORT", default_value = "8080")]
pub port: u16,
#[arg(
long,
env = "MAPLE_BACKEND_URL",
default_value = "https://enclave.trymaple.ai"
)]
pub backend_url: String,
#[arg(long, env = "MAPLE_API_KEY")]
pub default_api_key: Option<String>,
#[arg(short, long, env = "MAPLE_DEBUG")]
pub debug: bool,
#[arg(long, env = "MAPLE_ENABLE_CORS")]
pub enable_cors: bool,
}
impl Config {
pub fn socket_addr(&self) -> anyhow::Result<SocketAddr> {
let addr = format!("{}:{}", self.host, self.port);
addr.parse()
.map_err(|e| anyhow::anyhow!("Invalid socket address '{}': {}", addr, e))
}
pub fn load() -> Self {
let _ = dotenvy::dotenv();
Config::parse()
}
pub fn new(host: String, port: u16, backend_url: String) -> Self {
Self {
host,
port,
backend_url,
default_api_key: None,
debug: false,
enable_cors: false,
}
}
pub fn with_api_key(mut self, api_key: String) -> Self {
self.default_api_key = Some(api_key);
self
}
pub fn with_debug(mut self, debug: bool) -> Self {
self.debug = debug;
self
}
pub fn with_cors(mut self, enable_cors: bool) -> Self {
self.enable_cors = enable_cors;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenAIError {
pub error: OpenAIErrorDetails,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenAIErrorDetails {
pub message: String,
#[serde(rename = "type")]
pub error_type: String,
pub param: Option<String>,
pub code: Option<String>,
}
impl OpenAIError {
pub fn new(message: impl Into<String>, error_type: impl Into<String>) -> Self {
Self {
error: OpenAIErrorDetails {
message: message.into(),
error_type: error_type.into(),
param: None,
code: None,
},
}
}
pub fn authentication_error(message: impl Into<String>) -> Self {
Self::new(message, "invalid_request_error")
}
pub fn server_error(message: impl Into<String>) -> Self {
Self::new(message, "server_error")
}
}