-
Notifications
You must be signed in to change notification settings - Fork 46
/
stateMachine.js
111 lines (93 loc) · 2.96 KB
/
stateMachine.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
'use strict';
const MemoryStore = require('./memoryStore');
class StateMachine {
constructor(options) {
this.options = options || {};
if (!this.options.script) {
throw new Error('Missing required option script');
}
if (!this.options.bot) {
throw new Error('Missing required option bot');
}
this.script = options.script;
this.bot = options.bot;
this.initialState = this.options.initialState || 'start';
}
receiveMessage(message) {
if (message.text === 'reset') {
return Promise.all([
this.bot.releaseLock(),
this.setState('start')
]);
}
return Promise.all([
this.getState(),
this.bot.acquireLock()
])
.then((results) => {
const state = results[0];
const lock = results[1];
if (!lock) {
return this.prompt('processing');
}
return this.transition(message, state);
})
.then(() => this.bot.releaseLock())
.catch((err) => {
this.bot.releaseLock();
this.prompt('error');
throw err;
});
}
transition(message, state) {
let nextState;
const step = this.step(state);
Promise.resolve(step.receive(this.bot, message))
.then((returnedState) => {
nextState = this.validateState(returnedState);
return this.setState(nextState);
})
.then(() => {
return this.prompt(nextState);
});
}
_doPrompt(state) {
const step = this.step(state);
return step.prompt ?
step.prompt(this.bot) :
Promise.resolve();
}
prompt(state) {
if (state) {
return this._doPrompt(state);
} else {
return this.getState().then((s) => this._doPrompt(s));
}
}
step(state) {
state = this.validateState(state);
return this.script.steps[state];
}
validateState(state) {
const step = this.script.steps[state];
if (!step) {
console.error(`Undefined state ${state} for user ${this.bot.userId},`
+ `reverting to default state '${this.initialState}'`);
return this.initialState;
}
if (!step.receive || typeof step.receive !== 'function') {
console.error(`Invalid state ${state} for user ${this.bot.userId}`
+ `has no receive method, reverting to default state '${this.initialState}'`);
return this.initialState;
}
return state;
}
getState() {
return this.bot.getState()
.then((state) => state || this.initialState);
}
setState(state) {
return this.bot.setState(state);
}
}
module.exports = StateMachine;