@zlepper/rpc
Version:
Allows RPC from the main thread to a background worker thread (Of any kind), using ES6 classes.
101 lines • 3.25 kB
JavaScript
// @ts-ignore
function isEventDispatcher(target) {
return '__initializeEventDispatcher' in target;
}
class WorkerProvider {
target;
serverConnection;
constructor(target, serverConnection) {
this.target = target;
this.serverConnection = serverConnection;
if (isEventDispatcher(target)) {
target.__initializeEventDispatcher(this);
}
}
stop() {
this.serverConnection.removeListener();
}
start() {
this.serverConnection.addListener(data => this.handleInvocation(data));
}
sendErrorResponse(invocation, error) {
const errorMessage = {
kind: 'message',
refId: invocation.refId,
success: false,
error,
};
// Not entirely sure why typescript confuses the overload here, but i'm not going to think too much about it
// this specific part is never exposed to the end consumer, so it should be safe to just "ignore"
this.serverConnection.send(errorMessage);
}
sendSuccessResponse(invocation, result) {
const message = {
kind: 'message',
refId: invocation.refId,
result,
success: true,
};
this.serverConnection.send(message);
}
sendEvent(type, data) {
const event = {
refId: -1,
kind: 'event',
type,
data
};
this.serverConnection.send(event);
}
handleInvocation(invocation) {
try {
const prop = this.target[invocation.propertyName];
if (typeof prop !== 'function') {
this.sendErrorResponse(invocation, new Error(`Property ${String(invocation.propertyName)} is not a function on the underlying worker objects. Did you use the correct type in both the Worker and main code?`));
return;
}
const result = prop.apply(this.target, invocation.args);
Promise.resolve(result)
.then(response => {
this.sendSuccessResponse(invocation, response);
})
.catch(error => {
this.sendErrorResponse(invocation, error);
});
}
catch (e) {
this.sendErrorResponse(invocation, e);
}
}
}
export function startWorkerProvider(target, serverConnection) {
const provider = createWorkerProvider(target, serverConnection);
provider.start();
return provider;
}
export function createWorkerProvider(target, serverConnection) {
return new WorkerProvider(target, serverConnection);
}
export class EventDispatcher {
/**
* @private
*/
___typescriptInferenceHack = null;
/**
* @internal
*/
__workerProvider = null;
/**
* @internal
*/
__initializeEventDispatcher(provider) {
this.__workerProvider = provider;
}
dispatchEvent(type, data) {
if (!this.__workerProvider) {
throw new Error('Worker provider has not been initialized. Did you call dispatchEvent before passing the worker to the provider?');
}
this.__workerProvider.sendEvent(type, data);
}
}
//# sourceMappingURL=worker-provider.js.map