axum-cometd 0.7.1

Framework for CometD server creation
Documentation
use crate::{
    messages::{Advice, Message},
    CheckExt, CookieJarExt, HandlerResult, LongPollingServiceContext, SendError,
};
use axum::http::StatusCode;
use axum_extra::extract::CookieJar;

#[inline]
pub(super) async fn publish_handle(
    context: &LongPollingServiceContext,
    jar: CookieJar,
    mut messages: Vec<Message>,
) -> HandlerResult<Vec<Message>> {
    is_contains_meta_channel(&messages).check(&false, StatusCode::BAD_REQUEST)?;

    let cookie_id = jar
        .get_cookie_id()
        .ok_or_else(|| Message::session_unknown(None, None, None))?;

    for message in &mut messages {
        let Message {
            id,
            channel,
            data,
            client_id,
            ..
        } = core::mem::take(message);

        *message = match (channel, client_id) {
            (None, _) => Message::channel_missing(id),
            (channel, None) => Message::session_unknown(id, channel, Some(Advice::handshake())),
            (Some(channel), Some(client_id)) => {
                if context.check_client(cookie_id, &client_id).await.is_some() {
                    match context.send(&channel, data.unwrap_or_default()).await {
                        Ok(()) => {}
                        Err(SendError::Closed) => {
                            tracing::error!(
                                client_id = %client_id,
                                channel = channel,
                                "Channel was closed!"
                            );
                        }
                        Err(SendError::ClientWasntFound(_)) => unreachable!(
                            "LongPollingServiceContext::send shouldn't return ClientWasntFound"
                        ),
                        Err(SendError::InvalidChannel) => {
                            tracing::error!(
                                client_id = %client_id,
                                channel = channel,
                                "Invalid channel: `{channel}`!"
                            );
                        }
                    }

                    Message::ok(id, Some(channel))
                } else {
                    Message::session_unknown(id, Some(channel), None)
                }
            }
        };
    }

    Ok(messages)
}

#[inline]
fn is_contains_meta_channel(messages: &[Message]) -> bool {
    messages.iter().any(|message| {
        message
            .channel
            .as_ref()
            .map_or(false, |channel| channel.contains("/meta/"))
    })
}