openvibers/openvibe.live Commits
Dead code out: media.completeVodChunks (Media never had /chunks/complete, so it 404'd on every upload and chunk recording before finalize did the work) and the cosmetics activate/deactivate 410 stubs, whose one-release N-1 window ended (#294)
Changes
@@@ -197,11 +197,6 @@ async function uploadVodChunk(vodId, chunk, fields = {}, opts = {}) {return await request('POST', `/vods/${vodId}/chunks`, { body: fd, timeoutMs: 120000, ...opts });}--/** POST /vods/:id/chunks/complete */--async function completeVodChunks(vodId, opts = {}) {-- return await request('POST', `/vods/${vodId}/chunks/complete`, opts);--}--/** POST /vods/:id/finalize → close recording, kick off thumbnail + probe */async function finalizeVod(vodId, opts = {}) {return await request('POST', `/vods/${vodId}/finalize`, opts);@@@ -428,7 +423,7 @@ module.exports = {request, proxy, actingUserFrom, _formData, _authHeader, _reset, MEDIA_AUDIENCE,// vodscreateVod, ingestRtmp, ingestRtpStart, ingestRtpStop,-- uploadVodChunk, completeVodChunks, finalizeVod,++ uploadVodChunk, finalizeVod,getVod, listVods, updateVod, deleteVod,// clipscreateClip, getClip, listClips, updateClip, deleteClip, recutClip, trimClip, getJob,@@@ -635,7 +635,6 @@ router.post('/upload', requireAuth, memUpload.single('video'), async (req, res)filename: req.file.originalname || 'upload.webm',contentType: req.file.mimetype || 'video/webm',});-- await media.completeVodChunks(id).catch(() => {});await media.finalizeVod(id);const vod = await media.getVod(id).catch(() => ({ id, status: 'processing' }));res.status(201).json({ vod });@@@ -60,11 +60,4 @@ router.post('/unequip', requireAuth, async (req, res) => {res.json(result);});--// The openvibe-quest game-item bridge is gone (plan T2; the quest game runs nowhere, so these always failed). Open--// tabs of the previous release may still call them for one release (ADR-016 N-1): they answer 410 behind the same--// auth, then the next release deletes both.--for (const p of ['/activate', '/deactivate']) {-- router.post(p, requireAuth, (req, res) => res.status(410).json({ error: 'Game items no longer convert to cosmetics' }));--}--module.exports = router;@@@ -342,7 +342,6 @@ class StreamRecorder {if (rec.type === 'rtp') {await media.ingestRtpStop(rec.vodId).catch((e) => console.warn(`[VOD] rtp stop failed (vod ${rec.vodId}):`, e.message));} else if (rec.type === 'chunks') {-- await media.completeVodChunks(rec.vodId).catch(() => {});await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));} else {await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));@@@ -48,8 +48,8 @@ const token = (cap, { aud = 'openvibe.live', sub = 'svc:network', env } = {}) =>for (const h of [{ 'x-internal-key': KEY }, { 'x-internal-secret': 'openvibe-internal-2026' }]) {assert.strictEqual((await post('/api/cosmetics/internal-unlock', h, { userId: 1, itemId: 'fx_fire' })).status, 404, 'internal-unlock no longer exists');}-- // activate/deactivate answer 410 for one release (old tabs, ADR-016), behind the same auth.-- for (const p of ['/api/cosmetics/activate', '/api/cosmetics/deactivate']) assert.strictEqual((await post(p, {}, { itemId: 'fx_fire' })).status, 401, `${p} still needs a session`);++ // activate/deactivate answered 410 for one release (old tabs, ADR-016) and are gone now.++ for (const p of ['/api/cosmetics/activate', '/api/cosmetics/deactivate']) assert.strictEqual((await post(p, {}, { itemId: 'fx_fire' })).status, 404, `${p} no longer exists`);// ── /internal/user-avatar: live.avatar.write ─────────────────────────────────const avatar = (headers) => post('/internal/user-avatar', headers, { username: 'nobody-here' });@@@ -51,7 +51,6 @@ media.createVod = async (body) => { const id = nextVod++; note('createVod', id,media.ingestRtmp = async (id, url) => { note('ingestRtmp', id, url); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.mp4` }); };media.ingestRtpStart = async (id, codecs) => { note('ingestRtpStart', id, codecs); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.webm` }); return { videoPort: 12000, audioPort: 12002 }; };media.ingestRtpStop = async (id) => { note('ingestRtpStop', id); };--media.completeVodChunks = async (id) => { note('completeVodChunks', id); };media.finalizeVod = async (id) => { note('finalizeVod', id); };media.deleteVod = async (id) => { note('deleteVod', id); delete VODS[id]; };media.getVod = async (id) => {@@@ -203,12 +202,12 @@ async function check(name, fn) {assert.deepStrictEqual(plain.closed.sort(), ['plain-12000', 'plain-12002']);});-- await check('browser chunks: stream end completes the chunk session and finalises it', async () => {++ await check('browser chunks: stream end finalises the chunk session', async () => {const sid = await newStream('webrtc');recorder.registerChunkSession(sid, 900);recorder.stopRecording(sid);await until(() => !recorder.isFinalizingStream(sid), 'the chunk finalise');-- assert.deepStrictEqual(callsFor(900), ['completeVodChunks', 'finalizeVod']);++ assert.deepStrictEqual(callsFor(900), ['finalizeVod']);});await check('clips-only recording (VOD-disabled slot) is finalised and then discarded', async () => {
@@ -197,11 +197,6 @@ async function uploadVodChunk(vodId, chunk, fields = {}, opts = {}) {
@@ -197,11 +197,6 @@ async function uploadVodChunk(vodId, chunk, fields = {}, opts = {}) {
return await request('POST', `/vods/${vodId}/chunks`, { body: fd, timeoutMs: 120000, ...opts });
return await request('POST', `/vods/${vodId}/chunks`, { body: fd, timeoutMs: 120000, ...opts });
}
}
-/** POST /vods/:id/chunks/complete */
-async function completeVodChunks(vodId, opts = {}) {
- return await request('POST', `/vods/${vodId}/chunks/complete`, opts);
-}
-
/** POST /vods/:id/finalize → close recording, kick off thumbnail + probe */
/** POST /vods/:id/finalize → close recording, kick off thumbnail + probe */
async function finalizeVod(vodId, opts = {}) {
async function finalizeVod(vodId, opts = {}) {
return await request('POST', `/vods/${vodId}/finalize`, opts);
return await request('POST', `/vods/${vodId}/finalize`, opts);
@@ -428,7 +423,7 @@ module.exports = {
@@ -428,7 +423,7 @@ module.exports = {
request, proxy, actingUserFrom, _formData, _authHeader, _reset, MEDIA_AUDIENCE,
request, proxy, actingUserFrom, _formData, _authHeader, _reset, MEDIA_AUDIENCE,
// vods
// vods
createVod, ingestRtmp, ingestRtpStart, ingestRtpStop,
createVod, ingestRtmp, ingestRtpStart, ingestRtpStop,
- uploadVodChunk, completeVodChunks, finalizeVod,
+ uploadVodChunk, finalizeVod,
getVod, listVods, updateVod, deleteVod,
getVod, listVods, updateVod, deleteVod,
// clips
// clips
createClip, getClip, listClips, updateClip, deleteClip, recutClip, trimClip, getJob,
createClip, getClip, listClips, updateClip, deleteClip, recutClip, trimClip, getJob,
@@ -635,7 +635,6 @@ router.post('/upload', requireAuth, memUpload.single('video'), async (req, res)
@@ -635,7 +635,6 @@ router.post('/upload', requireAuth, memUpload.single('video'), async (req, res)
filename: req.file.originalname || 'upload.webm',
filename: req.file.originalname || 'upload.webm',
contentType: req.file.mimetype || 'video/webm',
contentType: req.file.mimetype || 'video/webm',
});
});
- await media.completeVodChunks(id).catch(() => {});
await media.finalizeVod(id);
await media.finalizeVod(id);
const vod = await media.getVod(id).catch(() => ({ id, status: 'processing' }));
const vod = await media.getVod(id).catch(() => ({ id, status: 'processing' }));
res.status(201).json({ vod });
res.status(201).json({ vod });
@@ -60,11 +60,4 @@ router.post('/unequip', requireAuth, async (req, res) => {
@@ -60,11 +60,4 @@ router.post('/unequip', requireAuth, async (req, res) => {
res.json(result);
res.json(result);
});
});
-// The openvibe-quest game-item bridge is gone (plan T2; the quest game runs nowhere, so these always failed). Open
-// tabs of the previous release may still call them for one release (ADR-016 N-1): they answer 410 behind the same
-// auth, then the next release deletes both.
-for (const p of ['/activate', '/deactivate']) {
- router.post(p, requireAuth, (req, res) => res.status(410).json({ error: 'Game items no longer convert to cosmetics' }));
-}
-
module.exports = router;
module.exports = router;
@@ -342,7 +342,6 @@ class StreamRecorder {
@@ -342,7 +342,6 @@ class StreamRecorder {
if (rec.type === 'rtp') {
if (rec.type === 'rtp') {
await media.ingestRtpStop(rec.vodId).catch((e) => console.warn(`[VOD] rtp stop failed (vod ${rec.vodId}):`, e.message));
await media.ingestRtpStop(rec.vodId).catch((e) => console.warn(`[VOD] rtp stop failed (vod ${rec.vodId}):`, e.message));
} else if (rec.type === 'chunks') {
} else if (rec.type === 'chunks') {
- await media.completeVodChunks(rec.vodId).catch(() => {});
await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));
await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));
} else {
} else {
await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));
await media.finalizeVod(rec.vodId).catch((e) => console.warn(`[VOD] finalize failed (vod ${rec.vodId}):`, e.message));
@@ -48,8 +48,8 @@ const token = (cap, { aud = 'openvibe.live', sub = 'svc:network', env } = {}) =>
@@ -48,8 +48,8 @@ const token = (cap, { aud = 'openvibe.live', sub = 'svc:network', env } = {}) =>
for (const h of [{ 'x-internal-key': KEY }, { 'x-internal-secret': 'openvibe-internal-2026' }]) {
for (const h of [{ 'x-internal-key': KEY }, { 'x-internal-secret': 'openvibe-internal-2026' }]) {
assert.strictEqual((await post('/api/cosmetics/internal-unlock', h, { userId: 1, itemId: 'fx_fire' })).status, 404, 'internal-unlock no longer exists');
assert.strictEqual((await post('/api/cosmetics/internal-unlock', h, { userId: 1, itemId: 'fx_fire' })).status, 404, 'internal-unlock no longer exists');
}
}
- // activate/deactivate answer 410 for one release (old tabs, ADR-016), behind the same auth.
- for (const p of ['/api/cosmetics/activate', '/api/cosmetics/deactivate']) assert.strictEqual((await post(p, {}, { itemId: 'fx_fire' })).status, 401, `${p} still needs a session`);
+ // activate/deactivate answered 410 for one release (old tabs, ADR-016) and are gone now.
+ for (const p of ['/api/cosmetics/activate', '/api/cosmetics/deactivate']) assert.strictEqual((await post(p, {}, { itemId: 'fx_fire' })).status, 404, `${p} no longer exists`);
// ── /internal/user-avatar: live.avatar.write ─────────────────────────────────
// ── /internal/user-avatar: live.avatar.write ─────────────────────────────────
const avatar = (headers) => post('/internal/user-avatar', headers, { username: 'nobody-here' });
const avatar = (headers) => post('/internal/user-avatar', headers, { username: 'nobody-here' });
@@ -51,7 +51,6 @@ media.createVod = async (body) => { const id = nextVod++; note('createVod', id,
@@ -51,7 +51,6 @@ media.createVod = async (body) => { const id = nextVod++; note('createVod', id,
media.ingestRtmp = async (id, url) => { note('ingestRtmp', id, url); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.mp4` }); };
media.ingestRtmp = async (id, url) => { note('ingestRtmp', id, url); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.mp4` }); };
media.ingestRtpStart = async (id, codecs) => { note('ingestRtpStart', id, codecs); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.webm` }); return { videoPort: 12000, audioPort: 12002 }; };
media.ingestRtpStart = async (id, codecs) => { note('ingestRtpStart', id, codecs); Object.assign(VODS[id], { status: 'recording', is_recording: true, file_path: `vod-${id}.webm` }); return { videoPort: 12000, audioPort: 12002 }; };
media.ingestRtpStop = async (id) => { note('ingestRtpStop', id); };
media.ingestRtpStop = async (id) => { note('ingestRtpStop', id); };
-media.completeVodChunks = async (id) => { note('completeVodChunks', id); };
media.finalizeVod = async (id) => { note('finalizeVod', id); };
media.finalizeVod = async (id) => { note('finalizeVod', id); };
media.deleteVod = async (id) => { note('deleteVod', id); delete VODS[id]; };
media.deleteVod = async (id) => { note('deleteVod', id); delete VODS[id]; };
media.getVod = async (id) => {
media.getVod = async (id) => {
@@ -203,12 +202,12 @@ async function check(name, fn) {
@@ -203,12 +202,12 @@ async function check(name, fn) {
assert.deepStrictEqual(plain.closed.sort(), ['plain-12000', 'plain-12002']);
assert.deepStrictEqual(plain.closed.sort(), ['plain-12000', 'plain-12002']);
});
});
- await check('browser chunks: stream end completes the chunk session and finalises it', async () => {
+ await check('browser chunks: stream end finalises the chunk session', async () => {
const sid = await newStream('webrtc');
const sid = await newStream('webrtc');
recorder.registerChunkSession(sid, 900);
recorder.registerChunkSession(sid, 900);
recorder.stopRecording(sid);
recorder.stopRecording(sid);
await until(() => !recorder.isFinalizingStream(sid), 'the chunk finalise');
await until(() => !recorder.isFinalizingStream(sid), 'the chunk finalise');
- assert.deepStrictEqual(callsFor(900), ['completeVodChunks', 'finalizeVod']);
+ assert.deepStrictEqual(callsFor(900), ['finalizeVod']);
});
});
await check('clips-only recording (VOD-disabled slot) is finalised and then discarded', async () => {
await check('clips-only recording (VOD-disabled slot) is finalised and then discarded', async () => {