Files
rustfs/crates/notify

RustFS

RustFS Notify - Event Notification System

Real-time event notification system for RustFS distributed object storage

CI 📖 Documentation · 🐛 Bug Reports · 💬 Discussions


📖 Overview

RustFS Notify is the event notification system for the RustFS distributed object storage platform. It provides real-time event publishing and delivery to various targets including webhooks, MQTT brokers, and message queues, enabling seamless integration with external systems and workflows.

Note: This is a core submodule of RustFS that provides essential event notification capabilities for the distributed object storage system. For the complete RustFS experience, please visit the main RustFS repository.

Features

📡 Event Publishing

  • Real-time Events: Instant notification of storage events
  • Event Filtering: Advanced filtering based on object patterns and event types
  • Reliable Delivery: Guaranteed delivery with retry mechanisms
  • Batch Processing: Efficient batch event delivery

🎯 Multiple Targets

  • Webhooks: HTTP/HTTPS webhook notifications
  • MQTT: MQTT broker integration for IoT scenarios
  • Message Queues: Integration with popular message queue systems
  • Custom Targets: Extensible target system for custom integrations

🔧 Advanced Features

  • Event Transformation: Custom event payload transformation
  • Pattern Matching: Flexible pattern-based event filtering
  • Rate Limiting: Configurable rate limiting for targets
  • Dead Letter Queue: Failed event handling and recovery

📦 Installation

Add this to your Cargo.toml:

[dependencies]
rustfs-notify = "0.1.0"

🔧 Usage

Basic Event Notification

use rustfs_notify::{Event, EventType, NotificationTarget, NotifySystem};
use rustfs_notify::target::WebhookTarget;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create notification system
    let notify_system = NotifySystem::new().await?;

    // Create webhook target
    let webhook = WebhookTarget::new(
        "webhook-1",
        "https://api.example.com/webhook",
        vec![EventType::ObjectCreated, EventType::ObjectRemoved],
    );

    // Add target to notification system
    notify_system.add_target(Box::new(webhook)).await?;

    // Create and send event
    let event = Event::new(
        EventType::ObjectCreated,
        "my-bucket",
        "path/to/object.txt",
        "user123",
    );

    notify_system.publish_event(event).await?;

    Ok(())
}

Advanced Event Configuration

use rustfs_notify::{Event, EventType, NotificationConfig};
use rustfs_notify::target::{WebhookTarget, MqttTarget};
use rustfs_notify::filter::{EventFilter, PatternRule};

async fn setup_advanced_notifications() -> Result<(), Box<dyn std::error::Error>> {
    let notify_system = NotifySystem::new().await?;

    // Create webhook with custom configuration
    let webhook_config = NotificationConfig {
        retry_attempts: 3,
        retry_delay: std::time::Duration::from_secs(5),
        timeout: std::time::Duration::from_secs(30),
        rate_limit: Some(100), // 100 events per minute
        ..Default::default()
    };

    let webhook = WebhookTarget::builder()
        .id("production-webhook")
        .url("https://api.example.com/events")
        .events(vec![EventType::ObjectCreated, EventType::ObjectRemoved])
        .config(webhook_config)
        .headers(vec![
            ("Authorization".to_string(), "Bearer token123".to_string()),
            ("Content-Type".to_string(), "application/json".to_string()),
        ])
        .build()?;

    // Create MQTT target
    let mqtt_target = MqttTarget::builder()
        .id("iot-mqtt")
        .broker_url("mqtt://broker.example.com:1883")
        .topic("storage/events")
        .qos(1)
        .events(vec![EventType::ObjectCreated])
        .build()?;

    // Add targets
    notify_system.add_target(Box::new(webhook)).await?;
    notify_system.add_target(Box::new(mqtt_target)).await?;

    Ok(())
}

Event Filtering and Pattern Matching

use rustfs_notify::filter::{EventFilter, PatternRule, ConditionRule};

fn setup_event_filters() -> Result<EventFilter, Box<dyn std::error::Error>> {
    let filter = EventFilter::builder()
        // Only images and documents
        .pattern_rule(PatternRule::new(
            "suffix",
            vec!["*.jpg", "*.png", "*.pdf", "*.doc"]
        ))
        // Exclude temporary files
        .pattern_rule(PatternRule::new(
            "exclude",
            vec!["*/tmp/*", "*.tmp"]
        ))
        // Only files larger than 1MB
        .condition_rule(ConditionRule::new(
            "object_size",
            ">",
            1024 * 1024
        ))
        // Only from specific buckets
        .bucket_filter(vec!["important-bucket", "backup-bucket"])
        .build()?;

    Ok(filter)
}

Custom Target Implementation

use rustfs_notify::{Event, NotificationTarget, TargetResult};
use async_trait::async_trait;

pub struct SlackTarget {
    id: String,
    webhook_url: String,
    channel: String,
}

#[async_trait]
impl NotificationTarget for SlackTarget {
    fn id(&self) -> &str {
        &self.id
    }

    async fn deliver_event(&self, event: &Event) -> TargetResult<()> {
        let message = format!(
            "🔔 Storage Event: {} in bucket `{}` - object `{}`",
            event.event_type,
            event.bucket_name,
            event.object_name
        );

        let payload = serde_json::json!({
            "text": message,
            "channel": self.channel,
        });

        let client = reqwest::Client::new();
        let response = client
            .post(&self.webhook_url)
            .json(&payload)
            .send()
            .await?;

        if response.status().is_success() {
            Ok(())
        } else {
            Err(format!("Slack delivery failed: {}", response.status()).into())
        }
    }

    fn supports_event_type(&self, event_type: &EventType) -> bool {
        // Support all event types
        true
    }
}

Event Transformation

use rustfs_notify::{Event, EventTransformer};
use serde_json::{json, Value};

pub struct CustomEventTransformer;

impl EventTransformer for CustomEventTransformer {
    fn transform(&self, event: &Event) -> Value {
        json!({
            "eventVersion": "2.1",
            "eventSource": "rustfs:s3",
            "eventTime": event.timestamp.to_rfc3339(),
            "eventName": event.event_type.to_string(),
            "s3": {
                "bucket": {
                    "name": event.bucket_name,
                    "arn": format!("arn:aws:s3:::{}", event.bucket_name)
                },
                "object": {
                    "key": event.object_name,
                    "size": event.object_size.unwrap_or(0),
                    "eTag": event.etag.as_ref().unwrap_or(&"".to_string()),
                }
            },
            "userIdentity": {
                "principalId": event.user_identity
            }
        })
    }
}

🏗️ Architecture

Notification System Architecture

Notify Architecture:
┌─────────────────────────────────────────────────────────────┐
│                    Event Publisher                          │
├─────────────────────────────────────────────────────────────┤
│   Event Filter   │   Event Queue   │   Event Transformer   │
├─────────────────────────────────────────────────────────────┤
│              Target Manager                                  │
├─────────────────────────────────────────────────────────────┤
│  Webhook Target  │   MQTT Target   │   Custom Targets       │
├─────────────────────────────────────────────────────────────┤
│              Delivery Engine                                 │
└─────────────────────────────────────────────────────────────┘

Supported Event Types

Event Type Description Triggers
ObjectCreated Object creation events PUT, POST, COPY
ObjectRemoved Object deletion events DELETE
ObjectAccessed Object access events GET, HEAD
ObjectRestore Object restoration events Restore operations
BucketCreated Bucket creation events CreateBucket
BucketRemoved Bucket deletion events DeleteBucket

Target Types

Target Protocol Use Case Reliability
Webhook HTTP/HTTPS Web applications, APIs High
MQTT MQTT IoT devices, real-time systems Medium
Message Queue AMQP, Redis Microservices, async processing High
Custom Any Specialized integrations Configurable

🧪 Testing

Run the test suite:

# Run all tests
cargo test

# Run integration tests
cargo test --test integration

# Test webhook delivery
cargo test webhook

# Test MQTT integration
cargo test mqtt

# Run with coverage
cargo test --features test-coverage

⚙️ Configuration

Basic Configuration

[notify]
# Global settings
enabled = true
max_concurrent_deliveries = 100
default_retry_attempts = 3
default_timeout = "30s"

# Queue settings
event_queue_size = 10000
batch_size = 100
batch_timeout = "5s"

# Dead letter queue
dlq_enabled = true
dlq_max_size = 1000

Target Configuration

[[notify.targets]]
type = "webhook"
id = "primary-webhook"
url = "https://api.example.com/webhook"
events = ["ObjectCreated", "ObjectRemoved"]
retry_attempts = 5
timeout = "30s"

[[notify.targets]]
type = "mqtt"
id = "iot-broker"
broker_url = "mqtt://broker.example.com:1883"
topic = "storage/events"
qos = 1
events = ["ObjectCreated"]

🚀 Performance

The notification system is designed for high-throughput scenarios:

  • Async Processing: Non-blocking event delivery
  • Batch Delivery: Efficient batch processing for high-volume events
  • Connection Pooling: Reused connections for better performance
  • Rate Limiting: Configurable rate limiting to prevent overwhelming targets

📋 Requirements

  • Rust: 1.70.0 or later
  • Platforms: Linux, macOS, Windows
  • Network: Outbound connectivity for target delivery
  • Memory: Scales with event queue size

This module is part of the RustFS ecosystem:

📚 Documentation

For comprehensive documentation, visit:

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

Licensed under the Apache License, Version 2.0. See LICENSE for details.


RustFS is a trademark of RustFS, Inc.
All other trademarks are the property of their respective owners.

Made with 📡 by the RustFS Team