Skip to content

Commit 249863a

Browse files
authored
Merge pull request #1179 from layer5io/webworker
Enhance Support for cross thread actor communication
2 parents bf3da7a + 8be8acd commit 249863a

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

src/actors/utils.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { AnyActorRef, AnyEventObject, assign, enqueueActions, sendTo } from 'xstate';
55
import { AnyActorSystem } from 'xstate/dist/declarations/src/system';
6+
import { workerEvents } from './worker/events';
67

78
type ContextWithReturnAddress = { returnAddress: AnyActorRef };
89

@@ -39,8 +40,28 @@ export const forwardToActors = (actorSystemIds: string[]) =>
3940

4041
export const deadLetter = (event: AnyEventObject) => ({ type: 'DEAD_LETTER', event });
4142

42-
export const reply = (eventFn: (actionArgs: any, params: any) => AnyEventObject) =>
43-
sendTo(({ context }: { context: ContextWithReturnAddress }) => context.returnAddress, eventFn);
43+
44+
45+
function isInWorker() {
46+
return (
47+
typeof self !== 'undefined' && // 'self' exists
48+
typeof self?.document === 'undefined' // no Window in worker
49+
);
50+
}
51+
52+
export const reply = (eventFn: (actionArgs: any, params: any) => AnyEventObject) => enqueueActions(({ enqueue, ...actionArgs }, params) => {
53+
54+
if (!actionArgs.context.returnAddress) {
55+
console.warn('No return address specified in context for reply action');
56+
return;
57+
}
58+
if (isInWorker()) {
59+
console.log('reply in worker - posting message to main thread', actionArgs.context.returnAddress, eventFn(actionArgs, params));
60+
postMessage(workerEvents.proxyEvent(eventFn(actionArgs, params), actionArgs.context.returnAddress));
61+
return;
62+
}
63+
enqueue.sendTo(actionArgs.context.returnAddress, eventFn);
64+
})
4465

4566
export const XSTATE_DEBUG_EVENT = 'XSTATE_DEBUG_EVENT';
4667

src/actors/worker/fromWorkerfiedActor.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ export const fromWorkerfiedActor = (
3535
worker: Worker
3636
): WorkerActorLogic<EventObject, WorkerInput> => ({
3737
config: Worker,
38+
39+
40+
3841

3942
start: (state, actorScope) => {
4043
const { self, system } = actorScope;
@@ -46,22 +49,39 @@ export const fromWorkerfiedActor = (
4649
};
4750

4851
worker.addEventListener('message', (event) => {
49-
const eventFromWorker = event.data as AnyEventObject;
50-
if (eventFromWorker.type == 'STATE_SNAPSHOT') {
52+
console.log('Message received from worker --> ', event,event.data.type == WORKER_EVENTS.PROXY_EVENT,WORKER_EVENTS.PROXY_EVENT);
53+
const eventPayload = event.data;
54+
if (eventPayload.type === WORKER_EVENTS.STATE_SNAPSHOT) {
55+
const eventFromWorker = eventPayload as STATE_SNAPSHOT_EVENT;
5156
self.send(eventFromWorker);
5257
return state;
5358
}
5459

55-
if (event.type === WORKER_EVENTS.PROXY_EVENT) {
56-
const proxyEvent = event as ProxyEvent;
57-
if (proxyEvent.data.to === 'parent' && self._parent) {
60+
if (eventPayload.type === WORKER_EVENTS.PROXY_EVENT) {
61+
62+
const proxyEvent = eventPayload as ProxyEvent;
63+
const targetActorId = proxyEvent.data.to;
64+
const targetEvent = proxyEvent.data.event;
65+
const isToParent = targetActorId === 'parent';
66+
console.log('Proxy event received from worker to', targetActorId, targetEvent, isToParent);
67+
68+
69+
if (isToParent && self._parent) {
5870
console.log('Relaying to parent', proxyEvent.data);
5971
self._parent.send(proxyEvent.data.event);
6072
return state;
6173
}
74+
if (!isToParent) {
75+
const targetActor = system.get(proxyEvent.data.to);
76+
console.log('Relaying to system actor', proxyEvent.data, targetActor,system,self);
77+
if (targetActor){
78+
targetActor.send(proxyEvent.data.event);
79+
}
80+
return state;
81+
}
82+
83+
6284

63-
system.get(proxyEvent.data.to).send(proxyEvent.data.event);
64-
return state;
6585
}
6686
});
6787

@@ -70,6 +90,8 @@ export const fromWorkerfiedActor = (
7090
transition: (state, event, actorScope) => {
7191
const { self } = actorScope;
7292
const workerState = instanceStates.get(self);
93+
console.log('fromWorkerActor transition', state, event, actorScope);
94+
7395
if (event.type === 'xstate.stop') {
7496
console.log('Stopping fromWorkerActor...', state, event, actorScope);
7597
workerState.worker.postMessage(workerCommands.stopActor());
@@ -80,6 +102,9 @@ export const fromWorkerfiedActor = (
80102
error: undefined
81103
};
82104
}
105+
106+
107+
83108
if (event.type == WORKER_EVENTS.STATE_SNAPSHOT) {
84109
const snapshot = (event as STATE_SNAPSHOT_EVENT).data.snapshot as AnyMachineSnapshot;
85110
return {

src/actors/worker/workerfy.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const ProxyActor = setup({
2626
on: {
2727
'*': {
2828
actions: [
29-
({ event, context }) => console.log('Proxying event', event, 'to', context.proxyToId),
29+
({ event, context }) => console.log('Proxying actor event', event, 'to', context.proxyToId),
3030
({ event, context }) => postMessage(workerEvents.proxyEvent(event, context.proxyToId))
3131
]
3232
}
@@ -56,6 +56,8 @@ export const workerfyActor = (actor: AnyActorLogic) => {
5656
}
5757
}).start();
5858

59+
console.log('Worker actor initialized, waiting for commands...');
60+
5961
addEventListener('message', (event) => {
6062
if (event.data.type === WORKER_COMMANDS.START_ACTOR) {
6163
actorRef = createActor(actor, {

0 commit comments

Comments
 (0)