'use client'; import { useEffect, useRef, useState } from 'react'; import Sidebar from '@/components/Sidebar'; import { Activity, Pause, Play } from 'lucide-react'; type StreamMessage = { local_id: number; username: string; chat_name: string; sender: string; content: string; time: string; timestamp: number; type: string; }; type StreamEvent = | { type: 'open'; interval: number } | { type: 'tick'; count: number; items: StreamMessage[]; ts: number } | { type: 'error'; error: string }; export default function SignalsPage() { const [items, setItems] = useState([]); const [running, setRunning] = useState(true); const [lastTick, setLastTick] = useState(null); const [err, setErr] = useState(null); const ctlRef = useRef(null); useEffect(() => { if (!running) { ctlRef.current?.abort(); ctlRef.current = null; return; } const ctl = new AbortController(); ctlRef.current = ctl; (async () => { try { const r = await fetch('/api/new-messages', { signal: ctl.signal }); if (!r.body) return; const reader = r.body.getReader(); const dec = new TextDecoder(); let buf = ''; while (true) { const { value, done } = await reader.read(); if (done) break; buf += dec.decode(value, { stream: true }); let nl; while ((nl = buf.indexOf('\n\n')) !== -1) { const chunk = buf.slice(0, nl).trim(); buf = buf.slice(nl + 2); if (!chunk.startsWith('data:')) continue; try { const evt = JSON.parse(chunk.slice(5).trim()) as StreamEvent; if (evt.type === 'tick') { setLastTick(evt.ts); setErr(null); if (evt.items.length) { setItems((prev) => [...evt.items, ...prev].slice(0, 200)); } } else if (evt.type === 'error') { setErr(evt.error); } } catch {} } } } catch (e) { if ((e as Error).name !== 'AbortError') setErr((e as Error).message); } })(); return () => ctl.abort(); }, [running]); return (
Live Signals
信号流 · 实时
{err ? `错误:${err}` : lastTick ? `上次刷新:${new Date(lastTick).toLocaleTimeString()} · ${items.length} 条已收` : '等待第一条消息…'}
{items.length === 0 ? (
等待新消息(每 5 秒拉取一次)…
) : (
{items.map((m, i) => ( ))}
)}
); } function Row({ m }: { m: StreamMessage }) { return (
{m.chat_name}
{m.sender}
{m.content}
类型:{m.type}
{m.time}
); }