use lingshu_types::Platform;
use crate::config::GatewayConfig;
fn non_empty(value: Option<String>) -> Option<String> {
value.and_then(|v| {
let trimmed = v.trim().to_string();
if trimmed.is_empty() {
None
} else {
Some(trimmed)
}
})
}
pub fn resolve_gateway_home_channel(gateway: &GatewayConfig, platform: Platform) -> Option<String> {
home_channel_from_config(gateway, platform).or_else(|| home_channel_from_env(platform))
}
fn home_channel_from_config(gateway: &GatewayConfig, platform: Platform) -> Option<String> {
non_empty(match platform {
Platform::Telegram => gateway.telegram.home_channel.clone(),
Platform::Discord => gateway.discord.home_channel.clone(),
Platform::Slack => gateway.slack.home_channel.clone(),
Platform::Whatsapp => gateway.whatsapp.home_channel.clone(),
Platform::Signal => gateway.signal.home_channel.clone(),
_ => None,
})
}
fn home_channel_from_env(platform: Platform) -> Option<String> {
let key = match platform {
Platform::Telegram => "TELEGRAM_HOME_CHANNEL",
Platform::Discord => "DISCORD_HOME_CHANNEL",
Platform::Slack => "SLACK_HOME_CHANNEL",
Platform::Whatsapp => "WHATSAPP_HOME_CHANNEL",
Platform::Signal => "SIGNAL_HOME_CHANNEL",
Platform::Matrix => "MATRIX_HOME_CHANNEL",
Platform::Feishu => "FEISHU_HOME_CHANNEL",
Platform::Wecom => "WECOM_HOME_CHANNEL",
Platform::Email => "EMAIL_HOME_CHANNEL",
Platform::Mattermost => "MATTERMOST_HOME_CHANNEL",
Platform::DingTalk => "DINGTALK_HOME_CHANNEL",
Platform::Sms => "SMS_HOME_CHANNEL",
Platform::Webhook => "WEBHOOK_HOME_CHANNEL",
Platform::HomeAssistant => "HOMEASSISTANT_HOME_CHANNEL",
Platform::BlueBubbles => "BLUEBUBBLES_HOME_CHANNEL",
Platform::Weixin => "WEIXIN_HOME_CHANNEL",
Platform::Api => "API_HOME_CHANNEL",
Platform::Cli | Platform::Cron | Platform::Acp => return None,
};
non_empty(std::env::var(key).ok())
}
pub fn handoff_platform_from_name(name: &str) -> Option<Platform> {
match name.trim().to_ascii_lowercase().as_str() {
"telegram" => Some(Platform::Telegram),
"discord" => Some(Platform::Discord),
"slack" => Some(Platform::Slack),
"whatsapp" => Some(Platform::Whatsapp),
"signal" => Some(Platform::Signal),
"matrix" => Some(Platform::Matrix),
_ => None,
}
}
pub const HANDOFF_PLATFORM_HINT: &str = "telegram, discord, slack, whatsapp, signal, matrix";
impl GatewayConfig {
pub fn set_home_channel(
&mut self,
platform: &str,
channel: Option<String>,
) -> Result<(), String> {
let channel = non_empty(channel);
match platform.trim().to_ascii_lowercase().as_str() {
"telegram" => {
self.telegram.enabled = true;
self.enable_platform("telegram");
self.telegram.home_channel = channel;
}
"discord" => {
self.discord.enabled = true;
self.enable_platform("discord");
self.discord.home_channel = channel;
}
"slack" => {
self.slack.enabled = true;
self.enable_platform("slack");
self.slack.home_channel = channel;
}
"whatsapp" => {
self.whatsapp.enabled = true;
self.enable_platform("whatsapp");
self.whatsapp.home_channel = channel;
}
"signal" => {
self.signal.enabled = true;
self.enable_platform("signal");
self.signal.home_channel = channel;
}
"matrix" => {
self.enable_platform("matrix");
if let Some(ref id) = channel {
#[allow(unsafe_code)]
unsafe {
std::env::set_var("MATRIX_HOME_CHANNEL", id);
}
} else {
#[allow(unsafe_code)]
unsafe {
std::env::remove_var("MATRIX_HOME_CHANNEL");
}
}
}
other => {
return Err(format!(
"Unsupported platform '{other}'. Supported: {HANDOFF_PLATFORM_HINT}"
));
}
}
Ok(())
}
pub fn home_channel_platforms(&self) -> Vec<&'static str> {
let mut platforms = Vec::new();
let candidates = [
(
"telegram",
self.platform_enabled("telegram") || self.telegram.enabled,
),
(
"discord",
self.platform_enabled("discord") || self.discord.enabled,
),
(
"slack",
self.platform_enabled("slack") || self.slack.enabled,
),
(
"whatsapp",
self.platform_enabled("whatsapp") || self.whatsapp.enabled,
),
(
"signal",
self.platform_enabled("signal") || self.signal.enabled,
),
("matrix", self.platform_enabled("matrix")),
];
for (name, enabled) in candidates {
if enabled {
platforms.push(name);
}
}
platforms
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_home_channel_beats_empty_string() {
let mut gateway = GatewayConfig::default();
gateway.telegram.home_channel = Some(" ".into());
assert!(resolve_gateway_home_channel(&gateway, Platform::Telegram).is_none());
gateway.telegram.home_channel = Some("chat-1".into());
assert_eq!(
resolve_gateway_home_channel(&gateway, Platform::Telegram).as_deref(),
Some("chat-1")
);
}
#[test]
fn env_fallback_for_matrix() {
let gateway = GatewayConfig::default();
unsafe { std::env::set_var("MATRIX_HOME_CHANNEL", " !room:abc ") };
let resolved = resolve_gateway_home_channel(&gateway, Platform::Matrix);
unsafe { std::env::remove_var("MATRIX_HOME_CHANNEL") };
assert_eq!(resolved.as_deref(), Some("!room:abc"));
}
#[test]
fn set_home_channel_whatsapp_roundtrip() {
let mut gateway = GatewayConfig::default();
gateway
.set_home_channel("whatsapp", Some("+15551234567".into()))
.expect("set");
assert_eq!(
gateway.whatsapp.home_channel.as_deref(),
Some("+15551234567")
);
}
}