Airweave推送通知:Web Push API的实时提醒

Airweave推送通知:Web Push API的实时提醒

【免费下载链接】airweave Turn any app into agent knowledge 【免费下载链接】airweave 项目地址: https://gitcode.com/GitHub_Trending/ai/airweave

概述

在现代Web应用中,实时通知是提升用户体验的关键功能。Airweave作为一个强大的数据同步和搜索平台,可以通过集成Web Push API来实现实时的推送通知功能。本文将深入探讨如何在Airweave中实现Web Push API,为用户提供实时的数据同步状态、搜索结果和系统事件通知。

Web Push API基础

什么是Web Push API?

Web Push API是一种浏览器技术,允许网站向用户发送推送通知,即使用户没有主动访问该网站。它基于Service Worker和Push API构建,是现代Web应用的重要功能。

核心组件

mermaid

在Airweave中集成Web Push API

1. Service Worker注册

首先需要在Airweave前端注册Service Worker:

// frontend/src/utils/push-notification.ts
export async function registerServiceWorker(): Promise<ServiceWorkerRegistration> {
  if (!('serviceWorker' in navigator)) {
    throw new Error('Service workers are not supported');
  }

  const registration = await navigator.serviceWorker.register('/sw.js', {
    scope: '/'
  });

  return registration;
}

export async function requestNotificationPermission(): Promise<NotificationPermission> {
  return await Notification.requestPermission();
}

2. Service Worker实现

创建Service Worker文件处理推送事件:

// frontend/public/sw.js
self.addEventListener('push', (event) => {
  if (event.data) {
    const data = event.data.json();
    const options = {
      body: data.body,
      icon: '/logo-192x192.png',
      badge: '/badge-72x72.png',
      vibrate: [200, 100, 200],
      tag: data.tag || 'airweave-notification',
      data: {
        url: data.url || '/'
      }
    };

    event.waitUntil(
      self.registration.showNotification(data.title, options)
    );
  }
});

self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  
  if (event.notification.data && event.notification.data.url) {
    event.waitUntil(
      clients.openWindow(event.notification.data.url)
    );
  }
});

3. 后端推送服务

在Airweave后端实现推送服务:

# backend/airweave/core/push_service.py
import json
from typing import Dict, List
from pywebpush import webpush, WebPushException
import jwt
from datetime import datetime, timedelta
from airweave.core.config import settings

class PushNotificationService:
    def __init__(self):
        self.vapid_private_key = settings.VAPID_PRIVATE_KEY
        self.vapid_public_key = settings.VAPID_PUBLIC_KEY
        self.vapid_claims = {
            "sub": f"mailto:{settings.SUPPORT_EMAIL}",
            "exp": datetime.utcnow() + timedelta(hours=12)
        }

    async def send_notification(
        self, 
        subscription: Dict, 
        title: str, 
        body: str, 
        data: Dict = None
    ) -> bool:
        """
        发送推送通知
        
        Args:
            subscription: 用户订阅信息
            title: 通知标题
            body: 通知内容
            data: 附加数据
            
        Returns:
            bool: 发送是否成功
        """
        payload = {
            "title": title,
            "body": body,
            "data": data or {}
        }

        try:
            vapid_claims = {
                "sub": f"mailto:{settings.SUPPORT_EMAIL}",
                "exp": datetime.utcnow() + timedelta(hours=12)
            }
            
            webpush(
                subscription_info=subscription,
                data=json.dumps(payload),
                vapid_private_key=self.vapid_private_key,
                vapid_claims=vapid_claims
            )
            return True
        except WebPushException as e:
            if e.response.status_code == 410:
                # 订阅已过期,需要从数据库中删除
                return False
            return False

推送通知场景实现

1. 数据同步完成通知

# backend/airweave/core/sync_service.py
from airweave.core.push_service import PushNotificationService

class EnhancedSyncService(SyncService):
    def __init__(self, db: AsyncSession):
        super().__init__(db)
        self.push_service = PushNotificationService()

    async def handle_sync_completion(
        self, 
        sync_job_id: UUID, 
        user_id: UUID,
        status: SyncJobStatus
    ):
        """处理同步完成事件并发送推送通知"""
        # 获取用户推送订阅
        user_subscriptions = await self.get_user_push_subscriptions(user_id)
        
        if status == SyncJobStatus.COMPLETED:
            message = "数据同步已完成"
        elif status == SyncJobStatus.FAILED:
            message = "数据同步失败,请检查日志"
        else:
            message = f"同步状态更新: {status.value}"

        for subscription in user_subscriptions:
            await self.push_service.send_notification(
                subscription=subscription,
                title="Airweave同步通知",
                body=message,
                data={
                    "type": "sync_completion",
                    "sync_job_id": str(sync_job_id),
                    "status": status.value
                }
            )

2. 实时搜索结果通知

// frontend/src/hooks/usePushNotifications.ts
import { useCallback } from 'react';
import { useToast } from './use-toast';

export const usePushNotifications = () => {
  const { toast } = useToast();

  const subscribeToPush = useCallback(async (): Promise<PushSubscription | null> => {
    try {
      const registration = await navigator.serviceWorker.ready;
      const subscription = await registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: process.env.VAPID_PUBLIC_KEY
      });

      // 将订阅信息发送到后端
      await fetch('/api/push/subscribe', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(subscription),
      });

      toast({
        title: '推送通知已启用',
        description: '您将收到实时的搜索和同步通知',
      });

      return subscription;
    } catch (error) {
      console.error('推送订阅失败:', error);
      toast({
        title: '推送通知启用失败',
        description: '请检查浏览器设置',
        variant: 'destructive',
      });
      return null;
    }
  }, [toast]);

  return { subscribeToPush };
};

安全性和最佳实践

VAPID密钥管理

# backend/airweave/core/config.py
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    # VAPID配置
    VAPID_PRIVATE_KEY: str
    VAPID_PUBLIC_KEY: str
    VAPID_SUBJECT: str = "mailto:support@airweave.ai"
    
    class Config:
        env_file = ".env"

settings = Settings()

通知权限管理

// frontend/src/components/NotificationPermission.tsx
import { useState } from 'react';
import { Button } from './ui/button';
import { Bell, BellOff } from 'lucide-react';
import { usePushNotifications } from '../hooks/usePushNotifications';

export const NotificationPermission: React.FC = () => {
  const [permission, setPermission] = useState(Notification.permission);
  const { subscribeToPush } = usePushNotifications();

  const handleEnableNotifications = async () => {
    if (permission === 'default') {
      const newPermission = await Notification.requestPermission();
      setPermission(newPermission);
      
      if (newPermission === 'granted') {
        await subscribeToPush();
      }
    } else if (permission === 'denied') {
      // 指导用户如何手动启用通知
      alert('请在浏览器设置中启用通知权限');
    }
  };

  return (
    <Button
      variant="outline"
      onClick={handleEnableNotifications}
      disabled={permission === 'granted'}
    >
      {permission === 'granted' ? (
        <>
          <Bell className="w-4 h-4 mr-2" />
          通知已启用
        </>
      ) : (
        <>
          <BellOff className="w-4 h-4 mr-2" />
          启用通知
        </>
      )}
    </Button>
  );
};

性能优化

批量通知发送

# backend/airweave/core/batch_push_service.py
import asyncio
from typing import List, Dict
from airweave.core.push_service import PushNotificationService

class BatchPushService:
    def __init__(self, max_concurrent: int = 10):
        self.push_service = PushNotificationService()
        self.max_concurrent = max_concurrent
        self.semaphore = asyncio.Semaphore(max_concurrent)

    async def send_batch_notifications(
        self,
        subscriptions: List[Dict],
        title: str,
        body: str,
        data: Dict = None
    ) -> Dict[str, int]:
        """
        批量发送推送通知
        
        Returns:
            Dict: 包含成功和失败数量的统计
        """
        results = {
            "success": 0,
            "failed": 0,
            "expired": 0
        }

        async def send_single(subscription: Dict):
            async with self.semaphore:
                try:
                    success = await self.push_service.send_notification(
                        subscription, title, body, data
                    )
                    if success:
                        results["success"] += 1
                    else:
                        results["expired"] += 1
                except Exception:
                    results["failed"] += 1

        tasks = [send_single(sub) for sub in subscriptions]
        await asyncio.gather(*tasks, return_exceptions=True)
        
        return results

通知去重和节流

# backend/airweave/core/notification_throttler.py
from datetime import datetime, timedelta
from collections import defaultdict
import asyncio

class NotificationThrottler:
    def __init__(self, cooldown_period: timedelta = timedelta(minutes=5)):
        self.cooldown_period = cooldown_period
        self.last_notification_time = defaultdict(lambda: datetime.min)

    def should_send_notification(self, user_id: str, notification_type: str) -> bool:
        key = f"{user_id}:{notification_type}"
        now = datetime.now()
        
        if now - self.last_notification_time[key] >= self.cooldown_period:
            self.last_notification_time[key] = now
            return True
        return False

监控和日志

推送通知监控

# backend/airweave/core/monitoring.py
from prometheus_client import Counter, Histogram

# 指标定义
PUSH_NOTIFICATIONS_SENT = Counter(
    'push_notifications_sent_total',
    'Total push notifications sent',
    ['status']
)

PUSH_NOTIFICATION_LATENCY = Histogram(
    'push_notification_latency_seconds',
    'Push notification delivery latency',
    ['status']
)

class PushNotificationMonitor:
    @staticmethod
    def record_notification_sent(success: bool):
        status = 'success' if success else 'failure'
        PUSH_NOTIFICATIONS_SENT.labels(status=status).inc()

    @staticmethod
    def record_latency(latency: float, success: bool):
        status = 'success' if success else 'failure'
        PUSH_NOTIFICATION_LATENCY.labels(status=status).observe(latency)

部署配置

Docker配置

# 在Dockerfile中添加推送相关配置
ENV VAPID_PUBLIC_KEY=your_public_key_here
ENV VAPID_PRIVATE_KEY=your_private_key_here
ENV VAPID_SUBJECT=mailto:support@airweave.ai

# 确保Service Worker文件被正确服务
COPY frontend/public/sw.js /app/frontend/public/sw.js

Nginx配置

# 确保Service Worker文件可以被正确缓存
location /sw.js {
    add_header Cache-Control "public, max-age=0";
    add_header Service-Worker-Allowed "/";
    try_files $uri $uri/ =404;
}

location /push-manifest.json {
    add_header Cache-Control "public, max-age=3600";
}

测试策略

单元测试

# tests/unit/core/test_push_service.py
import pytest
from unittest.mock import AsyncMock, patch
from airweave.core.push_service import PushNotificationService

@pytest.mark.asyncio
async def test_send_notification_success():
    service = PushNotificationService()
    subscription = {
        "endpoint": "https://fcm.googleapis.com/fcm/send/test",
        "keys": {
            "p256dh": "test_key",
            "auth": "test_auth"
        }
    }
    
    with patch('pywebpush.webpush') as mock_webpush:
        mock_webpush.return_value = None
        result = await service.send_notification(
            subscription, "Test", "Message"
        )
        
        assert result is True
        mock_webpush.assert_called_once()

集成测试

// frontend/src/__tests__/push-notification.test.ts
import { registerServiceWorker } from '../utils/push-notification';

describe('Push Notification Service', () => {
  beforeEach(() => {
    // 模拟Service Worker API
    Object.defineProperty(navigator, 'serviceWorker', {
      value: {
        register: jest.fn().mockResolvedValue({}),
      },
      writable: true,
    });
  });

  test('should register service worker successfully', async () => {
    const registration = await registerServiceWorker();
    expect(registration).toBeDefined();
    expect(navigator.serviceWorker.register).toHaveBeenCalledWith('/sw.js', {
      scope: '/'
    });
  });
});

总结

通过集成Web Push API,Airweave可以为用户提供实时的数据同步状态、搜索结果和系统事件通知,大大提升了用户体验。本文详细介绍了从Service Worker注册到后端推送服务的完整实现方案,包括安全性、性能优化和监控等关键方面。

关键优势:

  • 实时性: 用户无需刷新页面即可收到最新通知
  • 跨平台: 支持桌面和移动设备
  • 个性化: 基于用户订阅的精准通知推送
  • 可扩展: 支持大规模并发推送

通过合理的架构设计和最佳实践,Airweave的推送通知系统可以稳定可靠地服务大量用户,为用户提供卓越的实时体验。

【免费下载链接】airweave Turn any app into agent knowledge 【免费下载链接】airweave 项目地址: https://gitcode.com/GitHub_Trending/ai/airweave

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值