#axum #http #cookies #cometd

axum-cometd

Framework for CometD server creation

28 releases (8 breaking)

0.10.0 Feb 14, 2023
0.9.4 May 2, 2023
0.9.3 Mar 13, 2023
0.7.0-beta.3 Dec 21, 2022
0.3.0 Nov 30, 2022

#42 in #cookies

Download history 1/week @ 2024-03-26 8/week @ 2024-04-02

82 downloads per month

Apache-2.0

81KB
2K SLoC

Rust 2K SLoC // 0.0% comments JavaScript 127 SLoC TypeScript 63 SLoC // 0.3% comments Shell 63 SLoC // 0.2% comments

axum-cometd


lib.rs:

This crate aims to make ability to use CometD protocol in servers written in Rust.

This project is in progress and might change a lot from version to version.

Table of contents

Server endpoints

Server have 4 endpoints:

  1. /handshake -- to register and get clientId;
  2. / -- to subscribe on channels;
  3. /connect -- to receiving or publish messages;
  4. /disconnect -- to say to server clean data for clientId;

You can change base part of these endpoints through RouterBuilder::handshake_base_path, RouterBuilder::subscribe_base_path, RouterBuilder::connect_base_path, RouterBuilder::disconnect_base_path. For example, to make /node/0/handshake and /node/1/connect you can do this:

use std::sync::Arc;
use axum_cometd::{LongPollingServiceContextBuilder, RouterBuilder};

let context = LongPollingServiceContextBuilder::new()
    .build();

let router = RouterBuilder::new()
    .handshake_base_path("/node/0")
    .connect_base_path("/node/1")
    .build(Arc::clone(&context));

clientId and BAYEUX_BROWSER cookie

clientId and BAYEUX_BROWSER cookie is 40-character length hex string, with possibility of leading zeroes. Server will return '402::session_unknown' error if it will be not. To get some uniquity first 8 bytes is taken from Unix timestamp, and for randomness last part filled with random numbers.

How server works

BAYEUX_BROWSER cookie will be generated and set at /handshake request, if there isn't one already.

At others endpoints ([Server endpoints]) server check clientId and BAYEUX_BROWSER cookie (in case of publish messages to /connect it will be check each clientId). If clientId will be used with different BAYEUX_BROWSER cookie, server will return '402::session_unknown' error.

How get server events

Server have 3 events:

  1. Event::SessionAdded
  2. Event::Subscribe
  3. Event::SessionRemoved
  4. Event::CustomData

SessionAdded and Subscribe can contain additional data, which will be attached through axum::Extension. To get those events, you must use get receive channel LongPollingServiceContext::rx. Server do not use Event::CustomData, it user custom message which can be received in receiver.

use std::sync::Arc;
use axum::Extension;
use axum_cometd::{LongPollingServiceContextBuilder, RouterBuilder};

#[derive(Debug, Clone)]
struct ContextData {
    server_name: Arc<str>,
}

use std::time::Duration;
use axum_cometd::Event;
let context = LongPollingServiceContextBuilder::new()
    .build::<ContextData, &'static str>();

let app = RouterBuilder::new()
    .build_with_additional_data(Arc::clone(&context))
    .layer(Extension(ContextData {
        server_name: std::env::var("SERVER_NAME")
            .map(Arc::from)
            .unwrap_or_else(|_| Arc::from("Skalica")),
    }));

let tx = context.tx();
let mut rx = context.rx();

tokio::task::spawn(async move {
    loop {
        tx.send("CUSTOM_DATA").await;
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
});

while let Some(event) = rx.recv().await {
    match *event {
        Event::SessionAdded{
            client_id,
            ref headers,
            ref data,
        } => {
            println!("sessionAdded with clientId({client_id}), headers({headers:?}), data({data:?})");
        }
        Event::Subscribe{
            client_id,
            ref headers,
            ref channels,
            ref data,
        } => {
            println!("subscribed on channels({channels:?}) with clientId({client_id}), headers({headers:?}), data({data:?})");
        }
        Event::SessionRemoved{
            client_id,
        } => println!("clientId({client_id}) session removed"),
        Event::CustomData(msg) => println!("got CustomData({msg})"),
    }
}

Dependencies

~14MB
~263K SLoC