Compare commits
2 Commits
master
...
work-issue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
303c182a4f | ||
|
|
6cdea12508 |
@ -18,6 +18,8 @@ pub struct DingTalkChannel {
|
|||||||
/// Per-chat session webhooks for sending replies (chatID -> webhook URL).
|
/// Per-chat session webhooks for sending replies (chatID -> webhook URL).
|
||||||
/// DingTalk provides a unique webhook URL with each incoming message.
|
/// DingTalk provides a unique webhook URL with each incoming message.
|
||||||
session_webhooks: Arc<RwLock<HashMap<String, String>>>,
|
session_webhooks: Arc<RwLock<HashMap<String, String>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response from DingTalk gateway connection registration.
|
/// Response from DingTalk gateway connection registration.
|
||||||
@ -34,11 +36,18 @@ impl DingTalkChannel {
|
|||||||
client_secret,
|
client_secret,
|
||||||
allowed_users,
|
allowed_users,
|
||||||
session_webhooks: Arc::new(RwLock::new(HashMap::new())),
|
session_webhooks: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.dingtalk")
|
crate::config::build_channel_proxy_client("channel.dingtalk", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_user_allowed(&self, user_id: &str) -> bool {
|
fn is_user_allowed(&self, user_id: &str) -> bool {
|
||||||
|
|||||||
@ -18,6 +18,8 @@ pub struct DiscordChannel {
|
|||||||
listen_to_bots: bool,
|
listen_to_bots: bool,
|
||||||
mention_only: bool,
|
mention_only: bool,
|
||||||
typing_handles: Mutex<HashMap<String, tokio::task::JoinHandle<()>>>,
|
typing_handles: Mutex<HashMap<String, tokio::task::JoinHandle<()>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiscordChannel {
|
impl DiscordChannel {
|
||||||
@ -35,11 +37,18 @@ impl DiscordChannel {
|
|||||||
listen_to_bots,
|
listen_to_bots,
|
||||||
mention_only,
|
mention_only,
|
||||||
typing_handles: Mutex::new(HashMap::new()),
|
typing_handles: Mutex::new(HashMap::new()),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.discord")
|
crate::config::build_channel_proxy_client("channel.discord", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a Discord user ID is in the allowlist.
|
/// Check if a Discord user ID is in the allowlist.
|
||||||
|
|||||||
@ -380,6 +380,8 @@ pub struct LarkChannel {
|
|||||||
tenant_token: Arc<RwLock<Option<CachedTenantToken>>>,
|
tenant_token: Arc<RwLock<Option<CachedTenantToken>>>,
|
||||||
/// Dedup set: WS message_ids seen in last ~30 min to prevent double-dispatch
|
/// Dedup set: WS message_ids seen in last ~30 min to prevent double-dispatch
|
||||||
ws_seen_ids: Arc<RwLock<HashMap<String, Instant>>>,
|
ws_seen_ids: Arc<RwLock<HashMap<String, Instant>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LarkChannel {
|
impl LarkChannel {
|
||||||
@ -423,6 +425,7 @@ impl LarkChannel {
|
|||||||
receive_mode: crate::config::schema::LarkReceiveMode::default(),
|
receive_mode: crate::config::schema::LarkReceiveMode::default(),
|
||||||
tenant_token: Arc::new(RwLock::new(None)),
|
tenant_token: Arc::new(RwLock::new(None)),
|
||||||
ws_seen_ids: Arc::new(RwLock::new(HashMap::new())),
|
ws_seen_ids: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,6 +447,7 @@ impl LarkChannel {
|
|||||||
platform,
|
platform,
|
||||||
);
|
);
|
||||||
ch.receive_mode = config.receive_mode.clone();
|
ch.receive_mode = config.receive_mode.clone();
|
||||||
|
ch.proxy_url = config.proxy_url.clone();
|
||||||
ch
|
ch
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,6 +465,7 @@ impl LarkChannel {
|
|||||||
LarkPlatform::Lark,
|
LarkPlatform::Lark,
|
||||||
);
|
);
|
||||||
ch.receive_mode = config.receive_mode.clone();
|
ch.receive_mode = config.receive_mode.clone();
|
||||||
|
ch.proxy_url = config.proxy_url.clone();
|
||||||
ch
|
ch
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,11 +481,15 @@ impl LarkChannel {
|
|||||||
LarkPlatform::Feishu,
|
LarkPlatform::Feishu,
|
||||||
);
|
);
|
||||||
ch.receive_mode = config.receive_mode.clone();
|
ch.receive_mode = config.receive_mode.clone();
|
||||||
|
ch.proxy_url = config.proxy_url.clone();
|
||||||
ch
|
ch
|
||||||
}
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client(self.platform.proxy_service_key())
|
crate::config::build_channel_proxy_client(
|
||||||
|
self.platform.proxy_service_key(),
|
||||||
|
self.proxy_url.as_deref(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn channel_name(&self) -> &'static str {
|
fn channel_name(&self) -> &'static str {
|
||||||
@ -2113,6 +2122,7 @@ mod tests {
|
|||||||
use_feishu: false,
|
use_feishu: false,
|
||||||
receive_mode: LarkReceiveMode::default(),
|
receive_mode: LarkReceiveMode::default(),
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&lc).unwrap();
|
let json = serde_json::to_string(&lc).unwrap();
|
||||||
let parsed: LarkConfig = serde_json::from_str(&json).unwrap();
|
let parsed: LarkConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -2135,6 +2145,7 @@ mod tests {
|
|||||||
use_feishu: false,
|
use_feishu: false,
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&lc).unwrap();
|
let toml_str = toml::to_string(&lc).unwrap();
|
||||||
let parsed: LarkConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: LarkConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -2169,6 +2180,7 @@ mod tests {
|
|||||||
use_feishu: false,
|
use_feishu: false,
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ch = LarkChannel::from_config(&cfg);
|
let ch = LarkChannel::from_config(&cfg);
|
||||||
@ -2193,6 +2205,7 @@ mod tests {
|
|||||||
use_feishu: true,
|
use_feishu: true,
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ch = LarkChannel::from_lark_config(&cfg);
|
let ch = LarkChannel::from_lark_config(&cfg);
|
||||||
@ -2214,6 +2227,7 @@ mod tests {
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ch = LarkChannel::from_feishu_config(&cfg);
|
let ch = LarkChannel::from_feishu_config(&cfg);
|
||||||
@ -2386,6 +2400,7 @@ mod tests {
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Webhook,
|
receive_mode: crate::config::schema::LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let ch_feishu = LarkChannel::from_feishu_config(&feishu_cfg);
|
let ch_feishu = LarkChannel::from_feishu_config(&feishu_cfg);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@ -17,6 +17,8 @@ pub struct MattermostChannel {
|
|||||||
mention_only: bool,
|
mention_only: bool,
|
||||||
/// Handle for the background typing-indicator loop (aborted on stop_typing).
|
/// Handle for the background typing-indicator loop (aborted on stop_typing).
|
||||||
typing_handle: Mutex<Option<tokio::task::JoinHandle<()>>>,
|
typing_handle: Mutex<Option<tokio::task::JoinHandle<()>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MattermostChannel {
|
impl MattermostChannel {
|
||||||
@ -38,11 +40,18 @@ impl MattermostChannel {
|
|||||||
thread_replies,
|
thread_replies,
|
||||||
mention_only,
|
mention_only,
|
||||||
typing_handle: Mutex::new(None),
|
typing_handle: Mutex::new(None),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.mattermost")
|
crate::config::build_channel_proxy_client("channel.mattermost", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a user ID is in the allowlist.
|
/// Check if a user ID is in the allowlist.
|
||||||
|
|||||||
@ -3691,7 +3691,8 @@ fn collect_configured_channels(
|
|||||||
.with_streaming(tg.stream_mode, tg.draft_update_interval_ms)
|
.with_streaming(tg.stream_mode, tg.draft_update_interval_ms)
|
||||||
.with_transcription(config.transcription.clone())
|
.with_transcription(config.transcription.clone())
|
||||||
.with_tts(config.tts.clone())
|
.with_tts(config.tts.clone())
|
||||||
.with_workspace_dir(config.workspace_dir.clone()),
|
.with_workspace_dir(config.workspace_dir.clone())
|
||||||
|
.with_proxy_url(tg.proxy_url.clone()),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3699,13 +3700,16 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref dc) = config.channels_config.discord {
|
if let Some(ref dc) = config.channels_config.discord {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "Discord",
|
display_name: "Discord",
|
||||||
channel: Arc::new(DiscordChannel::new(
|
channel: Arc::new(
|
||||||
dc.bot_token.clone(),
|
DiscordChannel::new(
|
||||||
dc.guild_id.clone(),
|
dc.bot_token.clone(),
|
||||||
dc.allowed_users.clone(),
|
dc.guild_id.clone(),
|
||||||
dc.listen_to_bots,
|
dc.allowed_users.clone(),
|
||||||
dc.mention_only,
|
dc.listen_to_bots,
|
||||||
)),
|
dc.mention_only,
|
||||||
|
)
|
||||||
|
.with_proxy_url(dc.proxy_url.clone()),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3722,7 +3726,8 @@ fn collect_configured_channels(
|
|||||||
)
|
)
|
||||||
.with_thread_replies(sl.thread_replies.unwrap_or(true))
|
.with_thread_replies(sl.thread_replies.unwrap_or(true))
|
||||||
.with_group_reply_policy(sl.mention_only, Vec::new())
|
.with_group_reply_policy(sl.mention_only, Vec::new())
|
||||||
.with_workspace_dir(config.workspace_dir.clone()),
|
.with_workspace_dir(config.workspace_dir.clone())
|
||||||
|
.with_proxy_url(sl.proxy_url.clone()),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3730,14 +3735,17 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref mm) = config.channels_config.mattermost {
|
if let Some(ref mm) = config.channels_config.mattermost {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "Mattermost",
|
display_name: "Mattermost",
|
||||||
channel: Arc::new(MattermostChannel::new(
|
channel: Arc::new(
|
||||||
mm.url.clone(),
|
MattermostChannel::new(
|
||||||
mm.bot_token.clone(),
|
mm.url.clone(),
|
||||||
mm.channel_id.clone(),
|
mm.bot_token.clone(),
|
||||||
mm.allowed_users.clone(),
|
mm.channel_id.clone(),
|
||||||
mm.thread_replies.unwrap_or(true),
|
mm.allowed_users.clone(),
|
||||||
mm.mention_only.unwrap_or(false),
|
mm.thread_replies.unwrap_or(true),
|
||||||
)),
|
mm.mention_only.unwrap_or(false),
|
||||||
|
)
|
||||||
|
.with_proxy_url(mm.proxy_url.clone()),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3775,14 +3783,17 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref sig) = config.channels_config.signal {
|
if let Some(ref sig) = config.channels_config.signal {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "Signal",
|
display_name: "Signal",
|
||||||
channel: Arc::new(SignalChannel::new(
|
channel: Arc::new(
|
||||||
sig.http_url.clone(),
|
SignalChannel::new(
|
||||||
sig.account.clone(),
|
sig.http_url.clone(),
|
||||||
sig.group_id.clone(),
|
sig.account.clone(),
|
||||||
sig.allowed_from.clone(),
|
sig.group_id.clone(),
|
||||||
sig.ignore_attachments,
|
sig.allowed_from.clone(),
|
||||||
sig.ignore_stories,
|
sig.ignore_attachments,
|
||||||
)),
|
sig.ignore_stories,
|
||||||
|
)
|
||||||
|
.with_proxy_url(sig.proxy_url.clone()),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3799,12 +3810,15 @@ fn collect_configured_channels(
|
|||||||
if wa.is_cloud_config() {
|
if wa.is_cloud_config() {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "WhatsApp",
|
display_name: "WhatsApp",
|
||||||
channel: Arc::new(WhatsAppChannel::new(
|
channel: Arc::new(
|
||||||
wa.access_token.clone().unwrap_or_default(),
|
WhatsAppChannel::new(
|
||||||
wa.phone_number_id.clone().unwrap_or_default(),
|
wa.access_token.clone().unwrap_or_default(),
|
||||||
wa.verify_token.clone().unwrap_or_default(),
|
wa.phone_number_id.clone().unwrap_or_default(),
|
||||||
wa.allowed_numbers.clone(),
|
wa.verify_token.clone().unwrap_or_default(),
|
||||||
)),
|
wa.allowed_numbers.clone(),
|
||||||
|
)
|
||||||
|
.with_proxy_url(wa.proxy_url.clone()),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("WhatsApp Cloud API configured but missing required fields (phone_number_id, access_token, verify_token)");
|
tracing::warn!("WhatsApp Cloud API configured but missing required fields (phone_number_id, access_token, verify_token)");
|
||||||
@ -3861,11 +3875,12 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref wati_cfg) = config.channels_config.wati {
|
if let Some(ref wati_cfg) = config.channels_config.wati {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "WATI",
|
display_name: "WATI",
|
||||||
channel: Arc::new(WatiChannel::new(
|
channel: Arc::new(WatiChannel::new_with_proxy(
|
||||||
wati_cfg.api_token.clone(),
|
wati_cfg.api_token.clone(),
|
||||||
wati_cfg.api_url.clone(),
|
wati_cfg.api_url.clone(),
|
||||||
wati_cfg.tenant_id.clone(),
|
wati_cfg.tenant_id.clone(),
|
||||||
wati_cfg.allowed_numbers.clone(),
|
wati_cfg.allowed_numbers.clone(),
|
||||||
|
wati_cfg.proxy_url.clone(),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3873,10 +3888,11 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref nc) = config.channels_config.nextcloud_talk {
|
if let Some(ref nc) = config.channels_config.nextcloud_talk {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "Nextcloud Talk",
|
display_name: "Nextcloud Talk",
|
||||||
channel: Arc::new(NextcloudTalkChannel::new(
|
channel: Arc::new(NextcloudTalkChannel::new_with_proxy(
|
||||||
nc.base_url.clone(),
|
nc.base_url.clone(),
|
||||||
nc.app_token.clone(),
|
nc.app_token.clone(),
|
||||||
nc.allowed_users.clone(),
|
nc.allowed_users.clone(),
|
||||||
|
nc.proxy_url.clone(),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3948,11 +3964,14 @@ fn collect_configured_channels(
|
|||||||
if let Some(ref dt) = config.channels_config.dingtalk {
|
if let Some(ref dt) = config.channels_config.dingtalk {
|
||||||
channels.push(ConfiguredChannel {
|
channels.push(ConfiguredChannel {
|
||||||
display_name: "DingTalk",
|
display_name: "DingTalk",
|
||||||
channel: Arc::new(DingTalkChannel::new(
|
channel: Arc::new(
|
||||||
dt.client_id.clone(),
|
DingTalkChannel::new(
|
||||||
dt.client_secret.clone(),
|
dt.client_id.clone(),
|
||||||
dt.allowed_users.clone(),
|
dt.client_secret.clone(),
|
||||||
)),
|
dt.allowed_users.clone(),
|
||||||
|
)
|
||||||
|
.with_proxy_url(dt.proxy_url.clone()),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3965,7 +3984,8 @@ fn collect_configured_channels(
|
|||||||
qq.app_secret.clone(),
|
qq.app_secret.clone(),
|
||||||
qq.allowed_users.clone(),
|
qq.allowed_users.clone(),
|
||||||
)
|
)
|
||||||
.with_workspace_dir(config.workspace_dir.clone()),
|
.with_workspace_dir(config.workspace_dir.clone())
|
||||||
|
.with_proxy_url(qq.proxy_url.clone()),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -8721,6 +8741,7 @@ This is an example JSON object for profile settings."#;
|
|||||||
thread_replies: Some(true),
|
thread_replies: Some(true),
|
||||||
mention_only: Some(false),
|
mention_only: Some(false),
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let channels = collect_configured_channels(&config, "test");
|
let channels = collect_configured_channels(&config, "test");
|
||||||
@ -9613,6 +9634,7 @@ This is an example JSON object for profile settings."#;
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
match build_channel_by_id(&config, "telegram") {
|
match build_channel_by_id(&config, "telegram") {
|
||||||
Ok(channel) => assert_eq!(channel.name(), "telegram"),
|
Ok(channel) => assert_eq!(channel.name(), "telegram"),
|
||||||
|
|||||||
@ -17,11 +17,23 @@ pub struct NextcloudTalkChannel {
|
|||||||
|
|
||||||
impl NextcloudTalkChannel {
|
impl NextcloudTalkChannel {
|
||||||
pub fn new(base_url: String, app_token: String, allowed_users: Vec<String>) -> Self {
|
pub fn new(base_url: String, app_token: String, allowed_users: Vec<String>) -> Self {
|
||||||
|
Self::new_with_proxy(base_url, app_token, allowed_users, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_proxy(
|
||||||
|
base_url: String,
|
||||||
|
app_token: String,
|
||||||
|
allowed_users: Vec<String>,
|
||||||
|
proxy_url: Option<String>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_url: base_url.trim_end_matches('/').to_string(),
|
base_url: base_url.trim_end_matches('/').to_string(),
|
||||||
app_token,
|
app_token,
|
||||||
allowed_users,
|
allowed_users,
|
||||||
client: reqwest::Client::new(),
|
client: crate::config::build_channel_proxy_client(
|
||||||
|
"channel.nextcloud_talk",
|
||||||
|
proxy_url.as_deref(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -285,6 +285,8 @@ pub struct QQChannel {
|
|||||||
upload_cache: Arc<RwLock<HashMap<String, UploadCacheEntry>>>,
|
upload_cache: Arc<RwLock<HashMap<String, UploadCacheEntry>>>,
|
||||||
/// Passive reply tracker for QQ API rate limiting.
|
/// Passive reply tracker for QQ API rate limiting.
|
||||||
reply_tracker: Arc<RwLock<HashMap<String, ReplyRecord>>>,
|
reply_tracker: Arc<RwLock<HashMap<String, ReplyRecord>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QQChannel {
|
impl QQChannel {
|
||||||
@ -298,6 +300,7 @@ impl QQChannel {
|
|||||||
workspace_dir: None,
|
workspace_dir: None,
|
||||||
upload_cache: Arc::new(RwLock::new(HashMap::new())),
|
upload_cache: Arc::new(RwLock::new(HashMap::new())),
|
||||||
reply_tracker: Arc::new(RwLock::new(HashMap::new())),
|
reply_tracker: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,8 +310,14 @@ impl QQChannel {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.qq")
|
crate::config::build_channel_proxy_client("channel.qq", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_user_allowed(&self, user_id: &str) -> bool {
|
fn is_user_allowed(&self, user_id: &str) -> bool {
|
||||||
|
|||||||
@ -28,6 +28,8 @@ pub struct SignalChannel {
|
|||||||
allowed_from: Vec<String>,
|
allowed_from: Vec<String>,
|
||||||
ignore_attachments: bool,
|
ignore_attachments: bool,
|
||||||
ignore_stories: bool,
|
ignore_stories: bool,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── signal-cli SSE event JSON shapes ────────────────────────────
|
// ── signal-cli SSE event JSON shapes ────────────────────────────
|
||||||
@ -87,12 +89,23 @@ impl SignalChannel {
|
|||||||
allowed_from,
|
allowed_from,
|
||||||
ignore_attachments,
|
ignore_attachments,
|
||||||
ignore_stories,
|
ignore_stories,
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> Client {
|
fn http_client(&self) -> Client {
|
||||||
let builder = Client::builder().connect_timeout(Duration::from_secs(10));
|
let builder = Client::builder().connect_timeout(Duration::from_secs(10));
|
||||||
let builder = crate::config::apply_runtime_proxy_to_builder(builder, "channel.signal");
|
let builder = crate::config::apply_channel_proxy_to_builder(
|
||||||
|
builder,
|
||||||
|
"channel.signal",
|
||||||
|
self.proxy_url.as_deref(),
|
||||||
|
);
|
||||||
builder.build().expect("Signal HTTP client should build")
|
builder.build().expect("Signal HTTP client should build")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,8 @@ pub struct SlackChannel {
|
|||||||
workspace_dir: Option<PathBuf>,
|
workspace_dir: Option<PathBuf>,
|
||||||
/// Maps channel_id -> thread_ts for active assistant threads (used for status indicators).
|
/// Maps channel_id -> thread_ts for active assistant threads (used for status indicators).
|
||||||
active_assistant_thread: Mutex<HashMap<String, String>>,
|
active_assistant_thread: Mutex<HashMap<String, String>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SLACK_HISTORY_MAX_RETRIES: u32 = 3;
|
const SLACK_HISTORY_MAX_RETRIES: u32 = 3;
|
||||||
@ -121,6 +123,7 @@ impl SlackChannel {
|
|||||||
user_display_name_cache: Mutex::new(HashMap::new()),
|
user_display_name_cache: Mutex::new(HashMap::new()),
|
||||||
workspace_dir: None,
|
workspace_dir: None,
|
||||||
active_assistant_thread: Mutex::new(HashMap::new()),
|
active_assistant_thread: Mutex::new(HashMap::new()),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +151,19 @@ impl SlackChannel {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client_with_timeouts("channel.slack", 30, 10)
|
crate::config::build_channel_proxy_client_with_timeouts(
|
||||||
|
"channel.slack",
|
||||||
|
self.proxy_url.as_deref(),
|
||||||
|
30,
|
||||||
|
10,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a Slack user ID is in the allowlist.
|
/// Check if a Slack user ID is in the allowlist.
|
||||||
@ -804,12 +818,13 @@ impl SlackChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn slack_media_http_client_no_redirect(&self) -> anyhow::Result<reqwest::Client> {
|
fn slack_media_http_client_no_redirect(&self) -> anyhow::Result<reqwest::Client> {
|
||||||
let builder = crate::config::apply_runtime_proxy_to_builder(
|
let builder = crate::config::apply_channel_proxy_to_builder(
|
||||||
reqwest::Client::builder()
|
reqwest::Client::builder()
|
||||||
.redirect(reqwest::redirect::Policy::none())
|
.redirect(reqwest::redirect::Policy::none())
|
||||||
.timeout(Duration::from_secs(30))
|
.timeout(Duration::from_secs(30))
|
||||||
.connect_timeout(Duration::from_secs(10)),
|
.connect_timeout(Duration::from_secs(10)),
|
||||||
"channel.slack",
|
"channel.slack",
|
||||||
|
self.proxy_url.as_deref(),
|
||||||
);
|
);
|
||||||
builder
|
builder
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@ -337,6 +337,8 @@ pub struct TelegramChannel {
|
|||||||
voice_chats: Arc<std::sync::Mutex<std::collections::HashSet<String>>>,
|
voice_chats: Arc<std::sync::Mutex<std::collections::HashSet<String>>>,
|
||||||
pending_voice:
|
pending_voice:
|
||||||
Arc<std::sync::Mutex<std::collections::HashMap<String, (String, std::time::Instant)>>>,
|
Arc<std::sync::Mutex<std::collections::HashMap<String, (String, std::time::Instant)>>>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -379,6 +381,7 @@ impl TelegramChannel {
|
|||||||
tts_config: None,
|
tts_config: None,
|
||||||
voice_chats: Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())),
|
voice_chats: Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())),
|
||||||
pending_voice: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
|
pending_voice: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,6 +391,12 @@ impl TelegramChannel {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure workspace directory for saving downloaded attachments.
|
/// Configure workspace directory for saving downloaded attachments.
|
||||||
pub fn with_workspace_dir(mut self, dir: std::path::PathBuf) -> Self {
|
pub fn with_workspace_dir(mut self, dir: std::path::PathBuf) -> Self {
|
||||||
self.workspace_dir = Some(dir);
|
self.workspace_dir = Some(dir);
|
||||||
@ -478,7 +487,7 @@ impl TelegramChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.telegram")
|
crate::config::build_channel_proxy_client("channel.telegram", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_identity(value: &str) -> String {
|
fn normalize_identity(value: &str) -> String {
|
||||||
|
|||||||
@ -22,13 +22,23 @@ impl WatiChannel {
|
|||||||
api_url: String,
|
api_url: String,
|
||||||
tenant_id: Option<String>,
|
tenant_id: Option<String>,
|
||||||
allowed_numbers: Vec<String>,
|
allowed_numbers: Vec<String>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_with_proxy(api_token, api_url, tenant_id, allowed_numbers, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_proxy(
|
||||||
|
api_token: String,
|
||||||
|
api_url: String,
|
||||||
|
tenant_id: Option<String>,
|
||||||
|
allowed_numbers: Vec<String>,
|
||||||
|
proxy_url: Option<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
api_token,
|
api_token,
|
||||||
api_url,
|
api_url,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
allowed_numbers,
|
allowed_numbers,
|
||||||
client: crate::config::build_runtime_proxy_client("channel.wati"),
|
client: crate::config::build_channel_proxy_client("channel.wati", proxy_url.as_deref()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@ pub struct WhatsAppChannel {
|
|||||||
endpoint_id: String,
|
endpoint_id: String,
|
||||||
verify_token: String,
|
verify_token: String,
|
||||||
allowed_numbers: Vec<String>,
|
allowed_numbers: Vec<String>,
|
||||||
|
/// Per-channel proxy URL override.
|
||||||
|
proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WhatsAppChannel {
|
impl WhatsAppChannel {
|
||||||
@ -41,11 +43,18 @@ impl WhatsAppChannel {
|
|||||||
endpoint_id,
|
endpoint_id,
|
||||||
verify_token,
|
verify_token,
|
||||||
allowed_numbers,
|
allowed_numbers,
|
||||||
|
proxy_url: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a per-channel proxy URL that overrides the global proxy config.
|
||||||
|
pub fn with_proxy_url(mut self, proxy_url: Option<String>) -> Self {
|
||||||
|
self.proxy_url = proxy_url;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn http_client(&self) -> reqwest::Client {
|
fn http_client(&self) -> reqwest::Client {
|
||||||
crate::config::build_runtime_proxy_client("channel.whatsapp")
|
crate::config::build_channel_proxy_client("channel.whatsapp", self.proxy_url.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a phone number is allowed (E.164 format: +1234567890)
|
/// Check if a phone number is allowed (E.164 format: +1234567890)
|
||||||
|
|||||||
@ -4,7 +4,8 @@ pub mod workspace;
|
|||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub use schema::{
|
pub use schema::{
|
||||||
apply_runtime_proxy_to_builder, build_runtime_proxy_client,
|
apply_channel_proxy_to_builder, apply_runtime_proxy_to_builder, build_channel_proxy_client,
|
||||||
|
build_channel_proxy_client_with_timeouts, build_runtime_proxy_client,
|
||||||
build_runtime_proxy_client_with_timeouts, runtime_proxy_config, set_runtime_proxy_config,
|
build_runtime_proxy_client_with_timeouts, runtime_proxy_config, set_runtime_proxy_config,
|
||||||
AgentConfig, AssemblyAiSttConfig, AuditConfig, AutonomyConfig, BackupConfig,
|
AgentConfig, AssemblyAiSttConfig, AuditConfig, AutonomyConfig, BackupConfig,
|
||||||
BrowserComputerUseConfig, BrowserConfig, BuiltinHooksConfig, ChannelsConfig,
|
BrowserComputerUseConfig, BrowserConfig, BuiltinHooksConfig, ChannelsConfig,
|
||||||
@ -58,6 +59,7 @@ mod tests {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let discord = DiscordConfig {
|
let discord = DiscordConfig {
|
||||||
@ -67,6 +69,7 @@ mod tests {
|
|||||||
listen_to_bots: false,
|
listen_to_bots: false,
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let lark = LarkConfig {
|
let lark = LarkConfig {
|
||||||
@ -79,6 +82,7 @@ mod tests {
|
|||||||
use_feishu: false,
|
use_feishu: false,
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let feishu = FeishuConfig {
|
let feishu = FeishuConfig {
|
||||||
app_id: "app-id".into(),
|
app_id: "app-id".into(),
|
||||||
@ -88,6 +92,7 @@ mod tests {
|
|||||||
allowed_users: vec![],
|
allowed_users: vec![],
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let nextcloud_talk = NextcloudTalkConfig {
|
let nextcloud_talk = NextcloudTalkConfig {
|
||||||
@ -95,6 +100,7 @@ mod tests {
|
|||||||
app_token: "app-token".into(),
|
app_token: "app-token".into(),
|
||||||
webhook_secret: None,
|
webhook_secret: None,
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(telegram.allowed_users.len(), 1);
|
assert_eq!(telegram.allowed_users.len(), 1);
|
||||||
|
|||||||
@ -3381,6 +3381,116 @@ pub fn build_runtime_proxy_client_with_timeouts(
|
|||||||
client
|
client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build an HTTP client for a channel, using an explicit per-channel proxy URL
|
||||||
|
/// when configured. Falls back to the global runtime proxy when `proxy_url` is
|
||||||
|
/// `None` or empty.
|
||||||
|
pub fn build_channel_proxy_client(service_key: &str, proxy_url: Option<&str>) -> reqwest::Client {
|
||||||
|
match normalize_proxy_url_option(proxy_url) {
|
||||||
|
Some(url) => build_explicit_proxy_client(service_key, &url, None, None),
|
||||||
|
None => build_runtime_proxy_client(service_key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an HTTP client for a channel with custom timeouts, using an explicit
|
||||||
|
/// per-channel proxy URL when configured. Falls back to the global runtime
|
||||||
|
/// proxy when `proxy_url` is `None` or empty.
|
||||||
|
pub fn build_channel_proxy_client_with_timeouts(
|
||||||
|
service_key: &str,
|
||||||
|
proxy_url: Option<&str>,
|
||||||
|
timeout_secs: u64,
|
||||||
|
connect_timeout_secs: u64,
|
||||||
|
) -> reqwest::Client {
|
||||||
|
match normalize_proxy_url_option(proxy_url) {
|
||||||
|
Some(url) => build_explicit_proxy_client(
|
||||||
|
service_key,
|
||||||
|
&url,
|
||||||
|
Some(timeout_secs),
|
||||||
|
Some(connect_timeout_secs),
|
||||||
|
),
|
||||||
|
None => build_runtime_proxy_client_with_timeouts(
|
||||||
|
service_key,
|
||||||
|
timeout_secs,
|
||||||
|
connect_timeout_secs,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply an explicit proxy URL to a `reqwest::ClientBuilder`, returning the
|
||||||
|
/// modified builder. Used by channels that specify a per-channel `proxy_url`.
|
||||||
|
pub fn apply_channel_proxy_to_builder(
|
||||||
|
builder: reqwest::ClientBuilder,
|
||||||
|
service_key: &str,
|
||||||
|
proxy_url: Option<&str>,
|
||||||
|
) -> reqwest::ClientBuilder {
|
||||||
|
match normalize_proxy_url_option(proxy_url) {
|
||||||
|
Some(url) => apply_explicit_proxy_to_builder(builder, service_key, &url),
|
||||||
|
None => apply_runtime_proxy_to_builder(builder, service_key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a client with a single explicit proxy URL (http+https via `Proxy::all`).
|
||||||
|
fn build_explicit_proxy_client(
|
||||||
|
service_key: &str,
|
||||||
|
proxy_url: &str,
|
||||||
|
timeout_secs: Option<u64>,
|
||||||
|
connect_timeout_secs: Option<u64>,
|
||||||
|
) -> reqwest::Client {
|
||||||
|
let cache_key = format!(
|
||||||
|
"explicit|{}|{}|timeout={}|connect_timeout={}",
|
||||||
|
service_key.trim().to_ascii_lowercase(),
|
||||||
|
proxy_url,
|
||||||
|
timeout_secs
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.unwrap_or_else(|| "none".to_string()),
|
||||||
|
connect_timeout_secs
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.unwrap_or_else(|| "none".to_string()),
|
||||||
|
);
|
||||||
|
if let Some(client) = runtime_proxy_cached_client(&cache_key) {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut builder = reqwest::Client::builder();
|
||||||
|
if let Some(t) = timeout_secs {
|
||||||
|
builder = builder.timeout(std::time::Duration::from_secs(t));
|
||||||
|
}
|
||||||
|
if let Some(ct) = connect_timeout_secs {
|
||||||
|
builder = builder.connect_timeout(std::time::Duration::from_secs(ct));
|
||||||
|
}
|
||||||
|
builder = apply_explicit_proxy_to_builder(builder, service_key, proxy_url);
|
||||||
|
let client = builder.build().unwrap_or_else(|error| {
|
||||||
|
tracing::warn!(
|
||||||
|
service_key,
|
||||||
|
proxy_url,
|
||||||
|
"Failed to build channel proxy client: {error}"
|
||||||
|
);
|
||||||
|
reqwest::Client::new()
|
||||||
|
});
|
||||||
|
set_runtime_proxy_cached_client(cache_key, client.clone());
|
||||||
|
client
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a single explicit proxy URL to a builder via `Proxy::all`.
|
||||||
|
fn apply_explicit_proxy_to_builder(
|
||||||
|
mut builder: reqwest::ClientBuilder,
|
||||||
|
service_key: &str,
|
||||||
|
proxy_url: &str,
|
||||||
|
) -> reqwest::ClientBuilder {
|
||||||
|
match reqwest::Proxy::all(proxy_url) {
|
||||||
|
Ok(proxy) => {
|
||||||
|
builder = builder.proxy(proxy);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
tracing::warn!(
|
||||||
|
proxy_url,
|
||||||
|
service_key,
|
||||||
|
"Ignoring invalid channel proxy_url: {error}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_proxy_scope(raw: &str) -> Option<ProxyScope> {
|
fn parse_proxy_scope(raw: &str) -> Option<ProxyScope> {
|
||||||
match raw.trim().to_ascii_lowercase().as_str() {
|
match raw.trim().to_ascii_lowercase().as_str() {
|
||||||
"environment" | "env" => Some(ProxyScope::Environment),
|
"environment" | "env" => Some(ProxyScope::Environment),
|
||||||
@ -4885,6 +4995,10 @@ pub struct TelegramConfig {
|
|||||||
/// explicitly, it takes precedence.
|
/// explicitly, it takes precedence.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ack_reactions: Option<bool>,
|
pub ack_reactions: Option<bool>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for TelegramConfig {
|
impl ChannelConfig for TelegramConfig {
|
||||||
@ -4918,6 +5032,10 @@ pub struct DiscordConfig {
|
|||||||
/// Other messages in the guild are silently ignored.
|
/// Other messages in the guild are silently ignored.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub mention_only: bool,
|
pub mention_only: bool,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for DiscordConfig {
|
impl ChannelConfig for DiscordConfig {
|
||||||
@ -4954,6 +5072,10 @@ pub struct SlackConfig {
|
|||||||
/// Direct messages remain allowed.
|
/// Direct messages remain allowed.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub mention_only: bool,
|
pub mention_only: bool,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for SlackConfig {
|
impl ChannelConfig for SlackConfig {
|
||||||
@ -4989,6 +5111,10 @@ pub struct MattermostConfig {
|
|||||||
/// cancels the in-flight request and starts a fresh response with preserved history.
|
/// cancels the in-flight request and starts a fresh response with preserved history.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub interrupt_on_new_message: bool,
|
pub interrupt_on_new_message: bool,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for MattermostConfig {
|
impl ChannelConfig for MattermostConfig {
|
||||||
@ -5101,6 +5227,10 @@ pub struct SignalConfig {
|
|||||||
/// Skip incoming story messages.
|
/// Skip incoming story messages.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ignore_stories: bool,
|
pub ignore_stories: bool,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for SignalConfig {
|
impl ChannelConfig for SignalConfig {
|
||||||
@ -5195,6 +5325,10 @@ pub struct WhatsAppConfig {
|
|||||||
/// user's own self-chat (Notes to Self). Defaults to false.
|
/// user's own self-chat (Notes to Self). Defaults to false.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub self_chat_mode: bool,
|
pub self_chat_mode: bool,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for WhatsAppConfig {
|
impl ChannelConfig for WhatsAppConfig {
|
||||||
@ -5243,6 +5377,10 @@ pub struct WatiConfig {
|
|||||||
/// Allowed phone numbers (E.164 format) or "*" for all.
|
/// Allowed phone numbers (E.164 format) or "*" for all.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allowed_numbers: Vec<String>,
|
pub allowed_numbers: Vec<String>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_wati_api_url() -> String {
|
fn default_wati_api_url() -> String {
|
||||||
@ -5273,6 +5411,10 @@ pub struct NextcloudTalkConfig {
|
|||||||
/// Allowed Nextcloud actor IDs (`[]` = deny all, `"*"` = allow all).
|
/// Allowed Nextcloud actor IDs (`[]` = deny all, `"*"` = allow all).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allowed_users: Vec<String>,
|
pub allowed_users: Vec<String>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for NextcloudTalkConfig {
|
impl ChannelConfig for NextcloudTalkConfig {
|
||||||
@ -5400,6 +5542,10 @@ pub struct LarkConfig {
|
|||||||
/// Not required (and ignored) for websocket mode.
|
/// Not required (and ignored) for websocket mode.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for LarkConfig {
|
impl ChannelConfig for LarkConfig {
|
||||||
@ -5434,6 +5580,10 @@ pub struct FeishuConfig {
|
|||||||
/// Not required (and ignored) for websocket mode.
|
/// Not required (and ignored) for websocket mode.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for FeishuConfig {
|
impl ChannelConfig for FeishuConfig {
|
||||||
@ -5895,6 +6045,10 @@ pub struct DingTalkConfig {
|
|||||||
/// Allowed user IDs (staff IDs). Empty = deny all, "*" = allow all
|
/// Allowed user IDs (staff IDs). Empty = deny all, "*" = allow all
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allowed_users: Vec<String>,
|
pub allowed_users: Vec<String>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for DingTalkConfig {
|
impl ChannelConfig for DingTalkConfig {
|
||||||
@ -5935,6 +6089,10 @@ pub struct QQConfig {
|
|||||||
/// Allowed user IDs. Empty = deny all, "*" = allow all
|
/// Allowed user IDs. Empty = deny all, "*" = allow all
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allowed_users: Vec<String>,
|
pub allowed_users: Vec<String>,
|
||||||
|
/// Per-channel proxy URL (http, https, socks5, socks5h).
|
||||||
|
/// Overrides the global `[proxy]` setting for this channel only.
|
||||||
|
#[serde(default)]
|
||||||
|
pub proxy_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelConfig for QQConfig {
|
impl ChannelConfig for QQConfig {
|
||||||
@ -9335,6 +9493,7 @@ default_temperature = 0.7
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
}),
|
}),
|
||||||
discord: None,
|
discord: None,
|
||||||
slack: None,
|
slack: None,
|
||||||
@ -9789,6 +9948,7 @@ tool_dispatcher = "xml"
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: LarkReceiveMode::Websocket,
|
receive_mode: LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
config.agents.insert(
|
config.agents.insert(
|
||||||
@ -9930,6 +10090,7 @@ tool_dispatcher = "xml"
|
|||||||
interrupt_on_new_message: true,
|
interrupt_on_new_message: true,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&tc).unwrap();
|
let json = serde_json::to_string(&tc).unwrap();
|
||||||
let parsed: TelegramConfig = serde_json::from_str(&json).unwrap();
|
let parsed: TelegramConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -9958,6 +10119,7 @@ tool_dispatcher = "xml"
|
|||||||
listen_to_bots: false,
|
listen_to_bots: false,
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&dc).unwrap();
|
let json = serde_json::to_string(&dc).unwrap();
|
||||||
let parsed: DiscordConfig = serde_json::from_str(&json).unwrap();
|
let parsed: DiscordConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -9974,6 +10136,7 @@ tool_dispatcher = "xml"
|
|||||||
listen_to_bots: false,
|
listen_to_bots: false,
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&dc).unwrap();
|
let json = serde_json::to_string(&dc).unwrap();
|
||||||
let parsed: DiscordConfig = serde_json::from_str(&json).unwrap();
|
let parsed: DiscordConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -10075,6 +10238,7 @@ allowed_users = ["@ops:matrix.org"]
|
|||||||
allowed_from: vec!["+1111111111".into()],
|
allowed_from: vec!["+1111111111".into()],
|
||||||
ignore_attachments: true,
|
ignore_attachments: true,
|
||||||
ignore_stories: false,
|
ignore_stories: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&sc).unwrap();
|
let json = serde_json::to_string(&sc).unwrap();
|
||||||
let parsed: SignalConfig = serde_json::from_str(&json).unwrap();
|
let parsed: SignalConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -10095,6 +10259,7 @@ allowed_users = ["@ops:matrix.org"]
|
|||||||
allowed_from: vec!["*".into()],
|
allowed_from: vec!["*".into()],
|
||||||
ignore_attachments: false,
|
ignore_attachments: false,
|
||||||
ignore_stories: true,
|
ignore_stories: true,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&sc).unwrap();
|
let toml_str = toml::to_string(&sc).unwrap();
|
||||||
let parsed: SignalConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: SignalConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -10325,6 +10490,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&wc).unwrap();
|
let json = serde_json::to_string(&wc).unwrap();
|
||||||
let parsed: WhatsAppConfig = serde_json::from_str(&json).unwrap();
|
let parsed: WhatsAppConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -10349,6 +10515,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&wc).unwrap();
|
let toml_str = toml::to_string(&wc).unwrap();
|
||||||
let parsed: WhatsAppConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: WhatsAppConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -10378,6 +10545,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&wc).unwrap();
|
let toml_str = toml::to_string(&wc).unwrap();
|
||||||
let parsed: WhatsAppConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: WhatsAppConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -10399,6 +10567,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
assert!(wc.is_ambiguous_config());
|
assert!(wc.is_ambiguous_config());
|
||||||
assert_eq!(wc.backend_type(), "cloud");
|
assert_eq!(wc.backend_type(), "cloud");
|
||||||
@ -10419,6 +10588,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
assert!(!wc.is_ambiguous_config());
|
assert!(!wc.is_ambiguous_config());
|
||||||
assert_eq!(wc.backend_type(), "web");
|
assert_eq!(wc.backend_type(), "web");
|
||||||
@ -10449,6 +10619,7 @@ channel_id = "C123"
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
}),
|
}),
|
||||||
linq: None,
|
linq: None,
|
||||||
wati: None,
|
wati: None,
|
||||||
@ -11453,6 +11624,7 @@ default_model = "legacy-model"
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: LarkReceiveMode::Websocket,
|
receive_mode: LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
config.save().await.unwrap();
|
config.save().await.unwrap();
|
||||||
|
|
||||||
@ -12164,6 +12336,7 @@ default_model = "persisted-profile"
|
|||||||
use_feishu: true,
|
use_feishu: true,
|
||||||
receive_mode: LarkReceiveMode::Websocket,
|
receive_mode: LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&lc).unwrap();
|
let json = serde_json::to_string(&lc).unwrap();
|
||||||
let parsed: LarkConfig = serde_json::from_str(&json).unwrap();
|
let parsed: LarkConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -12187,6 +12360,7 @@ default_model = "persisted-profile"
|
|||||||
use_feishu: false,
|
use_feishu: false,
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&lc).unwrap();
|
let toml_str = toml::to_string(&lc).unwrap();
|
||||||
let parsed: LarkConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: LarkConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -12233,6 +12407,7 @@ default_model = "persisted-profile"
|
|||||||
allowed_users: vec!["user_123".into(), "user_456".into()],
|
allowed_users: vec!["user_123".into(), "user_456".into()],
|
||||||
receive_mode: LarkReceiveMode::Websocket,
|
receive_mode: LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&fc).unwrap();
|
let json = serde_json::to_string(&fc).unwrap();
|
||||||
let parsed: FeishuConfig = serde_json::from_str(&json).unwrap();
|
let parsed: FeishuConfig = serde_json::from_str(&json).unwrap();
|
||||||
@ -12253,6 +12428,7 @@ default_model = "persisted-profile"
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: LarkReceiveMode::Webhook,
|
receive_mode: LarkReceiveMode::Webhook,
|
||||||
port: Some(9898),
|
port: Some(9898),
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string(&fc).unwrap();
|
let toml_str = toml::to_string(&fc).unwrap();
|
||||||
let parsed: FeishuConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: FeishuConfig = toml::from_str(&toml_str).unwrap();
|
||||||
@ -12280,6 +12456,7 @@ default_model = "persisted-profile"
|
|||||||
app_token: "app-token".into(),
|
app_token: "app-token".into(),
|
||||||
webhook_secret: Some("webhook-secret".into()),
|
webhook_secret: Some("webhook-secret".into()),
|
||||||
allowed_users: vec!["user_a".into(), "*".into()],
|
allowed_users: vec!["user_a".into(), "*".into()],
|
||||||
|
proxy_url: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = serde_json::to_string(&nc).unwrap();
|
let json = serde_json::to_string(&nc).unwrap();
|
||||||
@ -12488,6 +12665,7 @@ require_otp_to_resume = true
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save (triggers encryption)
|
// Save (triggers encryption)
|
||||||
|
|||||||
@ -646,6 +646,7 @@ mod tests {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_supervised_channels(&config));
|
assert!(has_supervised_channels(&config));
|
||||||
}
|
}
|
||||||
@ -657,6 +658,7 @@ mod tests {
|
|||||||
client_id: "client_id".into(),
|
client_id: "client_id".into(),
|
||||||
client_secret: "client_secret".into(),
|
client_secret: "client_secret".into(),
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_supervised_channels(&config));
|
assert!(has_supervised_channels(&config));
|
||||||
}
|
}
|
||||||
@ -672,6 +674,7 @@ mod tests {
|
|||||||
thread_replies: Some(true),
|
thread_replies: Some(true),
|
||||||
mention_only: Some(false),
|
mention_only: Some(false),
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_supervised_channels(&config));
|
assert!(has_supervised_channels(&config));
|
||||||
}
|
}
|
||||||
@ -683,6 +686,7 @@ mod tests {
|
|||||||
app_id: "app-id".into(),
|
app_id: "app-id".into(),
|
||||||
app_secret: "app-secret".into(),
|
app_secret: "app-secret".into(),
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_supervised_channels(&config));
|
assert!(has_supervised_channels(&config));
|
||||||
}
|
}
|
||||||
@ -695,6 +699,7 @@ mod tests {
|
|||||||
app_token: "app-token".into(),
|
app_token: "app-token".into(),
|
||||||
webhook_secret: None,
|
webhook_secret: None,
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_supervised_channels(&config));
|
assert!(has_supervised_channels(&config));
|
||||||
}
|
}
|
||||||
@ -761,6 +766,7 @@ mod tests {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let target = resolve_heartbeat_delivery(&config).unwrap();
|
let target = resolve_heartbeat_delivery(&config).unwrap();
|
||||||
@ -778,6 +784,7 @@ mod tests {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let target = resolve_heartbeat_delivery(&config).unwrap();
|
let target = resolve_heartbeat_delivery(&config).unwrap();
|
||||||
|
|||||||
@ -1457,6 +1457,7 @@ mod tests {
|
|||||||
api_url: "https://live-mt-server.wati.io".to_string(),
|
api_url: "https://live-mt-server.wati.io".to_string(),
|
||||||
tenant_id: None,
|
tenant_id: None,
|
||||||
allowed_numbers: vec![],
|
allowed_numbers: vec![],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
cfg.channels_config.feishu = Some(crate::config::schema::FeishuConfig {
|
cfg.channels_config.feishu = Some(crate::config::schema::FeishuConfig {
|
||||||
app_id: "cli_aabbcc".to_string(),
|
app_id: "cli_aabbcc".to_string(),
|
||||||
@ -1466,6 +1467,7 @@ mod tests {
|
|||||||
allowed_users: vec!["*".to_string()],
|
allowed_users: vec!["*".to_string()],
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
cfg.channels_config.email = Some(crate::channels::email_channel::EmailConfig {
|
cfg.channels_config.email = Some(crate::channels::email_channel::EmailConfig {
|
||||||
imap_host: "imap.example.com".to_string(),
|
imap_host: "imap.example.com".to_string(),
|
||||||
@ -1591,6 +1593,7 @@ mod tests {
|
|||||||
api_url: "https://live-mt-server.wati.io".to_string(),
|
api_url: "https://live-mt-server.wati.io".to_string(),
|
||||||
tenant_id: None,
|
tenant_id: None,
|
||||||
allowed_numbers: vec![],
|
allowed_numbers: vec![],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
current.channels_config.feishu = Some(crate::config::schema::FeishuConfig {
|
current.channels_config.feishu = Some(crate::config::schema::FeishuConfig {
|
||||||
app_id: "cli_current".to_string(),
|
app_id: "cli_current".to_string(),
|
||||||
@ -1600,6 +1603,7 @@ mod tests {
|
|||||||
allowed_users: vec!["*".to_string()],
|
allowed_users: vec!["*".to_string()],
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
current.channels_config.email = Some(crate::channels::email_channel::EmailConfig {
|
current.channels_config.email = Some(crate::channels::email_channel::EmailConfig {
|
||||||
imap_host: "imap.example.com".to_string(),
|
imap_host: "imap.example.com".to_string(),
|
||||||
|
|||||||
@ -841,6 +841,7 @@ mod tests {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
let entries = all_integrations();
|
let entries = all_integrations();
|
||||||
let tg = entries.iter().find(|e| e.name == "Telegram").unwrap();
|
let tg = entries.iter().find(|e| e.name == "Telegram").unwrap();
|
||||||
|
|||||||
@ -3790,6 +3790,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
ack_reactions: None,
|
ack_reactions: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::Discord => {
|
ChannelMenuChoice::Discord => {
|
||||||
@ -3890,6 +3891,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
listen_to_bots: false,
|
listen_to_bots: false,
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::Slack => {
|
ChannelMenuChoice::Slack => {
|
||||||
@ -4020,6 +4022,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
thread_replies: None,
|
thread_replies: None,
|
||||||
mention_only: false,
|
mention_only: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::IMessage => {
|
ChannelMenuChoice::IMessage => {
|
||||||
@ -4271,6 +4274,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
allowed_from,
|
allowed_from,
|
||||||
ignore_attachments,
|
ignore_attachments,
|
||||||
ignore_stories,
|
ignore_stories,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
println!(" {} Signal configured", style("✅").green().bold());
|
println!(" {} Signal configured", style("✅").green().bold());
|
||||||
@ -4372,6 +4376,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@ -4477,6 +4482,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
dm_policy: WhatsAppChatPolicy::default(),
|
dm_policy: WhatsAppChatPolicy::default(),
|
||||||
group_policy: WhatsAppChatPolicy::default(),
|
group_policy: WhatsAppChatPolicy::default(),
|
||||||
self_chat_mode: false,
|
self_chat_mode: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::Linq => {
|
ChannelMenuChoice::Linq => {
|
||||||
@ -4810,6 +4816,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
Some(webhook_secret.trim().to_string())
|
Some(webhook_secret.trim().to_string())
|
||||||
},
|
},
|
||||||
allowed_users,
|
allowed_users,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
println!(" {} Nextcloud Talk configured", style("✅").green().bold());
|
println!(" {} Nextcloud Talk configured", style("✅").green().bold());
|
||||||
@ -4882,6 +4889,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
client_id,
|
client_id,
|
||||||
client_secret,
|
client_secret,
|
||||||
allowed_users,
|
allowed_users,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::QqOfficial => {
|
ChannelMenuChoice::QqOfficial => {
|
||||||
@ -4958,6 +4966,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
app_id,
|
app_id,
|
||||||
app_secret,
|
app_secret,
|
||||||
allowed_users,
|
allowed_users,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ChannelMenuChoice::Lark | ChannelMenuChoice::Feishu => {
|
ChannelMenuChoice::Lark | ChannelMenuChoice::Feishu => {
|
||||||
@ -5147,6 +5156,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||||||
use_feishu: is_feishu,
|
use_feishu: is_feishu,
|
||||||
receive_mode,
|
receive_mode,
|
||||||
port,
|
port,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(feature = "channel-nostr")]
|
#[cfg(feature = "channel-nostr")]
|
||||||
@ -7511,6 +7521,7 @@ mod tests {
|
|||||||
allowed_from: vec!["*".into()],
|
allowed_from: vec!["*".into()],
|
||||||
ignore_attachments: false,
|
ignore_attachments: false,
|
||||||
ignore_stories: true,
|
ignore_stories: true,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_launchable_channels(&channels));
|
assert!(has_launchable_channels(&channels));
|
||||||
|
|
||||||
@ -7523,6 +7534,7 @@ mod tests {
|
|||||||
thread_replies: Some(true),
|
thread_replies: Some(true),
|
||||||
mention_only: Some(false),
|
mention_only: Some(false),
|
||||||
interrupt_on_new_message: false,
|
interrupt_on_new_message: false,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_launchable_channels(&channels));
|
assert!(has_launchable_channels(&channels));
|
||||||
|
|
||||||
@ -7531,6 +7543,7 @@ mod tests {
|
|||||||
app_id: "app-id".into(),
|
app_id: "app-id".into(),
|
||||||
app_secret: "app-secret".into(),
|
app_secret: "app-secret".into(),
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_launchable_channels(&channels));
|
assert!(has_launchable_channels(&channels));
|
||||||
|
|
||||||
@ -7540,6 +7553,7 @@ mod tests {
|
|||||||
app_token: "token".into(),
|
app_token: "token".into(),
|
||||||
webhook_secret: Some("secret".into()),
|
webhook_secret: Some("secret".into()),
|
||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_launchable_channels(&channels));
|
assert!(has_launchable_channels(&channels));
|
||||||
|
|
||||||
@ -7552,6 +7566,7 @@ mod tests {
|
|||||||
allowed_users: vec!["*".into()],
|
allowed_users: vec!["*".into()],
|
||||||
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
receive_mode: crate::config::schema::LarkReceiveMode::Websocket,
|
||||||
port: None,
|
port: None,
|
||||||
|
proxy_url: None,
|
||||||
});
|
});
|
||||||
assert!(has_launchable_channels(&channels));
|
assert!(has_launchable_channels(&channels));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user