File size: 6,214 Bytes
3c2af29 |
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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
use super::constant::{
COMMA, CURSOR_API2_HOST, CURSOR_HOST, DEFAULT_TOKEN_LIST_FILE_NAME, EMPTY_STRING,
};
use crate::common::utils::{
parse_ascii_char_from_env, parse_bool_from_env, parse_string_from_env, parse_usize_from_env,
};
use std::sync::LazyLock;
use tokio::sync::{Mutex, OnceCell};
macro_rules! def_pub_static {
// 基础版本:直接存储 String
($name:ident, $value:expr) => {
pub static $name: LazyLock<String> = LazyLock::new(|| $value);
};
// 环境变量版本
($name:ident, env: $env_key:expr, default: $default:expr) => {
pub static $name: LazyLock<String> =
LazyLock::new(|| parse_string_from_env($env_key, $default).trim().to_string());
};
}
// macro_rules! def_pub_static_getter {
// ($name:ident) => {
// paste::paste! {
// pub fn [<get_ $name:lower>]() -> String {
// (*$name).clone()
// }
// }
// };
// }
def_pub_static!(ROUTE_PREFIX, env: "ROUTE_PREFIX", default: EMPTY_STRING);
def_pub_static!(AUTH_TOKEN, env: "AUTH_TOKEN", default: EMPTY_STRING);
def_pub_static!(TOKEN_LIST_FILE, env: "TOKEN_LIST_FILE", default: DEFAULT_TOKEN_LIST_FILE_NAME);
def_pub_static!(ROUTE_MODELS_PATH, format!("{}/v1/models", *ROUTE_PREFIX));
def_pub_static!(
ROUTE_CHAT_PATH,
format!("{}/v1/chat/completions", *ROUTE_PREFIX)
);
pub static START_TIME: LazyLock<chrono::DateTime<chrono::Local>> =
LazyLock::new(chrono::Local::now);
pub fn get_start_time() -> chrono::DateTime<chrono::Local> {
*START_TIME
}
def_pub_static!(DEFAULT_INSTRUCTIONS, env: "DEFAULT_INSTRUCTIONS", default: "Respond in Chinese by default");
def_pub_static!(REVERSE_PROXY_HOST, env: "REVERSE_PROXY_HOST", default: EMPTY_STRING);
const DEFAULT_KEY_PREFIX: &str = "sk-";
pub static KEY_PREFIX: LazyLock<String> = LazyLock::new(|| {
let value = parse_string_from_env("KEY_PREFIX", DEFAULT_KEY_PREFIX)
.trim()
.to_string();
if value.is_empty() {
DEFAULT_KEY_PREFIX.to_string()
} else {
value
}
});
pub static KEY_PREFIX_LEN: LazyLock<usize> = LazyLock::new(|| KEY_PREFIX.len());
pub static TOKEN_DELIMITER: LazyLock<char> = LazyLock::new(|| {
let delimiter = parse_ascii_char_from_env("TOKEN_DELIMITER", COMMA);
if delimiter.is_ascii_alphabetic()
|| delimiter.is_ascii_digit()
|| delimiter == '+'
|| delimiter == '/'
{
COMMA
} else {
delimiter
}
});
pub static USE_COMMA_DELIMITER: LazyLock<bool> = LazyLock::new(|| {
let enable = parse_bool_from_env("USE_COMMA_DELIMITER", true);
if enable && *TOKEN_DELIMITER == COMMA {
false
} else {
enable
}
});
pub static USE_REVERSE_PROXY: LazyLock<bool> = LazyLock::new(|| !REVERSE_PROXY_HOST.is_empty());
macro_rules! def_cursor_api_url {
($name:ident, $api_host:expr, $path:expr) => {
pub static $name: LazyLock<String> = LazyLock::new(|| {
let host = if *USE_REVERSE_PROXY {
&*REVERSE_PROXY_HOST
} else {
$api_host
};
format!("https://{}{}", host, $path)
});
};
}
def_cursor_api_url!(
CURSOR_API2_CHAT_URL,
CURSOR_API2_HOST,
"/aiserver.v1.AiService/StreamChat"
);
def_cursor_api_url!(
CURSOR_API2_CHAT_WEB_URL,
CURSOR_API2_HOST,
"/aiserver.v1.AiService/StreamChatWeb"
);
def_cursor_api_url!(
CURSOR_API2_STRIPE_URL,
CURSOR_API2_HOST,
"/auth/full_stripe_profile"
);
def_cursor_api_url!(CURSOR_USAGE_API_URL, CURSOR_HOST, "/api/usage");
def_cursor_api_url!(CURSOR_USER_API_URL, CURSOR_HOST, "/api/auth/me");
pub(super) static LOGS_FILE_PATH: LazyLock<String> =
LazyLock::new(|| parse_string_from_env("LOGS_FILE_PATH", "logs.bin"));
pub(super) static PAGES_FILE_PATH: LazyLock<String> =
LazyLock::new(|| parse_string_from_env("PAGES_FILE_PATH", "pages.bin"));
pub static DEBUG: LazyLock<bool> = LazyLock::new(|| parse_bool_from_env("DEBUG", false));
// 使用环境变量 "DEBUG_LOG_FILE" 来指定日志文件路径,默认值为 "debug.log"
static DEBUG_LOG_FILE: LazyLock<String> =
LazyLock::new(|| parse_string_from_env("DEBUG_LOG_FILE", "debug.log"));
// 使用 OnceCell 结合 Mutex 来异步初始化 LOG_FILE
static LOG_FILE: OnceCell<Mutex<tokio::fs::File>> = OnceCell::const_new();
pub(crate) async fn get_log_file() -> &'static Mutex<tokio::fs::File> {
LOG_FILE
.get_or_init(|| async {
Mutex::new(
tokio::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&*DEBUG_LOG_FILE)
.await
.expect("无法打开日志文件"),
)
})
.await
}
#[macro_export]
macro_rules! debug_println {
($($arg:tt)*) => {
if *crate::app::lazy::DEBUG {
let time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
let log_message = format!("{} - {}", time, format!($($arg)*));
use tokio::io::AsyncWriteExt as _;
// 使用 tokio 的 spawn 在后台异步写入日志
tokio::spawn(async move {
let log_file = crate::app::lazy::get_log_file().await;
// 使用 MutexGuard 获取可变引用
let mut file = log_file.lock().await;
if let Err(err) = file.write_all(log_message.as_bytes()).await {
eprintln!("写入日志文件失败: {}", err);
}
if let Err(err) = file.write_all(b"\n").await {
eprintln!("写入换行符失败: {}", err);
}
// 可以选择在写入失败时 panic,或者忽略
// panic!("写入日志文件失败: {}", err);
});
}
};
}
pub static REQUEST_LOGS_LIMIT: LazyLock<usize> =
LazyLock::new(|| std::cmp::min(parse_usize_from_env("REQUEST_LOGS_LIMIT", 100), 2000));
pub static SERVICE_TIMEOUT: LazyLock<u64> = LazyLock::new(|| {
let timeout = parse_usize_from_env("SERVICE_TIMEOUT", 30);
u64::try_from(timeout).map(|t| t.min(600)).unwrap_or(30)
});
|