Skip to content

Commit 94392f6

Browse files
committed
feat: add send_image and send_text methods to TryxClient for media messaging
1 parent ecb828e commit 94392f6

4 files changed

Lines changed: 118 additions & 4 deletions

File tree

python/tryx/client.pyi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ class TryxClient:
3232
async def upload(self, data: bytes, media_type: MediaType) -> UploadResponse: ...
3333
async def upload_file(self, path: str, media_type: MediaType) -> UploadResponse: ...
3434
async def download_media(self, message: DownloadableMedia) -> bytes: ...
35+
async def send_image(
36+
self,
37+
to: JID,
38+
photo_data: bytes,
39+
caption: str,
40+
quoted: MessageProto | None = None,
41+
) -> str: ...
42+
async def send_text(
43+
self,
44+
to: JID,
45+
text: str,
46+
quoted: MessageProto | None = None,
47+
) -> str: ...
3548

3649
class Nu[T]:
3750
X: T

src/client.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use whatsapp_rust_tokio_transport::TokioWebSocketTransportFactory;
1616
use whatsapp_rust_ureq_http_client::UreqHttpClient;
1717
use waproto::whatsapp::Message as WhatsappMessage;
1818
use waproto::whatsapp::message::{self as wa};
19+
use wacore::proto_helpers::build_quote_context;
1920
use prost::Message;
2021
use tokio::signal;
2122
use tracing::{debug, error, info, warn};
@@ -214,6 +215,106 @@ impl TryxClient {
214215
Ok(message_id.to_string())
215216
})
216217
}
218+
#[pyo3(signature = (to, text, quoted=None))]
219+
fn send_text<'py>(&self, py: Python<'py>, to: Py<JID>, text: String, quoted: Option<Py<WAMessage>>) -> PyResult<Bound<'py, PyAny>> {
220+
let client = self.client_rx.borrow().clone().ok_or_else(|| {
221+
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Bot is not running")
222+
})?;
223+
let jid = to.bind(py).borrow().as_whatsapp_jid();
224+
let locals = get_current_locals(py)?;
225+
let context_info = quoted.as_ref().map(|q| {
226+
let quote = q.bind(py).borrow();
227+
let msg = quote.inner.as_ref();
228+
build_quote_context(
229+
quote.message_info.id.clone(),
230+
quote.message_info.inner.source.chat.clone(),
231+
msg,
232+
)
233+
});
234+
future_into_py_with_locals(py, locals, async move {
235+
match quoted {
236+
Some(_) => {
237+
let message = WhatsappMessage {
238+
extended_text_message: Some(Box::new(wa::ExtendedTextMessage {
239+
text: Some(text),
240+
context_info: context_info.map(Box::new),
241+
..Default::default()
242+
})),
243+
..Default::default()
244+
};
245+
let message_id = client
246+
.send_message(jid, message)
247+
.await
248+
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
249+
Ok(message_id.to_string())
250+
}
251+
None => {
252+
let message = WhatsappMessage {
253+
conversation: Some(text),
254+
..Default::default()
255+
};
256+
let message_id = client
257+
.send_message(jid, message)
258+
.await
259+
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
260+
Ok(message_id.to_string())
261+
}
262+
}
263+
})
264+
}
265+
#[pyo3(signature = (to, photo_data, caption, quoted=None))]
266+
fn send_photo<'py>(&self, py: Python<'py>, to: Py<JID>, photo_data: &[u8], caption: String, quoted: Option<Py<WAMessage>>) -> PyResult<Bound<'py, PyAny>> {
267+
let client = self.client_rx.borrow().clone().ok_or_else(|| {
268+
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Bot is not running")
269+
})?;
270+
let jid = to.bind(py).borrow().as_whatsapp_jid();
271+
let photo_clone = photo_data.to_vec();
272+
let locals = get_current_locals(py)?;
273+
let context_info = quoted.as_ref().map(|q| {
274+
let quote = q.bind(py).borrow();
275+
let msg = quote.inner.as_ref();
276+
build_quote_context(
277+
quote.message_info.id.clone(),
278+
quote.message_info.inner.source.chat.clone(),
279+
msg,
280+
)
281+
});
282+
future_into_py_with_locals(py, locals, async move {
283+
let upload = client
284+
.upload(photo_clone, wacore::download::MediaType::Image)
285+
.await
286+
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
287+
// let image_message = wa::ImageMessage {
288+
// url: Some(upload.url),
289+
// direct_path: Some(upload.direct_path),
290+
// media_key: Some(upload.media_key),
291+
// file_enc_sha256: Some(upload.file_enc_sha256),
292+
// file_sha256: Some(upload.file_sha256),
293+
// file_length: Some(upload.file_length),
294+
// caption: Some(caption),
295+
// ..Default::default()
296+
// };
297+
let message = WhatsappMessage {
298+
image_message: Some(Box::new(wa::ImageMessage {
299+
url: Some(upload.url),
300+
direct_path: Some(upload.direct_path),
301+
media_key: Some(upload.media_key),
302+
file_enc_sha256: Some(upload.file_enc_sha256),
303+
file_sha256: Some(upload.file_sha256),
304+
file_length: Some(upload.file_length),
305+
caption: Some(caption),
306+
context_info: context_info.map(Box::new),
307+
..Default::default()
308+
})),
309+
..Default::default()
310+
};
311+
let message_id = client
312+
.send_message(jid, message)
313+
.await
314+
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
315+
Ok(message_id.to_string())
316+
})
317+
}
217318
}
218319

219320
impl Tryx {
@@ -230,7 +331,7 @@ impl Tryx {
230331
(
231332
dispatcher.pairing_qr_handlers(py),
232333
dispatcher.message_handlers(py),
233-
dispatcher.conneccted_handlers(py),
334+
dispatcher.connected_handlers(py),
234335
dispatcher.logout_handlers(py),
235336
)
236337
});

src/dispatcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl Dispatcher {
125125
debug!(handlers = handlers.len(), "collected logged out handlers");
126126
handlers
127127
}
128-
pub fn conneccted_handlers(&self, py: Python<'_>) -> Vec<Py<PyAny>> {
128+
pub fn connected_handlers(&self, py: Python<'_>) -> Vec<Py<PyAny>> {
129129
let handlers = self.connected
130130
.iter()
131131
.map(|handler| handler.clone_ref(py))

src/events.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ pub struct ClientOutDated;
113113

114114
#[pyclass]
115115
pub struct Message {
116-
inner: Box<waproto::whatsapp::Message>,
116+
pub inner: Box<waproto::whatsapp::Message>,
117117
#[pyo3(get)]
118-
message_info: MessageInfo,
118+
pub message_info: MessageInfo,
119119
message_proto: Option<Py<PyAny>>,
120120
}
121121
impl Message {

0 commit comments

Comments
 (0)