refactor(backend): split stream routes into focused modules
This commit is contained in:
166
Backend/routes/streams/credentials.ts
Normal file
166
Backend/routes/streams/credentials.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { Router } from 'express';
|
||||
|
||||
import { mediaProvider } from '../../media/service';
|
||||
import { simpleStreamingEnabled } from '../../media/config';
|
||||
import { requireDeviceAuth } from '../../middleware/device-auth';
|
||||
import { writeAuditLog } from '../../services/audit';
|
||||
import { streamParamSchema } from './schemas';
|
||||
import { ensureStreamDeviceAuth, getOwnedStreamSession, isStreamParticipant } from './shared';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/:streamSessionId/publish-credentials', requireDeviceAuth, async (req, res) => {
|
||||
const parsedParams = streamParamSchema.safeParse(req.params);
|
||||
|
||||
if (!parsedParams.success) {
|
||||
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceAuth = ensureStreamDeviceAuth(req, res);
|
||||
if (!deviceAuth) return;
|
||||
|
||||
if (simpleStreamingEnabled) {
|
||||
res.status(409).json({ message: 'SIMPLE_STREAMING does not use publish credentials' });
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
|
||||
|
||||
if (!session) {
|
||||
res.status(404).json({ message: 'Stream session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.cameraDeviceId !== deviceAuth.deviceId) {
|
||||
res.status(403).json({ message: 'Only camera device can request publish credentials' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session.mediaSessionId || session.status !== 'streaming') {
|
||||
res.status(409).json({ message: 'Stream session is not ready for publish credentials' });
|
||||
return;
|
||||
}
|
||||
|
||||
const credentials = await mediaProvider.issuePublishCredentials({
|
||||
mediaSessionId: session.mediaSessionId,
|
||||
cameraDeviceId: session.cameraDeviceId,
|
||||
ownerUserId: session.ownerUserId,
|
||||
});
|
||||
|
||||
res.json(credentials);
|
||||
|
||||
await writeAuditLog({
|
||||
ownerUserId: session.ownerUserId,
|
||||
actorDeviceId: session.cameraDeviceId,
|
||||
action: 'stream.publish_credentials_issued',
|
||||
targetType: 'stream_session',
|
||||
targetId: session.id,
|
||||
metadata: { mediaProvider: credentials.provider },
|
||||
ipAddress: req.ip,
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/:streamSessionId/subscribe-credentials', requireDeviceAuth, async (req, res) => {
|
||||
const parsedParams = streamParamSchema.safeParse(req.params);
|
||||
|
||||
if (!parsedParams.success) {
|
||||
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceAuth = ensureStreamDeviceAuth(req, res);
|
||||
if (!deviceAuth) return;
|
||||
|
||||
if (simpleStreamingEnabled) {
|
||||
res.status(409).json({ message: 'SIMPLE_STREAMING does not use subscribe credentials' });
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
|
||||
|
||||
if (!session) {
|
||||
res.status(404).json({ message: 'Stream session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isStreamParticipant(session, deviceAuth.deviceId)) {
|
||||
res.status(403).json({ message: 'Device cannot request subscribe credentials for this stream' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session.mediaSessionId || session.status !== 'streaming') {
|
||||
res.status(409).json({ message: 'Stream is not active yet' });
|
||||
return;
|
||||
}
|
||||
|
||||
const credentials = await mediaProvider.issueSubscribeCredentials({
|
||||
mediaSessionId: session.mediaSessionId,
|
||||
viewerDeviceId: deviceAuth.deviceId,
|
||||
ownerUserId: session.ownerUserId,
|
||||
});
|
||||
|
||||
res.json(credentials);
|
||||
|
||||
await writeAuditLog({
|
||||
ownerUserId: session.ownerUserId,
|
||||
actorDeviceId: deviceAuth.deviceId,
|
||||
action: 'stream.subscribe_credentials_issued',
|
||||
targetType: 'stream_session',
|
||||
targetId: session.id,
|
||||
metadata: { mediaProvider: credentials.provider },
|
||||
ipAddress: req.ip,
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/:streamSessionId/playback-token', requireDeviceAuth, async (req, res) => {
|
||||
const parsedParams = streamParamSchema.safeParse(req.params);
|
||||
|
||||
if (!parsedParams.success) {
|
||||
res.status(400).json({ message: 'Invalid streamSessionId', errors: parsedParams.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceAuth = ensureStreamDeviceAuth(req, res);
|
||||
if (!deviceAuth) return;
|
||||
|
||||
if (simpleStreamingEnabled) {
|
||||
res.status(409).json({ message: 'SIMPLE_STREAMING does not issue playback tokens' });
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await getOwnedStreamSession(parsedParams.data.streamSessionId, deviceAuth.userId);
|
||||
|
||||
if (!session) {
|
||||
res.status(404).json({ message: 'Stream session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isStreamParticipant(session, deviceAuth.deviceId)) {
|
||||
res.status(403).json({ message: 'Device cannot request playback token for this stream' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session.streamKey || !session.mediaSessionId || session.status !== 'streaming') {
|
||||
res.status(409).json({ message: 'Stream is not active yet' });
|
||||
return;
|
||||
}
|
||||
|
||||
const credentials = await mediaProvider.issueSubscribeCredentials({
|
||||
mediaSessionId: session.mediaSessionId,
|
||||
viewerDeviceId: deviceAuth.deviceId,
|
||||
ownerUserId: deviceAuth.userId,
|
||||
});
|
||||
|
||||
res.json({
|
||||
streamSessionId: session.id,
|
||||
streamKey: session.streamKey,
|
||||
status: session.status,
|
||||
playbackToken: credentials.subscribeToken,
|
||||
subscribeUrl: credentials.subscribeUrl,
|
||||
mediaProvider: credentials.provider,
|
||||
expiresInSeconds: credentials.expiresInSeconds,
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user