Skip to content

Instantly share code, notes, and snippets.

@karkowg
Last active December 3, 2020 16:14
Show Gist options
  • Select an option

  • Save karkowg/58e6769261451a5d656e9854c497dacc to your computer and use it in GitHub Desktop.

Select an option

Save karkowg/58e6769261451a5d656e9854c497dacc to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
function dayjs() {
return new Date();
}
function goLive(uid) {
return Promise.resolve({ startedAt: dayjs() });
}
function stopLive(uid) {
return Promise.resolve();
}
const makeCountdownMachine = counter => Machine({
id: 'countdown',
initial: 'running',
context: {
counter,
},
states: {
running: {
invoke: {
id: 'countdownInterval',
src: () => callback => {
const intervalId = setInterval(() => {
callback('TICK');
}, 1000);
return () => clearInterval(intervalId);
},
},
on: {
'': {
target: 'done',
cond: ctx => ctx.counter <= 0,
},
TICK: {
actions: ['decrement', 'notify'],
},
},
},
done: {
type: 'final',
},
},
}, {
actions: {
decrement: assign({ counter: ctx => ctx.counter - 1 }),
notify: sendParent(ctx => ({
type: 'COUNTDOWN.UPDATE',
counter: ctx.counter,
})),
},
});
const webcastMachine = {
id: 'webcast',
initial: 'default',
states: {
default: {
on: {
'': [
{ target: 'live', cond: 'isLive' },
{ target: 'upcoming' },
],
},
},
upcoming: {
initial: 'default',
states: {
default: {
on: {
'': [
{ target: 'starting', cond: 'isStarting' },
{ target: 'pre', cond: 'isPre' },
{ target: 'preparing', cond: 'isPreparing' },
{ target: 'idle' },
],
},
},
idle: {
on: {
PREPARE: 'preparing',
},
},
preparing: {
type: 'parallel',
states: {
pexip: {
initial: 'default',
states: {
default: {
on: {
'': [
{ target: 'ready', cond: 'isPexipReady' },
{ target: 'preparing' },
],
},
},
preparing: {
on: {
PEXIP_VA_READY: {
target: 'ready',
actions: assign({
isPexipReady: true,
}),
},
},
},
ready: {
type: 'final',
}
},
},
mediaLive: {
initial: 'default',
states: {
default: {
on: {
'': [
{ target: 'ready', cond: 'isMediaLiveReady' },
{ target: 'preparing', cond: 'isPreparingMediaLive' },
{ target: 'idle' },
],
},
},
idle: {
on: {
PREPARE_WEBCAST: 'preparing',
},
},
preparing: {
on: {
ML_CHANNEL_READY: {
target: 'ready',
actions: assign({
isMediaLiveReady: true,
}),
},
},
},
ready: {
type: 'final',
},
},
},
},
on: {
READY: {
target: 'pre',
cond: ctx => [ctx.isPexipReady, ctx.isMediaLiveReady].every(Boolean),
},
},
},
pre: {
on: {
GO_LIVE: 'starting',
},
},
starting: {
invoke: {
id: 'goLive',
src: ctx => goLive(ctx.uid),
},
on: {
COUNTDOWN: {
actions: 'setLiveContext',
target: '#countdown',
},
},
},
countdown: {
id: 'countdown',
invoke: {
id: 'countdown',
src: (ctx) => makeCountdownMachine(ctx.countdownCounter),
onDone: '#live',
},
on: {
'COUNTDOWN.UPDATE': {
actions: 'setCountdownCounter',
},
},
},
},
},
live: {
id: 'live',
initial: 'streaming',
on: {
'ELAPSED.UPDATE': {
actions: 'setElapsed',
},
'STATS.UPDATE': {
actions: 'setViewingSessionStats',
},
STOP_LIVE: 'after',
},
invoke: [
// { id: 'elapsed', src: ctx => makeElapsedMachine(ctx.startedAt) },
// { id: 'stats', src: ctx => makeStatsMachine(ctx.uid) },
],
states: {
playback: {
on: {
STOP_VIDEO: 'streaming',
},
},
streaming: {
on: {
PLAY_VIDEO: 'playback',
},
},
},
},
after: {
actions: [
send('DONE', { to: 'elapsed' }),
send('DONE', { to: 'stats' }),
],
invoke: {
id: 'stopLive',
src: ctx => stopLive(ctx.uid),
onDone: {
target: '#controlRoom.done',
},
},
},
},
};
const makeControlRoomMachine = event => Machine({
id: 'controlRoom',
initial: 'default',
context: {
countdownCounter: undefined,
elapsed: undefined,
hasFinished: event.event_mode === 'after',
isLive: event.event_mode === 'live',
isMediaLiveReady: event.media_live_state === 'ready',
isPexipReady: event.pexip_state === 'ready',
isPreparing: event.event_mode === 'preparing',
isPreparingMediaLive: event.media_live_state === 'preparing',
isPre: event.event_mode === 'pre',
isStarting: event.event_mode === 'starting',
startedAt: event.start_timecode ?? null,
uid: event.uid,
viewingSessions: {
online: 0,
peak: 0,
total: 0,
},
},
states: {
default: {
on: {
'': [
{ target: 'done', cond: 'hasFinished' },
{ target: 'interactive' },
],
},
},
interactive: {
type: 'parallel',
states: {
webcast: { ...webcastMachine },
},
},
done: {
type: 'final',
},
},
}, {
actions: {
setCountdownCounter: assign({ countdownCounter: (ctx, event) => event.counter }),
setElapsed: assign({ elapsed: (ctx, event) => event.elapsed }),
setLiveContext: assign({
startedAt: (ctx, event) => dayjs(event.starts_at),
countdownCounter: (ctx, event) => event?.countdown ?? 10,
}),
setViewingSessionStats: assign({ viewingSessions: (ctx, event) => event.viewingSessions }),
},
guards: {
hasFinished: ctx => ctx.hasFinished,
isLive: ctx => ctx.isLive,
isMediaLiveReady: ctx => ctx.isMediaLiveReady,
isPexipReady: ctx => ctx.isPexipReady,
isPreparing: ctx => ctx.isPreparing,
isPreparingMediaLive: ctx => ctx.isPreparingMediaLive,
isPre: ctx => ctx.isPre,
isStarting: ctx => ctx.isStarting,
},
});
makeControlRoomMachine({
uid: 'abc123',
event_mode: 'preparing',
pexip_state: 'ready',
media_live_state: 'idle',
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment