Skip to content

Instantly share code, notes, and snippets.

@rads
Last active December 6, 2019 22:27
Show Gist options
  • Select an option

  • Save rads/7b11c3f8cc67bc36698dff93a002cd14 to your computer and use it in GitHub Desktop.

Select an option

Save rads/7b11c3f8cc67bc36698dff93a002cd14 to your computer and use it in GitHub Desktop.

Revisions

  1. rads revised this gist Dec 6, 2019. 1 changed file with 25 additions and 17 deletions.
    42 changes: 25 additions & 17 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -5,14 +5,13 @@
    // https://xstate.js.org/viz/
    // =============================================================================

    const { cancel } = XState.actions;

    const incErrorCount = assign({ errorCount: (ctx, event) => ctx.errorCount + 1 });
    const incInitCount = assign({ initCount: (ctx, event) => ctx.initCount + 1 });
    const incRecoveryCount = assign({ recoveryCount: (ctx, event) => ctx.recoveryCount + 1 });
    const setCurrentEditor = assign({ currentEditor: (context, event) => event.editor });
    const setPendingInitializationTrue = assign({ pendingInitialization: (context, event) => true });
    const setPendingInitializationFalse = assign({ pendingInitialization: (context, event) => false });
    const setLastError = assign({ lastError: (context, event) => event.error });

    function isNotPendingInitialization(context, event) {
    return !context.pendingInitialization;
    @@ -51,7 +50,7 @@ function createMachine(options) {
    context: {
    initEditor: options.initEditor,
    windowEvents: options.windowEvents,
    startRecovery: options.startRecovery,
    sendRecoveryRequest: options.sendRecoveryRequest,
    docEvents: options.docEvents,
    requestRefresh: options.requestRefresh,
    beforeDestroy: options.beforeDestroy,
    @@ -60,7 +59,8 @@ function createMachine(options) {
    errorCount: 0,
    initCount: 0,
    recoveryCount: 0,
    pendingInitialization: false
    pendingInitialization: false,
    lastError: null
    },
    states: {
    stopping: {
    @@ -118,44 +118,52 @@ function createMachine(options) {
    },
    editing: { },
    error: {
    entry: incErrorCount,
    entry: [
    incErrorCount,
    setLastError
    ],
    on: {
    '': [
    {
    cond: isMaxErrors,
    actions: send('maxErrors'),
    target: 'failed'
    },
    {
    cond: 'isRecoveryTimeout',
    actions: send('recoveryTimeout'),
    target: 'failed'
    },
    { target: 'recovering' }
    ]
    }
    },
    failed: { type: 'final' },
    recovering: {
    initial: 'waiting',
    initial: 'starting',
    states: {
    waiting: {
    starting: {
    entry: incRecoveryCount,
    after: { recoveryStartDelay: 'started' }
    after: { recoveryStartDelay: 'sendingRequest' }
    },
    started: {
    sendingRequest: {
    entry: [
    'startRecovery',
    send('recoveryTimeout', {
    id: 'recoveryTimeout',
    delay: 'recoveryTimeoutDelay'
    })
    'sendRecoveryRequest',
    'startRecoveryTimeout',
    ],
    exit: cancel('recoveryTimeout'),
    on: {
    '': [
    {
    cond: isVersionMismatch,
    actions: send('versionMismatch'),
    internal: true
    }
    target: 'waiting'
    },
    { target: 'waiting' }
    ]
    }
    },
    waiting: {
    exit: 'cancelRecoveryTimeout'
    }
    }
    }
  2. rads revised this gist Dec 6, 2019. 1 changed file with 10 additions and 6 deletions.
    16 changes: 10 additions & 6 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -126,11 +126,6 @@ function createMachine(options) {
    actions: send('maxErrors'),
    target: 'failed'
    },
    {
    cond: isVersionMismatch,
    actions: send('versionMismatch'),
    target: 'recovering'
    },
    { target: 'recovering' }
    ]
    }
    @@ -151,7 +146,16 @@ function createMachine(options) {
    delay: 'recoveryTimeoutDelay'
    })
    ],
    exit: cancel('recoveryTimeout')
    exit: cancel('recoveryTimeout'),
    on: {
    '': [
    {
    cond: isVersionMismatch,
    actions: send('versionMismatch'),
    internal: true
    }
    ]
    }
    }
    }
    }
  3. rads created this gist Dec 6, 2019.
    176 changes: 176 additions & 0 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,176 @@
    // =============================================================================
    // Updating the Visualization
    //
    // The code after this comment can be copy-pasted into the XState Visualizer:
    // https://xstate.js.org/viz/
    // =============================================================================

    const { cancel } = XState.actions;

    const incErrorCount = assign({ errorCount: (ctx, event) => ctx.errorCount + 1 });
    const incInitCount = assign({ initCount: (ctx, event) => ctx.initCount + 1 });
    const incRecoveryCount = assign({ recoveryCount: (ctx, event) => ctx.recoveryCount + 1 });
    const setCurrentEditor = assign({ currentEditor: (context, event) => event.editor });
    const setPendingInitializationTrue = assign({ pendingInitialization: (context, event) => true });
    const setPendingInitializationFalse = assign({ pendingInitialization: (context, event) => false });

    function isNotPendingInitialization(context, event) {
    return !context.pendingInitialization;
    }

    function isMaxErrors(context, event) {
    return context.errorCount > 2;
    }

    function isVersionMismatch(context, event) {
    const { currentEditor } = context;

    const clientEngineVersion = currentEditor && currentEditor.plugins
    .get('RealTimeCollaborationClient').service._engineVersion;

    return (
    window._CK_ENGINE_VERSION &&
    clientEngineVersion !== window._CK_ENGINE_VERSION
    );
    }

    function randInt(start, end) {
    return start + Math.floor(Math.random() * Math.floor(end - start));
    }

    const recoveryTimeoutDelay = 1000;

    function recoveryStartDelay(context, event) {
    return (context.recoveryCount === 1) ? 0 : randInt(1000, 3000);
    }

    function createMachine(options) {
    return Machine({
    id: 'supervisor',
    initial: 'started',
    context: {
    initEditor: options.initEditor,
    windowEvents: options.windowEvents,
    startRecovery: options.startRecovery,
    docEvents: options.docEvents,
    requestRefresh: options.requestRefresh,
    beforeDestroy: options.beforeDestroy,
    online: navigator.onLine,
    currentEditor: null,
    errorCount: 0,
    initCount: 0,
    recoveryCount: 0,
    pendingInitialization: false
    },
    states: {
    stopping: {
    on: {
    '': { cond: isNotPendingInitialization, target: 'stopped' },
    initSuccess: 'stopped',
    initError: 'stopped'
    }
    },
    stopped: {
    entry: 'destroyEditor',
    type: 'final'
    },
    started: {
    initial: 'online',
    on: {
    stop: 'stopping',
    maxErrors: '.manualRefresh',
    versionMismatch: '.manualRefresh',
    recoveryTimeout: '.manualRefresh'
    },
    states: {
    manualRefresh: {
    type: 'final',
    entry: 'requestRefresh'
    },
    offline: {
    on: {
    online: 'online'
    }
    },
    online: {
    invoke: {
    id: 'addEventListeners',
    src: 'addEventListeners'
    },
    initial: 'initializing',
    on: {
    offline: 'offline',
    flushReceived: '.initializing',
    errorDetected: '.error'
    },
    states: {
    initializing: {
    entry: [incInitCount, setPendingInitializationTrue, 'destroyEditor'],
    exit: [setPendingInitializationFalse],
    invoke: {
    id: 'initializeEditor',
    src: 'initializeEditor'
    },
    on: {
    initSuccess: { target: 'editing', actions: setCurrentEditor },
    initError: { target: 'error', actions: 'sendErrorDetected' }
    }
    },
    editing: { },
    error: {
    entry: incErrorCount,
    on: {
    '': [
    {
    cond: isMaxErrors,
    actions: send('maxErrors'),
    target: 'failed'
    },
    {
    cond: isVersionMismatch,
    actions: send('versionMismatch'),
    target: 'recovering'
    },
    { target: 'recovering' }
    ]
    }
    },
    failed: { type: 'final' },
    recovering: {
    initial: 'waiting',
    states: {
    waiting: {
    entry: incRecoveryCount,
    after: { recoveryStartDelay: 'started' }
    },
    started: {
    entry: [
    'startRecovery',
    send('recoveryTimeout', {
    id: 'recoveryTimeout',
    delay: 'recoveryTimeoutDelay'
    })
    ],
    exit: cancel('recoveryTimeout')
    }
    }
    }
    }
    }
    }
    }
    }
    }, {
    activities: options.activities,
    actions: options.actions,
    guards: options.guards,
    services: options.services,
    delays: {
    recoveryStartDelay,
    recoveryTimeoutDelay
    }
    });
    }

    // Uncomment the following line for the visualizer:
    const machine = createMachine({});