Skip to content

Instantly share code, notes, and snippets.

@jlengstorf
Last active June 13, 2020 21:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlengstorf/8135f632165c4582f2c357abeda619bb to your computer and use it in GitHub Desktop.
Save jlengstorf/8135f632165c4582f2c357abeda619bb to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const formatCommand = msg => {
const { name, duration, message, audio, image } = msg.handler;
return {
command: name,
message,
audio,
image,
duration: duration * 1000, // convert seconds to milliseconds
};
};
const handleQueue = {
ADD_TO_QUEUE: {
actions: assign((context, event) => {
return {
queue: context.queue.concat(formatCommand(event.message)),
};
}),
},
};
const commandMachine = Machine({
id: 'commands',
initial: 'idle',
context: {
current: {},
queue: [],
},
states: {
idle: {
on: {
RUN: {
actions: assign({
current: (_context, event) => formatCommand(event.message),
}),
target: 'loadingCommandAssets',
},
},
},
loadingCommandAssets: {
on: handleQueue,
invoke: {
src: 'commandLoadAssets',
onDone: 'starting',
onError: 'error',
},
},
starting: {
on: handleQueue,
invoke: {
src: 'commandStart',
onDone: 'active',
onError: 'error',
},
},
active: {
on: handleQueue,
after: {
COMMAND_DURATION: 'stopping',
},
},
stopping: {
on: handleQueue,
invoke: {
src: 'commandEnd',
onDone: 'checkingForQueuedCommands',
onError: 'error',
},
exit: assign({ current: {} }),
},
checkingForQueuedCommands: {
on: {
...handleQueue,
'': [
{
cond: context => context.queue.length > 0,
target: 'startNextCommand',
},
{ target: 'idle' },
],
},
},
startNextCommand: {
on: {
...handleQueue,
'': {
actions: assign({
current: context => context.queue[0],
queue: context => context.queue.slice(1),
}),
target: 'loadingCommandAssets',
},
},
},
error: {
entry: (context, event) => console.error({ context, event }),
on: {
...handleQueue,
'': 'idle',
},
},
},
}, {
services: {
commandLoadAssets: ({ image, audio }) =>
Promise.all([
new Promise((resolve, reject) => {
if (!image) {
resolve(true);
return;
}
console.log({ image });
const img = new Image();
img.onload = () => resolve(img);
img.onerror = err => reject(err);
img.src = image;
}),
new Promise((resolve, reject) => {
if (!audio) {
resolve(true);
return;
}
console.log({ audio });
const sound = new Audio();
sound.addEventListener('canplaythrough', () => resolve(sound));
sound.onerror = err => reject(err);
sound.src = audio;
}),
]),
commandStart: () => new Promise(resolve => resolve('started!')),
commandEnd: () => new Promise(resolve => resolve('ended!')),
},
delays: {
COMMAND_DURATION: context => {
return context.current.duration ?? 4000;
},
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment