fix(feishu): respect region setting for WebSocket endpoint URL

When using Lark international (open.larksuite.com) with WebSocket mode,
the adapter was hardcoding the Chinese Feishu endpoint URL and also
ignoring the configured region entirely when constructing the adapter.

Two bugs fixed:
1. FEISHU_WS_ENDPOINT_URL was hardcoded to open.feishu.cn — international
   Lark apps could not authenticate because their credentials are only
   valid on open.larksuite.com. Changed to FEISHU_WS_ENDPOINT_PATH and
   compute the full URL using self.region.domain() at call time.
2. new_websocket() in FeishuAdapter always set region = FeishuRegion::Cn.
   Added new_websocket_with_region() that accepts an explicit region, and
   updated the call site in channel_bridge.rs to pass the parsed region.

Fixes #1081
This commit is contained in:
octo-patch
2026-04-19 11:23:46 +08:00
parent d3d9fa842d
commit 45e7ea7948
2 changed files with 18 additions and 5 deletions
+2 -1
View File
@@ -1458,9 +1458,10 @@ pub async fn start_channel_bridge_with_config(
encrypt_key,
fs_config.bot_names.clone(),
)),
FeishuMode::Websocket => Arc::new(FeishuAdapter::new_websocket(
FeishuMode::Websocket => Arc::new(FeishuAdapter::new_websocket_with_region(
fs_config.app_id.clone(),
secret,
region,
)),
};
adapters.push((adapter, fs_config.default_agent.clone()));
+16 -4
View File
@@ -42,8 +42,8 @@ const MAX_MESSAGE_LEN: usize = 4000;
/// Token refresh buffer — refresh 5 minutes before actual expiry.
const TOKEN_REFRESH_BUFFER_SECS: u64 = 300;
/// Feishu websocket endpoint discovery API.
const FEISHU_WS_ENDPOINT_URL: &str = "https://open.feishu.cn/callback/ws/endpoint";
/// WebSocket endpoint path (appended to the region domain).
const FEISHU_WS_ENDPOINT_PATH: &str = "/callback/ws/endpoint";
const INITIAL_BACKOFF: Duration = Duration::from_secs(1);
const MAX_BACKOFF: Duration = Duration::from_secs(60);
@@ -269,13 +269,24 @@ impl FeishuAdapter {
///
/// WebSocket mode does not require a public IP or webhook configuration.
pub fn new_websocket(app_id: String, app_secret: String) -> Self {
Self::new_websocket_with_region(app_id, app_secret, FeishuRegion::Cn)
}
/// Create a new Feishu adapter in WebSocket mode with an explicit region.
///
/// Use this when the app is registered on Lark international (`open.larksuite.com`).
pub fn new_websocket_with_region(
app_id: String,
app_secret: String,
region: FeishuRegion,
) -> Self {
let (shutdown_tx, shutdown_rx) = watch::channel(false);
Self {
app_id,
app_secret: Zeroizing::new(app_secret),
connection_mode: FeishuConnectionMode::WebSocket,
webhook_port: 0,
region: FeishuRegion::Cn,
region,
webhook_path: String::new(),
verification_token: None,
encrypt_key: None,
@@ -918,9 +929,10 @@ struct FeishuAdapterClone {
impl FeishuAdapterClone {
/// Get WebSocket endpoint from Feishu API.
async fn get_websocket_endpoint(&self) -> Result<FeishuWsEndpoint, Box<dyn std::error::Error>> {
let url = format!("{}{}", self.region.domain(), FEISHU_WS_ENDPOINT_PATH);
let resp = self
.client
.post(FEISHU_WS_ENDPOINT_URL)
.post(&url)
.json(&serde_json::json!({
"AppID": self.app_id,
"AppSecret": self.app_secret.as_str(),