Skip to content

Commit

Permalink
Worker Com example uses canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
kaisalmen committed Nov 6, 2023
1 parent 256640a commit 9615f4f
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 60 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
node-version: '18'
- name: Lint
shell: bash
run: |
npm run lint
- name: Build
shell: bash
run: |
Expand All @@ -27,7 +31,3 @@ jobs:
shell: bash
run: |
npm --prefix packages/examples run build:production
- name: Lint
shell: bash
run: |
npm run lint
108 changes: 78 additions & 30 deletions packages/examples/src/com/WorkerCom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,86 @@ import {
WorkerTaskMessage,
WorkerTaskMessageType
} from 'wtd-core';
import { updateText } from '../worker/ComWorkerCommon.js';

/**
* Hello World example using a classic worker
*/
class HelloWorldStandardWorkerExample {

async run() {
const workerTaskCom1 = new WorkerTask('Com1Worker', 1, {
private workerTaskCom1: WorkerTask;
private workerTaskCom2: WorkerTask;
private canvasMain: HTMLCanvasElement;
private canvasCom1: HTMLCanvasElement;
private canvasCom2: HTMLCanvasElement;

constructor() {
this.canvasMain = document.getElementById('main') as HTMLCanvasElement;
this.canvasCom1 = document.getElementById('com1') as HTMLCanvasElement;
this.canvasCom2 = document.getElementById('com2') as HTMLCanvasElement;

this.recalAspectRatio(this.canvasMain);
this.recalAspectRatio(this.canvasCom1);
this.recalAspectRatio(this.canvasCom2);

updateText({
text: 'Main: Init',
width: this.canvasMain?.clientWidth ?? 0,
height: this.canvasMain?.clientHeight ?? 0,
canvas: this.canvasMain,
log: true
});

this.workerTaskCom1 = new WorkerTask('Com1Worker', 1, {
module: true,
blob: false,
url: new URL(import.meta.env.DEV ? '../worker/Com1Worker.ts' : '../worker/generated/Com1Worker-es.js', import.meta.url)
});
const workerTaskCom2 = new WorkerTask('Com2Worker', 1, {
this.workerTaskCom2 = new WorkerTask('Com2Worker', 1, {
module: true,
blob: false,
url: new URL(import.meta.env.DEV ? '../worker/Com2Worker.ts' : '../worker/generated/Com2Worker-es.js', import.meta.url)
});
}

try {
const channel = new MessageChannel();
recalAspectRatio(canvas: HTMLCanvasElement) {
canvas.width = canvas.height * (canvas.clientWidth / canvas.clientHeight);
}

async run() {
const channel = new MessageChannel();
const initCom1 = new WorkerTaskMessage();
const payload1 = new RawPayload();

const initCom1 = new WorkerTaskMessage();
const payload1 = new RawPayload();
payload1.message.raw = { port: channel.port1 };
try {
const offscreenCom1 = this.canvasCom1.transferControlToOffscreen();
payload1.message.raw = {
port: channel.port1,
drawingSurface: offscreenCom1,
width: this.canvasCom1.clientWidth,
height: this.canvasCom1.clientHeight
};
initCom1.addPayload(payload1);

const initCom2 = new WorkerTaskMessage();
const payload2 = new RawPayload();
payload2.message.raw = { port: channel.port2 };
const offscreenCom2 = this.canvasCom2.transferControlToOffscreen();
payload2.message.raw = {
port: channel.port2,
drawingSurface: offscreenCom2,
width: this.canvasCom2.clientWidth,
height: this.canvasCom2.clientHeight
};
initCom2.addPayload(payload2);

const promisesinit = [];
promisesinit.push(workerTaskCom1.initWorker({
promisesinit.push(this.workerTaskCom1.initWorker({
message: initCom1,
transferables: [channel.port1]
transferables: [channel.port1, offscreenCom1]
}));
promisesinit.push(workerTaskCom2.initWorker({
promisesinit.push(this.workerTaskCom2.initWorker({
message: initCom2,
transferables: [channel.port2],
transferables: [channel.port2, offscreenCom2],
}));
await Promise.all(promisesinit);

Expand All @@ -54,29 +95,36 @@ class HelloWorldStandardWorkerExample {
console.log(`Worker said onComplete: ${rawPayload.message.raw.finished}`);
};

const promisesExec = [];
promisesExec.push(workerTaskCom1.executeWorker({
message: new WorkerTaskMessage(),
onComplete
}));
promisesExec.push(workerTaskCom2.executeWorker({
message: new WorkerTaskMessage(),
onComplete
}));
const promisesExec: Array<Promise<unknown>> = [];
setTimeout(async () => {
promisesExec.push(this.workerTaskCom1.executeWorker({
message: new WorkerTaskMessage(),
onComplete
}));
promisesExec.push(this.workerTaskCom2.executeWorker({
message: new WorkerTaskMessage(),
onComplete
}));

const result = await Promise.all(promisesExec);
console.log(`Overall result: ${result}`);
const result = await Promise.all(promisesExec);
console.log(`Overall result: ${result}`);

const t1 = performance.now();
const msg = `Worker execution has been completed after ${t1 - t0}ms.`;
console.log(msg);
alert(msg);
console.log('Done');
const t1 = performance.now();
const text = `Main: Worker execution has been completed after ${t1 - t0}ms.`;
updateText({
text,
width: this.canvasMain?.clientWidth ?? 0,
height: this.canvasMain?.clientHeight ?? 0,
canvas: this.canvasMain,
log: true
});
console.log('Done');
}, 2000);
} catch (e) {
console.error(e);
}
}
}

const app = new HelloWorldStandardWorkerExample();
app.run();
await app.run();
49 changes: 38 additions & 11 deletions packages/examples/src/worker/Com1Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,30 @@ import {
WorkerTaskMessageType,
WorkerTaskWorker
} from 'wtd-core';
import { getOffScreenCanvas, updateText } from './ComWorkerCommon.js';

export class Com1Worker implements WorkerTaskWorker, InterComWorker {

private icph = new InterComPortHandler();
private offScreenCanvas?: HTMLCanvasElement;

init(message: WorkerTaskMessageType): void {
// register the default com-routing function for inter-worker communication
this.icph.registerPort('com2', message.payloads[0], message => comRouting(this, message));
const payload = message.payloads[0];
this.icph.registerPort('com2', payload, message => comRouting(this, message));
this.offScreenCanvas = getOffScreenCanvas(payload);
updateText({
text: 'Worker 1: init',
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// send initComplete to main
const initComplete = WorkerTaskMessage.createFromExisting({} as WorkerTaskMessageType, WorkerTaskCommandResponse.INIT_COMPLETE);
const payload = new RawPayload({ hello: 'Worker 1 initComplete!' });
initComplete.addPayload(payload);
const payloadResponse = new RawPayload({ hello: 'Worker 1 initComplete!' });
initComplete.addPayload(payloadResponse);

self.postMessage(initComplete);
}
Expand All @@ -37,27 +48,43 @@ export class Com1Worker implements WorkerTaskWorker, InterComWorker {

interComIntermediate(message: WorkerTaskMessageType): void {
const rawPayload = message.payloads[0] as RawPayload;
console.log(`Worker 2 said: ${rawPayload.message.raw.hello}`);
const text = `Worker 1: Worker 2 said: ${rawPayload.message.raw.hello}`;
updateText({
text,
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// after receiving the message from Com2Worker, send interComIntermediateConfirm to worker 2
const intermediateConfirm = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.INTERCOM_INTERMEDIATE_CONFIRM);
const payload = new RawPayload({ confirmed: 'Hi Worker 2. I confirm!' });
intermediateConfirm.addPayload(payload);
setTimeout(() => {
// after receiving the message from Com2Worker, send interComIntermediateConfirm to worker 2
const intermediateConfirm = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.INTERCOM_INTERMEDIATE_CONFIRM);
const payload = new RawPayload({ confirmed: 'Hi Worker 2. I confirm!' });
intermediateConfirm.addPayload(payload);

this.icph.postMessageOnPort('com2', intermediateConfirm);
this.icph.postMessageOnPort('com2', intermediateConfirm);
}, 2000);
}

interComIntermediateConfirm(message: WorkerTaskMessageType): void {
const rawPayload = message.payloads[0] as RawPayload;
console.log(`Worker 2 confirmed: ${rawPayload.message.raw.confirmed}`);
const text = `Worker 1: Worker 2 confirmed: ${rawPayload.message.raw.confirmed}`;

updateText({
text,
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// after receiving the interComIntermediateConfirm from Com2Worker, send execComplete to main
const execComplete = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.EXECUTE_COMPLETE);
const payload = new RawPayload({ finished: 'Hi Main. Worker 1 completed!' });
execComplete.addPayload(payload);
self.postMessage(execComplete);
}

}

const worker = new Com1Worker();
Expand Down
47 changes: 37 additions & 10 deletions packages/examples/src/worker/Com2Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,30 @@ import {
WorkerTaskMessageType,
WorkerTaskWorker
} from 'wtd-core';
import { getOffScreenCanvas, updateText } from './ComWorkerCommon.js';

export class Com2Worker implements WorkerTaskWorker, InterComWorker {

private icph = new InterComPortHandler();
private offScreenCanvas?: HTMLCanvasElement;

init(message: WorkerTaskMessageType): void {
// register the default com-routing function for inter-worker communication
this.icph.registerPort('com1', message.payloads[0], message => comRouting(this, message));
const payload = message.payloads[0];
this.icph.registerPort('com1', payload, message => comRouting(this, message));
this.offScreenCanvas = getOffScreenCanvas(payload);
updateText({
text: 'Worker 2: init',
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// send initComplete to main
const initComplete = WorkerTaskMessage.createFromExisting({} as WorkerTaskMessageType, WorkerTaskCommandResponse.INIT_COMPLETE);
const payload = new RawPayload({ hello: 'Worker 2 initComplete!' });
initComplete.addPayload(payload);
const payloadResponse = new RawPayload({ hello: 'Worker 2 initComplete!' });
initComplete.addPayload(payloadResponse);

self.postMessage(initComplete);
}
Expand All @@ -37,19 +48,35 @@ export class Com2Worker implements WorkerTaskWorker, InterComWorker {

interComIntermediate(message: WorkerTaskMessageType): void {
const rawPayload = message.payloads[0] as RawPayload;
console.log(`Worker 1 said: ${rawPayload.message.raw.hello}`);
const text = `Worker 2: Worker 1 said: ${rawPayload.message.raw.hello}`;
updateText({
text,
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// after receiving the message from Com1Worker, send interComIntermediateConfirm to worker 2
const intermediateConfirm = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.INTERCOM_INTERMEDIATE_CONFIRM);
const payload = new RawPayload({ confirmed: 'Hi Worker 1. I confirm!' });
intermediateConfirm.addPayload(payload);
setTimeout(() => {
// after receiving the message from Com1Worker, send interComIntermediateConfirm to worker 2
const intermediateConfirm = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.INTERCOM_INTERMEDIATE_CONFIRM);
const payload = new RawPayload({ confirmed: 'Hi Worker 1. I confirm!' });
intermediateConfirm.addPayload(payload);

this.icph.postMessageOnPort('com1', intermediateConfirm);
this.icph.postMessageOnPort('com1', intermediateConfirm);
}, 2000);
}

interComIntermediateConfirm(message: WorkerTaskMessageType): void {
const rawPayload = message.payloads[0] as RawPayload;
console.log(`Worker 1 confirmed: ${rawPayload.message.raw.confirmed}`);
const text = `Worker 2: Worker 1 confirmed: ${rawPayload.message.raw.confirmed}`;
updateText({
text,
width: this.offScreenCanvas?.width ?? 0,
height: this.offScreenCanvas?.height ?? 0,
canvas: this.offScreenCanvas,
log: true
});

// after receiving the interComIntermediateConfirm from Com1Worker, send execComplete to main
const execComplete = WorkerTaskMessage.createFromExisting(message, WorkerTaskCommandResponse.EXECUTE_COMPLETE);
Expand Down
23 changes: 23 additions & 0 deletions packages/examples/src/worker/ComWorkerCommon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Payload, RawPayload } from 'wtd-core';

export const getOffScreenCanvas = (payload: Payload) => {
return payload ? (payload as RawPayload).message.raw.drawingSurface as HTMLCanvasElement : undefined;
};

export const updateText = (params: {
text: string;
width: number;
height: number;
canvas?: HTMLCanvasElement;
log?: boolean;
}) => {
const context = params.canvas?.getContext('2d');
if (context) {
context.clearRect(0, 0, params.width, params.height);
context.font = '12px Arial';
context?.fillText(params.text, 12, 48);
}
if (params.log === true) {
console.log(params.text);
}
};
4 changes: 2 additions & 2 deletions packages/examples/vite.config.production.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default defineConfig(({ command }) => {
console.log(`Running: ${command}`);
return {
build: {
target: ['es2020'],
target: ['es2022'],
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
Expand All @@ -35,7 +35,7 @@ export default defineConfig(({ command }) => {
},
optimizeDeps: {
esbuildOptions: {
target: 'es2020'
target: 'es2022'
}
}
};
Expand Down
8 changes: 6 additions & 2 deletions packages/examples/workerCom.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
</head>

<body>
<canvas id="example" style="width: 100%; height: 100vh;"></canvas>
<div id="info">Inter-Worker Communication</div>
<div>
<div id="info" style="height: 33vh">Inter-Worker Communication</div>
<canvas id="main" style="width: 100%; position: absolute; height: 33vh; background-color: grey;"></canvas>
<canvas id="com1" style="width: 100%; position: absolute; top: 33vh; height: 33vh; background-color: darkcyan;"></canvas>
<canvas id="com2" style="width: 100%; position: absolute; top: 66vh; height: 33vh; background-color: purple"></canvas>
</div>
<script type="module" src="./src/com/WorkerCom.ts"></script>
</body>
</html>

0 comments on commit 9615f4f

Please sign in to comment.