This commit is contained in:
2025-09-09 11:09:43 +04:00
parent 458486486d
commit 0145de19a3
54 changed files with 11278 additions and 1 deletions

View File

@@ -0,0 +1,89 @@
import { randomString } from '@/lib/client-utils';
import { getLiveKitURL } from '@/lib/getLiveKitURL';
import { ConnectionDetails } from '@/lib/types';
import { AccessToken, AccessTokenOptions, VideoGrant } from 'livekit-server-sdk';
import { NextRequest, NextResponse } from 'next/server';
const API_KEY = process.env.LIVEKIT_API_KEY;
const API_SECRET = process.env.LIVEKIT_API_SECRET;
const LIVEKIT_URL = process.env.LIVEKIT_URL;
const COOKIE_KEY = 'random-participant-postfix';
export async function GET(request: NextRequest) {
try {
// Parse query parameters
const roomName = request.nextUrl.searchParams.get('roomName');
const participantName = request.nextUrl.searchParams.get('participantName');
const metadata = request.nextUrl.searchParams.get('metadata') ?? '';
const region = request.nextUrl.searchParams.get('region');
if (!LIVEKIT_URL) {
throw new Error('LIVEKIT_URL is not defined');
}
const livekitServerUrl = region ? getLiveKitURL(LIVEKIT_URL, region) : LIVEKIT_URL;
let randomParticipantPostfix = request.cookies.get(COOKIE_KEY)?.value;
if (livekitServerUrl === undefined) {
throw new Error('Invalid region');
}
if (typeof roomName !== 'string') {
return new NextResponse('Missing required query parameter: roomName', { status: 400 });
}
if (participantName === null) {
return new NextResponse('Missing required query parameter: participantName', { status: 400 });
}
// Generate participant token
if (!randomParticipantPostfix) {
randomParticipantPostfix = randomString(4);
}
const participantToken = await createParticipantToken(
{
identity: `${participantName}__${randomParticipantPostfix}`,
name: participantName,
metadata,
},
roomName,
);
// Return connection details
const data: ConnectionDetails = {
serverUrl: livekitServerUrl,
roomName: roomName,
participantToken: participantToken,
participantName: participantName,
};
return new NextResponse(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Set-Cookie': `${COOKIE_KEY}=${randomParticipantPostfix}; Path=/; HttpOnly; SameSite=Strict; Secure; Expires=${getCookieExpirationTime()}`,
},
});
} catch (error) {
if (error instanceof Error) {
return new NextResponse(error.message, { status: 500 });
}
}
}
function createParticipantToken(userInfo: AccessTokenOptions, roomName: string) {
const at = new AccessToken(API_KEY, API_SECRET, userInfo);
at.ttl = '5m';
const grant: VideoGrant = {
room: roomName,
roomJoin: true,
canPublish: true,
canPublishData: true,
canSubscribe: true,
};
at.addGrant(grant);
return at.toJwt();
}
function getCookieExpirationTime(): string {
var now = new Date();
var time = now.getTime();
var expireTime = time + 60 * 120 * 1000;
now.setTime(expireTime);
return now.toUTCString();
}