hubot 8.0.2 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/hubot.js +7 -7
- package/package.json +6 -8
- package/src/adapter.js +13 -14
- package/src/adapters/shell.js +5 -9
- package/src/listener.js +27 -47
- package/src/message.js +1 -1
- package/src/middleware.js +13 -54
- package/src/response.js +25 -49
- package/src/robot.js +53 -76
package/bin/hubot.js
CHANGED
|
@@ -8,13 +8,13 @@ const OptParse = require('optparse')
|
|
|
8
8
|
const Hubot = require('..')
|
|
9
9
|
|
|
10
10
|
const switches = [
|
|
11
|
-
['-a', '--adapter
|
|
12
|
-
['-f', '--file
|
|
13
|
-
['-c', '--create
|
|
14
|
-
['-d', '--disable-httpd
|
|
11
|
+
['-a', '--adapter HUBOT_ADAPTER', 'The Adapter to use, e.g. "shell" (to load the default hubot shell adapter)'],
|
|
12
|
+
['-f', '--file HUBOT_FILE', 'Path to adapter file, e.g. "./adapters/CustomAdapter.mjs"'],
|
|
13
|
+
['-c', '--create HUBOT_CREATE', 'Create a deployable hubot'],
|
|
14
|
+
['-d', '--disable-httpd HUBOT_HTTPD', 'Disable the HTTP server'],
|
|
15
15
|
['-h', '--help', 'Display the help information'],
|
|
16
|
-
['-l', '--alias
|
|
17
|
-
['-n', '--name
|
|
16
|
+
['-l', '--alias HUBOT_ALIAS', "Enable replacing the robot's name with alias"],
|
|
17
|
+
['-n', '--name HUBOT_NAME', 'The name of the robot in chat'],
|
|
18
18
|
['-r', '--require PATH', 'Alternative scripts path'],
|
|
19
19
|
['-t', '--config-check', "Test hubot's config to make sure it won't fail at startup"],
|
|
20
20
|
['-v', '--version', 'Displays the version of hubot installed']
|
|
@@ -97,6 +97,7 @@ if (options.create) {
|
|
|
97
97
|
if (options.file) {
|
|
98
98
|
options.adapter = options.file.split('/').pop().split('.')[0]
|
|
99
99
|
}
|
|
100
|
+
|
|
100
101
|
const robot = Hubot.loadBot(options.adapter, options.enableHttpd, options.name, options.alias)
|
|
101
102
|
module.exports = robot
|
|
102
103
|
|
|
@@ -107,7 +108,6 @@ async function loadScripts () {
|
|
|
107
108
|
loadExternalScripts()
|
|
108
109
|
|
|
109
110
|
const tasks = options.scripts.map((scriptPath) => {
|
|
110
|
-
console.log('loadding', scriptPath)
|
|
111
111
|
if (scriptPath[0] === '/') {
|
|
112
112
|
return robot.load(scriptPath)
|
|
113
113
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hubot",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"author": "hubot",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github",
|
|
@@ -15,28 +15,26 @@
|
|
|
15
15
|
"url": "https://github.com/hubotio/hubot.git"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"async": "^3.2.4",
|
|
19
18
|
"cline": "^0.8.2",
|
|
20
19
|
"coffeescript": "^2.7.0",
|
|
21
20
|
"connect-multiparty": "^2.2.0",
|
|
22
21
|
"express": "^4.18.2",
|
|
23
22
|
"express-basic-auth": "^1.2.1",
|
|
24
23
|
"optparse": "^1.0.5",
|
|
25
|
-
"pino": "^8.11.0"
|
|
26
|
-
"standard": "^17.1.0"
|
|
24
|
+
"pino": "^8.11.0"
|
|
27
25
|
},
|
|
28
26
|
"devDependencies": {
|
|
29
27
|
"chai": "^4.3.7",
|
|
30
28
|
"is-circular": "^1.0.2",
|
|
31
29
|
"mocha": "^10.2.0",
|
|
32
|
-
"mockery": "^2.1.0",
|
|
33
30
|
"semantic-release": "^21.0.1",
|
|
34
31
|
"sinon": "^15.0.4",
|
|
35
|
-
"sinon-chai": "^3.7.0"
|
|
32
|
+
"sinon-chai": "^3.7.0",
|
|
33
|
+
"standard": "^17.1.0"
|
|
36
34
|
},
|
|
37
35
|
"engines": {
|
|
38
|
-
"node": ">
|
|
39
|
-
"npm": ">
|
|
36
|
+
"node": "> 16.20.2",
|
|
37
|
+
"npm": "> 8.19.4"
|
|
40
38
|
},
|
|
41
39
|
"main": "./index",
|
|
42
40
|
"bin": {
|
package/src/adapter.js
CHANGED
|
@@ -16,8 +16,8 @@ class Adapter extends EventEmitter {
|
|
|
16
16
|
// envelope - A Object with message, room and user details.
|
|
17
17
|
// strings - One or more Strings for each message to send.
|
|
18
18
|
//
|
|
19
|
-
// Returns
|
|
20
|
-
send (envelope
|
|
19
|
+
// Returns results from adapter.
|
|
20
|
+
async send (envelope, ...strings) {}
|
|
21
21
|
|
|
22
22
|
// Public: Raw method for sending emote data back to the chat source.
|
|
23
23
|
// Defaults as an alias for send
|
|
@@ -25,10 +25,9 @@ class Adapter extends EventEmitter {
|
|
|
25
25
|
// envelope - A Object with message, room and user details.
|
|
26
26
|
// strings - One or more Strings for each message to send.
|
|
27
27
|
//
|
|
28
|
-
// Returns
|
|
29
|
-
emote (envelope
|
|
30
|
-
|
|
31
|
-
return this.send.apply(this, [envelope].concat(strings))
|
|
28
|
+
// Returns results from adapter.
|
|
29
|
+
async emote (envelope, ...strings) {
|
|
30
|
+
return this.senda(envelope, ...strings)
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
// Public: Raw method for building a reply and sending it back to the chat
|
|
@@ -37,24 +36,24 @@ class Adapter extends EventEmitter {
|
|
|
37
36
|
// envelope - A Object with message, room and user details.
|
|
38
37
|
// strings - One or more Strings for each reply to send.
|
|
39
38
|
//
|
|
40
|
-
// Returns
|
|
41
|
-
reply (envelope
|
|
39
|
+
// Returns results from adapter.
|
|
40
|
+
async reply (envelope, ...strings) {}
|
|
42
41
|
|
|
43
42
|
// Public: Raw method for setting a topic on the chat source. Extend this.
|
|
44
43
|
//
|
|
45
44
|
// envelope - A Object with message, room and user details.
|
|
46
45
|
// strings - One more more Strings to set as the topic.
|
|
47
46
|
//
|
|
48
|
-
// Returns
|
|
49
|
-
topic (envelope
|
|
47
|
+
// Returns results from adapter.
|
|
48
|
+
async topic (envelope, ...strings) {}
|
|
50
49
|
|
|
51
50
|
// Public: Raw method for playing a sound in the chat source. Extend this.
|
|
52
51
|
//
|
|
53
52
|
// envelope - A Object with message, room and user details.
|
|
54
53
|
// strings - One or more strings for each play message to send.
|
|
55
54
|
//
|
|
56
|
-
// Returns
|
|
57
|
-
play (envelope
|
|
55
|
+
// Returns results from adapter.
|
|
56
|
+
async play (envelope, ...strings) {}
|
|
58
57
|
|
|
59
58
|
// Public: Raw method for invoking the bot to run. Extend this.
|
|
60
59
|
//
|
|
@@ -69,8 +68,8 @@ class Adapter extends EventEmitter {
|
|
|
69
68
|
// Public: Dispatch a received message to the robot.
|
|
70
69
|
//
|
|
71
70
|
// Returns nothing.
|
|
72
|
-
receive (message) {
|
|
73
|
-
this.robot.receive(message)
|
|
71
|
+
async receive (message) {
|
|
72
|
+
await this.robot.receive(message)
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
// Public: Get an Array of User objects stored in the brain.
|
package/src/adapters/shell.js
CHANGED
|
@@ -22,21 +22,17 @@ class Shell extends Adapter {
|
|
|
22
22
|
this.name = 'Shell'
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
send (envelope
|
|
26
|
-
const strings = [].slice.call(arguments, 1)
|
|
27
|
-
|
|
25
|
+
async send (envelope, ...strings) {
|
|
28
26
|
Array.from(strings).forEach(str => console.log(bold(str)))
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
emote (envelope
|
|
32
|
-
const strings = [].slice.call(arguments, 1)
|
|
29
|
+
async emote (envelope, ...strings) {
|
|
33
30
|
Array.from(strings).map(str => this.send(envelope, `* ${str}`))
|
|
34
31
|
}
|
|
35
32
|
|
|
36
|
-
reply (envelope
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.send.apply(this, [envelope].concat(strings))
|
|
33
|
+
async reply (envelope, ...strings) {
|
|
34
|
+
strings = strings.map((s) => `${envelope.user.name}: ${s}`)
|
|
35
|
+
this.send(envelope, ...strings)
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
run () {
|
package/src/listener.js
CHANGED
|
@@ -20,19 +20,19 @@ class Listener {
|
|
|
20
20
|
constructor (robot, matcher, options, callback) {
|
|
21
21
|
this.robot = robot
|
|
22
22
|
this.matcher = matcher
|
|
23
|
-
this.options = options
|
|
23
|
+
this.options = options ?? {}
|
|
24
24
|
this.callback = callback
|
|
25
25
|
|
|
26
26
|
if (this.matcher == null) {
|
|
27
27
|
throw new Error('Missing a matcher for Listener')
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
if (this.callback
|
|
30
|
+
if (!this.callback) {
|
|
31
31
|
this.callback = this.options
|
|
32
32
|
this.options = {}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (this.options
|
|
35
|
+
if (!this.options?.id) {
|
|
36
36
|
this.options.id = null
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -49,60 +49,40 @@ class Listener {
|
|
|
49
49
|
//
|
|
50
50
|
// message - A Message instance.
|
|
51
51
|
// middleware - Optional Middleware object to execute before the Listener callback
|
|
52
|
-
// callback - Optional Function called with a boolean of whether the matcher matched
|
|
53
52
|
//
|
|
54
|
-
// Returns
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
middleware = undefined
|
|
53
|
+
// Returns the result of the callback.
|
|
54
|
+
async call (message, middleware) {
|
|
55
|
+
if (middleware && typeof middleware === 'function') {
|
|
56
|
+
const fn = middleware
|
|
57
|
+
middleware = new Middleware(this.robot)
|
|
58
|
+
middleware.register(fn)
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
if (middleware == null) {
|
|
61
|
+
if (!middleware) {
|
|
65
62
|
middleware = new Middleware(this.robot)
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
const match = this.matcher(message)
|
|
69
|
-
if (match)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// special middleware-like function that always executes the Listener's
|
|
75
|
-
// callback and calls done (never calls 'next')
|
|
76
|
-
const executeListener = (context, done) => {
|
|
77
|
-
this.robot.logger.debug(`Executing listener callback for Message '${message}'`)
|
|
78
|
-
try {
|
|
79
|
-
this.callback(context.response)
|
|
80
|
-
} catch (err) {
|
|
81
|
-
this.robot.emit('error', err, context.response)
|
|
82
|
-
}
|
|
83
|
-
done()
|
|
84
|
-
}
|
|
66
|
+
if (!match) return null
|
|
67
|
+
if (this.regex) {
|
|
68
|
+
this.robot.logger.debug(`Message '${message}' matched regex /${inspect(this.regex)}/; listener.options = ${inspect(this.options)}`)
|
|
69
|
+
}
|
|
85
70
|
|
|
86
|
-
|
|
87
|
-
// pass control back to the robot
|
|
88
|
-
const allDone = function allDone () {
|
|
89
|
-
// Yes, we tried to execute the listener callback (middleware may
|
|
90
|
-
// have intercepted before actually executing though)
|
|
91
|
-
if (didMatchCallback != null) {
|
|
92
|
-
process.nextTick(() => didMatchCallback(true))
|
|
93
|
-
}
|
|
94
|
-
}
|
|
71
|
+
const response = new this.robot.Response(this.robot, message, match)
|
|
95
72
|
|
|
96
|
-
|
|
97
|
-
middleware.execute({ listener: this, response }
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
73
|
+
try {
|
|
74
|
+
const shouldContinue = await middleware.execute({ listener: this, response })
|
|
75
|
+
if (shouldContinue === false) return null
|
|
76
|
+
} catch (e) {
|
|
77
|
+
this.robot.logger.error(`Error executing middleware for listener: ${e.stack}`)
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return await this.callback(response)
|
|
81
|
+
} catch (e) {
|
|
82
|
+
this.robot.logger.error(`Error executing listener callback: ${e.stack}`)
|
|
83
|
+
this.robot.emit('error', e, response)
|
|
105
84
|
}
|
|
85
|
+
return null
|
|
106
86
|
}
|
|
107
87
|
}
|
|
108
88
|
|
package/src/message.js
CHANGED
package/src/middleware.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const async = require('async')
|
|
4
|
-
|
|
5
3
|
class Middleware {
|
|
6
4
|
constructor (robot) {
|
|
7
5
|
this.robot = robot
|
|
@@ -16,68 +14,29 @@ class Middleware {
|
|
|
16
14
|
// context - context object that is passed through the middleware stack.
|
|
17
15
|
// When handling errors, this is assumed to have a `response` property.
|
|
18
16
|
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// executed middleware.
|
|
24
|
-
//
|
|
25
|
-
// Returns nothing
|
|
26
|
-
// Returns before executing any middleware
|
|
27
|
-
execute (context, next, done) {
|
|
28
|
-
const self = this
|
|
29
|
-
|
|
30
|
-
if (done == null) {
|
|
31
|
-
done = function () {}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Execute a single piece of middleware and update the completion callback
|
|
35
|
-
// (each piece of middleware can wrap the 'done' callback with additional
|
|
36
|
-
// logic).
|
|
37
|
-
function executeSingleMiddleware (doneFunc, middlewareFunc, cb) {
|
|
38
|
-
// Match the async.reduce interface
|
|
39
|
-
function nextFunc (newDoneFunc) {
|
|
40
|
-
cb(null, newDoneFunc || doneFunc)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Catch errors in synchronous middleware
|
|
17
|
+
// Returns bool, true | false, whether or not to continue execution
|
|
18
|
+
async execute (context) {
|
|
19
|
+
let shouldContinue = true
|
|
20
|
+
for await (const middleware of this.stack) {
|
|
44
21
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
doneFunc()
|
|
22
|
+
shouldContinue = await middleware(context)
|
|
23
|
+
if (shouldContinue === false) break
|
|
24
|
+
} catch (e) {
|
|
25
|
+
this.robot.emit('error', e, context.response)
|
|
26
|
+
break
|
|
51
27
|
}
|
|
52
28
|
}
|
|
53
|
-
|
|
54
|
-
// Executed when the middleware stack is finished
|
|
55
|
-
function allDone (_, finalDoneFunc) {
|
|
56
|
-
next(context, finalDoneFunc)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Execute each piece of middleware, collecting the latest 'done' callback
|
|
60
|
-
// at each step.
|
|
61
|
-
process.nextTick(async.reduce.bind(null, this.stack, done, executeSingleMiddleware, allDone))
|
|
29
|
+
return shouldContinue
|
|
62
30
|
}
|
|
63
31
|
|
|
64
32
|
// Public: Registers new middleware
|
|
65
33
|
//
|
|
66
|
-
// middleware -
|
|
67
|
-
// continue the pipeline or interrupt it. The function is called
|
|
68
|
-
// with (robot, context, next, done). If execution should
|
|
69
|
-
// continue (next middleware, final callback), the middleware
|
|
70
|
-
// should call the 'next' function with 'done' as an optional
|
|
71
|
-
// argument.
|
|
72
|
-
// If not, the middleware should call the 'done' function with
|
|
73
|
-
// no arguments. Middleware may wrap the 'done' function in
|
|
74
|
-
// order to execute logic after the final callback has been
|
|
75
|
-
// executed.
|
|
34
|
+
// middleware - Middleware function to execute prior to the listener callback. Return false to prevent execution of the listener callback.
|
|
76
35
|
//
|
|
77
36
|
// Returns nothing.
|
|
78
37
|
register (middleware) {
|
|
79
|
-
if (middleware.length !==
|
|
80
|
-
throw new Error(`Incorrect number of arguments for middleware callback (expected
|
|
38
|
+
if (middleware.length !== 1) {
|
|
39
|
+
throw new Error(`Incorrect number of arguments for middleware callback (expected 1, got ${middleware.length})`)
|
|
81
40
|
}
|
|
82
41
|
this.stack.push(middleware)
|
|
83
42
|
}
|
package/src/response.js
CHANGED
|
@@ -14,8 +14,7 @@ class Response {
|
|
|
14
14
|
this.match = match
|
|
15
15
|
this.envelope = {
|
|
16
16
|
room: this.message.room,
|
|
17
|
-
user: this.message.user
|
|
18
|
-
message: this.message
|
|
17
|
+
user: this.message.user
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -24,10 +23,9 @@ class Response {
|
|
|
24
23
|
// strings - One or more strings to be posted. The order of these strings
|
|
25
24
|
// should be kept intact.
|
|
26
25
|
//
|
|
27
|
-
// Returns
|
|
28
|
-
send (
|
|
29
|
-
|
|
30
|
-
this.runWithMiddleware.apply(this, ['send', { plaintext: true }].concat(strings))
|
|
26
|
+
// Returns result from middleware.
|
|
27
|
+
async send (...strings) {
|
|
28
|
+
return await this.#runWithMiddleware('send', { plaintext: true }, ...strings)
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
// Public: Posts an emote back to the chat source
|
|
@@ -35,10 +33,9 @@ class Response {
|
|
|
35
33
|
// strings - One or more strings to be posted. The order of these strings
|
|
36
34
|
// should be kept intact.
|
|
37
35
|
//
|
|
38
|
-
// Returns
|
|
39
|
-
emote (
|
|
40
|
-
|
|
41
|
-
this.runWithMiddleware.apply(this, ['emote', { plaintext: true }].concat(strings))
|
|
36
|
+
// Returns result from middleware.
|
|
37
|
+
async emote (...strings) {
|
|
38
|
+
return await this.#runWithMiddleware('emote', { plaintext: true }, ...strings)
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
// Public: Posts a message mentioning the current user.
|
|
@@ -46,10 +43,9 @@ class Response {
|
|
|
46
43
|
// strings - One or more strings to be posted. The order of these strings
|
|
47
44
|
// should be kept intact.
|
|
48
45
|
//
|
|
49
|
-
// Returns
|
|
50
|
-
reply (
|
|
51
|
-
|
|
52
|
-
this.runWithMiddleware.apply(this, ['reply', { plaintext: true }].concat(strings))
|
|
46
|
+
// Returns result from middleware.
|
|
47
|
+
async reply (...strings) {
|
|
48
|
+
return await this.#runWithMiddleware('reply', { plaintext: true }, ...strings)
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
// Public: Posts a topic changing message
|
|
@@ -57,10 +53,9 @@ class Response {
|
|
|
57
53
|
// strings - One or more strings to set as the topic of the
|
|
58
54
|
// room the bot is in.
|
|
59
55
|
//
|
|
60
|
-
// Returns
|
|
61
|
-
topic (
|
|
62
|
-
|
|
63
|
-
this.runWithMiddleware.apply(this, ['topic', { plaintext: true }].concat(strings))
|
|
56
|
+
// Returns result from middleware.
|
|
57
|
+
async topic (...strings) {
|
|
58
|
+
return await this.#runWithMiddleware('topic', { plaintext: true }, ...strings)
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
// Public: Play a sound in the chat source
|
|
@@ -68,10 +63,9 @@ class Response {
|
|
|
68
63
|
// strings - One or more strings to be posted as sounds to play. The order of
|
|
69
64
|
// these strings should be kept intact.
|
|
70
65
|
//
|
|
71
|
-
// Returns
|
|
72
|
-
play (
|
|
73
|
-
|
|
74
|
-
this.runWithMiddleware.apply(this, ['play'].concat(strings))
|
|
66
|
+
// Returns result from middleware.
|
|
67
|
+
async play (...strings) {
|
|
68
|
+
return await this.#runWithMiddleware('play', ...strings)
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
// Public: Posts a message in an unlogged room
|
|
@@ -79,27 +73,17 @@ class Response {
|
|
|
79
73
|
// strings - One or more strings to be posted. The order of these strings
|
|
80
74
|
// should be kept intact.
|
|
81
75
|
//
|
|
82
|
-
// Returns
|
|
83
|
-
locked (
|
|
84
|
-
|
|
85
|
-
this.runWithMiddleware.apply(this, ['locked', { plaintext: true }].concat(strings))
|
|
76
|
+
// Returns result from middleware.
|
|
77
|
+
async locked (...strings) {
|
|
78
|
+
await this.#runWithMiddleware('locked', { plaintext: true }, ...strings)
|
|
86
79
|
}
|
|
87
80
|
|
|
88
|
-
//
|
|
81
|
+
// Call with a method for the given strings using response
|
|
89
82
|
// middleware.
|
|
90
|
-
runWithMiddleware (methodName, opts
|
|
91
|
-
const self = this
|
|
92
|
-
const strings = [].slice.call(arguments, 2)
|
|
93
|
-
const copy = strings.slice(0)
|
|
94
|
-
let callback
|
|
95
|
-
|
|
96
|
-
if (typeof copy[copy.length - 1] === 'function') {
|
|
97
|
-
callback = copy.pop()
|
|
98
|
-
}
|
|
99
|
-
|
|
83
|
+
async #runWithMiddleware (methodName, opts, ...strings) {
|
|
100
84
|
const context = {
|
|
101
85
|
response: this,
|
|
102
|
-
strings
|
|
86
|
+
strings,
|
|
103
87
|
method: methodName
|
|
104
88
|
}
|
|
105
89
|
|
|
@@ -107,17 +91,9 @@ class Response {
|
|
|
107
91
|
context.plaintext = true
|
|
108
92
|
}
|
|
109
93
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (callback != null) {
|
|
114
|
-
result.push(callback)
|
|
115
|
-
}
|
|
116
|
-
self.robot.adapter[methodName].apply(self.robot.adapter, [self.envelope].concat(result))
|
|
117
|
-
done()
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return this.robot.middleware.response.execute(context, runAdapterSend, responseMiddlewareDone)
|
|
94
|
+
const shouldContinue = await this.robot.middleware.response.execute(context)
|
|
95
|
+
if (shouldContinue === false) return
|
|
96
|
+
return await this.robot.adapter[methodName](this.envelope, ...context.strings)
|
|
121
97
|
}
|
|
122
98
|
|
|
123
99
|
// Public: Picks a random item from the given items.
|
package/src/robot.js
CHANGED
|
@@ -4,7 +4,6 @@ const fs = require('fs')
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const pathToFileURL = require('url').pathToFileURL
|
|
6
6
|
|
|
7
|
-
const async = require('async')
|
|
8
7
|
const pino = require('pino')
|
|
9
8
|
const HttpClient = require('./httpclient')
|
|
10
9
|
|
|
@@ -244,11 +243,8 @@ class Robot {
|
|
|
244
243
|
//
|
|
245
244
|
// middleware - A function that determines whether or not a given matching
|
|
246
245
|
// Listener should be executed. The function is called with
|
|
247
|
-
// (context
|
|
248
|
-
//
|
|
249
|
-
// should call the 'next' function with 'done' as an argument.
|
|
250
|
-
// If not, the middleware should call the 'done' function with
|
|
251
|
-
// no arguments.
|
|
246
|
+
// (context). If execution should, the middleware should return
|
|
247
|
+
// true. If not, the middleware should return false.
|
|
252
248
|
//
|
|
253
249
|
// Returns nothing.
|
|
254
250
|
listenerMiddleware (middleware) {
|
|
@@ -260,9 +256,8 @@ class Robot {
|
|
|
260
256
|
//
|
|
261
257
|
// middleware - A function that examines an outgoing message and can modify
|
|
262
258
|
// it or prevent its sending. The function is called with
|
|
263
|
-
// (context
|
|
264
|
-
//
|
|
265
|
-
// stop, the middleware should call done(). To modify the
|
|
259
|
+
// (context). If execution should continue, return true
|
|
260
|
+
// otherwise return false to stop. To modify the
|
|
266
261
|
// outgoing message, set context.string to a new message.
|
|
267
262
|
//
|
|
268
263
|
// Returns nothing.
|
|
@@ -273,11 +268,10 @@ class Robot {
|
|
|
273
268
|
// Public: Registers new middleware for execution before matching
|
|
274
269
|
//
|
|
275
270
|
// middleware - A function that determines whether or not listeners should be
|
|
276
|
-
// checked. The function is called with (context
|
|
277
|
-
//
|
|
278
|
-
// middleware or matching phase, it should
|
|
279
|
-
//
|
|
280
|
-
// should call the 'done' function with no arguments.
|
|
271
|
+
// checked. The function is called with (context). If execution
|
|
272
|
+
// should continue to the next
|
|
273
|
+
// middleware or matching phase, it should return true or nothing
|
|
274
|
+
// otherwise return false to stop.
|
|
281
275
|
//
|
|
282
276
|
// Returns nothing.
|
|
283
277
|
receiveMiddleware (middleware) {
|
|
@@ -290,14 +284,12 @@ class Robot {
|
|
|
290
284
|
// message - A Message instance. Listeners can flag this message as 'done' to
|
|
291
285
|
// prevent further execution.
|
|
292
286
|
//
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// pass control back to the robot
|
|
300
|
-
this.middleware.receive.execute({ response: new Response(this, message) }, this.processListeners.bind(this), cb)
|
|
287
|
+
// Returns array of results from listeners.
|
|
288
|
+
async receive (message) {
|
|
289
|
+
const context = { response: new Response(this, message) }
|
|
290
|
+
const shouldContinue = await this.middleware.receive.execute(context)
|
|
291
|
+
if (shouldContinue === false) return null
|
|
292
|
+
return await this.processListeners(context)
|
|
301
293
|
}
|
|
302
294
|
|
|
303
295
|
// Private: Passes the given message to any interested Listeners.
|
|
@@ -305,49 +297,44 @@ class Robot {
|
|
|
305
297
|
// message - A Message instance. Listeners can flag this message as 'done' to
|
|
306
298
|
// prevent further execution.
|
|
307
299
|
//
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
// Returns nothing.
|
|
311
|
-
// Returns before executing callback
|
|
312
|
-
processListeners (context, done) {
|
|
300
|
+
// Returns array of results from listeners.
|
|
301
|
+
async processListeners (context) {
|
|
313
302
|
// Try executing all registered Listeners in order of registration
|
|
314
303
|
// and return after message is done being processed
|
|
304
|
+
const results = []
|
|
315
305
|
let anyListenersExecuted = false
|
|
316
|
-
|
|
317
|
-
async.detectSeries(this.listeners, (listener, done) => {
|
|
306
|
+
for await (const listener of this.listeners) {
|
|
318
307
|
try {
|
|
319
|
-
listener.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
)
|
|
327
|
-
})
|
|
308
|
+
const match = listener.matcher(context.response.message)
|
|
309
|
+
if (!match) {
|
|
310
|
+
continue
|
|
311
|
+
}
|
|
312
|
+
const result = await listener.call(context.response.message, this.middleware.listener)
|
|
313
|
+
results.push(result)
|
|
314
|
+
anyListenersExecuted = true
|
|
328
315
|
} catch (err) {
|
|
329
|
-
this.emit('error', err,
|
|
330
|
-
// Continue to next listener when there is an error
|
|
331
|
-
done(null, false)
|
|
316
|
+
this.emit('error', err, context)
|
|
332
317
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
_ => {
|
|
336
|
-
// If no registered Listener matched the message
|
|
337
|
-
|
|
338
|
-
if (!(context.response.message instanceof Message.CatchAllMessage) && !anyListenersExecuted) {
|
|
339
|
-
this.logger.debug('No listeners executed; falling back to catch-all')
|
|
340
|
-
this.receive(new Message.CatchAllMessage(context.response.message), done)
|
|
341
|
-
} else {
|
|
342
|
-
if (done != null) {
|
|
343
|
-
process.nextTick(done)
|
|
344
|
-
}
|
|
318
|
+
if (context.response.message.done) {
|
|
319
|
+
break
|
|
345
320
|
}
|
|
346
|
-
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!isCatchAllMessage(context.response.message) && !anyListenersExecuted) {
|
|
324
|
+
this.logger.debug('No listeners executed; falling back to catch-all')
|
|
325
|
+
try {
|
|
326
|
+
const result = await this.receive(new Message.CatchAllMessage(context.response.message))
|
|
327
|
+
results.push(result)
|
|
328
|
+
} catch (err) {
|
|
329
|
+
this.emit('error', err, context)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return results
|
|
347
334
|
}
|
|
348
335
|
|
|
349
336
|
async loadmjs (filePath) {
|
|
350
|
-
const script = await import(filePath)
|
|
337
|
+
const script = await import(pathToFileURL(filePath))
|
|
351
338
|
if (typeof script?.default === 'function') {
|
|
352
339
|
script.default(this)
|
|
353
340
|
} else {
|
|
@@ -526,7 +513,7 @@ class Robot {
|
|
|
526
513
|
try {
|
|
527
514
|
this.adapter = this.requireAdapterFrom(adapterPathInCurrentWorkingDirectory)
|
|
528
515
|
} catch (err) {
|
|
529
|
-
if (err.name === 'SyntaxError'
|
|
516
|
+
if (err.name === 'SyntaxError') {
|
|
530
517
|
this.adapter = await this.importAdapterFrom(adapterPathInCurrentWorkingDirectory)
|
|
531
518
|
} else {
|
|
532
519
|
throw err
|
|
@@ -616,10 +603,8 @@ class Robot {
|
|
|
616
603
|
// strings - One or more Strings for each message to send.
|
|
617
604
|
//
|
|
618
605
|
// Returns whatever the extending adapter returns.
|
|
619
|
-
send (envelope
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
return this.adapter.send.apply(this.adapter, [envelope].concat(strings))
|
|
606
|
+
async send (envelope, ...strings) {
|
|
607
|
+
return await this.adapter.send(envelope, ...strings)
|
|
623
608
|
}
|
|
624
609
|
|
|
625
610
|
// Public: A helper reply function which delegates to the adapter's reply
|
|
@@ -629,10 +614,8 @@ class Robot {
|
|
|
629
614
|
// strings - One or more Strings for each message to send.
|
|
630
615
|
//
|
|
631
616
|
// Returns whatever the extending adapter returns.
|
|
632
|
-
reply (envelope
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
return this.adapter.reply.apply(this.adapter, [envelope].concat(strings))
|
|
617
|
+
async reply (envelope, ...strings) {
|
|
618
|
+
return await this.adapter.reply(envelope, ...strings)
|
|
636
619
|
}
|
|
637
620
|
|
|
638
621
|
// Public: A helper send function to message a room that the robot is in.
|
|
@@ -641,11 +624,9 @@ class Robot {
|
|
|
641
624
|
// strings - One or more Strings for each message to send.
|
|
642
625
|
//
|
|
643
626
|
// Returns whatever the extending adapter returns.
|
|
644
|
-
messageRoom (room
|
|
645
|
-
const strings = [].slice.call(arguments, 1)
|
|
627
|
+
async messageRoom (room, ...strings) {
|
|
646
628
|
const envelope = { room }
|
|
647
|
-
|
|
648
|
-
return this.adapter.send.apply(this.adapter, [envelope].concat(strings))
|
|
629
|
+
return await this.adapter.send(envelope, ...strings)
|
|
649
630
|
}
|
|
650
631
|
|
|
651
632
|
// Public: A wrapper around the EventEmitter API to make usage
|
|
@@ -656,10 +637,8 @@ class Robot {
|
|
|
656
637
|
// when event happens.
|
|
657
638
|
//
|
|
658
639
|
// Returns nothing.
|
|
659
|
-
on (event
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
this.events.on.apply(this.events, [event].concat(args))
|
|
640
|
+
on (event, ...args) {
|
|
641
|
+
this.events.on(event, ...args)
|
|
663
642
|
}
|
|
664
643
|
|
|
665
644
|
// Public: A wrapper around the EventEmitter API to make usage
|
|
@@ -669,10 +648,8 @@ class Robot {
|
|
|
669
648
|
// args... - Arguments emitted by the event
|
|
670
649
|
//
|
|
671
650
|
// Returns nothing.
|
|
672
|
-
emit (event
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
this.events.emit.apply(this.events, [event].concat(args))
|
|
651
|
+
emit (event, ...args) {
|
|
652
|
+
this.events.emit(event, ...args)
|
|
676
653
|
}
|
|
677
654
|
|
|
678
655
|
// Public: Kick off the event loop for the adapter
|