use std::sync::Arc;
use crate::{
Context,
Error,
EventHandler,
Rustybook,
SendReceipt,
User,
};
impl Rustybook {
pub async fn start<H>(&self, handler: Arc<H>) -> Result<(), Error>
where
H: EventHandler,
{
let client = self.ensure_messenger_client().await?;
client.start_listening().await?;
let mut events = client.subscribe();
let ctx = Context::new(self.clone());
let ready_user = self.current_user().await?;
#[cfg(all(feature = "messenger", feature = "cache"))]
self.set_user(ready_user.clone()).await;
let task = tokio::spawn(async move {
while let Ok(event) = events.recv().await {
#[cfg(all(feature = "messenger", feature = "cache"))]
let mut event = event;
#[cfg(all(feature = "messenger", feature = "cache"))]
ctx.client().inner.cache.update(&mut event);
crate::events::dispatch_event(&handler, ctx.clone(), &ready_user, event).await;
}
});
let mut handler_task = self.inner.handler_task.lock().await;
if let Some(existing) = handler_task.replace(task) {
existing.abort();
}
Ok(())
}
pub async fn stop(&self) -> Result<(), Error> {
let client = {
let guard = self.inner.messenger.lock().await;
guard.clone()
};
if let Some(client) = client {
client.stop_listening().await?;
}
let mut handler_task = self.inner.handler_task.lock().await;
if let Some(task) = handler_task.take() {
task.abort();
}
Ok(())
}
pub async fn send_text(&self, thread_id: &str, text: &str) -> Result<SendReceipt, Error> {
let client = {
let guard = self.inner.messenger.lock().await;
guard.clone()
};
let Some(client) = client else {
return Err(Error::Config(
"messenger is not started; call start() first".to_string(),
));
};
let receipt = client.send_text(thread_id, text).await?;
Ok(SendReceipt {
thread_id: receipt.thread_id,
message_id: receipt.message_id,
offline_threading_id: receipt.offline_threading_id,
})
}
async fn ensure_messenger_client(&self) -> Result<rustybook_messenger::MessengerClient, Error> {
{
let guard = self.inner.messenger.lock().await;
if let Some(existing) = guard.as_ref() {
return Ok(existing.clone());
}
}
let session = self
.inner
.session
.as_ref()
.ok_or_else(|| {
Error::Config(
"messenger requires cookies_file_path on RustybookBuilder".to_string(),
)
})?
.clone();
let mut builder = rustybook_messenger::MessengerClient::builder()
.shared_session(
session.user_id,
session.cookie_header,
self.inner.http.clone(),
)
.online(self.inner.messenger_online);
if let Some(user_agent) = self.inner.user_agent.as_deref() {
builder = builder.user_agent(user_agent.to_string());
}
if let Some(proxy) = self.inner.proxy.as_deref() {
builder = builder.proxy(proxy.to_string());
}
let client = builder.build()?;
let mut guard = self.inner.messenger.lock().await;
if guard.is_none() {
*guard = Some(client.clone());
}
Ok(client)
}
async fn current_user(&self) -> Result<User, Error> {
let client = {
let guard = self.inner.messenger.lock().await;
guard.clone()
};
let Some(client) = client else {
return Err(Error::Config(
"messenger is not started; call start() first".to_string(),
));
};
let id = client
.uid()
.await
.ok_or_else(|| Error::Config("missing user id from messenger state".to_string()))?;
let name = client.name().await;
Ok(User { id, name })
}
}