feat: add {stream} opt to custom protocol registry to configure media player (#22955)

This commit is contained in:
Paul Frazee 2020-06-08 11:49:36 -05:00 committed by GitHub
parent 261f385b5e
commit c6c022dc46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 719 additions and 4 deletions

View file

@ -9,6 +9,7 @@ import * as qs from 'querystring';
import * as stream from 'stream';
import { closeWindow } from './window-helpers';
import { emittedOnce } from './events-helpers';
import { WebmGenerator } from './video-helpers';
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures');
@ -822,4 +823,99 @@ describe('protocol module', () => {
}
}
});
describe('protocol.registerSchemesAsPrivileged stream', async function () {
const pagePath = path.join(fixturesPath, 'pages', 'video.html');
const videoSourceImagePath = path.join(fixturesPath, 'video-source-image.webp');
const videoPath = path.join(fixturesPath, 'video.webm');
const standardScheme = (global as any).standardScheme;
let w: BrowserWindow = null as unknown as BrowserWindow;
before(async () => {
// generate test video
const imageBase64 = await fs.promises.readFile(videoSourceImagePath, 'base64');
const imageDataUrl = `data:image/webp;base64,${imageBase64}`;
const encoder = new WebmGenerator(15);
for (let i = 0; i < 30; i++) {
encoder.add(imageDataUrl);
}
await new Promise((resolve, reject) => {
encoder.compile((output:Uint8Array) => {
fs.promises.writeFile(videoPath, output).then(resolve, reject);
});
});
});
after(async () => {
await fs.promises.unlink(videoPath);
});
beforeEach(async () => {
w = new BrowserWindow({ show: false });
});
afterEach(async () => {
await closeWindow(w);
w = null as unknown as BrowserWindow;
await protocol.unregisterProtocol(standardScheme);
await protocol.unregisterProtocol('stream');
});
it('does not successfully play videos with stream: false on streaming protocols', async () => {
await streamsResponses(standardScheme, 'error');
});
it('successfully plays videos with stream: true on streaming protocols', async () => {
await streamsResponses('stream', 'play');
});
async function streamsResponses (testingScheme: string, expected: any) {
const protocolHandler = (request: any, callback: Function) => {
if (request.url.includes('/video.webm')) {
const stat = fs.statSync(videoPath);
const fileSize = stat.size;
const range = request.headers.Range;
if (range) {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = (end - start) + 1;
const headers = {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': String(chunksize),
'Content-Type': 'video/webm'
};
callback({ statusCode: 206, headers, data: fs.createReadStream(videoPath, { start, end }) });
} else {
callback({
statusCode: 200,
headers: {
'Content-Length': String(fileSize),
'Content-Type': 'video/webm'
},
data: fs.createReadStream(videoPath)
});
}
} else {
callback({ data: fs.createReadStream(pagePath), headers: { 'Content-Type': 'text/html' }, statusCode: 200 });
}
};
await registerStreamProtocol(standardScheme, protocolHandler);
await registerStreamProtocol('stream', protocolHandler);
const newContents: WebContents = (webContents as any).create({ nodeIntegration: true });
try {
newContents.loadURL(testingScheme + '://fake-host');
const [, response] = await emittedOnce(ipcMain, 'result');
expect(response).to.deep.equal(expected);
} finally {
// This is called in a timeout to avoid a crash that happens when
// calling destroy() in a microtask.
setTimeout(() => {
(newContents as any).destroy();
});
}
}
});
});