Skip to content

Commit 782253d

Browse files
committed
Simplify messaging.
1 parent 2e07d25 commit 782253d

File tree

11 files changed

+3897
-17120
lines changed

11 files changed

+3897
-17120
lines changed

README.md

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,6 @@ Same as Linux but with `Win` suffix, e.g. `npm run integrateWin`, `buildWin:all:
3838

3939
The React application runs in the main thread, that has access to DOM. It imports functions for launching a .NET runtime on a Web Worker from a WebAssembly (WASM) application (refer to [client.js](react/src/client.js)) and executes them. These functions establish a Web Worker using the [worker.js](dotnet/wwwroot/worker.js) file. Web Worker can perform heavy tasks without blocking the UI, however it does not have direct control over DOM and relies on communication with main thread for changes to UI. Communication between the Web Worker and the main thread occurs through message passing. The demo includes a few simple examples of passing information from dotnet to React frontend and the other way.
4040

41-
From dotnet to react - exports ready.
42-
43-
+-------------------------------------------+ +---------------------+
44-
| React App | | WASM App |
45-
| (Main Thread) | | (WebWorker Thread) |
46-
|+---------------+ +---------------+| | +------------------+|
47-
|| QrImage | | client.js || | | worker.js ||
48-
|| Component | | || | | ||
49-
|| | | || | | ||
50-
||+-------------+| |+-------------+|| Message | | ||
51-
||| || Event || ||| Passing | | ||
52-
||| EventEmitter|| <------ || EventEmitter||| <------ | | startDotnet() ||
53-
||| on('READY') || || emit() ||| READY | | ||
54-
||| re-render || || ||| | | ||
55-
||| || || ||| | | ||
56-
||+-------------+| |+-------------+|| | | ||
57-
|+---------------+ +---------------+| | +------------------+|
58-
+-------------------------------------------+ +---------------------+
59-
6041
From react to dotnet - QR generation request.
6142

6243
From dotnet to react - populating frontend element with data.
@@ -71,11 +52,11 @@ From dotnet to react - populating frontend element with data.
7152
||+--------------+ | API | +-------------+|| -----------> | +------------------+|
7253
||| Button | | Call | | generate() ||| | |
7354
||| onClick | | -------> | | function ||| Message | ^ Built-in | |
74-
||+--------------+ | | +-------------+|| Passing | | interop V |
75-
||+--------------+ | | +-------------+|| Transferable | |
76-
||| EventEmitter | | Event | | EventEmitter||| <----------- | +------------------+|
77-
||| on('IMAGE') | | <------- | | emit() ||| IMAGE | | JS's imports ||
78-
||| <img src=..> | | | | ||| | | ||
55+
||+--------------+ | | | ||| Passing | | interop V |
56+
||+--------------+ | | | ||| Transferable | |
57+
||| | | update | | ||| <----------- | +------------------+|
58+
||| <img src=..> | | <------- | | ||| IMAGE | | JS's imports ||
59+
||| | | | | ||| | | ||
7960
||+--------------+ | | +-------------+|| | | ||
8061
|+-----------------+ +----------------+| | +------------------+|
8162
+-----------------------------------------------+ +---------------------+

dotnet/Program.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
3+
34
using System;
45
using System.Runtime.InteropServices.JavaScript;
56
using QRCoder;
@@ -18,15 +19,11 @@ internal static byte[] Generate(string text, int qrSize)
1819
{
1920
if (qrSize >= MAX_QR_SIZE)
2021
{
21-
SendErrorMessage($"QR code size must be less than {MAX_QR_SIZE}. Try again.");
22-
return Array.Empty<byte>();
22+
throw new Exception($"QR code size must be less than {MAX_QR_SIZE}. Try again.");
2323
}
2424
QRCodeGenerator qrGenerator = new QRCodeGenerator();
2525
QRCodeData qrCodeData = qrGenerator.CreateQrCode(text, QRCodeGenerator.ECCLevel.Q);
2626
BitmapByteQRCode qrCode = new BitmapByteQRCode(qrCodeData);
2727
return qrCode.GetGraphic(qrSize);
2828
}
29-
30-
[JSImport("QRGenerator.sendErrorMessage", "dotnetWorker.js")]
31-
internal static partial void SendErrorMessage(string message);
3229
}

dotnet/wwwroot/worker.js

Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,48 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
3-
import { dotnet, exit } from './_framework/dotnet.js'
3+
4+
import { dotnet } from './_framework/dotnet.js'
45

56
let assemblyExports = null;
7+
let startupError = undefined;
68

7-
self.addEventListener('message', async function(e) {
8-
switch (e.data.command)
9-
{
10-
case "startDotnet":
11-
console.log("Starting dotnet, says the worker");
12-
await startDotnet();
13-
break;
14-
case "generateQRCode":
15-
if (!assemblyExports)
16-
throw new Error("Exports not found");
17-
const size = Number(e.data.size);
18-
const text = e.data.text;
19-
if (size === undefined || text === undefined)
20-
new Error("Inner error, got empty QR generation data from React");
21-
const imageBytes = assemblyExports.QRGenerator.Generate(text, size);
22-
self.postMessage({ command: "generateQRCodeResponse", image: imageBytes.buffer }, [imageBytes.buffer]);
23-
default:
24-
self.postMessage(e.data.command);
25-
break;
26-
}
27-
}, false);
9+
try {
10+
const { getAssemblyExports, getConfig } = await dotnet.create();
11+
const config = getConfig();
12+
assemblyExports = await getAssemblyExports(config.mainAssemblyName);
13+
}
14+
catch (err) {
15+
startupError = err.message;
16+
}
2817

29-
async function startDotnet(){
18+
self.addEventListener('message', async function(e) {
3019
try {
31-
self.postMessage("creating dotnet");
32-
const { setModuleImports, getAssemblyExports, getConfig } = await dotnet
33-
.create();
34-
self.postMessage("getting config");
35-
const config = getConfig();
36-
self.postMessage("getting exports");
37-
assemblyExports = await getAssemblyExports(config.mainAssemblyName);
38-
39-
self.postMessage("setting imports");
40-
setModuleImports("worker.js", {
41-
QRGenerator: {
42-
sendErrorMessage
43-
}
20+
if (!assemblyExports) {
21+
throw new Error(startupError || "worker exports not loaded");
22+
}
23+
let result = null;
24+
switch (e.data.command) {
25+
case "generateQR":
26+
const size = Number(e.data.size);
27+
const text = e.data.text;
28+
if (size === undefined || text === undefined)
29+
new Error("Inner error, got empty QR generation data from React");
30+
result = assemblyExports.QRGenerator.Generate(text, size);
31+
break;
32+
default:
33+
throw new Error("Unknown command: " + e.data.command);
34+
}
35+
self.postMessage({
36+
command: "response",
37+
requestId: e.data.requestId,
38+
result,
4439
});
45-
46-
self.postMessage({ command: "exportsReady" });
47-
self.postMessage("starting dotnet");
48-
await dotnet.run();
4940
}
5041
catch (err) {
51-
console.log(`err: ${err}; ${err.message}`);
52-
exit(2, err);
42+
self.postMessage({
43+
command: "response",
44+
requestId: e.data.requestId,
45+
error: err.message,
46+
});
5347
}
54-
}
55-
56-
export function sendErrorMessage(message) {
57-
console.log(`sendErrorMessage is passing message: ${message}`);
58-
self.postMessage({ command: "error", message: message });
59-
}
48+
}, false);

0 commit comments

Comments
 (0)