feat(recorders): add PortBindings for SRT/RTMP listener mode containers

When source_config.mode === 'listener':
- SRT: bind UDP listen_port (default 9000) on container host
- RTMP: bind TCP listen_port (default 1935) on container host
Add ExposedPorts to container config alongside HostConfig.PortBindings.
Also pass LISTEN, LISTEN_PORT, STREAM_KEY env vars to container.
This commit is contained in:
Zac Gaetano 2026-05-16 08:21:03 -04:00
parent 55fec605c6
commit 78b1f3482f

View file

@ -46,6 +46,31 @@ function generateClipName(recorderName) {
return `${recorderName}_${year}${month}${day}_${hours}${minutes}${seconds}`;
}
/**
* Build Docker PortBindings and ExposedPorts for listener-mode recorders.
* Returns { portBindings, exposedPorts } both empty objects for non-listener sources.
*/
function buildPortConfig(sourceType, sourceConfig) {
const portBindings = {};
const exposedPorts = {};
if (sourceConfig && sourceConfig.mode === 'listener') {
if (sourceType === 'srt') {
const port = String(sourceConfig.listen_port || 9000);
const proto = `${port}/udp`;
portBindings[proto] = [{ HostPort: port }];
exposedPorts[proto] = {};
} else if (sourceType === 'rtmp') {
const port = String(sourceConfig.listen_port || 1935);
const proto = `${port}/tcp`;
portBindings[proto] = [{ HostPort: port }];
exposedPorts[proto] = {};
}
}
return { portBindings, exposedPorts };
}
// GET / - List all recorders
router.get('/', async (req, res, next) => {
try {
@ -172,30 +197,57 @@ router.post('/:id/start', async (req, res, next) => {
// Generate clip name with timestamp
const clipName = generateClipName(recorder.name);
// Determine source config and whether this is a listener-mode recorder
const sourceConfig = recorder.source_config || {};
const isListener = sourceConfig.mode === 'listener';
const sourceType = recorder.source_type;
// Build port bindings for listener-mode SRT/RTMP containers
const { portBindings, exposedPorts } = buildPortConfig(sourceType, sourceConfig);
// Build container environment — pass all source params so the capture
// service can auto-start recording on container startup
const env = [
`S3_ENDPOINT=${s3Endpoint}`,
`S3_BUCKET=${s3Bucket}`,
`S3_ACCESS_KEY=${s3AccessKey}`,
`S3_SECRET_KEY=${s3SecretKey}`,
`S3_REGION=${process.env.S3_REGION || 'us-east-1'}`,
`MAM_API_URL=${mamApiUrl}`,
`RECORDER_ID=${id}`,
`SOURCE_TYPE=${sourceType}`,
`SOURCE_CONFIG=${JSON.stringify(sourceConfig)}`,
`RECORDING_CODEC=${recorder.recording_codec}`,
`RECORDING_RESOLUTION=${recorder.recording_resolution}`,
`PROXY_ENABLED=${recorder.proxy_enabled}`,
`PROXY_CODEC=${recorder.proxy_codec}`,
`PROXY_RESOLUTION=${recorder.proxy_resolution}`,
`PROJECT_ID=${recorder.project_id}`,
`CLIP_NAME=${clipName}`,
];
// Add source-specific env vars for SRT/RTMP
if (sourceType === 'srt' || sourceType === 'rtmp') {
env.push(`LISTEN=${isListener ? '1' : '0'}`);
if (isListener) {
env.push(`LISTEN_PORT=${sourceConfig.listen_port || (sourceType === 'srt' ? 9000 : 1935)}`);
if (sourceType === 'rtmp' && sourceConfig.stream_key) {
env.push(`STREAM_KEY=${sourceConfig.stream_key}`);
}
} else if (sourceConfig.url) {
env.push(`SOURCE_URL=${sourceConfig.url}`);
}
}
// Build container config
const containerConfig = {
Image: 'wild-dragon-capture:latest',
Env: [
`S3_ENDPOINT=${s3Endpoint}`,
`S3_BUCKET=${s3Bucket}`,
`S3_ACCESS_KEY=${s3AccessKey}`,
`S3_SECRET_KEY=${s3SecretKey}`,
`S3_REGION=${process.env.S3_REGION || 'us-east-1'}`,
`MAM_API_URL=${mamApiUrl}`,
`RECORDER_ID=${id}`,
`SOURCE_TYPE=${recorder.source_type}`,
`SOURCE_CONFIG=${JSON.stringify(recorder.source_config)}`,
`RECORDING_CODEC=${recorder.recording_codec}`,
`RECORDING_RESOLUTION=${recorder.recording_resolution}`,
`PROXY_ENABLED=${recorder.proxy_enabled}`,
`PROXY_CODEC=${recorder.proxy_codec}`,
`PROXY_RESOLUTION=${recorder.proxy_resolution}`,
`PROJECT_ID=${recorder.project_id}`,
`CLIP_NAME=${clipName}`,
],
Env: env,
ExposedPorts: Object.keys(exposedPorts).length > 0 ? exposedPorts : undefined,
HostConfig: {
Privileged: true,
NetworkMode: dockerNetwork,
PortBindings: Object.keys(portBindings).length > 0 ? portBindings : undefined,
},
Hostname: `recorder-${recorder.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`,
};