Skip to content

Instantly share code, notes, and snippets.

@drmikecrowe
Last active November 16, 2019 12:29
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 drmikecrowe/72faa83a5a0d21b36a1bdb9489ab2c79 to your computer and use it in GitHub Desktop.
Save drmikecrowe/72faa83a5a0d21b36a1bdb9489ab2c79 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
const SECONDS = 1000;
const MINUTES = 60 * SECONDS;
const HOURS = 60 * MINUTES;
const MAX_RETRIES = 3;
const RETRY_INTERVAL = 3 * SECONDS;
const UPDATE_PODCAST_INTERVAL = 4 * HOURS;
const initializeStates = {
id: "initialize",
initial: "initHardware",
states: {
initHardware: {
on: {
INIT_HARDWARE_COMPLETE: "connectNetwork",
},
},
connectNetwork: {
on: {
WIFI_CONNECTED: "provision",
ERROR: "error",
},
},
provision: {
on: {
IOT_CONNECTED: {
actions: "resetRetries",
target: "connected",
},
ERROR: "error",
},
},
error: {
on: {
"": [
{
target: "retry",
cond: "condHaveRetries",
actions: "incrementRetries",
},
{
target: "fatal",
cond: "condHaveNoRetries",
},
],
},
},
retry: {
after: {
[RETRY_INTERVAL]: "initHardware",
},
},
fatal: {
type: "final",
data: { error: "Hardware Failure" },
},
connected: {
type: "final",
},
},
};
const waitingMenuStates = {
id: "waitmenu",
initial: "askUpdateNow",
context: {},
states: {
askUpdateNow: {
on: {
PLAY_BUTTON: {
actions: send({ type: "UPDATE_NOW", to: "#Root.running.updater" }),
target: "done",
},
MENU_BUTTON: "askMenuTwo",
},
},
askMenuTwo: {
on: {
PLAY_BUTTON: {
actions: ["TBD"],
target: "done",
},
MENU_BUTTON: "askMenuThree",
},
},
askMenuThree: {
on: {
PLAY_BUTTON: {
actions: ["TBD"],
target: "done",
},
MENU_BUTTON: "done",
},
},
done: {
type: "final",
},
},
};
const playMenuStates = {
id: "playmenu",
initial: "askMenuOne",
context: {},
states: {
askMenuOne: {
on: {
PLAY_BUTTON: {
actions: ["TBD"],
target: "done",
},
MENU_BUTTON: "askMenuTwo",
},
},
askMenuTwo: {
on: {
PLAY_BUTTON: {
actions: ["TBD"],
target: "done",
},
MENU_BUTTON: "askMenuThree",
},
},
askMenuThree: {
on: {
PLAY_BUTTON: {
actions: ["TBD"],
target: "done",
},
MENU_BUTTON: "done",
},
},
done: {
type: "final",
},
},
};
const playerStates = {
id: "player",
initial: "waiting",
context: {
retries: 0,
},
states: {
waiting: {
on: {
PLAY_BUTTON: {
target: "playing",
cond: "condHaveEpisodes",
},
MENU_BUTTON: "waitingMenu",
},
},
waitingMenu: {
...waitingMenuStates,
onDone: "waiting",
},
playing: {
on: {
"": {
actions: "playPodcast",
},
STOP_BUTTON: "waiting",
MENU_BUTTON: "playingMenu",
},
},
playingMenu: {
...playMenuStates,
onDone: "playing",
},
},
};
const updaterStates = {
id: "updater",
initial: "checkForUpdates",
context: {},
states: {
checkForUpdates: {
on: {
CHECK_UPDATE_COMPLETE: "waitForUpdates",
},
},
waitForUpdates: {
on: {
UPDATE_NOW: { target: "checkForUpdates", cond: "logEvent" },
},
after: {
[UPDATE_PODCAST_INTERVAL]: {
target: "checkForUpdates",
},
},
},
},
};
const runningStates = {
id: "running",
type: "parallel",
initial: "waiting",
states: {
player: {
...playerStates,
},
updater: {
...updaterStates,
},
},
};
const masterMachine = Machine(
{
id: "Root",
initial: "initialize",
context: {
retries: 0,
},
states: {
initialize: {
...initializeStates,
onDone: [
{ target: "running", cond: "isNotError" },
{ target: "shutdown", cond: "isError" },
],
onError: "shutdown",
},
running: {
...runningStates,
onDone: "shutdown",
on: {
SHUTDOWN: "shutdown",
},
},
shutdown: {
on: {
"": {
actions: "powerOff",
target: "off",
},
},
},
off: {
type: "final",
},
},
on: {
STOP_BUTTON_HELD: "shutdown",
},
},
{
actions: {
incrementRetries: assign({ retries: ctx => ctx.retries + 1 }),
resetRetries: assign({ retries: ctx => (ctx.retries = 0) }),
},
guards: {
condHaveRetries: ctx => ctx.retries < MAX_RETRIES,
condHaveNoRetries: ctx => ctx.retries >= MAX_RETRIES,
condHaveEpisodes: (ctx, _evt) => ctx.downloadCount > 0 || true,
logEvent: (ctx, e) => {
console.log("logEvent: ", ctx, e);
return true;
},
isNotError: (_ctx, event) => {
const data = (event && event.data) || { error: false };
return !data.error;
},
isError: (_ctx, event) => {
const data = (event && event.data) || { error: false };
console.log("Machine:guards:error:event.data.error=", event, data.error);
return data.error;
},
},
},
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment