lilydocs
HTTP APIWebSocketConsumer
Pipeline3 dk okuma

Message middleware

Mesaj öncesi ve sonrası davranış ekleyin; kesintide bağımsız cleanup yolunu kullanın.

Message middleware, mesajın ortak politikasını ve gözlemini toplar. before_message giriş, after_message normal çıkış, on_message_termination kesilmiş işlemin cleanup yoludur.

Middleware örneği#

middleware.rs dosyası bir zaman ölçer ve sonraki sayfada açıklanan scope guard'ını içerir. DI gerektirmeyen ilk uygulamanın facade ve Tokio bağımlılıkları yeterlidir.

middleware.rs
use std::sync::Arc;
use lilyrs::websocket::{CleanupCancellation, ExecutionCancellation, Extensions,
    WebSocketErrorCode, WsAppBuilder, async_trait};
use lilyrs::websocket::guard::{GuardInitializationError, WebSocketGuardRejection, WsGuard};
use lilyrs::websocket::middleware::{MiddlewareDescriptor, MiddlewareErrorCode, MiddlewareKind,
    WsMessageDecision, WsMessageExchange, WsMessageMiddleware, WsMessageOutcome,
    WsMessageTerminationContext, WsMiddlewareError, WsMiddlewareInitError};

#[derive(Clone)]
pub struct StartedAt(pub tokio::time::Instant);
pub struct MessageTimer;

#[async_trait]
impl WsMessageMiddleware for MessageTimer {
    async fn new(_: Arc<Extensions>) -> Result<Self, WsMiddlewareInitError> { Ok(Self) }
    fn descriptor(&self) -> MiddlewareDescriptor {
        MiddlewareDescriptor::new("message_timer", MiddlewareKind::WebSocketMessage)
    }
    async fn before_message(&self, exchange: &mut WsMessageExchange,
        _: ExecutionCancellation) -> Result<WsMessageDecision, WsMiddlewareError>
    {
        exchange.insert_message_local(StartedAt(tokio::time::Instant::now()))
            .map_err(|_| WsMiddlewareError::internal(MiddlewareErrorCode::INTERNAL))?;
        Ok(WsMessageDecision::Continue)
    }
    async fn after_message(&self, exchange: &mut WsMessageExchange,
        _outcome: WsMessageOutcome, _: ExecutionCancellation)
        -> Result<WsMessageDecision, WsMiddlewareError>
    {
        if let Some(StartedAt(start)) = exchange.message_local::<StartedAt>() {
            let _elapsed = start.elapsed(); // Uygulamanın bounded metriğine gönderilir.
        }
        Ok(WsMessageDecision::Continue)
    }
    async fn on_message_termination(&self, context: WsMessageTerminationContext<'_>,
        cancellation: CleanupCancellation) -> Result<(), WsMiddlewareError>
    {
        let _normal_exit = context.normal_exit();
        if cancellation.is_cancelled() { return Ok(()); }
        // Normal exit'in kısmi yan etkilerini tekrar etmeyen cleanup burada yapılır.
        Ok(())
    }
}

pub struct ChatWriteGuard;
#[async_trait]
impl WsGuard for ChatWriteGuard {
    async fn new(_: Arc<Extensions>) -> Result<Self, GuardInitializationError> { Ok(Self) }
    async fn can_activate(&self, exchange: &mut WsMessageExchange,
        _: ExecutionCancellation) -> Result<(), WebSocketGuardRejection>
    {
        if exchange.principal().is_some_and(|p| p.has_scope("chat:write")) {
            Ok(())
        } else {
            Err(WebSocketGuardRejection::error(
                WebSocketErrorCode::new("CHAT_FORBIDDEN").expect("sabit kod"),
                "Bu işlem için yetkiniz yok.",
            ).expect("sabit mesaj"))
        }
    }
}
pub fn with_policies(builder: WsAppBuilder) -> WsAppBuilder {
    builder.message_middleware::<MessageTimer>().guard::<ChatWriteGuard>()
}

Tam örnek dosyasını indirin.

StartedAt message local'i aynı mesajda kullanılabilir. _elapsed henüz metric exporter'a gönderilmez; uygulamanızın bounded ölçümünü buraya bağlayın. Örneğin with_policies fonksiyonu hem timer hem guard kurar; guard için identity de gerekir. Yalnız timer isterseniz .message_middleware::<MessageTimer>() kullanın.

Kayıt seviyeleri#

Global kayıt builder'daki .message_middleware::<M>(), controller veya action kaydı #[message_middleware(M)] biçimindedir. Effective sıra global → controller → action'dır. Aynı route üzerinde aynı concrete tipi tekrar etmeyin. Middleware planı en fazla 64 öğe içerir.

Constructor fallible'dır ve app başına bir kez çalışır. Descriptor MiddlewareKind::WebSocketMessage döndürür. Scoped servis gerekiyorsa constructor'da saklamak yerine exchange.service::<T>().await ile aktif mesaj scope'undan çözün.

Normal çıkış#

before_message Continue döndüğünde middleware entered olur. Reject, hata, panic veya timeout ile biten before callback'inin kendisi için başarılı giriş varsayılmaz. Entered prefix ters sırada after_message çalıştırır.

Continue mevcut sonucu korur. Reject yalnızca başarılı sonucu değiştirebilir. İlk seçilen Close sonradan outer middleware'in başka Close kararıyla ezilmez. Normal çıkışlar mesajın aynı deadline'ını paylaşır; after callback için taze süre verilmez.

Termination cleanup#

Normal exit'i başlamamış veya kesilmiş entered middleware on_message_termination alabilir. Tamamlanmış, hata dönmüş veya panic etmiş normal exit bu yolda tekrar edilmez. context.normal_exit() ilk poll kanıtını bildirir; yarım yan etkiyi geri almaz.

Cleanup bütçesi bitmişse callback'in ilk poll'ü bile garanti değildir. Callback idempotent, bounded olmalı ve bağımsız CleanupCancellation sinyalini izlemelidir. Bu yolda response değiştirilemez. Ayrıntılar deadline ve shutdown sayfalarındadır.

Bu sayfanın kaynakları v0.1.0

Anlatım, incelenen framework commit’ine dayanır.

HIZLI BAŞLANGIÇ
Dokümantasyon
Kaynak kod