fix order of execution
This commit is contained in:
Vendored
+21
-7
@@ -10,7 +10,7 @@ export interface EventReactionCouplings_T<C> {
|
||||
eventName: string;
|
||||
reactions: Array<Reaction_T<C>>;
|
||||
}
|
||||
export type Reaction_T<C> = SideEffect_T<C> | ContextMutation_T<C> | Goto_T;
|
||||
export type Reaction_T<C> = SideEffect_T<C> | ContextMutation_T<C> | Peering_T<C, unknown> | Goto_T;
|
||||
export interface SideEffect_T<C> {
|
||||
type: 'SideEffect';
|
||||
fn: SideEffectFunction_T<C>;
|
||||
@@ -21,6 +21,12 @@ export interface ContextMutation_T<C> {
|
||||
fn: ContextMutationFunction_T<C>;
|
||||
}
|
||||
export type ContextMutationFunction_T<C> = (ctx: C, e: Event_T, self: Interpreter_T<C>) => C;
|
||||
export interface Peering_T<C, C_Peer> {
|
||||
type: 'Peering';
|
||||
name: string;
|
||||
peerCreationFunction: PeerCreationFunction_T<C, C_Peer>;
|
||||
}
|
||||
export type PeerCreationFunction_T<C, C_Peer> = (ctx: C, e: Event_T, self: Interpreter_T<C>) => Interpreter_T<C_Peer>;
|
||||
export interface Goto_T {
|
||||
type: 'Goto';
|
||||
targetStateName: string;
|
||||
@@ -31,16 +37,20 @@ export declare const On: <C>(eventName: string, ...reactions: Reaction_T<C>[]) =
|
||||
export declare const SideEffect: <C>(fn: SideEffectFunction_T<C>) => SideEffect_T<C>;
|
||||
export declare const Goto: (targetStateName: string) => Goto_T;
|
||||
export declare const Context: <C>(fn: ContextMutationFunction_T<C>) => ContextMutation_T<C>;
|
||||
export declare const Peer: <C, C_Peer>(name: string, peerCreationFunction: PeerCreationFunction_T<C, C_Peer>) => Peering_T<C, C_Peer>;
|
||||
export interface Interpreter_T<C> {
|
||||
machine: Machine_T<C>;
|
||||
state: string;
|
||||
context: C;
|
||||
peers: Record<string, Interpreter_T<unknown>>;
|
||||
peerSubscriptionIds: Map<Interpreter_T<unknown>, string>;
|
||||
eventQueue: Array<Event_T>;
|
||||
subscriptions: Record<string, SubscriptionCallbackFunction_T<C>>;
|
||||
subscriptionsToEvents: Record<string, EventsSubscriptionCallbackFunction_T<C>>;
|
||||
subscriptionsToState: Record<string, StateSubscriptionCallbackFunction_T<C>>;
|
||||
subscriptionsToSettledState: Record<string, SettledStateSubscriptionCallbackFunction_T<C>>;
|
||||
isTransitioning: boolean;
|
||||
isPaused: boolean;
|
||||
start: () => Interpreter_T<C>;
|
||||
subscribe: (callback: SubscriptionCallbackFunction_T<C>) => Interpreter_T<C>;
|
||||
}
|
||||
/**
|
||||
* Description placeholder
|
||||
@@ -66,8 +76,12 @@ export declare function pause<C>(interpreter: Interpreter_T<C>): void;
|
||||
*/
|
||||
export declare function send<C>(interpreter: Interpreter_T<C>, event: Event_T): void;
|
||||
export declare const enqueue: typeof send;
|
||||
export type SubscriptionCallbackFunction_T<C> = (self: Interpreter_T<C>) => void;
|
||||
export declare function subscribe<C>(interpreter: Interpreter_T<C>, callback: SubscriptionCallbackFunction_T<C>): string;
|
||||
export type EventsSubscriptionCallbackFunction_T<C> = (e: Event_T, self: Interpreter_T<C>) => void;
|
||||
export type StateSubscriptionCallbackFunction_T<C> = (e: Event_T, self: Interpreter_T<C>) => void;
|
||||
export type SettledStateSubscriptionCallbackFunction_T<C> = (self: Interpreter_T<C>) => void;
|
||||
export declare function subscribe<C>(interpreter: Interpreter_T<C>, callback: SettledStateSubscriptionCallbackFunction_T<C>): string;
|
||||
export declare const subscribeToSettledState: typeof subscribe;
|
||||
export declare function subscribeToState<C>(interpreter: Interpreter_T<C>, callback: StateSubscriptionCallbackFunction_T<C>): string;
|
||||
export declare function subscribeToEvents<C>(interpreter: Interpreter_T<C>, callback: StateSubscriptionCallbackFunction_T<C>): string;
|
||||
export declare function unsubscribe<C>(interpreter: Interpreter_T<C>, subscriptionId: string): void;
|
||||
export declare const Spawn: () => void;
|
||||
export declare const Unspawn: () => void;
|
||||
export declare function addPeer<C, C_Peer>(self: Interpreter_T<C>, name: string, peer: Interpreter_T<C_Peer>): void;
|
||||
|
||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
||||
var y=function(...t){return{states:t}},E=function(t,...e){return{name:t,eventReactionCouplings:e}},v=function(t,...e){return{eventName:t,reactions:e}},S=function(t){return{type:"SideEffect",fn:t}},b=function(t){return{type:"Goto",targetStateName:t}},M=function(t){return{type:"ContextMutation",fn:t}};function I(t,e,o){typeof o>"u"&&(o=t.states[0].name);let n={machine:t,state:o,context:e,eventQueue:[],isTransitioning:!1,subscriptions:{},isPaused:!0};return n.start=()=>(_(n),n),n.subscribe=i=>(d(n,i),n),a(n,["entry",null]),n}function _(t){t.isPaused===!0&&(t.isPaused=!1,u(t))}function h(t){t.isPaused===!1&&(t.isPaused=!0)}function p(t){return t.machine.states.find(e=>e.name===t.state)}function l(t,e){return t.eventReactionCouplings.filter(o=>o.eventName===e[0])}function a(t,e){t.eventQueue.push(e),t.isTransitioning===!1&&u(t)}var R=a;function u(t){for(t.isTransitioning=!0;t.eventQueue.length>0&&t.isPaused===!1;)x(t);t.isTransitioning=!1,Object.values(t.subscriptions).forEach(e=>{e(t)})}function x(t){let e=t.eventQueue.shift();if(typeof e<"u"){let o=p(t),i=l(o,e).map(s=>s.reactions).flat(),{sideEffects:C,contextMutations:f,goto_:c}=g(i),T=t.context;f.forEach(s=>{t.context=s.fn(t.context,e,t)}),C.forEach(s=>{s.fn(t.context,e,t,T)}),c!==null&&(a(t,["exit",null]),t.state=c.targetStateName,a(t,["entry",null]))}}function g(t){let e=[],o=[],n=null;return t.forEach(i=>{i.type==="SideEffect"?e.push(i):i.type==="ContextMutation"?o.push(i):i.type==="Goto"&&(n=i)}),{sideEffects:e,contextMutations:o,goto_:n}}var r=0;function d(t,e){return r++,t.subscriptions[r.toString()]=e,r.toString()}function A(t,e){delete t.subscriptions[e.toString()]}var F=function(){},m=function(){};export{M as Context,b as Goto,I as Interpreter,y as Machine,v as On,S as SideEffect,F as Spawn,E as State,m as Unspawn,R as enqueue,h as pause,a as send,_ as start,d as subscribe,A as unsubscribe};
|
||||
var v=function(...t){return{states:t}},y=function(t,...e){return{name:t,eventReactionCouplings:e}},P=function(t,...e){return{eventName:t,reactions:e}},I=function(t){return{type:"SideEffect",fn:t}},M=function(t){return{type:"Goto",targetStateName:t}},h=function(t){return{type:"ContextMutation",fn:t}},F=function(t,e){return{type:"Peering",name:t,peerCreationFunction:e}};function R(t,e,n){typeof n>"u"&&(n=t.states[0].name);let o={machine:t,state:n,context:e,eventQueue:[],isTransitioning:!1,peers:{},peerSubscriptionIds:new Map,subscriptionsToEvents:{},subscriptionsToState:{},subscriptionsToSettledState:{},isPaused:!0};return o.start=()=>(f(o),o),c(o,["entry",null]),o}function f(t){t.isPaused===!0&&(t.isPaused=!1,C(t))}function k(t){t.isPaused===!1&&(t.isPaused=!0)}function l(t){return t.machine.states.find(e=>e.name===t.state)}function S(t,e){return t.eventReactionCouplings.filter(n=>n.eventName===e[0])}function c(t,e){t.eventQueue.push(e),t.isTransitioning===!1&&C(t)}var A=c;function C(t){for(t.isTransitioning=!0;t.eventQueue.length>0&&t.isPaused===!1;)g(t);t.isTransitioning=!1,Object.values(t.subscriptionsToSettledState).forEach(e=>{e(t)})}function g(t){let e=t.eventQueue.shift();if(typeof e<"u"){let n=l(t),a=S(n,e).map(i=>i.reactions).flat(),{sideEffects:r,contextMutations:T,peerings:p,goto_:u}=x(a),_=t.context;T.forEach(i=>{t.context=i.fn(t.context,e,t)}),u!==null&&(c(t,["exit",null]),t.state=u.targetStateName,Object.values(t.subscriptionsToState).forEach(i=>{i(e,t)}),c(t,["entry",null])),p.forEach(i=>{E(t,i.name,i.peerCreationFunction(t.context,e,t))}),Object.values(t.subscriptionsToEvents).forEach(i=>{i(e,t)}),r.forEach(i=>{i.fn(t.context,e,t,_)})}}function x(t){let e=[],n=[],o=[],a=null;return t.forEach(r=>{r.type==="SideEffect"?e.push(r):r.type==="ContextMutation"?n.push(r):r.type==="Peering"?o.push(r):r.type==="Goto"&&(a=r)}),{sideEffects:e,contextMutations:n,peerings:o,goto_:a}}var s=0;function d(t,e){return s++,t.subscriptionsToSettledState[s.toString()]=e,s.toString()}var m=d;function G(t,e){return s++,t.subscriptionsToState[s.toString()]=e,s.toString()}function b(t,e){return s++,t.subscriptionsToEvents[s.toString()]=e,s.toString()}function w(t,e){delete t.subscriptionsToSettledState[e.toString()],delete t.subscriptionsToState[e.toString()],delete t.subscriptionsToEvents[e.toString()]}function E(t,e,n){t.peers[e]=n,b(n,(o,a)=>{t.isTransitioning===!1&&c(t,[e+"."+o[0],o[1]])})}export{h as Context,M as Goto,R as Interpreter,v as Machine,P as On,F as Peer,I as SideEffect,y as State,E as addPeer,A as enqueue,k as pause,c as send,f as start,d as subscribe,b as subscribeToEvents,m as subscribeToSettledState,G as subscribeToState,w as unsubscribe};
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
Vendored
+63
-21
@@ -15,15 +15,24 @@
|
||||
var Goto = function(targetStateName) {
|
||||
return { type: "Goto", targetStateName };
|
||||
};
|
||||
function interpret(machine2, options) {
|
||||
let { state, context } = options;
|
||||
if (typeof state === "undefined") {
|
||||
state = machine2.states[0].name;
|
||||
function Interpreter(machine2, initialContext, initialStateName) {
|
||||
if (typeof initialStateName === "undefined") {
|
||||
initialStateName = machine2.states[0].name;
|
||||
}
|
||||
const interpreter = { machine: machine2, state, context, eventQueue: [], isTransitioning: false };
|
||||
const interpreter = { machine: machine2, state: initialStateName, context: initialContext, eventQueue: [], isTransitioning: false, peers: {}, peerSubscriptionIds: /* @__PURE__ */ new Map(), subscriptionsToEvents: {}, subscriptionsToState: {}, subscriptionsToSettledState: {}, isPaused: true };
|
||||
interpreter.start = () => {
|
||||
start(interpreter);
|
||||
return interpreter;
|
||||
};
|
||||
send(interpreter, ["entry", null]);
|
||||
return interpreter;
|
||||
}
|
||||
function start(interpreter) {
|
||||
if (interpreter.isPaused === true) {
|
||||
interpreter.isPaused = false;
|
||||
processEvents(interpreter);
|
||||
}
|
||||
}
|
||||
function getState(interpreter) {
|
||||
return interpreter.machine.states.find((state) => state.name === interpreter.state);
|
||||
}
|
||||
@@ -33,44 +42,77 @@
|
||||
function send(interpreter, event) {
|
||||
interpreter.eventQueue.push(event);
|
||||
if (interpreter.isTransitioning === false) {
|
||||
interpreter.isTransitioning = true;
|
||||
while (interpreter.eventQueue.length > 0) {
|
||||
processNextEvent(interpreter);
|
||||
}
|
||||
interpreter.isTransitioning = false;
|
||||
processEvents(interpreter);
|
||||
}
|
||||
}
|
||||
function processEvents(interpreter) {
|
||||
interpreter.isTransitioning = true;
|
||||
while (interpreter.eventQueue.length > 0 && interpreter.isPaused === false) {
|
||||
processNextEvent(interpreter);
|
||||
}
|
||||
interpreter.isTransitioning = false;
|
||||
Object.values(interpreter.subscriptionsToSettledState).forEach((callbackFunction) => {
|
||||
callbackFunction(interpreter);
|
||||
});
|
||||
}
|
||||
function processNextEvent(interpreter) {
|
||||
const nextEvent = interpreter.eventQueue.shift();
|
||||
if (typeof nextEvent !== "undefined") {
|
||||
const event = interpreter.eventQueue.shift();
|
||||
if (typeof event !== "undefined") {
|
||||
const state = getState(interpreter);
|
||||
const eventReactionCouplings = getMatchingEventReactionCouplings(state, nextEvent);
|
||||
const eventReactionCouplings = getMatchingEventReactionCouplings(state, event);
|
||||
const reactions = eventReactionCouplings.map((eventReactionCoupling) => eventReactionCoupling.reactions).flat();
|
||||
const { sideEffects, contextMutations, goto_ } = categorizeReactions(reactions);
|
||||
sideEffects.forEach((sideEffect) => {
|
||||
sideEffect.fn(interpreter.context, nextEvent, interpreter);
|
||||
});
|
||||
const { sideEffects, contextMutations, peerings, goto_ } = categorizeReactions(reactions);
|
||||
const originalContext = interpreter.context;
|
||||
contextMutations.forEach((contextMutation) => {
|
||||
interpreter.context = contextMutation.fn(interpreter.context, nextEvent, interpreter);
|
||||
interpreter.context = contextMutation.fn(interpreter.context, event, interpreter);
|
||||
});
|
||||
if (goto_ !== null) {
|
||||
send(interpreter, ["exit", null]);
|
||||
interpreter.state = goto_.targetStateName;
|
||||
Object.values(interpreter.subscriptionsToState).forEach((callbackFunction) => {
|
||||
callbackFunction(event, interpreter);
|
||||
});
|
||||
send(interpreter, ["entry", null]);
|
||||
}
|
||||
peerings.forEach((peering) => {
|
||||
addPeer(interpreter, peering.name, peering.peerCreationFunction(interpreter.context, event, interpreter));
|
||||
});
|
||||
Object.values(interpreter.subscriptionsToEvents).forEach((callbackFunction) => {
|
||||
callbackFunction(event, interpreter);
|
||||
});
|
||||
sideEffects.forEach((sideEffect) => {
|
||||
sideEffect.fn(interpreter.context, event, interpreter, originalContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
function categorizeReactions(reactions) {
|
||||
let sideEffects = [], contextMutations = [], goto_ = null;
|
||||
let sideEffects = [], contextMutations = [], peerings = [], goto_ = null;
|
||||
reactions.forEach((reaction) => {
|
||||
if (reaction.type === "SideEffect") {
|
||||
sideEffects.push(reaction);
|
||||
} else if (reaction.type === "ContextMutation") {
|
||||
contextMutations.push(reaction);
|
||||
} else if (reaction.type === "Peering") {
|
||||
peerings.push(reaction);
|
||||
} else if (reaction.type === "Goto") {
|
||||
goto_ = reaction;
|
||||
}
|
||||
});
|
||||
return { sideEffects, contextMutations, goto_ };
|
||||
return { sideEffects, contextMutations, peerings, goto_ };
|
||||
}
|
||||
var subscriptionId = 0;
|
||||
function subscribeToEvents(interpreter, callback) {
|
||||
subscriptionId++;
|
||||
interpreter.subscriptionsToEvents[subscriptionId.toString()] = callback;
|
||||
return subscriptionId.toString();
|
||||
}
|
||||
function addPeer(self, name, peer) {
|
||||
self.peers[name] = peer;
|
||||
subscribeToEvents(peer, (e, peer2) => {
|
||||
if (self.isTransitioning === false) {
|
||||
send(self, [name + "." + e[0], e[1]]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// src/tests/00-basic.ts
|
||||
@@ -120,5 +162,5 @@
|
||||
)
|
||||
)
|
||||
);
|
||||
var actor = interpret(machine, { context: {} });
|
||||
var actor = Interpreter(machine, { context: {} }).start();
|
||||
})();
|
||||
|
||||
Vendored
+106
-43
@@ -18,15 +18,27 @@
|
||||
var Context = function(fn) {
|
||||
return { type: "ContextMutation", fn };
|
||||
};
|
||||
function interpret(machine, options) {
|
||||
let { state, context } = options;
|
||||
if (typeof state === "undefined") {
|
||||
state = machine.states[0].name;
|
||||
var Peer = function(name, peerCreationFunction) {
|
||||
return { type: "Peering", name, peerCreationFunction };
|
||||
};
|
||||
function Interpreter(machine, initialContext, initialStateName) {
|
||||
if (typeof initialStateName === "undefined") {
|
||||
initialStateName = machine.states[0].name;
|
||||
}
|
||||
const interpreter = { machine, state, context, eventQueue: [], isTransitioning: false };
|
||||
const interpreter = { machine, state: initialStateName, context: initialContext, eventQueue: [], isTransitioning: false, peers: {}, peerSubscriptionIds: /* @__PURE__ */ new Map(), subscriptionsToEvents: {}, subscriptionsToState: {}, subscriptionsToSettledState: {}, isPaused: true };
|
||||
interpreter.start = () => {
|
||||
start(interpreter);
|
||||
return interpreter;
|
||||
};
|
||||
send(interpreter, ["entry", null]);
|
||||
return interpreter;
|
||||
}
|
||||
function start(interpreter) {
|
||||
if (interpreter.isPaused === true) {
|
||||
interpreter.isPaused = false;
|
||||
processEvents(interpreter);
|
||||
}
|
||||
}
|
||||
function getState(interpreter) {
|
||||
return interpreter.machine.states.find((state) => state.name === interpreter.state);
|
||||
}
|
||||
@@ -36,44 +48,77 @@
|
||||
function send(interpreter, event) {
|
||||
interpreter.eventQueue.push(event);
|
||||
if (interpreter.isTransitioning === false) {
|
||||
interpreter.isTransitioning = true;
|
||||
while (interpreter.eventQueue.length > 0) {
|
||||
processNextEvent(interpreter);
|
||||
}
|
||||
interpreter.isTransitioning = false;
|
||||
processEvents(interpreter);
|
||||
}
|
||||
}
|
||||
function processEvents(interpreter) {
|
||||
interpreter.isTransitioning = true;
|
||||
while (interpreter.eventQueue.length > 0 && interpreter.isPaused === false) {
|
||||
processNextEvent(interpreter);
|
||||
}
|
||||
interpreter.isTransitioning = false;
|
||||
Object.values(interpreter.subscriptionsToSettledState).forEach((callbackFunction) => {
|
||||
callbackFunction(interpreter);
|
||||
});
|
||||
}
|
||||
function processNextEvent(interpreter) {
|
||||
const nextEvent = interpreter.eventQueue.shift();
|
||||
if (typeof nextEvent !== "undefined") {
|
||||
const event = interpreter.eventQueue.shift();
|
||||
if (typeof event !== "undefined") {
|
||||
const state = getState(interpreter);
|
||||
const eventReactionCouplings = getMatchingEventReactionCouplings(state, nextEvent);
|
||||
const eventReactionCouplings = getMatchingEventReactionCouplings(state, event);
|
||||
const reactions = eventReactionCouplings.map((eventReactionCoupling) => eventReactionCoupling.reactions).flat();
|
||||
const { sideEffects, contextMutations, goto_ } = categorizeReactions(reactions);
|
||||
sideEffects.forEach((sideEffect) => {
|
||||
sideEffect.fn(interpreter.context, nextEvent, interpreter);
|
||||
});
|
||||
const { sideEffects, contextMutations, peerings, goto_ } = categorizeReactions(reactions);
|
||||
const originalContext = interpreter.context;
|
||||
contextMutations.forEach((contextMutation) => {
|
||||
interpreter.context = contextMutation.fn(interpreter.context, nextEvent, interpreter);
|
||||
interpreter.context = contextMutation.fn(interpreter.context, event, interpreter);
|
||||
});
|
||||
if (goto_ !== null) {
|
||||
send(interpreter, ["exit", null]);
|
||||
interpreter.state = goto_.targetStateName;
|
||||
Object.values(interpreter.subscriptionsToState).forEach((callbackFunction) => {
|
||||
callbackFunction(event, interpreter);
|
||||
});
|
||||
send(interpreter, ["entry", null]);
|
||||
}
|
||||
peerings.forEach((peering) => {
|
||||
addPeer(interpreter, peering.name, peering.peerCreationFunction(interpreter.context, event, interpreter));
|
||||
});
|
||||
Object.values(interpreter.subscriptionsToEvents).forEach((callbackFunction) => {
|
||||
callbackFunction(event, interpreter);
|
||||
});
|
||||
sideEffects.forEach((sideEffect) => {
|
||||
sideEffect.fn(interpreter.context, event, interpreter, originalContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
function categorizeReactions(reactions) {
|
||||
let sideEffects = [], contextMutations = [], goto_ = null;
|
||||
let sideEffects = [], contextMutations = [], peerings = [], goto_ = null;
|
||||
reactions.forEach((reaction) => {
|
||||
if (reaction.type === "SideEffect") {
|
||||
sideEffects.push(reaction);
|
||||
} else if (reaction.type === "ContextMutation") {
|
||||
contextMutations.push(reaction);
|
||||
} else if (reaction.type === "Peering") {
|
||||
peerings.push(reaction);
|
||||
} else if (reaction.type === "Goto") {
|
||||
goto_ = reaction;
|
||||
}
|
||||
});
|
||||
return { sideEffects, contextMutations, goto_ };
|
||||
return { sideEffects, contextMutations, peerings, goto_ };
|
||||
}
|
||||
var subscriptionId = 0;
|
||||
function subscribeToEvents(interpreter, callback) {
|
||||
subscriptionId++;
|
||||
interpreter.subscriptionsToEvents[subscriptionId.toString()] = callback;
|
||||
return subscriptionId.toString();
|
||||
}
|
||||
function addPeer(self, name, peer) {
|
||||
self.peers[name] = peer;
|
||||
subscribeToEvents(peer, (e, peer2) => {
|
||||
if (self.isTransitioning === false) {
|
||||
send(self, [name + "." + e[0], e[1]]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// src/tests/01-ping-pong.ts
|
||||
@@ -83,30 +128,36 @@
|
||||
}, ms);
|
||||
});
|
||||
var makeRequest = (ctx, e, self) => {
|
||||
send(ctx.serverActor, ["received-request", self]);
|
||||
send(self.peers.server, ["received-request", self]);
|
||||
};
|
||||
var sendResponse = (ctx, e, self) => {
|
||||
send(ctx.clientActor, ["received-response", self]);
|
||||
send(ctx.client, ["received-response", self]);
|
||||
};
|
||||
var startTimer = async (ctx, e, self) => {
|
||||
await wait(1500);
|
||||
console.log(" timer actually finished");
|
||||
send(self, ["timer-finished", null]);
|
||||
};
|
||||
var log = (ctx, e, self) => {
|
||||
console.log(self.state, ctx);
|
||||
var logServerStats = (ctx, e, self) => {
|
||||
console.log("server", ctx.requestsReceived, ctx.responsesSent);
|
||||
};
|
||||
var saveClient = (ctx, e, self) => ({ ...ctx, client: e[1] });
|
||||
var createServer = (ctx, e, self) => Interpreter(server, { requestsReceived: 0, responsesSent: 0 }).start();
|
||||
var client = Machine(
|
||||
State(
|
||||
"initializing",
|
||||
On(
|
||||
"entry",
|
||||
Peer("server", createServer),
|
||||
//SideEffect(log('client')),
|
||||
Goto("idle")
|
||||
)
|
||||
),
|
||||
State(
|
||||
"idle",
|
||||
On(
|
||||
"entry",
|
||||
SideEffect(log)
|
||||
),
|
||||
On(
|
||||
"server-created",
|
||||
SideEffect((_ctx, [_eventName, serverActor2], self) => {
|
||||
self.context.serverActor = serverActor2;
|
||||
}),
|
||||
//SideEffect(log('client')),
|
||||
Goto("making-request")
|
||||
)
|
||||
),
|
||||
@@ -114,7 +165,7 @@
|
||||
"making-request",
|
||||
On(
|
||||
"entry",
|
||||
SideEffect(log),
|
||||
//SideEffect(log('client')),
|
||||
SideEffect(makeRequest),
|
||||
Context((ctx) => ({ ...ctx, requestsMade: ctx.requestsMade + 1 })),
|
||||
Goto("awaiting-response")
|
||||
@@ -123,13 +174,13 @@
|
||||
State(
|
||||
"awaiting-response",
|
||||
On(
|
||||
"entry",
|
||||
SideEffect(log)
|
||||
"entry"
|
||||
//SideEffect(log('client')),
|
||||
),
|
||||
On(
|
||||
"received-response",
|
||||
SideEffect(log),
|
||||
Context((ctx) => ({ ...ctx, responsesReceived: ctx.responsesReceived + 1 })),
|
||||
//SideEffect(log('client')),
|
||||
Goto("making-request")
|
||||
)
|
||||
)
|
||||
@@ -139,13 +190,13 @@
|
||||
"awaiting-request",
|
||||
On(
|
||||
"entry",
|
||||
SideEffect(log)
|
||||
//SideEffect(log('server')),
|
||||
Context((ctx) => ({ ...ctx, requestsReceived: ctx.requestsReceived + 1 }))
|
||||
),
|
||||
On(
|
||||
"received-request",
|
||||
SideEffect((_ctx, [_eventName, clientActor2], self) => {
|
||||
self.context.clientActor = clientActor2;
|
||||
}),
|
||||
//SideEffect(log('server')),
|
||||
Context(saveClient),
|
||||
Goto("sending-response")
|
||||
)
|
||||
),
|
||||
@@ -153,17 +204,29 @@
|
||||
"sending-response",
|
||||
On(
|
||||
"entry",
|
||||
SideEffect(log),
|
||||
//SideEffect(log('server')),
|
||||
SideEffect(startTimer)
|
||||
),
|
||||
On(
|
||||
"timer-finished",
|
||||
//SideEffect(log('server')),
|
||||
SideEffect(logServerStats),
|
||||
SideEffect(sendResponse),
|
||||
Context((ctx) => ({ ...ctx, responsesSent: ctx.responsesSent + 1 })),
|
||||
Goto("awaiting-request")
|
||||
// for some reason, at this point there's a "received-request" waiting in the eventQueue, which gets processed before the "exit" then "entry" that get appended to the queue due to this Goto, which makes the Interpreter come right back to this State
|
||||
/*
|
||||
Server gets timer-finished, which sends response to client.
|
||||
|
||||
But client, at the time, is not transitioning, so it immediately begins
|
||||
processing that event. The problem is that one of the sideeffects involved
|
||||
in processing that event is to send another request to the server,
|
||||
which hasn't yet even queued `exit`-then-`entry` events for its next state!
|
||||
|
||||
So we have to ensure they get queued first, before processing the client.
|
||||
*/
|
||||
)
|
||||
)
|
||||
);
|
||||
var clientActor = interpret(client, { context: { requestsMade: 0, responsesReceived: 0 } });
|
||||
var serverActor = interpret(server, { context: {} });
|
||||
send(clientActor, ["server-created", serverActor]);
|
||||
var clientActor = Interpreter(client, { requestsMade: 0, responsesReceived: 0 }).start();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user