simploxide-client 0.13.0

SimpleX-Chat API client
Documentation
//! The examples expects that SimpleX-CLI(`simplex-chat` binary) is installed locally on the system
//! and is available via `$PATH` or at the `simploxide/simploxide-client` directory(you can symlink
//! it there)
//!
//! To compile this example pass the --features flag like this:
//! `cargo run --example remote_control`
//!
//!
//! ----
//!
//! A demonstration of obtaining a direct access to the SimpleX-Chat instance the bot is running on
//! via the desktop client.
//!
//! Go to `SimpleX Desktop > Link Mobile` and generate and connection link for localhost there. By
//! pasting this link to the bot you will be able to access the SimpleX-Chat instance the bot is
//! running on from your desktop client.

use simploxide_client::{
    ffi::{self, ClientResult},
    prelude::*,
    remote::CtrlHandle,
};
use std::{error::Error, sync::Arc};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let (bot, events) = ffi::BotBuilder::new("SimplOxide Examples", ffi::DbOpts::unencrypted("test_db/bot"))
        // create a public bot address auto-accepting new users with a welcome message
        .auto_accept_with(
            "Remote controller demostration. Send me a link to connect to my SimpleX-Chat instance via your Desktop client",
        )
        // Launch CLI, connect the client, and initialise the bot
        .launch()
        .await?;

    // Set up a hook to handle remote control events under the hood. The returned `ctrl` handle can
    // be used to accept remote control sessions
    let (ctrl, events) = events.hook_remote_control();

    let address = bot.address().await?;
    println!("Bot address: {address}");

    tokio::spawn(ping_task(bot.clone()));

    events
        .into_dispatcher((bot, ctrl))
        .on(new_msgs)
        .dispatch()
        .await?;

    Ok(())
}

async fn new_msgs(
    ev: Arc<NewChatItems>,
    (bot, ctrl): (ffi::Bot, Arc<CtrlHandle>),
) -> ClientResult<StreamEvents> {
    for (chat, msg, content) in ev.chat_items.filter_messages() {
        if msg.meta.item_text.trim() == "/die" {
            return Ok(StreamEvents::Break);
        }

        let Some(link) = content.text() else {
            bot.send_msg(
                chat,
                Text::Yellow(
                    "Please, send a regular text link generated by your SimpleX Desktop client",
                ),
            )
            .await?;

            return Ok(StreamEvents::Continue);
        };

        match bot.accept_remote_ctrl(&ctrl, link.trim()).await {
            Ok(_) => {
                bot.send_msg(
                    chat,
                    Text::Green("Remote control session has successfully started"),
                )
                .await?;
            }
            Err(e) => {
                bot.send_msg(
                    chat,
                    format!("Failed to esablish a remote control session\n{e}").red(),
                )
                .await?;
            }
        }
    }

    Ok(StreamEvents::Continue)
}

async fn ping_task(bot: ffi::Bot) {
    loop {
        tokio::time::sleep(std::time::Duration::from_secs(15)).await;

        let broadcast = async {
            let results = bot.prepare_broadcast("Ping".blue()).await?.deliver().await;

            match results.into_iter().find_map(|res| res.err()) {
                Some(err) => Err(err),
                None => Ok(()),
            }
        };

        if let Err(e) = broadcast.await {
            println!("Broadcast task error: {e:?}");
        }
    }
}