Skip to content

Add async/sync ack methods for responding to emitWithAck calls #493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dontcryme
Copy link

@dontcryme dontcryme commented Jan 29, 2025

I added asynchronous and synchronous ack functions to enable responses since there was no way to respond with ack when called via emitWithAck. Additionally, I introduced a separate ack_id variable for response handling.

 ///[sync/socket.rs]
pub(crate) struct Socket {
    //TODO: 0.4.0 refactor this
    engine_client: Arc<EngineClient>,
    connected: Arc<AtomicBool>,
    ack_id: Arc<AtomicI32>,
}
...
 pub fn ack(&self, nsp: &str, data: Payload) -> Result<()> {
        let socket_packet =
            Packet::ack_from_payload(data, nsp, Some(self.ack_id.load(Ordering::Acquire)))?;
        self.send(socket_packet)
}
...
...
 ///[async/socket.rs]
#[derive(Clone)]
pub(crate) struct Socket {
    engine_client: Arc<EngineClient>,
    connected: Arc<AtomicBool>,
    generator: StreamGenerator<Packet>,
    ack_id: Arc<AtomicI32>,
}
...
pub async fn ack(&self, nsp: &str, data: Payload) -> Result<()> {
    let socket_packet =
    Packet::ack_from_payload(data, nsp, Some(self.ack_id.load(Ordering::Acquire)))?;
    self.send(socket_packet).await
}

///[packet.rs]
pub(crate) fn ack_from_payload<'a>(
        payload: Payload,
        nsp: &'a str,
        ack_id: Option<i32>,
) ...{ ... }

The code below was tested on a Node.js Socket.IO server using emitWithAck

 ///sync use case
use rust_socketio::{ClientBuilder, Payload, RawClient};
use std::{thread::sleep, time::Duration};

fn main() {
    let callback = |payload: Payload, socket: RawClient| {
        match payload {
            #![allow(deprecated)]
            Payload::String(str) => println!("Received: {}", str),
            Payload::Binary(bin_data) => println!("Received bytes: {:#?}", bin_data),
            Payload::Text(vec) => println!("Received text: {:#?}", vec),
        }
        socket.ack("ack resend").expect("Server unreachable");
    };

    // get a socket that is connected to the admin namespace
    let socket = ClientBuilder::new("http://localhost:3000")
        //.namespace("/admin")
        .on("test", callback)
        .on("error", |err, _| eprintln!("Error: {:#?}", err))
        .connect()
        .expect("Connection failed");

    sleep(Duration::from_secs(5));
    println!("waiting...");
    socket.disconnect().expect("Disconnect failed");
    println!("disconnected waiting completed");
}
 ///async use case
use bytes::Bytes;
use futures_util::FutureExt;
use rust_socketio::{
    asynchronous::{Client, ClientBuilder},
    Payload,
};
use std::thread;
use std::time::Duration;

#[tokio::main]
async fn main() {
    let callback3 = |_payload: Payload, socket: Client| {
        async move {
            //Test React-to-Server communication (when the Socket.IO server invokes the emitWithAck method and expects a result)
            let buf: Bytes = Bytes::from_static(&[0x00, 0x01, 0x03]);
            //or socket.ack("string").await.expect("Ack invoke failed");
            socket.ack(buf).await.expect("Ack invoke failed");
        }
        .boxed()
    };

    let socket = ClientBuilder::new("http://localhost:3000")
        .namespace("/")
        .reconnect(false)
        .on("test", callback3)
        .on("error", |err, _| {
            async move { eprintln!("Error: {:#?}", err) }.boxed()
        })
        .connect()
        .await
        .expect("Connection Failed");

    thread::sleep(Duration::from_millis(25000));
    socket.disconnect().await.expect("Disconnect failed");
}

Fixes #491

@dontcryme dontcryme changed the title Add missing async/ack ack method Add missing async/sync ack method Jan 31, 2025
@dontcryme dontcryme changed the title Add missing async/sync ack method Add async/sync ack methods for responding to emitWithAck calls Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support responses for emitWithAck by adding synchronous and asynchronous ack functions
1 participant