feat: 模块统一 ias- 前缀、独立版本与内网地址支持 (0.1.7)
- 所有 Rust crate 统一加 ias- 前缀:ai → ias-ai、common → ias-common、context → ias-context、mail → ias-mail、service → ias-service、wechat → ias-wechat - 新增 ias-main 模块承载 CLI 入口和二进制打包 - 各模块开始独立维护版本号,ias-main 0.1.7 代表整体版本 - 新增 IA_WEB_INTERNAL_URL 环境变量,版本通知同时发送公网和内网链接 - 将已有升级日志翻译为中文 - ias_upgrade_logs 新增 modules JSONB 字段 - 新增 VERSION 文件和 CHANGELOG.md - 新增 AGENTS.md 项目规则文件
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::model::MailAccount;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MailPollerConfig {
|
||||
pub mail_account_id: Option<i64>,
|
||||
pub name: String,
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub mailbox: String,
|
||||
pub source_key: String,
|
||||
pub notify_account_id: String,
|
||||
pub notify_user_id: String,
|
||||
pub poll_interval: Duration,
|
||||
pub fetch_limit: usize,
|
||||
pub accept_invalid_certs: bool,
|
||||
}
|
||||
|
||||
impl MailPollerConfig {
|
||||
pub fn from_account(account: MailAccount) -> Self {
|
||||
Self {
|
||||
mail_account_id: Some(account.id),
|
||||
name: account.name,
|
||||
source_key: account.source_key,
|
||||
host: account.imap_host,
|
||||
port: account.imap_port.clamp(1, u16::MAX as i32) as u16,
|
||||
username: account.imap_username,
|
||||
password: account.imap_password,
|
||||
mailbox: account.mailbox,
|
||||
notify_account_id: account.notify_account_id,
|
||||
notify_user_id: account.notify_user_id,
|
||||
poll_interval: Duration::from_secs(account.poll_seconds.max(10) as u64),
|
||||
fetch_limit: account.fetch_limit.clamp(1, 100) as usize,
|
||||
accept_invalid_certs: account.accept_invalid_certs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_env() -> anyhow::Result<Option<Self>> {
|
||||
if !env_bool("IA_MAIL_ENABLED", true) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let host = optional_env("IA_MAIL_IMAP_HOST");
|
||||
let username = optional_env("IA_MAIL_IMAP_USERNAME");
|
||||
let password = optional_env("IA_MAIL_IMAP_PASSWORD");
|
||||
let notify_account_id = optional_env("IA_MAIL_NOTIFY_ACCOUNT_ID");
|
||||
let notify_user_id = optional_env("IA_MAIL_NOTIFY_USER_ID")
|
||||
.or_else(|| optional_env("IA_MAIL_NOTIFY_FROM_USER_ID"));
|
||||
|
||||
let required_values = [
|
||||
host.as_ref(),
|
||||
username.as_ref(),
|
||||
password.as_ref(),
|
||||
notify_account_id.as_ref(),
|
||||
notify_user_id.as_ref(),
|
||||
];
|
||||
if required_values.iter().all(|value| value.is_none()) {
|
||||
return Ok(None);
|
||||
}
|
||||
if required_values.iter().any(|value| value.is_none()) {
|
||||
return Err(anyhow!(
|
||||
"邮件轮询配置不完整,需要 IA_MAIL_IMAP_HOST、IA_MAIL_IMAP_USERNAME、IA_MAIL_IMAP_PASSWORD、IA_MAIL_NOTIFY_ACCOUNT_ID、IA_MAIL_NOTIFY_USER_ID"
|
||||
));
|
||||
}
|
||||
|
||||
let host = host.unwrap();
|
||||
let username = username.unwrap();
|
||||
let port = optional_env("IA_MAIL_IMAP_PORT")
|
||||
.and_then(|value| value.parse::<u16>().ok())
|
||||
.unwrap_or(993);
|
||||
let mailbox = optional_env("IA_MAIL_IMAP_MAILBOX").unwrap_or_else(|| "INBOX".to_string());
|
||||
let poll_seconds = optional_env("IA_MAIL_POLL_SECONDS")
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.unwrap_or(60)
|
||||
.max(10);
|
||||
let fetch_limit = optional_env("IA_MAIL_FETCH_LIMIT")
|
||||
.and_then(|value| value.parse::<usize>().ok())
|
||||
.unwrap_or(10)
|
||||
.clamp(1, 100);
|
||||
|
||||
Ok(Some(Self {
|
||||
mail_account_id: None,
|
||||
name: username.clone(),
|
||||
source_key: format!("imap:{host}:{username}"),
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password: password.unwrap(),
|
||||
mailbox,
|
||||
notify_account_id: notify_account_id.unwrap(),
|
||||
notify_user_id: notify_user_id.unwrap(),
|
||||
poll_interval: Duration::from_secs(poll_seconds),
|
||||
fetch_limit,
|
||||
accept_invalid_certs: env_bool("IA_MAIL_ACCEPT_INVALID_CERTS", false),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn optional_env(name: &str) -> Option<String> {
|
||||
env::var(name)
|
||||
.ok()
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty())
|
||||
}
|
||||
|
||||
fn env_bool(name: &str, default: bool) -> bool {
|
||||
env::var(name)
|
||||
.map(|value| {
|
||||
let value = value.trim().to_ascii_lowercase();
|
||||
!matches!(value.as_str(), "0" | "false" | "no" | "off")
|
||||
})
|
||||
.unwrap_or(default)
|
||||
}
|
||||
Reference in New Issue
Block a user