core ran in a worker thread

This commit is contained in:
nklhrstv 2022-07-09 23:16:43 +03:00
parent 73d6213427
commit de9577efe5
6 changed files with 102 additions and 38 deletions

View file

@ -5,24 +5,22 @@ const React = require('react');
const { Router } = require('stremio-router'); const { Router } = require('stremio-router');
const { Core, Shell, Chromecast, KeyboardShortcuts, ServicesProvider } = require('stremio/services'); const { Core, Shell, Chromecast, KeyboardShortcuts, ServicesProvider } = require('stremio/services');
const { NotFound } = require('stremio/routes'); const { NotFound } = require('stremio/routes');
const { ToastProvider, sanitizeLocationPath, CONSTANTS } = require('stremio/common'); const { ToastProvider, CONSTANTS } = require('stremio/common');
const CoreEventsToaster = require('./CoreEventsToaster'); const CoreEventsToaster = require('./CoreEventsToaster');
const ErrorDialog = require('./ErrorDialog'); const ErrorDialog = require('./ErrorDialog');
const routerViewsConfig = require('./routerViewsConfig'); const routerViewsConfig = require('./routerViewsConfig');
const styles = require('./styles'); const styles = require('./styles');
window.core_imports = {
app_version: process.env.VERSION,
shell_version: null,
sanitize_location_path: sanitizeLocationPath
};
const App = () => { const App = () => {
const onPathNotMatch = React.useCallback(() => { const onPathNotMatch = React.useCallback(() => {
return NotFound; return NotFound;
}, []); }, []);
const services = React.useMemo(() => ({ const services = React.useMemo(() => ({
core: new Core(), core: new Core({
baseURI: document.baseURI,
appVersion: process.env.VERSION,
shellVersion: null
}),
shell: new Shell(), shell: new Shell(),
chromecast: new Chromecast(), chromecast: new Chromecast(),
keyboardShortcuts: new KeyboardShortcuts() keyboardShortcuts: new KeyboardShortcuts()

View file

@ -3,7 +3,7 @@
const EventEmitter = require('eventemitter3'); const EventEmitter = require('eventemitter3');
const CoreTransport = require('./CoreTransport'); const CoreTransport = require('./CoreTransport');
function Core() { function Core(args) {
let active = false; let active = false;
let error = null; let error = null;
let starting = false; let starting = false;
@ -66,7 +66,7 @@ function Core() {
} }
starting = true; starting = true;
transport = new CoreTransport(); transport = new CoreTransport(args);
transport.on('init', onTransportInit); transport.on('init', onTransportInit);
transport.on('error', onTransportError); transport.on('error', onTransportError);
onStateChanged(); onStateChanged();

View file

@ -1,19 +1,22 @@
// Copyright (C) 2017-2022 Smart code 203358507 // Copyright (C) 2017-2022 Smart code 203358507
const EventEmitter = require('eventemitter3'); const EventEmitter = require('eventemitter3');
const { default: initialize_api, initialize_runtime, get_state, get_debug_state, dispatch, analytics, decode_stream } = require('@stremio/stremio-core-web'); const Bridge = require('./bridge');
function CoreTransport() { function CoreTransport(args) {
const events = new EventEmitter(); const events = new EventEmitter();
const worker = new Worker(`${process.env.COMMIT_HASH}/scripts/worker.js`);
const bridge = new Bridge(worker, window);
initialize_api(require('@stremio/stremio-core-web/stremio_core_web_bg.wasm')) window.onCoreEvent = ({ name, args }) => {
.then(() => initialize_runtime(({ name, args }) => { try {
try { events.emit(name, args);
events.emit(name, args); } catch (error) {
} catch (error) { console.error('CoreTransport', error);
console.error('CoreTransport', error); }
} };
}))
bridge.call(['init'], [args])
.then(() => { .then(() => {
try { try {
events.emit('init'); events.emit('init');
@ -35,27 +38,19 @@ function CoreTransport() {
events.removeAllListeners(); events.removeAllListeners();
}; };
this.getState = async function(field) { this.getState = async function(field) {
return Promise.resolve(get_state(field)); return bridge.call(['getState'], [field]);
}; };
this.getDebugState = function() { this.getDebugState = async function() {
return get_debug_state(); return bridge.call(['getDebugState'], []);
}; };
this.dispatch = function(action, field) { this.dispatch = async function(action, field) {
try { return bridge.call(['dispatch'], [action, field, location.hash]);
dispatch(action, field);
} catch (error) {
console.error('CoreTransport', error);
}
}; };
this.analytics = function(event) { this.analytics = async function(event) {
try { return bridge.call(['analytics'], [event, location.hash]);
analytics(event);
} catch (error) {
console.error('CoreTransport', error);
}
}; };
this.decodeStream = function(stream) { this.decodeStream = async function(stream) {
return decode_stream(stream); return bridge.call(['decodeStream'], [stream]);
}; };
} }

View file

@ -0,0 +1,45 @@
function getId() {
return Math.random().toString(32).slice(2);
}
function Bridge(context, scope) {
context.addEventListener('message', async ({ data: { request } }) => {
if (!request) return;
const { id, path, args } = request;
try {
const object = path.reduce((obj, prop) => obj[prop], scope);
let data;
if (typeof object === 'function') {
const thisArg = path.slice(0, path.length - 1).reduce((obj, prop) => obj[prop], scope);
data = await object.apply(thisArg, args);
} else {
data = await object;
}
context.postMessage({ response: { id, result: { data } } });
} catch (error) {
context.postMessage({ response: { id, result: { error } } });
}
});
this.call = async (path, args) => {
const id = getId();
return new Promise((resolve, reject) => {
const onMessage = ({ data: { response } }) => {
if (!response || response.id !== id) return;
context.removeEventListener('message', onMessage);
if ('error' in response.result) {
reject(response.result.error);
} else {
resolve(response.result.data);
}
};
context.addEventListener('message', onMessage);
context.postMessage({ request: { id, path, args } });
});
};
}
module.exports = Bridge;

View file

@ -0,0 +1,23 @@
const sanitizeLocationPath = require('stremio/common/sanitizeLocationPath');
const Bridge = require('./bridge');
const bridge = new Bridge(self, self);
self.init = async ({ baseURI, appVersion, shellVersion }) => {
self.document = { baseURI };
self.app_version = appVersion;
self.shell_version = shellVersion;
self.sanitize_location_path = sanitizeLocationPath;
self.get_location_hash = async () => bridge.call(['location', 'hash'], []);
self.local_storage_get_item = async (key) => bridge.call(['localStorage', 'getItem'], [key]);
self.local_storage_set_item = async (key, value) => bridge.call(['localStorage', 'setItem'], [key, value]);
self.local_storage_remove_item = async (key) => bridge.call(['localStorage', 'removeItem'], [key]);
const { default: initialize_api, initialize_runtime, get_state, get_debug_state, dispatch, analytics, decode_stream } = require('@stremio/stremio-core-web');
self.getState = get_state;
self.getDebugState = get_debug_state;
self.dispatch = dispatch;
self.analytics = analytics;
self.decodeStream = decode_stream;
await initialize_api(require('@stremio/stremio-core-web/stremio_core_web_bg.wasm'));
await initialize_runtime((event) => bridge.call(['onCoreEvent'], [event]));
};

View file

@ -15,7 +15,10 @@ const COMMIT_HASH = execSync('git rev-parse HEAD').toString().trim();
module.exports = (env, argv) => ({ module.exports = (env, argv) => ({
mode: argv.mode, mode: argv.mode,
devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map', devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map',
entry: './src/index.js', entry: {
main: './src/index.js',
worker: './src/services/Core/worker.js'
},
output: { output: {
path: path.join(__dirname, 'build'), path: path.join(__dirname, 'build'),
filename: `${COMMIT_HASH}/scripts/[name].js` filename: `${COMMIT_HASH}/scripts/[name].js`