fix(channels): complete SendMessage migration after rebase
This commit is contained in:
parent
dbebd48dfe
commit
cd0dd13476
7 changed files with 57 additions and 67 deletions
|
|
@ -250,7 +250,10 @@ async fn process_channel_message(ctx: Arc<ChannelRuntimeContext>, msg: traits::C
|
|||
);
|
||||
if let Some(channel) = target_channel.as_ref() {
|
||||
let _ = channel
|
||||
.send(&SendMessage::new(format!("⚠️ Error: {e}"), &msg.reply_target))
|
||||
.send(&SendMessage::new(
|
||||
format!("⚠️ Error: {e}"),
|
||||
&msg.reply_target,
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::traits::{Channel, ChannelMessage};
|
||||
use super::traits::{Channel, ChannelMessage, SendMessage};
|
||||
use async_trait::async_trait;
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use serde_json::json;
|
||||
|
|
@ -162,25 +162,28 @@ impl Channel for QQChannel {
|
|||
"qq"
|
||||
}
|
||||
|
||||
async fn send(&self, message: &str, recipient: &str) -> anyhow::Result<()> {
|
||||
async fn send(&self, message: &SendMessage) -> anyhow::Result<()> {
|
||||
let token = self.get_token().await?;
|
||||
|
||||
// Determine if this is a group or private message based on recipient format
|
||||
// Format: "user:{openid}" or "group:{group_openid}"
|
||||
let (url, body) = if let Some(group_id) = recipient.strip_prefix("group:") {
|
||||
let (url, body) = if let Some(group_id) = message.recipient.strip_prefix("group:") {
|
||||
(
|
||||
format!("{QQ_API_BASE}/v2/groups/{group_id}/messages"),
|
||||
json!({
|
||||
"content": message,
|
||||
"content": &message.content,
|
||||
"msg_type": 0,
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
let user_id = recipient.strip_prefix("user:").unwrap_or(recipient);
|
||||
let user_id = message
|
||||
.recipient
|
||||
.strip_prefix("user:")
|
||||
.unwrap_or(&message.recipient);
|
||||
(
|
||||
format!("{QQ_API_BASE}/v2/users/{user_id}/messages"),
|
||||
json!({
|
||||
"content": message,
|
||||
"content": &message.content,
|
||||
"msg_type": 0,
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::channels::traits::{Channel, ChannelMessage};
|
||||
use crate::channels::traits::{Channel, ChannelMessage, SendMessage};
|
||||
use async_trait::async_trait;
|
||||
use futures_util::StreamExt;
|
||||
use reqwest::Client;
|
||||
|
|
@ -269,17 +269,17 @@ impl Channel for SignalChannel {
|
|||
"signal"
|
||||
}
|
||||
|
||||
async fn send(&self, message: &str, recipient: &str) -> anyhow::Result<()> {
|
||||
let params = match Self::parse_recipient_target(recipient) {
|
||||
async fn send(&self, message: &SendMessage) -> anyhow::Result<()> {
|
||||
let params = match Self::parse_recipient_target(&message.recipient) {
|
||||
RecipientTarget::Direct(number) => serde_json::json!({
|
||||
"recipient": [number],
|
||||
"message": message,
|
||||
"account": self.account,
|
||||
"message": &message.content,
|
||||
"account": &self.account,
|
||||
}),
|
||||
RecipientTarget::Group(group_id) => serde_json::json!({
|
||||
"groupId": group_id,
|
||||
"message": message,
|
||||
"account": self.account,
|
||||
"message": &message.content,
|
||||
"account": &self.account,
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -423,11 +423,11 @@ impl Channel for SignalChannel {
|
|||
let params = match Self::parse_recipient_target(recipient) {
|
||||
RecipientTarget::Direct(number) => serde_json::json!({
|
||||
"recipient": [number],
|
||||
"account": self.account,
|
||||
"account": &self.account,
|
||||
}),
|
||||
RecipientTarget::Group(group_id) => serde_json::json!({
|
||||
"groupId": group_id,
|
||||
"account": self.account,
|
||||
"account": &self.account,
|
||||
}),
|
||||
};
|
||||
self.rpc_request("sendTyping", params).await?;
|
||||
|
|
|
|||
|
|
@ -380,10 +380,10 @@ impl TelegramChannel {
|
|||
match self.persist_allowed_identity(&identity).await {
|
||||
Ok(()) => {
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"✅ Telegram account bound successfully. You can talk to ZeroClaw now.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
tracing::info!(
|
||||
"Telegram: paired and allowlisted identity={identity}"
|
||||
|
|
@ -394,45 +394,45 @@ impl TelegramChannel {
|
|||
"Telegram: failed to persist allowlist after bind: {e}"
|
||||
);
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"⚠️ Bound for this runtime, but failed to persist config. Access may be lost after restart; check config file permissions.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"❌ Could not identify your Telegram account. Ensure your account has a username or stable user ID, then retry.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"❌ Invalid binding code. Ask operator for the latest code and retry.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
Err(lockout_secs) => {
|
||||
let _ = self
|
||||
.send(
|
||||
&format!("⏳ Too many invalid attempts. Retry in {lockout_secs}s."),
|
||||
.send(&SendMessage::new(
|
||||
format!("⏳ Too many invalid attempts. Retry in {lockout_secs}s."),
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"ℹ️ Telegram pairing is not active. Ask operator to update allowlist in config.toml.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
return;
|
||||
|
|
@ -456,23 +456,20 @@ Allowlist Telegram username (without '@') or numeric user ID.",
|
|||
.unwrap_or_else(|| "YOUR_TELEGRAM_ID".to_string());
|
||||
|
||||
let _ = self
|
||||
.send(
|
||||
&format!(
|
||||
"🔐 This bot requires operator approval.\n\n\
|
||||
Copy this command to operator terminal:\n\
|
||||
`zeroclaw channel bind-telegram {suggested_identity}`\n\n\
|
||||
After operator runs it, send your message again."
|
||||
.send(&SendMessage::new(
|
||||
format!(
|
||||
"🔐 This bot requires operator approval.\n\nCopy this command to operator terminal:\n`zeroclaw channel bind-telegram {suggested_identity}`\n\nAfter operator runs it, send your message again."
|
||||
),
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
|
||||
if self.pairing_code_active() {
|
||||
let _ = self
|
||||
.send(
|
||||
.send(&SendMessage::new(
|
||||
"ℹ️ If operator provides a one-time pairing code, you can also run `/bind <code>`.",
|
||||
&chat_id,
|
||||
)
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
|
@ -1066,7 +1063,8 @@ impl Channel for TelegramChannel {
|
|||
}
|
||||
|
||||
if let Some(attachment) = parse_path_only_attachment(&message.content) {
|
||||
self.send_attachment(&message.recipient, &attachment).await?;
|
||||
self.send_attachment(&message.recipient, &attachment)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -1369,7 +1367,7 @@ mod tests {
|
|||
"username": "alice"
|
||||
},
|
||||
"chat": {
|
||||
"id": -100200300
|
||||
"id": -100_200_300
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub struct ChannelMessage {
|
|||
}
|
||||
|
||||
/// Message to send through a channel
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SendMessage {
|
||||
pub content: String,
|
||||
pub recipient: String,
|
||||
|
|
@ -43,26 +43,6 @@ impl SendMessage {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&str> for SendMessage {
|
||||
fn from(content: &str) -> Self {
|
||||
Self {
|
||||
content: content.to_string(),
|
||||
recipient: String::new(),
|
||||
subject: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(String, String)> for SendMessage {
|
||||
fn from(value: (String, String)) -> Self {
|
||||
Self {
|
||||
content: value.0,
|
||||
recipient: value.1,
|
||||
subject: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Core channel trait — implement for any messaging platform
|
||||
#[async_trait]
|
||||
pub trait Channel: Send + Sync {
|
||||
|
|
@ -152,7 +132,10 @@ mod tests {
|
|||
assert!(channel.health_check().await);
|
||||
assert!(channel.start_typing("bob").await.is_ok());
|
||||
assert!(channel.stop_typing("bob").await.is_ok());
|
||||
assert!(channel.send(&SendMessage::new("hello", "bob")).await.is_ok());
|
||||
assert!(channel
|
||||
.send(&SendMessage::new("hello", "bob"))
|
||||
.await
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::channels::{Channel, DiscordChannel, SlackChannel, TelegramChannel};
|
||||
use crate::channels::{Channel, DiscordChannel, SendMessage, SlackChannel, TelegramChannel};
|
||||
use crate::config::Config;
|
||||
use crate::cron::{
|
||||
due_jobs, next_run_for_schedule, record_last_run, record_run, remove_job, reschedule_after_run,
|
||||
|
|
@ -232,7 +232,7 @@ async fn deliver_if_configured(config: &Config, job: &CronJob, output: &str) ->
|
|||
.as_ref()
|
||||
.ok_or_else(|| anyhow::anyhow!("telegram channel not configured"))?;
|
||||
let channel = TelegramChannel::new(tg.bot_token.clone(), tg.allowed_users.clone());
|
||||
channel.send(output, target).await?;
|
||||
channel.send(&SendMessage::new(output, target)).await?;
|
||||
}
|
||||
"discord" => {
|
||||
let dc = config
|
||||
|
|
@ -247,7 +247,7 @@ async fn deliver_if_configured(config: &Config, job: &CronJob, output: &str) ->
|
|||
dc.listen_to_bots,
|
||||
dc.mention_only,
|
||||
);
|
||||
channel.send(output, target).await?;
|
||||
channel.send(&SendMessage::new(output, target)).await?;
|
||||
}
|
||||
"slack" => {
|
||||
let sl = config
|
||||
|
|
@ -260,7 +260,7 @@ async fn deliver_if_configured(config: &Config, job: &CronJob, output: &str) ->
|
|||
sl.channel_id.clone(),
|
||||
sl.allowed_users.clone(),
|
||||
);
|
||||
channel.send(output, target).await?;
|
||||
channel.send(&SendMessage::new(output, target)).await?;
|
||||
}
|
||||
other => anyhow::bail!("unsupported delivery channel: {other}"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -704,7 +704,10 @@ async fn handle_whatsapp_message(
|
|||
{
|
||||
Ok(response) => {
|
||||
// Send reply via WhatsApp
|
||||
if let Err(e) = wa.send(&SendMessage::new(response, &msg.reply_target)).await {
|
||||
if let Err(e) = wa
|
||||
.send(&SendMessage::new(response, &msg.reply_target))
|
||||
.await
|
||||
{
|
||||
tracing::error!("Failed to send WhatsApp reply: {e}");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue