feat(media): add phase5 media provider abstraction and stream credentials APIs
This commit is contained in:
96
Backend/media/providers/mock.ts
Normal file
96
Backend/media/providers/mock.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { createHmac } from 'crypto';
|
||||
|
||||
import type {
|
||||
MediaProvider,
|
||||
MediaPublishCredentials,
|
||||
MediaSessionCreateInput,
|
||||
MediaSessionCreateResult,
|
||||
MediaSubscribeCredentials,
|
||||
} from '../types';
|
||||
|
||||
const secret = process.env.BETTER_AUTH_SECRET;
|
||||
|
||||
if (!secret) {
|
||||
throw new Error('BETTER_AUTH_SECRET is required for mock media provider token signing');
|
||||
}
|
||||
|
||||
const DEFAULT_TTL_SECONDS = 60 * 10;
|
||||
|
||||
const signToken = (payload: Record<string, unknown>, ttlSeconds = DEFAULT_TTL_SECONDS): { token: string; expiresInSeconds: number } => {
|
||||
const body = {
|
||||
...payload,
|
||||
exp: Math.floor(Date.now() / 1000) + ttlSeconds,
|
||||
};
|
||||
|
||||
const encoded = Buffer.from(JSON.stringify(body), 'utf8').toString('base64url');
|
||||
const signature = createHmac('sha256', secret).update(encoded).digest('base64url');
|
||||
|
||||
return {
|
||||
token: `${encoded}.${signature}`,
|
||||
expiresInSeconds: ttlSeconds,
|
||||
};
|
||||
};
|
||||
|
||||
const getBaseUrl = (): string => process.env.MEDIA_MOCK_BASE_URL ?? process.env.BETTER_AUTH_URL ?? 'http://localhost:3000';
|
||||
|
||||
export class MockMediaProvider implements MediaProvider {
|
||||
name = 'mock';
|
||||
|
||||
async createSession(input: MediaSessionCreateInput): Promise<MediaSessionCreateResult> {
|
||||
const mediaSessionId = `mock_${input.streamSessionId}`;
|
||||
const baseUrl = getBaseUrl();
|
||||
|
||||
return {
|
||||
provider: this.name,
|
||||
mediaSessionId,
|
||||
publishUrl: `${baseUrl}/media/mock/publish/${mediaSessionId}`,
|
||||
subscribeUrl: `${baseUrl}/media/mock/subscribe/${mediaSessionId}`,
|
||||
};
|
||||
}
|
||||
|
||||
async issuePublishCredentials(input: {
|
||||
mediaSessionId: string;
|
||||
cameraDeviceId: string;
|
||||
ownerUserId: string;
|
||||
}): Promise<MediaPublishCredentials> {
|
||||
const baseUrl = getBaseUrl();
|
||||
const { token, expiresInSeconds } = signToken({
|
||||
typ: 'publish',
|
||||
provider: this.name,
|
||||
mediaSessionId: input.mediaSessionId,
|
||||
cameraDeviceId: input.cameraDeviceId,
|
||||
ownerUserId: input.ownerUserId,
|
||||
});
|
||||
|
||||
return {
|
||||
provider: this.name,
|
||||
mediaSessionId: input.mediaSessionId,
|
||||
publishToken: token,
|
||||
publishUrl: `${baseUrl}/media/mock/publish/${input.mediaSessionId}`,
|
||||
expiresInSeconds,
|
||||
};
|
||||
}
|
||||
|
||||
async issueSubscribeCredentials(input: {
|
||||
mediaSessionId: string;
|
||||
viewerDeviceId: string;
|
||||
ownerUserId: string;
|
||||
}): Promise<MediaSubscribeCredentials> {
|
||||
const baseUrl = getBaseUrl();
|
||||
const { token, expiresInSeconds } = signToken({
|
||||
typ: 'subscribe',
|
||||
provider: this.name,
|
||||
mediaSessionId: input.mediaSessionId,
|
||||
viewerDeviceId: input.viewerDeviceId,
|
||||
ownerUserId: input.ownerUserId,
|
||||
});
|
||||
|
||||
return {
|
||||
provider: this.name,
|
||||
mediaSessionId: input.mediaSessionId,
|
||||
subscribeToken: token,
|
||||
subscribeUrl: `${baseUrl}/media/mock/subscribe/${input.mediaSessionId}`,
|
||||
expiresInSeconds,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user