Last active
April 15, 2021 14:54
-
-
Save elsangedy/406c699dac828d3bbd6cbd0fac87d4a1 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TAP BACKEND | |
const appMachine = Machine( | |
{ | |
id: 'tap', | |
context: {}, | |
initial: 'bootstrap', | |
on: { | |
RESTART: 'bootstrap', | |
}, | |
states: { | |
bootstrap: { | |
entry: ['reset', 'bootstrapStarted'], | |
onDone: [ | |
{ | |
target: 'maintenance', | |
cond: 'isOnMaintenance', | |
}, | |
{ | |
target: 'operation', | |
cond: 'isConfigured', | |
}, | |
{ | |
target: 'bootstrap', | |
}, | |
], | |
initial: 'authentication', | |
on: { | |
ERROR: '.unavailable', | |
}, | |
states: { | |
authentication: { | |
entry: ['authenticationStarted'], | |
on: { | |
AUTHENTICATE: [ | |
{ | |
target: 'configuration', | |
actions: ['saveAuth'], | |
cond: 'isSetuped', | |
}, | |
{ | |
target: 'setup', | |
actions: ['saveAuth'], | |
}, | |
], | |
}, | |
after: { | |
AUTHENTICATION_TIMEOUT: 'unavailable', | |
}, | |
}, | |
setup: { | |
entry: ['setupStarted'], | |
on: { | |
AUTHENTICATE: [ | |
{ | |
target: 'configuration', | |
actions: ['saveAuth'], | |
cond: 'isSetuped', | |
}, | |
{ | |
target: 'setup', | |
actions: ['saveAuth'], | |
}, | |
], | |
}, | |
}, | |
configuration: { | |
invoke: { | |
src: 'getConfiguration', | |
onDone: { | |
target: 'done', | |
actions: ['saveConfiguration'], | |
}, | |
onError: 'unavailable', | |
}, | |
}, | |
unavailable: { | |
entry: ['unavailableStarted'], | |
after: { | |
UNAVAILABLE_RETRY_TIMEOUT: 'done', | |
}, | |
}, | |
done: { | |
type: 'final' | |
} | |
}, | |
}, | |
maintenance: { | |
entry: ['startMaintenance', 'maintenanceStarted'], | |
exit: ['finishMaintenance'], | |
on: { | |
FINISH_MAINTENANCE: 'bootstrap', | |
}, | |
initial: 'idle', | |
states: { | |
idle: { | |
on: { | |
START_CALIBRATION: { | |
actions: ['saveMaintenanceConsumption'], | |
target: 'calibration', | |
}, | |
START_DEPLETION: { | |
actions: ['saveMaintenanceConsumption'], | |
target: 'depletion', | |
}, | |
}, | |
}, | |
calibration: { | |
entry: ['calibrationStarted'], | |
exit: ['calibrationFinished'], | |
onDone: 'idle', | |
initial: 'flow', | |
states: { | |
flow: { | |
on: { | |
FLOW: { | |
actions: ['incrementPulses', 'flowmeterPulsed'], | |
target: 'flow', | |
}, | |
}, | |
after: { | |
CALIBRATION_TIMEOUT: 'calibrate', | |
}, | |
}, | |
calibrate: { | |
invoke: { | |
src: 'calibrate', | |
onDone: 'done', | |
onError: 'done', | |
}, | |
}, | |
done: { | |
type: 'final', | |
}, | |
}, | |
}, | |
depletion: { | |
entry: ['depletionStarted'], | |
exit: ['depletionFinished'], | |
on: { | |
FINISH_DEPLETION: 'idle', | |
FLOW: { | |
actions: ['incrementPulses', 'flowmeterPulsed'], | |
}, | |
}, | |
}, | |
}, | |
}, | |
operation: { | |
entry: ['operationStarted'], | |
on: { | |
START_MAINTENANCE: 'maintenance', | |
}, | |
initial: 'idle', | |
states: { | |
idle: { | |
on: { | |
ORDER: { | |
target: 'startingConsumption', | |
actions: ['saveCustomer'], | |
}, | |
IDENTIFIED: 'identifying', | |
}, | |
}, | |
identifying: { | |
invoke: { | |
src: 'getCustomerByTag', | |
onDone: { | |
target: 'startingConsumption', | |
actions: ['saveCustomer'], | |
}, | |
onError: { | |
target: 'idle', | |
actions: ['identificationFailure'], | |
}, | |
}, | |
}, | |
startingConsumption: { | |
invoke: { | |
src: 'startConsumption', | |
onDone: { | |
target: 'consumption', | |
actions: ['saveConsumption'], | |
}, | |
onError: { | |
target: 'idle', | |
actions: ['startingConsumptionFailure'], | |
}, | |
}, | |
}, | |
consumption: { | |
entry: ['consumptionStarted'], | |
initial: 'flow', | |
onDone: 'idle', | |
states: { | |
flow: { | |
on: { | |
FLOW: [ | |
{ | |
actions: ['incrementPulses', 'flowmeterPulsed'], | |
target: 'flow', | |
cond: 'hasCredit', | |
}, | |
{ | |
actions: [ | |
'incrementPulses', | |
'flowmeterPulsed', | |
'consumptionFinishedByNoCredit', | |
], | |
target: 'done', | |
}, | |
], | |
}, | |
after: { | |
CONSUMPTION_TIMEOUT: [ | |
{ | |
target: 'done', | |
cond: (context) => context.consumption?.pulses === 0, | |
actions: ['consumptionFinishedByTimeout'], | |
}, | |
{ | |
target: 'done', | |
actions: ['consumptionFinishedByDebounce'], | |
}, | |
], | |
}, | |
}, | |
done: { | |
type: 'final', | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
{ | |
delays: { | |
CALIBRATION_TIMEOUT: 20000, | |
AUTHENTICATION_TIMEOUT: 30000, | |
UNAVAILABLE_RETRY_TIMEOUT: 10000, | |
CONSUMPTION_TIMEOUT: (context) => { | |
if (context?.consumption?.pulses === 0) { | |
return context?.configuration?.consumptionTimeoutTime; | |
} | |
return context?.configuration?.consumptionDebounceTime; | |
}, | |
}, | |
guards: { | |
isSetuped: (_, event) => { | |
return !!event.data?.active; | |
}, | |
isConfigured: (context) => { | |
return !!context.configuration; | |
}, | |
isOnMaintenance: (_, event) => { | |
return !!event.data?.inMaintenance; | |
}, | |
hasCredit: (context) => { | |
return context.consumption?.pulses < context.consumption?.maxPulses; | |
}, | |
}, | |
actions: { | |
reset: assign({ | |
auth: null, | |
customer: null, | |
consumption: null, | |
configuration: null, | |
}), | |
saveAuth: assign({ | |
auth: (_, event) => { | |
return event.data; | |
}, | |
}), | |
saveConfiguration: assign({ | |
configuration: (_, event) => { | |
return event.data; | |
}, | |
}), | |
startMaintenance: assign({ | |
configuration: (context) => { | |
return { | |
...context.configuration, | |
inMaintenance: true, | |
}; | |
}, | |
}), | |
finishMaintenance: assign({ | |
configuration: (context) => { | |
return { | |
...context.configuration, | |
inMaintenance: false, | |
}; | |
}, | |
}), | |
saveCustomer: assign( | |
{ | |
customer: (_, event) => { | |
return event.data; | |
}, | |
}, | |
), | |
saveMaintenanceConsumption: assign({ | |
consumption: () => { | |
return { | |
id: null, | |
pulses: 0, | |
maxPulses: Infinity, | |
}; | |
}, | |
}), | |
saveConsumption: assign({ | |
consumption: (context, event) => { | |
const factor = context.configuration.factorPulseToMl; | |
const balance = context.customer.balance; | |
const price = context.configuration.productPrice; | |
const maxAmount = Math.floor(balance / price); | |
const maxPulses = Math.floor(maxAmount / factor); | |
return { | |
...event.data, | |
pulses: 0, | |
maxPulses, | |
}; | |
}, | |
}), | |
incrementPulses: assign({ | |
consumption: (context) => { | |
return { | |
...context.consumption, | |
pulses: context.consumption.pulses + 1, | |
}; | |
}, | |
}), | |
}, | |
}, | |
); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment