【m】修改为服务器录屏
This commit is contained in:
157
src/server.ts
157
src/server.ts
@@ -7,6 +7,29 @@ import signaling from './signaling';
|
||||
import { log, LogLevel } from './log';
|
||||
import Options from './class/options';
|
||||
import { reset as resetHandler } from './class/httphandler';
|
||||
import {
|
||||
broadcastRecordingPeerRequest,
|
||||
broadcastRecordingStarted,
|
||||
broadcastRecordingStopped,
|
||||
onGetRooms as getWebSocketRooms
|
||||
} from './class/websockethandler';
|
||||
import {
|
||||
getRecordingAgent,
|
||||
startRecordingAgent,
|
||||
stopRecordingAgent
|
||||
} from './recording/agent';
|
||||
import {
|
||||
getRecordingSession,
|
||||
listRecordingSessions,
|
||||
startRecordingSession,
|
||||
stopRecordingSession
|
||||
} from './recording/session-manager';
|
||||
import {
|
||||
getRecordingCompositionJob,
|
||||
listRecordingCompositionJobs,
|
||||
startRecordingCompositionJob
|
||||
} from './recording/composer';
|
||||
import { stopRecordingPeer } from './recording/werift-adapter';
|
||||
import { initSwagger } from './swagger';
|
||||
|
||||
const cors = require('cors');
|
||||
@@ -139,7 +162,15 @@ function sanitizeMetadataString(value: any, maxLength = 200): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
return String(value).replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, maxLength);
|
||||
return String(value)
|
||||
.split('')
|
||||
.filter((character) => {
|
||||
const code = character.charCodeAt(0);
|
||||
return code >= 32 && code !== 127;
|
||||
})
|
||||
.join('')
|
||||
.trim()
|
||||
.slice(0, maxLength);
|
||||
}
|
||||
|
||||
function sanitizeRecordingPerson(value: any, fallbackRole: string): RecordingPerson | undefined {
|
||||
@@ -285,6 +316,16 @@ function removeEmptyDirectory(directory: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
function getActiveRecordingSession(connectionId: string) {
|
||||
const sessions = listRecordingSessions(connectionId);
|
||||
for (const session of sessions) {
|
||||
if (session.status === 'recording') {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const createServer = (config: Options): express.Express => {
|
||||
const app: express.Express = express();
|
||||
resetHandler(config.mode);
|
||||
@@ -452,6 +493,120 @@ export const createServer = (config: Options): express.Express => {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/recording-sessions', (req: express.Request, res: express.Response) => {
|
||||
const connectionId = typeof req.query.connectionId === 'string'
|
||||
? sanitizeMetadataString(req.query.connectionId, 120)
|
||||
: undefined;
|
||||
const sessions = listRecordingSessions(connectionId);
|
||||
res.json({ success: true, sessions, totalCount: sessions.length });
|
||||
});
|
||||
|
||||
app.get('/api/recording-sessions/:recordingId', (req: express.Request, res: express.Response) => {
|
||||
const session = getRecordingSession(req.params.recordingId);
|
||||
if (!session) {
|
||||
res.status(404).json({ success: false, message: 'Recording session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, session, agent: getRecordingAgent(session.id) });
|
||||
});
|
||||
|
||||
app.post('/api/recording-sessions', (req: express.Request, res: express.Response) => {
|
||||
const connectionId = sanitizeMetadataString(req.body.connectionId, 120);
|
||||
if (!connectionId) {
|
||||
res.status(400).json({ success: false, message: 'connectionId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.type === 'websocket' && getWebSocketRooms(connectionId).length === 0) {
|
||||
res.status(404).json({ success: false, message: 'Active WebSocket room not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
const activeSession = getActiveRecordingSession(connectionId);
|
||||
if (activeSession) {
|
||||
res.status(409).json({ success: false, message: 'Recording is already running', session: activeSession });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const session = startRecordingSession({
|
||||
connectionId,
|
||||
layout: req.body.layout,
|
||||
format: req.body.format
|
||||
});
|
||||
const agent = startRecordingAgent(session);
|
||||
const notified = broadcastRecordingStarted(session);
|
||||
const peerRequestNotified = broadcastRecordingPeerRequest(session);
|
||||
res.status(201).json({ success: true, session, agent, notified, peerRequestNotified });
|
||||
} catch (error) {
|
||||
log(LogLevel.error, 'Failed to start recording session:', error);
|
||||
res.status(500).json({ success: false, message: 'Failed to start recording session' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/recording-sessions/:recordingId', async (req: express.Request, res: express.Response) => {
|
||||
const session = stopRecordingSession(req.params.recordingId);
|
||||
if (!session) {
|
||||
res.status(404).json({ success: false, message: 'Recording session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
const notified = broadcastRecordingStopped(session);
|
||||
const agent = stopRecordingAgent(session.id);
|
||||
try {
|
||||
await stopRecordingPeer(session.id);
|
||||
} catch (error) {
|
||||
log(LogLevel.warn, 'Failed to stop recording peer:', error);
|
||||
}
|
||||
|
||||
const shouldCompose = req.query.compose !== 'false';
|
||||
const compositionJob = shouldCompose
|
||||
? startRecordingCompositionJob({
|
||||
meetingId: session.connectionId,
|
||||
recordingId: session.id,
|
||||
layout: session.layout,
|
||||
format: session.format
|
||||
})
|
||||
: null;
|
||||
res.json({ success: true, session, agent, notified, compositionJob });
|
||||
});
|
||||
|
||||
app.get('/api/recording-compositions', (req: express.Request, res: express.Response) => {
|
||||
const meetingId = typeof req.query.meetingId === 'string'
|
||||
? sanitizePathSegment(req.query.meetingId, 'unknown')
|
||||
: undefined;
|
||||
const jobs = listRecordingCompositionJobs(meetingId);
|
||||
res.json({ success: true, jobs, totalCount: jobs.length });
|
||||
});
|
||||
|
||||
app.get('/api/recording-compositions/:compositionId', (req: express.Request, res: express.Response) => {
|
||||
const job = getRecordingCompositionJob(req.params.compositionId);
|
||||
if (!job) {
|
||||
res.status(404).json({ success: false, message: 'Recording composition job not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, job });
|
||||
});
|
||||
|
||||
app.post('/api/recording-compositions', (req: express.Request, res: express.Response) => {
|
||||
const meetingId = sanitizeMetadataString(req.body.meetingId, 120);
|
||||
const recordingId = sanitizeMetadataString(req.body.recordingId, 120);
|
||||
if (!meetingId || !recordingId) {
|
||||
res.status(400).json({ success: false, message: 'meetingId and recordingId are required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const job = startRecordingCompositionJob({
|
||||
meetingId,
|
||||
recordingId,
|
||||
layout: req.body.layout,
|
||||
format: req.body.format
|
||||
});
|
||||
res.status(202).json({ success: true, job });
|
||||
});
|
||||
|
||||
app.get('/api/recordings', (_req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const recordings = listRecordings(recordingRoot);
|
||||
|
||||
Reference in New Issue
Block a user