story-kit: merge 320_story_whatsapp_business_api_integration_for_bot_commands
This commit is contained in:
@@ -368,8 +368,11 @@ pub async fn run_bot(
|
||||
// Create the transport abstraction based on the configured transport type.
|
||||
let transport: Arc<dyn ChatTransport> = match config.transport.as_str() {
|
||||
"whatsapp" => {
|
||||
slog!("[matrix-bot] Using WhatsApp transport (stub)");
|
||||
Arc::new(crate::whatsapp::WhatsAppTransport::new())
|
||||
slog!("[matrix-bot] Using WhatsApp transport");
|
||||
Arc::new(crate::whatsapp::WhatsAppTransport::new(
|
||||
config.whatsapp_phone_number_id.clone().unwrap_or_default(),
|
||||
config.whatsapp_access_token.clone().unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
slog!("[matrix-bot] Using Matrix transport");
|
||||
@@ -1393,7 +1396,7 @@ mod tests {
|
||||
ambient_rooms: Arc::new(std::sync::Mutex::new(HashSet::new())),
|
||||
agents: Arc::new(AgentPool::new_test(3000)),
|
||||
htop_sessions: Arc::new(TokioMutex::new(HashMap::new())),
|
||||
transport: Arc::new(crate::whatsapp::WhatsAppTransport::new()),
|
||||
transport: Arc::new(crate::whatsapp::WhatsAppTransport::new("test-phone".to_string(), "test-token".to_string())),
|
||||
};
|
||||
// Clone must work (required by Matrix SDK event handler injection).
|
||||
let _cloned = ctx.clone();
|
||||
|
||||
@@ -66,6 +66,20 @@ pub struct BotConfig {
|
||||
/// round-tripping.
|
||||
#[serde(default = "default_transport")]
|
||||
pub transport: String,
|
||||
|
||||
// ── WhatsApp Business API fields ─────────────────────────────────
|
||||
// These are only required when `transport = "whatsapp"`.
|
||||
|
||||
/// WhatsApp Business phone number ID from the Meta dashboard.
|
||||
#[serde(default)]
|
||||
pub whatsapp_phone_number_id: Option<String>,
|
||||
/// Long-lived access token for the WhatsApp Business API.
|
||||
#[serde(default)]
|
||||
pub whatsapp_access_token: Option<String>,
|
||||
/// Verify token used in the webhook handshake (you choose this value
|
||||
/// and configure it in the Meta webhook settings).
|
||||
#[serde(default)]
|
||||
pub whatsapp_verify_token: Option<String>,
|
||||
}
|
||||
|
||||
fn default_transport() -> String {
|
||||
@@ -97,7 +111,31 @@ impl BotConfig {
|
||||
{
|
||||
config.room_ids.push(single);
|
||||
}
|
||||
if config.room_ids.is_empty() {
|
||||
|
||||
if config.transport == "whatsapp" {
|
||||
// Validate WhatsApp-specific fields.
|
||||
if config.whatsapp_phone_number_id.as_ref().is_none_or(|s| s.is_empty()) {
|
||||
eprintln!(
|
||||
"[bot] bot.toml: transport=\"whatsapp\" requires \
|
||||
whatsapp_phone_number_id"
|
||||
);
|
||||
return None;
|
||||
}
|
||||
if config.whatsapp_access_token.as_ref().is_none_or(|s| s.is_empty()) {
|
||||
eprintln!(
|
||||
"[bot] bot.toml: transport=\"whatsapp\" requires \
|
||||
whatsapp_access_token"
|
||||
);
|
||||
return None;
|
||||
}
|
||||
if config.whatsapp_verify_token.as_ref().is_none_or(|s| s.is_empty()) {
|
||||
eprintln!(
|
||||
"[bot] bot.toml: transport=\"whatsapp\" requires \
|
||||
whatsapp_verify_token"
|
||||
);
|
||||
return None;
|
||||
}
|
||||
} else if config.room_ids.is_empty() {
|
||||
eprintln!(
|
||||
"[matrix-bot] bot.toml has no room_ids configured — \
|
||||
add `room_ids = [\"!roomid:example.com\"]` to bot.toml"
|
||||
@@ -556,10 +594,88 @@ password = "secret"
|
||||
room_ids = ["!abc:example.com"]
|
||||
enabled = true
|
||||
transport = "whatsapp"
|
||||
whatsapp_phone_number_id = "123456"
|
||||
whatsapp_access_token = "EAAtoken"
|
||||
whatsapp_verify_token = "my-verify"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let config = BotConfig::load(tmp.path()).unwrap();
|
||||
assert_eq!(config.transport, "whatsapp");
|
||||
assert_eq!(
|
||||
config.whatsapp_phone_number_id.as_deref(),
|
||||
Some("123456")
|
||||
);
|
||||
assert_eq!(
|
||||
config.whatsapp_access_token.as_deref(),
|
||||
Some("EAAtoken")
|
||||
);
|
||||
assert_eq!(
|
||||
config.whatsapp_verify_token.as_deref(),
|
||||
Some("my-verify")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_whatsapp_returns_none_when_missing_phone_number_id() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".story_kit");
|
||||
fs::create_dir_all(&sk).unwrap();
|
||||
fs::write(
|
||||
sk.join("bot.toml"),
|
||||
r#"
|
||||
homeserver = "https://matrix.example.com"
|
||||
username = "@bot:example.com"
|
||||
password = "secret"
|
||||
enabled = true
|
||||
transport = "whatsapp"
|
||||
whatsapp_access_token = "EAAtoken"
|
||||
whatsapp_verify_token = "my-verify"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(BotConfig::load(tmp.path()).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_whatsapp_returns_none_when_missing_access_token() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".story_kit");
|
||||
fs::create_dir_all(&sk).unwrap();
|
||||
fs::write(
|
||||
sk.join("bot.toml"),
|
||||
r#"
|
||||
homeserver = "https://matrix.example.com"
|
||||
username = "@bot:example.com"
|
||||
password = "secret"
|
||||
enabled = true
|
||||
transport = "whatsapp"
|
||||
whatsapp_phone_number_id = "123456"
|
||||
whatsapp_verify_token = "my-verify"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(BotConfig::load(tmp.path()).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_whatsapp_returns_none_when_missing_verify_token() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".story_kit");
|
||||
fs::create_dir_all(&sk).unwrap();
|
||||
fs::write(
|
||||
sk.join("bot.toml"),
|
||||
r#"
|
||||
homeserver = "https://matrix.example.com"
|
||||
username = "@bot:example.com"
|
||||
password = "secret"
|
||||
enabled = true
|
||||
transport = "whatsapp"
|
||||
whatsapp_phone_number_id = "123456"
|
||||
whatsapp_access_token = "EAAtoken"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(BotConfig::load(tmp.path()).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ pub fn spawn_bot(
|
||||
}
|
||||
};
|
||||
|
||||
// WhatsApp transport is handled via HTTP webhooks, not the Matrix sync loop.
|
||||
if config.transport == "whatsapp" {
|
||||
crate::slog!("[bot] transport=whatsapp — skipping Matrix bot; webhooks handle WhatsApp");
|
||||
return;
|
||||
}
|
||||
|
||||
crate::slog!(
|
||||
"[matrix-bot] Starting Matrix bot → homeserver={} rooms={:?}",
|
||||
config.homeserver,
|
||||
|
||||
Reference in New Issue
Block a user