File size: 2,659 Bytes
84c1942 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | const generateId = () =>
// Such a random ID
Math.floor(Math.random() * 1000000 + Math.random() * 1000000);
const getConstructorName = (x: any) => {
try {
return x.constructor.name;
} catch(e) {
return '';
}
};
export default class Protocol {
private outgoingMessages: Set<number> = new Set();
private internalId: number;
private isWorker: boolean;
constructor(
private type: string,
private handleMessage: (message: any) => any,
private target: Worker | Window
) {
this.createConnection();
this.internalId = generateId();
this.isWorker = getConstructorName(target) === 'Worker';
}
getTypeId() {
return `p-${this.type}`;
}
createConnection() {
self.addEventListener('message', this._messageListener);
}
public dispose() {
self.removeEventListener('message', this._messageListener);
}
sendMessage<PromiseType>(data: any): Promise<PromiseType> {
return new Promise(resolve => {
const messageId = generateId();
const message = {
$originId: this.internalId,
$type: this.getTypeId(),
$data: data,
$id: messageId,
};
this.outgoingMessages.add(messageId);
const listenFunction = (e: MessageEvent) => {
const { data } = e;
if (
data.$type === this.getTypeId() &&
data.$id === messageId &&
data.$originId !== this.internalId
) {
resolve(data.$data);
self.removeEventListener('message', listenFunction);
}
};
self.addEventListener('message', listenFunction);
this._postMessage(message);
});
}
private _messageListener = async (e: MessageEvent) => {
const { data } = e;
if (data.$type !== this.getTypeId()) {
return;
}
// We are getting a response to the message
if (this.outgoingMessages.has(data.$id)) {
return;
}
const result = await this.handleMessage(data.$data);
const returnMessage = {
$originId: this.internalId,
$type: this.getTypeId(),
$data: result,
$id: data.$id,
};
if (e.source) {
// @ts-ignore
e.source.postMessage(returnMessage, '*');
} else {
this._postMessage(returnMessage);
}
};
private _postMessage(m: any) {
if (
this.isWorker ||
// @ts-ignore Unknown to TS
(typeof DedicatedWorkerGlobalScope !== 'undefined' &&
// @ts-ignore Unknown to TS
this.target instanceof DedicatedWorkerGlobalScope)
) {
// @ts-ignore
this.target.postMessage(m);
} else {
(this.target as Window).postMessage(m, '*');
}
}
}
|