Leptos server signals synced through Server-Sent-Events (SSE)

Overview

Leptos Server Sent Events

GitHub Actions Crates.io docs.rs

Server signals are leptos signals kept in sync with the server through server-sent-events (SSE).

The signals are read-only on the client side, and can be written to by the server. This is useful if you want real-time updates on the UI controlled by the server.

Changes to a signal are sent through a SSE to the client as json patches.

This project is heavily based on leptos_server_signal.

Feature flags

  • ssr: ssr is enabled when rendering the app on the server.
  • actix: integration with the Actix web framework.
  • axum: integration with the Axum web framework.

Example

Cargo.toml

[dependencies]
leptos_sse = "*"
serde = { version = "*", features = ["derive"] }

[features]
ssr = [
  "leptos_sse/ssr",
  "leptos_sse/axum", # or actix
]

Client

use leptos::*;
use leptos_sse::create_sse_signal;
use serde::{Deserialize, Serialize};

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct Count {
    pub value: i32,
}

#[component]
pub fn App() -> impl IntoView {
    // Provide SSE connection
    leptos_sse::provide_sse("http://localhost:3000/sse").unwrap();

    // Create server signal
    let count = create_sse_signal::<Count>("counter");

    view! {
        <h1>"Count: " {move || count().value.to_string()}</h1>
    }
}

If on stable, use count.get().value instead of count().value.

Server (Axum)

#[cfg(feature = "ssr")]
use {
    axum::response::sse::{Event, KeepAlive, Sse},
    futures::stream::Stream,
};

#[cfg(feature = "ssr")]
async fn handle_sse() -> Sse<impl Stream<Item = Result<Event, axum::BoxError>>> {
    use futures::stream;
    use leptos_sse::ServerSentEvents;
    use std::time::Duration;
    use tokio_stream::StreamExt as _;

    let mut value = 0;
    let stream = ServerSentEvents::new(
        "counter",
        stream::repeat_with(move || {
            let curr = value;
            value += 1;
            Ok(Count { value: curr })
        })
        .throttle(Duration::from_secs(1)),
    )
    .unwrap();
    Sse::new(stream).keep_alive(KeepAlive::default())
}

License

This work is released under the MIT license. A copy of the license is provided in the LICENSE file.

You might also like...
A binary that bootstraps a Leptos application with client side rendering, tailwind, and vercel

create-leptos-csr-tw This CLI provides a quick setup to start building web applications using the Leptos web framework integrated with TailwindCSS. It

💫 List-rendering component utilizing FLIP position transitions for Leptos
💫 List-rendering component utilizing FLIP position transitions for Leptos

AnimatedFor / component for Leptos FLIP animations for element and component groups inspired by Vue's TransitionGroup. This crate exports a compon

Simple template to use csr and ssr leptos with tauri for ios/android/windows/macos/linux and web dev

Tailwind-Leptos-Tauri Template Simple template to use csr and ssr leptos with tauri for ios/android/windows/macos/linux and web dev Just clone the rep

A fully extensible command interface to navigate around your leptos application.

leptos-kbar A fully extensible command interface to navigate around your leptos application. See demo: https://leptos-kbar.vercel.app/ Roadmap leptos-

Send copy events over the network

Copiepate Copiepate is a small utility to remotely set the content of a clipboard. I created this tool as I frequently use a remote tmux+vim setup and

Recollection Notify you for daily, weekly, monthly and yearly events

Recollection Notify you for daily, weekly, monthly and yearly events. Usage Use recollectctl to manage the events, and run recollectd daemon to monito

RedMaple offers an oppinionated yet extremely flexible data modeling system based on events for back-end applications.

RedMaple offers an oppinionated yet extremely flexible data modeling system based on events for back-end applications.

a search engine for your events!
a search engine for your events!

event engine description event engine is a search engine for your events! too many websites and emails to keep track of? event engine takes care of th

A Rust CLI tool that helps you enforce Git policies through Git hooks both server and client side

GitPolicyEnforcer This is a command line utility written in Rust, that helps you utilize Git hooks, to enforce various policies. It currently supports

Comments
  • Use multiple SSE event streams

    Use multiple SSE event streams

    It would be nice if one could open multiple SSE streams by using a path extractor in the SSE handler for each event type. So the diffing of the payload is more efficient.

    like this:

    pub async fn handle_sse(
        Path(event): Path<Cow<'static, str>>,
    ) -> Sse<impl Stream<Item = Result<Event, axum::BoxError>>> {
        let state = BACKEND_STATE.read();
        let stream = ServerSentEvents::new(
            event,
            BroadcastStream::new(state.sse_rx.resubscribe()).map_err(|e| e.into()),
        )
        .unwrap();
        Sse::new(stream).keep_alive(KeepAlive::default())
    }
    

    Each component could provide it's own stream in it's context. Unfortunately here only the existence of the ServerSignalEventSource type is checked in the context and creation of a new stream is skipped if it already exists.

    Would be cool if we also compare the URL and create a new stream in the context, if the URL is different.

    enhancement 
    opened by hirschenberger 0
  • Patch error when sending Enum-Values

    Patch error when sending Enum-Values

    Hey, an my app I want to use one SSE endpoint to send different signals to my GUI. I use a serializable enum as event-payload.

    #[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
    pub enum SseSignal {
        #[default]
        Nop,
        UpdateImage(String),
        AcquisitionProgress {
            sequence: (usize, usize),
            frame: (usize, usize),
        },
    }
    

    But when I send different enum values through the same stream, I get a panic from here with the error PatchError.

    My assumption is, that this error happens if json_patch tries to patch totally unrelated data. Can we maybe handle the error case and return the new data instead of patching the old?

    EDIT: My assumption seems to be true, if I wrap my enum in a struct, it works.

    EDIT2: After some investigation, it seems as if the patch fails, because the value of doc is still SseSignal::Nop (the default value) but the patch that should be applied is:

    Patch([
      Add(AddOperation { path: "/AcquisitionProgress", value: Object {"frame": Array [Number(1), Number(100)], "sequence": Array [Number(0), Number(2)]} }), 
      Remove(RemoveOperation { path: "/UpdateImage" })
    ])
    

    So it seems to be a synchronisation error between the two signals.

    opened by hirschenberger 0
Owner
messense
Pythonista, Rustacean.
messense
Periodically download a youtube playlist, extract audio, convert to mp3, move to directory (possibly synced using syncthing).

auto-dl Periodically download a youtube playlist, extract audio, convert to mp3, move to directory (possibly synced using syncthing). drop https://git

Paul Adenot 10 Jan 12, 2023
Estratto is a powerful and user-friendly Rust library designed for extracting rich audio features from digital audio signals.

estratto 〜 An Audio Feature Extraction Library estratto is a powerful and user-friendly Rust library designed for extracting rich audio features from

Amber J Blue 5 Aug 25, 2023
A simple solution for scoped styles in Leptos

Styled: Easy Styling for Leptos Components If you're looking for an easy way to apply scoped styles to your Leptos components, Styled is the Leptos ma

Eran Boodnero 8 Mar 5, 2023
A formatter for the leptos view! macro

leptosfmt A formatter for the leptos view! macro All notable changes are documented in: CHANGELOG.md Install cargo install leptosfmt or for trying out

Bram 13 Apr 4, 2023
A website for the Leptos Web Framework!

Leptos Website A Repo for the public facing Leptos website. Still a WIP. Client Side Rendering This example cannot be built as a trunk standalone CSR-

Leptos 7 May 2, 2023
A Nix template for full-stack web apps in Rust using Leptos

leptos-fullstack A Nix template for full-stack web apps in Rust using Leptos. Tech used: Leptos full-stack framework server functions ssr + hydration

Sridhar Ratnakumar 6 Aug 4, 2023
A zero-config leptos component to display markdown

A port of yew-markdown using leptos ! Usage You can use this component to render both static and dynamic markdown. Static markdown use leptos::*; {

Antonin Peronnet 4 Aug 4, 2023
Experimental integration of `fedimint-client` with the Leptos web frontend framework

CAUTION: highly experimental, the Database implementation is likely horribly broken Fedimint Client built with Leptos This repo contains a proof-of-co

null 3 Aug 27, 2023
Leptos integration with Golden Layout.

Leptos Golden Layout Leptos integration with Golden Layout. This has many features missing but covers the basics for integrating leptos with golden la

Ari Seyhun 3 Oct 23, 2023
A UI component library for Leptos, based on Tailwind Elements.

leptos-twelements A UI component library for Leptos, based on Tailwind Elements. Installation (for projects using cargo leptos) Use the nightly rust c

Sebastian Meßmer 4 Oct 20, 2023