rustybook 0.2.0

An ergonomic Facebook client in Rust
Documentation
#[cfg(feature = "messenger")]
use crate::Rustybook;
#[cfg(all(feature = "messenger", feature = "cache"))]
use crate::{
    Cache,
    CacheUpdate,
};

#[cfg(feature = "messenger")]
use std::sync::Arc;

#[cfg(feature = "messenger")]
#[derive(Clone)]
pub struct Context {
    client: Rustybook,
}

#[cfg(feature = "messenger")]
impl Context {
    pub(crate) fn new(client: Rustybook) -> Self {
        Self { client }
    }

    /// Returns the Rustybook client bound to this handler context.
    pub fn client(&self) -> &Rustybook {
        &self.client
    }
}

#[cfg(feature = "messenger")]
#[derive(Debug, Clone)]
pub struct User {
    pub id: String,
    pub name: Option<String>,
}

#[cfg(feature = "messenger")]
#[derive(Debug, Clone)]
pub struct Message {
    pub message_id: Option<String>,
    pub thread_id: String,
    pub sender_id: String,
    pub text: Option<String>,
    pub timestamp_ms: Option<i64>,
}

#[cfg(feature = "messenger")]
pub(crate) fn message_from_raw(message: &rustybook_messenger::MessageEvent) -> Message {
    Message {
        message_id: message.message_id.clone(),
        thread_id: message.thread_id.clone(),
        sender_id: message.sender_id.clone(),
        text: message.text.clone(),
        timestamp_ms: message.timestamp_ms,
    }
}

#[cfg(all(feature = "messenger", feature = "cache"))]
impl CacheUpdate for rustybook_messenger::MessageEvent {
    type Output = Message;

    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
        let mapped = message_from_raw(self);
        cache.push_message(mapped.clone());
        Some(mapped)
    }
}

#[cfg(all(feature = "messenger", feature = "cache"))]
impl CacheUpdate for rustybook_messenger::TypingEvent {
    type Output = ();

    fn update(&mut self, _cache: &Cache) -> Option<Self::Output> {
        None
    }
}

#[cfg(all(feature = "messenger", feature = "cache"))]
impl CacheUpdate for rustybook_messenger::PresenceEvent {
    type Output = ();

    fn update(&mut self, _cache: &Cache) -> Option<Self::Output> {
        None
    }
}

#[cfg(all(feature = "messenger", feature = "cache"))]
impl CacheUpdate for rustybook_messenger::EventError {
    type Output = ();

    fn update(&mut self, _cache: &Cache) -> Option<Self::Output> {
        None
    }
}

#[cfg(all(feature = "messenger", feature = "cache"))]
impl CacheUpdate for rustybook_messenger::Event {
    type Output = ();

    fn update(&mut self, cache: &Cache) -> Option<Self::Output> {
        match self {
            rustybook_messenger::Event::Message(event) => {
                let _ = event.update(cache);
                Some(())
            }
            rustybook_messenger::Event::Typing(event) => {
                let _ = event.update(cache);
                Some(())
            }
            rustybook_messenger::Event::Presence(event) => {
                let _ = event.update(cache);
                Some(())
            }
            rustybook_messenger::Event::Error(event) => {
                let _ = event.update(cache);
                Some(())
            }
            rustybook_messenger::Event::Listening | rustybook_messenger::Event::Disconnect => None,
        }
    }
}

#[cfg(feature = "messenger")]
#[derive(Debug, Clone)]
pub struct Typing {
    pub user_id: String,
    pub thread_id: Option<String>,
    pub is_typing: bool,
}

#[cfg(feature = "messenger")]
#[derive(Debug, Clone)]
pub struct Presence {
    pub user_id: String,
    pub is_active: bool,
    pub last_active_ms: Option<i64>,
}

#[cfg(feature = "messenger")]
#[derive(Debug, Clone)]
pub struct ErrorEvent {
    pub kind: String,
    pub message: String,
}

#[cfg(feature = "messenger")]
pub trait EventHandler: Send + Sync + 'static {
    /// Called when messenger listener is ready.
    fn ready(&self, _ctx: Context, _user: User) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }

    /// Called when a message event is received.
    fn message(
        &self,
        _ctx: Context,
        _msg: Message,
    ) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }

    /// Called when a typing event is received.
    fn typing(
        &self,
        _ctx: Context,
        _typing: Typing,
    ) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }

    /// Called when a presence event is received.
    fn presence(
        &self,
        _ctx: Context,
        _presence: Presence,
    ) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }

    /// Called when the messenger listener disconnects.
    fn disconnect(&self, _ctx: Context) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }

    /// Called when the messenger runtime emits an error event.
    fn error(
        &self,
        _ctx: Context,
        _error: ErrorEvent,
    ) -> impl std::future::Future<Output = ()> + Send {
        async {}
    }
}

#[cfg(feature = "messenger")]
macro_rules! emit_event {
    ($handler:expr, $method:ident, $ctx:expr) => {
        $handler.$method($ctx.clone()).await;
    };
    ($handler:expr, $method:ident, $ctx:expr, $value:expr) => {
        $handler.$method($ctx.clone(), $value).await;
    };
}

#[cfg(feature = "messenger")]
pub(crate) async fn dispatch_event(
    handler: &Arc<impl EventHandler>,
    ctx: Context,
    ready_user: &User,
    event: rustybook_messenger::Event,
) {
    match event {
        rustybook_messenger::Event::Listening => {
            emit_event!(handler, ready, ctx, ready_user.clone());
        }
        rustybook_messenger::Event::Disconnect => {
            emit_event!(handler, disconnect, ctx);
        }
        rustybook_messenger::Event::Message(message) => {
            emit_event!(handler, message, ctx, message_from_raw(&message));
        }
        rustybook_messenger::Event::Typing(typing) => {
            emit_event!(
                handler,
                typing,
                ctx,
                Typing {
                    user_id: typing.user_id,
                    thread_id: typing.thread_id,
                    is_typing: typing.is_typing,
                }
            );
        }
        rustybook_messenger::Event::Presence(presence) => {
            emit_event!(
                handler,
                presence,
                ctx,
                Presence {
                    user_id: presence.user_id,
                    is_active: presence.is_active,
                    last_active_ms: presence.last_active_ms,
                }
            );
        }
        rustybook_messenger::Event::Error(error) => {
            emit_event!(
                handler,
                error,
                ctx,
                ErrorEvent {
                    kind: format!("{:?}", error.kind),
                    message: error.message,
                }
            );
        }
    }
}