forked from bocoup/chatter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot-stateful.js
146 lines (132 loc) · 4.81 KB
/
bot-stateful.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// If this syntax looks unfamiliar, don't worry, it's just JavaScript!
// Learn more about ES2015 here: https://babeljs.io/docs/learn-es2015/
//
// Run "npm install" and then test with this command in your shell:
// node examples/bot-stateful.js
'use strict'; // eslint-disable-line strict
const Promise = require('bluebird');
const chalk = require('chalk');
// ES2015 syntax:
// import {createBot, createCommand, createArgsAdjuster} from 'chatter';
// ES5 syntax:
// const chatter = require('chatter');
const chatter = require('..');
const createBot = chatter.createBot;
const createCommand = chatter.createCommand;
const createArgsAdjuster = chatter.createArgsAdjuster;
// ===================
// timer utility class
// ===================
class Timer {
constructor() {
this.startTime = null;
}
wasStarted() {
return Boolean(this.startTime);
}
start() {
this.startTime = new Date();
}
getElapsed() {
if (!this.startTime) {
return 'Timer not yet started.';
}
const diff = new Date((new Date() - this.startTime));
const elapsed = diff.toISOString().slice(11, 19);
return `Elapsed time: ${elapsed}.`;
}
}
// ================
// message handlers
// ================
const startHandler = createCommand({
name: 'start',
description: 'Start or re-start the current timer.',
}, (text, timer) => {
const wasStarted = timer.wasStarted();
timer.start();
return `Timer ${wasStarted ? 're-' : ''}started.`;
});
const elapsedHandler = createCommand({
name: 'elapsed',
description: 'Get the elapsed time for the current timer.',
}, (text, timer) => {
return timer.getElapsed();
});
// =============
// the basic bot
// =============
const myBot = createBot({
// This function must be specified. Even though not used here, this function
// receives the id returned by getMessageHandlerCacheId, which can be used to
// programatically return a different message handler.
createMessageHandler(id) {
// Create a new instance of the Timer class.
const timer = new Timer();
// Create a message handler that first adjusts the args received from the
// bot to include the timer instance, then calls the command message handler
// with the adjusted arguments. While we're not using the original message
// object in our message handlers, it's included for completeness' sake.
const messageHandler = createArgsAdjuster({
adjustArgs(text, message) {
return [text, timer, message];
},
}, createCommand({
isParent: true,
description: 'Your own personal timer.',
}, [
startHandler,
elapsedHandler,
]));
// Let the Bot know the message handler has state so it will be cached and
// retrieved for future messages with the same id. Try commenting out this
// line to see how Bot uses hasState.
messageHandler.hasState = true;
// Return the message handler.
return messageHandler;
},
// Get a cache id from the "message" object passed into onMessage. Try
// returning a fixed value to show how the bot uses the return value to cache
// message handlers.
getMessageHandlerCacheId(message) {
return message.user;
},
// Normally, this would actually send a message to a chat service, but since
// this is a simulation, just log the response to the console.
sendResponse(message, text) {
// Display the bot response.
console.log(chalk.cyan(`[bot] ${text}`));
},
});
// ========================================
// simulate the bot interacting with a user
// ========================================
const colorMap = {cowboy: 'magenta', joe: 'yellow'};
function simulate(user, text) {
// Display the user message.
console.log(chalk[colorMap[user]](`\n[${user}] ${text}`));
// Create a "message" object for the Bot's methods to use.
const message = {user, text};
// Normally, this would be run when a message event is received from a chat
// service, but in this case we'll call it manually.
return myBot.onMessage(message).then(() => Promise.delay(1000));
}
// Simulate a series of messages, in order. Note that multiple users can talk
// simultaneously and the bot will keep track of their conversations separately
// because their user name is used as the message handler cache id (see the
// getMessageHandlerCacheId function). If both users were both talking in a
// shared channel and the channel name was used as the cache id, the results
// would be very different.
Promise.mapSeries([
() => simulate('cowboy', 'hello'),
() => simulate('cowboy', 'help'),
() => simulate('cowboy', 'elapsed'),
() => simulate('cowboy', 'start'),
() => simulate('cowboy', 'elapsed'),
() => simulate('joe', 'start'),
() => simulate('joe', 'elapsed'),
() => simulate('cowboy', 'elapsed'),
() => simulate('cowboy', 'start'),
() => simulate('cowboy', 'elapsed'),
() => simulate('joe', 'elapsed'),
], f => f());