Skip to content

Commit d5506b9

Browse files
NaktibaldaGintautas Miselis
authored andcommitted
Support Botkit 4
1 parent 3fc1bdc commit d5506b9

File tree

8 files changed

+801
-2714
lines changed

8 files changed

+801
-2714
lines changed

lib/middleware/index.d.ts

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import * as Botkit from 'botkit';
22
import Bluebird = require('bluebird');
3+
import { Storage } from 'botbuilder-core';
34

4-
declare module 'botkit' {
5-
interface Message {
6-
watsonError?: Error | string;
7-
watsonData?: WatsonMiddleware.Data;
8-
}
9-
}
105

116
declare namespace WatsonMiddleware {
127
interface Data {
@@ -74,32 +69,28 @@ declare namespace WatsonMiddleware {
7469
interface Middleware {
7570
minimum_confidence: number;
7671
conversation: any;
77-
storage: {
78-
users: Botkit.Storage<Botkit.User>;
79-
channels: Botkit.Storage<Botkit.Channel>;
80-
teams: Botkit.Storage<Botkit.Team>;
81-
};
82-
hear: (patterns: string[], message: Botkit.Message) => boolean;
72+
storage: Storage;
73+
hear: (patterns: string[], message: Botkit.BotkitMessage) => boolean;
8374
before: (
84-
message: Botkit.Message,
75+
message: Botkit.BotkitMessage,
8576
payload: Payload,
8677
callback: (err: string | Error, payload: Payload) => void
8778
) => void;
88-
after: (message: Botkit.Message, response, callback) => void;
79+
after: (message: Botkit.BotkitMessage, response, callback) => void;
8980
sendToWatson: (
90-
bot: Botkit.Bot<any, Botkit.Message>,
91-
message: Botkit.Message,
81+
bot: Botkit.BotWorker,
82+
message: Botkit.BotkitMessage,
9283
contextDelta: ContextDelta,
9384
next: () => void
9485
) => void;
9586
receive: (
96-
bot: Botkit.Bot<any, Botkit.Message>,
97-
message: Botkit.Message,
87+
bot: Botkit.BotWorker,
88+
message: Botkit.BotkitMessage,
9889
next: () => void
9990
) => void;
10091
interpret: (
101-
bot: Botkit.Bot<any, Botkit.Message>,
102-
message: Botkit.Message,
92+
bot: Botkit.BotWorker,
93+
message: Botkit.BotkitMessage,
10394
next: () => void
10495
) => void;
10596
readContext: (
@@ -112,13 +103,13 @@ declare namespace WatsonMiddleware {
112103
callback: (err: string | Error | null, watsonResponse?: Data) => void
113104
) => void;
114105
sendToWatsonAsync: (
115-
bot: Botkit.Bot<any, Botkit.Message>,
116-
message: Botkit.Message,
106+
bot: Botkit.BotWorker,
107+
message: Botkit.BotkitMessage,
117108
contextDelta: ContextDelta
118109
) => Bluebird<void>;
119110
interpretAsync: (
120-
bot: Botkit.Bot<any, Botkit.Message>,
121-
message: Botkit.Message
111+
bot: Botkit.BotWorker,
112+
message: Botkit.BotkitMessage
122113
) => Bluebird<void>;
123114
readContextAsync: (user: string) => Bluebird<Context>;
124115
updateContextAsync: (user: string, context: Context) => Bluebird<Data>;
@@ -136,7 +127,7 @@ declare namespace WatsonMiddleware {
136127
[index: string]: any;
137128
}
138129

139-
export function createWatsonMiddleware(config: MiddlewareConfig): Middleware;
130+
export function factory(config: MiddlewareConfig): Middleware;
140131
}
141132

142-
export = WatsonMiddleware.createWatsonMiddleware;
133+
export = WatsonMiddleware.factory;

lib/middleware/index.js

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,20 @@ var AssistantV1 = require('ibm-watson/assistant/v1');
2020
var watsonUtils = require('./utils');
2121
var deepMerge = require('deepmerge');
2222

23-
var readContext = Promise.promisify(watsonUtils.readContext);
24-
var updateContext = Promise.promisify(watsonUtils.updateContext);
23+
var readContext = watsonUtils.readContext;
24+
var updateContext = watsonUtils.updateContext;
2525
var postMessage = Promise.promisify(watsonUtils.postMessage);
2626

2727
// These are initiated by Slack itself and not from the end-user. Won't send these to WCS.
2828
var ignoreType = ['presence_change', 'reconnect_url'];
2929

30-
module.exports = function (config) {
30+
var factory = function (config) {
3131

3232
if (!config) {
3333
throw new Error('Watson Assistant config parameters absent.');
3434
}
3535

36-
if (config.version_date) {
37-
console.warn('"version_date" is deprecated and will be removed in the next major release. Use "version"');
38-
config.version = config.version_date;
39-
delete config.version_date;
40-
}
41-
4236
var middleware = {
43-
4437
minimum_confidence: (config.minimum_confidence || 0.75),
4538

4639
hear: function (patterns, message) {
@@ -66,15 +59,10 @@ module.exports = function (config) {
6659
callback(null, response);
6760
},
6861

69-
sendToWatson: function (bot, message, contextDelta, next) {
62+
sendToWatsonAsync: function (bot, message, contextDelta) {
7063
var before = Promise.promisify(middleware.before);
7164
var after = Promise.promisify(middleware.after);
7265

73-
if (!next && typeof contextDelta === 'function') {
74-
next = contextDelta;
75-
contextDelta = null;
76-
}
77-
7866
if (!middleware.conversation) {
7967
debug('Creating Assistant object with parameters: ' + JSON.stringify(config, null, 2));
8068
middleware.conversation = new AssistantV1(config);
@@ -87,12 +75,12 @@ module.exports = function (config) {
8775
text: []
8876
}
8977
};
90-
return next();
78+
return Promise.resolve();
9179
}
9280

93-
middleware.storage = bot.botkit.storage;
81+
middleware.storage = bot.controller.storage;
9482

95-
readContext(message.user, middleware.storage).then(function (userContext) {
83+
return readContext(message.user, middleware.storage).then(function (userContext) {
9684
var payload = {
9785
workspace_id: config.workspace_id
9886
};
@@ -130,52 +118,55 @@ module.exports = function (config) {
130118
}).catch(function (error) {
131119
message.watsonError = error;
132120
debug('Error: %s', JSON.stringify(error, Object.getOwnPropertyNames(error), 2));
133-
}).done(function () {
134-
next();
135121
});
136122
}
137123
};
138124

139-
middleware.receive = function (bot, message, next) {
140-
return middleware.sendToWatson(bot, message, null, next);
125+
middleware.receiveAsync = function (bot, message) {
126+
return middleware.sendToWatsonAsync(bot, message, null);
141127
};
142128

143-
middleware.interpret = middleware.receive;
129+
middleware.interpretAsync = middleware.receiveAsync;
144130

145131

146-
middleware.readContext = function (user, callback) {
132+
middleware.readContextAsync = function (user) {
147133
if (!middleware.storage) {
148-
return callback(new Error('readContext is called before the first middleware.receive call'));
134+
throw new Error('readContext is called before the first middleware.receive call');
149135
}
150-
return watsonUtils.readContext(user, middleware.storage, callback);
136+
return watsonUtils.readContext(user, middleware.storage);
151137
};
152138

153-
middleware.updateContext = function (user, context, callback) {
139+
middleware.updateContextAsync = function (user) {
154140
if (!middleware.storage) {
155-
return callback(new Error('updateContext is called before the first middleware.receive call'));
141+
throw new Error('updateContext is called before the first middleware.receive call');
156142
}
157-
watsonUtils.updateContext(
143+
return watsonUtils.updateContext(
158144
user,
159145
middleware.storage, {
160146
context: context
161-
},
162-
callback
147+
}
163148
);
164149
};
165150

166-
middleware.interpretAsync = Promise.promisify(middleware.interpret, {
167-
context: middleware
168-
});
169-
middleware.sendToWatsonAsync = Promise.promisify(middleware.sendToWatson, {
170-
context: middleware
171-
});
172-
middleware.readContextAsync = Promise.promisify(middleware.readContext, {
173-
context: middleware
174-
});
175-
middleware.updateContextAsync = Promise.promisify(middleware.updateContext, {
176-
context: middleware
177-
});
151+
middleware.receive = middleware.interpret = function (bot, message, callback) {
152+
return watsonUtils.asCallback(middleware.interpretAsync(bot, message), callback);
153+
};
154+
middleware.sendToWatson = function (bot, message, contextDelta, callback) {
155+
if (!callback && typeof contextDelta === 'function') {
156+
callback = contextDelta;
157+
contextDelta = null;
158+
}
159+
return watsonUtils.asCallback(middleware.sendToWatsonAsync(bot, message, contextDelta), callback);
160+
};
161+
middleware.readContext = function (user, callback) {
162+
return watsonUtils.asCallback(middleware.readContextAsync(user), callback);
163+
};
164+
middleware.updateContext = function (user, contextDelta, callback) {
165+
return watsonUtils.asCallback(middleware.updateContextAsync(user, contextDelta), callback);
166+
};
178167

179168
debug('Middleware: ' + JSON.stringify(middleware, null, 2));
180169
return middleware;
181170
};
171+
172+
module.exports = factory;

lib/middleware/utils.js

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,41 @@
1515
*/
1616
var debug = require('debug')('watson-middleware:utils');
1717

18-
var readContext = function (userId, storage, callback) {
19-
storage.users.get(userId, function (err, user_data) {
20-
if (err) {
21-
//error is returned if nothing is stored yet, so it is the best to ignore it
22-
debug('User: %s, read context error: %s', userId, err);
23-
}
18+
var storagePrefix = 'user.';
2419

25-
if (user_data && user_data.context) {
26-
debug('User: %s, Context: %s', userId, JSON.stringify(user_data.context, null, 2));
27-
callback(null, user_data.context);
28-
} else {
29-
debug('User: %s, Context: %s', userId, JSON.stringify(null));
30-
callback(null, null);
20+
var readContext = function (userId, storage) {
21+
var itemId = storagePrefix + userId;
22+
return storage.read([itemId]).then(function(result) {
23+
if (typeof result[itemId] !== 'undefined' && result[itemId].context) {
24+
debug('User: %s, Context: %s', userId, JSON.stringify(result[itemId].context, null, 2));
25+
return result[itemId].context;
3126
}
27+
return null;
28+
}).catch(function (err) {
29+
debug('User: %s, read context error: %s', userId, err);
30+
return null;
3231
});
3332
};
3433

35-
var updateContext = function (userId, storage, watsonResponse, callback) {
36-
storage.users.get(userId, function (err, user_data) {
37-
if (err) {
38-
//error is returned if nothing is stored yet, so it is the best to ignore it
39-
debug('User: %s, read context error: %s', userId, err);
34+
var updateContext = function (userId, storage, watsonResponse) {
35+
var itemId = storagePrefix + userId;
36+
return storage.read([itemId]).then(function(result) {
37+
if (typeof result[itemId] !== 'undefined') {
38+
debug('User: %s, Data: %s', userId, JSON.stringify(result[itemId], null, 2));
39+
return result[itemId];
4040
}
41-
42-
if (!user_data) {
43-
user_data = {};
41+
return null;
42+
}).then(function (userData) {
43+
if (userData == null) {
44+
userData = {};
4445
}
45-
user_data.id = userId;
46-
user_data.context = watsonResponse.context;
47-
48-
storage.users.save(user_data, function (err) {
49-
if (err) return callback(err);
50-
51-
debug('User: %s, Updated Context: %s', userId, JSON.stringify(watsonResponse.context, null, 2));
52-
callback(null, watsonResponse);
53-
});
46+
userData.id = userId;
47+
userData.context = watsonResponse.context;
48+
var changes = {};
49+
changes[itemId] = userData;
50+
return storage.write(changes);
51+
}).then(function () {
52+
return watsonResponse;
5453
});
5554
};
5655

@@ -64,8 +63,23 @@ var postMessage = function (conversation, payload, callback) {
6463
.catch(callback);
6564
};
6665

66+
var asCallback = function (promise, cb) {
67+
if (typeof cb !== 'function') {
68+
cb = function() {};
69+
}
70+
71+
return promise.then((result) => {
72+
cb(null, result);
73+
return promise;
74+
}).catch((err) => {
75+
cb(err);
76+
return promise;
77+
});
78+
};
79+
6780
module.exports = {
6881
readContext: readContext,
6982
updateContext: updateContext,
70-
postMessage: postMessage
71-
};
83+
postMessage: postMessage,
84+
asCallback: asCallback
85+
};

0 commit comments

Comments
 (0)