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
|
use std::env;
#[derive(Clone, Debug)]
pub struct Config {
pub bind_addr: String,
pub canonical_origin: String,
pub secure_cookies: bool,
pub db_path: String,
pub data_dir: String,
pub frontend_dir: String,
pub worker_image: String,
pub fetch_timeout_secs: u64,
pub backtest_timeout_secs: u64,
pub run_concurrency: usize,
pub fetch_concurrency: usize,
pub session_hours: i64,
pub bootstrap_admin_email: Option<String>,
pub bootstrap_admin_password: Option<String>,
pub ai_base_url: String,
pub ai_model: String,
pub ai_daily_request_cap: i64,
pub ai_input_token_cap: i64,
pub ai_output_token_cap: i64,
pub ai_enabled_poc: bool,
pub default_run_limit_per_day: i64,
pub version: String,
}
fn envs(k: &str, d: &str) -> String {
env::var(k).ok().filter(|v| !v.is_empty()).unwrap_or_else(|| d.to_string())
}
impl Config {
pub fn from_env() -> Self {
let canonical_origin = envs("ORIGIN", "");
Config {
bind_addr: envs("BIND", "127.0.0.1:8787"),
canonical_origin: canonical_origin.clone(),
secure_cookies: canonical_origin.starts_with("https://"),
db_path: envs("DB_PATH", "server-data/strategy-lab.sqlite3"),
data_dir: envs("DATA_DIR", "server-data/data"),
frontend_dir: envs("FRONTEND_DIR", "frontend/dist"),
worker_image: envs("WORKER_IMAGE", "strategy-lab-worker:local"),
fetch_timeout_secs: envs("FETCH_TIMEOUT_SECS", "1800").parse().unwrap_or(1800),
backtest_timeout_secs: envs("BACKTEST_TIMEOUT_SECS", "1800").parse().unwrap_or(1800),
run_concurrency: envs("RUN_CONCURRENCY", "1").parse().unwrap_or(1),
fetch_concurrency: envs("FETCH_CONCURRENCY", "2").parse().unwrap_or(2),
session_hours: envs("SESSION_HOURS", "336").parse().unwrap_or(336),
bootstrap_admin_email: env::var("BOOTSTRAP_ADMIN_EMAIL").ok(),
bootstrap_admin_password: env::var("BOOTSTRAP_ADMIN_PASSWORD").ok(),
ai_base_url: envs("AI_BASE_URL", "https://opencode.ai/zen/go/v1"),
ai_model: envs("AI_MODEL", "glm-5.3-flash"),
ai_daily_request_cap: envs("AI_DAILY_REQUEST_CAP", "20").parse().unwrap_or(20),
ai_input_token_cap: envs("AI_INPUT_TOKEN_CAP", "8000").parse().unwrap_or(8000),
ai_output_token_cap: envs("AI_OUTPUT_TOKEN_CAP", "6000").parse().unwrap_or(6000),
ai_enabled_poc: envs("AI_ENABLED_POC", "true") == "true",
default_run_limit_per_day: envs("DEFAULT_RUN_LIMIT_PER_DAY", "10").parse().unwrap_or(10),
version: envs("APP_VERSION", env!("CARGO_PKG_VERSION")),
}
}
}
pub const MAX_CODE_LEN: usize = 256_000;
pub const MAX_SYMBOLS: usize = 5;
pub const MAX_RANGE_YEARS: i64 = 15;
|