This commit is contained in:
78
server/utils/livekit.ts
Normal file
78
server/utils/livekit.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Session, User } from 'lucia'
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { AccessToken } from 'livekit-server-sdk'
|
||||
import { SESSION_EXPIRES_IN } from '../auth/lucia.ts'
|
||||
import prisma from '../prisma/client.ts'
|
||||
|
||||
/**
|
||||
* Re-issue the token slightly before it actually expires, so a client that
|
||||
* caches the /me response for a while still gets a usable token.
|
||||
*/
|
||||
const REFRESH_BEFORE_EXPIRY_SECONDS = 60 * 60
|
||||
|
||||
export async function createLivekitToken(user: User, ttlSeconds: number) {
|
||||
const apiKey = process.env.LIVEKIT_API_KEY
|
||||
const apiSecret = process.env.LIVEKIT_API_SECRET
|
||||
|
||||
if (!apiKey || !apiSecret)
|
||||
throw new Error('LIVEKIT_API_KEY and LIVEKIT_API_SECRET must be set')
|
||||
|
||||
const token = new AccessToken(apiKey, apiSecret, {
|
||||
identity: user.id,
|
||||
name: user.displayName,
|
||||
ttl: ttlSeconds,
|
||||
})
|
||||
|
||||
token.addGrant({
|
||||
room: process.env.LIVEKIT_ROOM || 'chad',
|
||||
roomJoin: true,
|
||||
canPublish: true,
|
||||
canSubscribe: true,
|
||||
canPublishData: true,
|
||||
canUpdateOwnMetadata: true,
|
||||
})
|
||||
|
||||
return token.toJwt()
|
||||
}
|
||||
|
||||
/** Mints the token that gets stored on a session at the moment it is created. */
|
||||
export function createSessionLivekitToken(user: User) {
|
||||
return createLivekitToken(user, SESSION_EXPIRES_IN.seconds())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token stored alongside the session, re-issuing and persisting it
|
||||
* when it is missing (session predates the column) or about to expire (Lucia
|
||||
* extends `expiresAt` on active sessions, outliving the original token).
|
||||
*/
|
||||
export async function getSessionLivekitToken(user: User, session: Session) {
|
||||
if (session.livekitToken && !isExpiringSoon(session.livekitToken))
|
||||
return session.livekitToken
|
||||
|
||||
const ttlSeconds = Math.max(
|
||||
Math.ceil((session.expiresAt.getTime() - Date.now()) / 1000),
|
||||
REFRESH_BEFORE_EXPIRY_SECONDS,
|
||||
)
|
||||
const livekitToken = await createLivekitToken(user, ttlSeconds)
|
||||
|
||||
await prisma.session.update({
|
||||
where: { id: session.id },
|
||||
data: { livekitToken },
|
||||
})
|
||||
|
||||
session.livekitToken = livekitToken
|
||||
|
||||
return livekitToken
|
||||
}
|
||||
|
||||
function isExpiringSoon(token: string) {
|
||||
try {
|
||||
const [, payload] = token.split('.')
|
||||
const { exp } = JSON.parse(Buffer.from(payload, 'base64url').toString())
|
||||
|
||||
return typeof exp !== 'number' || exp - REFRESH_BEFORE_EXPIRY_SECONDS <= Date.now() / 1000
|
||||
}
|
||||
catch {
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user