Leptos Axum Socket

Realtime pub/sub communication for Leptos + Axum applications.
Usage
#[derive(Clone, Serialize, Deserialize)]
pub struct MyKey {
pub bla: String,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MyMsg {
pub awesome_msg: String,
}
impl SocketMsg for MyMsg {
type Key = MyKey;
#[cfg(feature = "ssr")]
type AppState = AppState;
}
#[component]
pub fn MyComponent() -> impl IntoView {
let socket = expect_socket_context();
socket.subscribe(
MyKey {
bla: "bla".to_string(),
},
|msg: &MyMsg| {
leptos::logging::log!("message: {msg:#?}");
},
);
let on_click = move || {
socket.send(
MyKey {
bla: "bla".to_string(),
},
MyMsg {
awesome_msg: "awesome message".to_string(),
},
);
};
view! { "..." }
}
#[server]
pub async fn my_server_function() -> Result<(), ServerFnError> {
leptos_axum_socket::send(
&MyKey {
bla: "bla".to_string(),
},
&MyMsg {
awesome_msg: "Hello, world!".to_string(),
},
);
Ok(())
}
For this to work you have to prepare a little bit.
Define your app state in your lib.rs:
use leptos::prelude::*;
#[cfg(feature = "ssr")]
#[derive(Clone, axum::extract::FromRef)]
pub struct AppState {
pub socket: leptos_axum_socket::ServerSocket,
pub leptos_options: LeptosOptions,
}
Initialize your Axum app (probably in main.rs):
let state = AppState {
leptos_options: conf.leptos_options,
server_socket: ServerSocket::new(),
};
state.server_socket.add_permission_filter(|key: MyKey, _ctx: &()| {
if key.bla == "bla" {
SocketPermission::Allow
} else if key.bla == "bla2" {
SocketPermission::ReadOnly
} else {
SocketPermission::Deny
}
});
let app = Router::new()
.leptos_routes(&state, routes, {
use basic::app::shell;
let leptos_options = state.leptos_options.clone();
move || shell(leptos_options.clone())
})
.socket_route(connect_to_websocket) .fallback(leptos_axum::file_and_error_handler::<AppState, _>(shell))
.with_state(state);
Implement the connect_to_websocket handler:
#[cfg(feature = "ssr")]
pub async fn connect_to_websocket(
ws: WebSocketUpgrade,
State(socket): State<ServerSocket>,
) -> Response {
let ctx = ();
ws.on_upgrade(|websocket| leptos_axum_socket::handlers::handle_websocket_with_context(websocket, socket, ctx))
}
And finally provide the context in your root Leptos component:
#[component]
pub fn App() -> impl IntoView {
provide_socket_context();
view! { "..." }
}