136 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 弹幕API - 支持SSE实时推送和普通查询
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
// GET - 获取弹幕列表(支持SSE实时推送)
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const isSSE = searchParams.get('sse') === 'true';
// SSE模式 - 实时推送弹幕
if (isSSE) {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
// 首次发送最近50条弹幕
const recentDanmaku = await prisma.danmaku.findMany({
orderBy: { createdAt: 'desc' },
take: 50,
});
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(recentDanmaku)}\n\n`)
);
// 每秒检查新弹幕
const interval = setInterval(async () => {
try {
const newDanmaku = await prisma.danmaku.findMany({
orderBy: { createdAt: 'desc' },
take: 1,
});
if (newDanmaku.length > 0) {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(newDanmaku[0])}\n\n`)
);
}
} catch (error) {
console.error('SSE error:', error);
}
}, 1000);
// 客户端断开连接时清理
request.signal.addEventListener('abort', () => {
clearInterval(interval);
controller.close();
});
},
});
return new NextResponse(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
}
// 普通模式 - 返回弹幕列表
const limit = parseInt(searchParams.get('limit') || '50');
const danmaku = await prisma.danmaku.findMany({
orderBy: { createdAt: 'desc' },
take: limit,
});
return NextResponse.json(danmaku);
} catch (error) {
console.error('Get danmaku error:', error);
return NextResponse.json(
{ error: '获取弹幕失败' },
{ status: 500 }
);
}
}
// POST - 发送弹幕
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json(
{ error: '请先登录' },
{ status: 401 }
);
}
const { content } = await request.json();
// 验证弹幕内容
if (!content || content.trim().length === 0) {
return NextResponse.json(
{ error: '弹幕内容不能为空' },
{ status: 400 }
);
}
if (content.length > 100) {
return NextResponse.json(
{ error: '弹幕内容不能超过100字' },
{ status: 400 }
);
}
// 随机匿名昵称
const anonymousNames = [
'神秘访客', '路过的设计师', '热心网友', '匿名用户',
'悄悄路过', '神秘嘉宾', '隐身大佬', '低调看客',
'默默围观', '潜水员', '匿名网友', '神秘人士'
];
const randomName = anonymousNames[Math.floor(Math.random() * anonymousNames.length)];
// 创建弹幕
const userId = (session.user as any).id;
const danmaku = await prisma.danmaku.create({
data: {
content: content.trim(),
username: randomName,
userId: userId,
},
});
return NextResponse.json(danmaku);
} catch (error) {
console.error('Send danmaku error:', error);
return NextResponse.json(
{ error: '发送弹幕失败' },
{ status: 500 }
);
}
}