Module connect

Module connect 

Source
Expand description

ConnectHandler trait and implementations, used to handle the connect event. It has a flexible axum-like API, you can put any arguments as long as it implements the FromConnectParts trait.

You can also implement the FromConnectParts trait for your own types. See the extract module doc for more details on available extractors.

Handlers must be async.

§Middlewares

ConnectHandlers can have middlewares, they are called before the connection of the socket to the namespace and therefore before the handler.

Because the socket is not yet connected to the namespace, you can't send messages to it from the middleware.

Middlewares must be async and can be chained. They are defined with the ConnectMiddleware trait which is automatically implemented for any closure with up to 16 arguments with the following signature:

  • async FnOnce(*args) -> Result<(), E> where E: Display

Arguments must implement the FromConnectParts trait in the exact same way than handlers.

§Example with async closures

let (svc, io) = SocketIo::new_svc();
// Here the handler is async and extract the current socket and the auth payload
io.ns("/", async |io: SocketIo, s: SocketRef, TryData(auth): TryData<String>| {
    println!("Socket connected on / namespace with id and auth data: {} {:?}", s.id, auth);
});
// Here the handler is async and only extract the current socket.
// The auth payload won't be deserialized and will be dropped
io.ns("/async_nsp", async |s: SocketRef| {
    println!("Socket connected on /async_nsp namespace with id: {}", s.id);
});

§Example with async non anonymous functions

async fn handler(s: SocketRef, TryData(auth): TryData<String>) {
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    println!("Socket connected on {} namespace with id and auth data: {} {:?}", s.ns(), s.id, auth);
}

let (svc, io) = SocketIo::new_svc();

// You can reuse the same handler for multiple namespaces
io.ns("/", handler);
io.ns("/admin", handler);

§Example with middlewares

async fn handler(s: SocketRef) {
    println!("socket connected on / namespace with id: {}", s.id);
}

#[derive(Debug)]
struct AuthError;
impl std::fmt::Display for AuthError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "AuthError")
    }
}
impl std::error::Error for AuthError {}

async fn middleware(s: SocketRef, Data(token): Data<String>) -> Result<(), AuthError> {
    println!("second middleware called");
    if token != "secret" {
        Err(AuthError)
    } else {
        Ok(())
    }
}

async fn other_middleware(s: SocketRef) -> Result<(), AuthError> {
    println!("first middleware called");
    if s.req_parts().uri.query().map(|q| q.contains("secret")).unwrap_or_default() {
        Err(AuthError)
    } else {
        Ok(())
    }
}

let (_, io) = SocketIo::new_layer();
io.ns("/", handler.with(middleware).with(other_middleware));

Traits§

ConnectHandler
Define a handler for the connect event. It is implemented for closures with up to 16 arguments. They must implement the FromConnectParts trait.
ConnectMiddleware
Define a middleware for the connect event. It is implemented for closures with up to 16 arguments. They must implement the FromConnectParts trait and return Result<(), E> where E: Display.
FromConnectParts
A trait used to extract the arguments from the connect event. The Result associated type is used to return an error if the extraction fails, in this case the ConnectHandler is not called.