mirror of
https://github.com/nioc/xmpp-bot.git
synced 2024-12-04 22:23:36 +01:00
Set outgoing webhook asynchrone
This commit is contained in:
parent
c0a75ad1f3
commit
003ab013d3
3 changed files with 83 additions and 74 deletions
|
@ -9,14 +9,14 @@
|
||||||
* @license AGPL-3.0+
|
* @license AGPL-3.0+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (logger, config, xmpp, user, destination, message, type, code, callback = () => {}) => {
|
module.exports = async (logger, config, xmpp, user, destination, message, type, code) => {
|
||||||
let webhook = config.getOutgoingWebhook(code)
|
let webhook = config.getOutgoingWebhook(code)
|
||||||
if (!webhook) {
|
if (!webhook) {
|
||||||
logger.warn(`There is no webhook with code "${code}"`)
|
logger.warn(`There is no webhook with code "${code}"`)
|
||||||
callback(new Error(`There is no webhook with code "${code}"`), null, null)
|
throw new Error(`There is no webhook with code "${code}"`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
const request = require('request')
|
const { promisify } = require('util')
|
||||||
|
const request = promisify(require('request'))
|
||||||
// request.debug = true
|
// request.debug = true
|
||||||
let options = {
|
let options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -68,24 +68,20 @@ module.exports = (logger, config, xmpp, user, destination, message, type, code,
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
logger.trace('Outgoing webhook options:', options)
|
logger.trace('Outgoing webhook options:', options)
|
||||||
request(options, function (error, response, body) {
|
try {
|
||||||
logger.debug('statusCode:', response && response.statusCode)
|
const { statusCode, body } = await request(options)
|
||||||
if (error) {
|
if (statusCode === 200) {
|
||||||
logger.error('HTTP error:', error)
|
|
||||||
callback(new Error('HTTP error:', error), null, null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (response.statusCode === 200) {
|
|
||||||
logger.trace('Response:', body)
|
logger.trace('Response:', body)
|
||||||
if (body && typeof (body) === 'object' && 'reply' in body === true) {
|
if (body && typeof (body) === 'object' && 'reply' in body === true) {
|
||||||
logger.debug(`There is a reply to send back in chat ${destination}: ${body.reply}`)
|
logger.debug(`There is a reply to send back in chat ${destination}: ${body.reply}`)
|
||||||
xmpp.send(destination, body.reply, type)
|
xmpp.send(destination, body.reply, type)
|
||||||
callback(null, `Message sent. There is a reply to send back in chat ${destination}: ${body.reply}`, null)
|
return `Message sent. There is a reply to send back in chat ${destination}: ${body.reply}`
|
||||||
return
|
|
||||||
}
|
}
|
||||||
callback(null, 'Message sent', null)
|
return 'Message sent'
|
||||||
return
|
|
||||||
}
|
}
|
||||||
callback(new Error('HTTP error:', response.statusCode), null, null)
|
throw new Error(`HTTP error: ${statusCode}`)
|
||||||
})
|
} catch (error) {
|
||||||
|
logger.error(`Error during outgoing webhook request: ${error.message}`)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
],
|
],
|
||||||
"outgoingWebhooks": [
|
"outgoingWebhooks": [
|
||||||
{
|
{
|
||||||
"code": "w1",
|
"code": "basic-json-reply",
|
||||||
"url": "https://domain.ltd:port/path/resource",
|
"url": "https://domain.ltd:port/path/resource",
|
||||||
"strictSSL": true,
|
"strictSSL": true,
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
"bearer": null
|
"bearer": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "w2",
|
"code": "bearer-form",
|
||||||
"url": "https://domain.ltd:port/path/resource",
|
"url": "https://domain.ltd:port/path/resource",
|
||||||
"strictSSL": true,
|
"strictSSL": true,
|
||||||
"contentType": "application/x-www-form-urlencoded",
|
"contentType": "application/x-www-form-urlencoded",
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
"bearer": "abcdefgh"
|
"bearer": "abcdefgh"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "w3",
|
"code": "protected",
|
||||||
"url": "https://domain.ltd:port/path/protectedresource",
|
"url": "https://domain.ltd:port/path/protectedresource",
|
||||||
"strictSSL": true,
|
"strictSSL": true,
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
|
@ -116,8 +116,8 @@
|
||||||
"bearer": null
|
"bearer": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "w4",
|
"code": "request-error",
|
||||||
"url": "https://domain.ltd:port/path/errorresource",
|
"url": "https://domain.ltd:port/path/request-error",
|
||||||
"strictSSL": true,
|
"strictSSL": true,
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"authMethod": null,
|
"authMethod": null,
|
||||||
|
|
115
test/outgoing.js
115
test/outgoing.js
|
@ -6,7 +6,6 @@ const sinon = require('sinon')
|
||||||
const should = require('chai').should()
|
const should = require('chai').should()
|
||||||
const nock = require('nock')
|
const nock = require('nock')
|
||||||
const Outgoing = require('./../lib/outgoing')
|
const Outgoing = require('./../lib/outgoing')
|
||||||
require('chai').should()
|
|
||||||
|
|
||||||
describe('Outgoing webhook component', () => {
|
describe('Outgoing webhook component', () => {
|
||||||
let logger, config, xmppSendStub, xmpp, scope, scopeUnauthorized, scopeWithError, reqSpy
|
let logger, config, xmppSendStub, xmpp, scope, scopeUnauthorized, scopeWithError, reqSpy
|
||||||
|
@ -40,82 +39,96 @@ describe('Outgoing webhook component', () => {
|
||||||
.post('/path/resource')
|
.post('/path/resource')
|
||||||
.reply(200, { reply: 'This is a reply' })
|
.reply(200, { reply: 'This is a reply' })
|
||||||
scope.on('request', reqSpy)
|
scope.on('request', reqSpy)
|
||||||
|
|
||||||
scopeUnauthorized = nock('https://domain.ltd:port')
|
scopeUnauthorized = nock('https://domain.ltd:port')
|
||||||
.post('/path/protectedresource')
|
.post('/path/protectedresource')
|
||||||
.reply(401, {})
|
.reply(401, {})
|
||||||
scopeUnauthorized.on('request', reqSpy)
|
scopeUnauthorized.on('request', reqSpy)
|
||||||
|
|
||||||
scopeWithError = nock('https://domain.ltd:port')
|
scopeWithError = nock('https://domain.ltd:port')
|
||||||
.post('/path/errorresource')
|
.post('/path/request-error')
|
||||||
.replyWithError('')
|
.replyWithError('error in request')
|
||||||
scopeWithError.on('request', reqSpy)
|
scopeWithError.on('request', reqSpy)
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Unkwnow outgoing webhook', () => {
|
describe('Unkwnow outgoing webhook', () => {
|
||||||
it('Should not execute request', (done) => {
|
it('Should throw an exception and not execute request', async () => {
|
||||||
Outgoing(logger, config, xmpp, 'user', 'destination', 'message', 'type', 'code', (error, response, body) => {
|
try {
|
||||||
should.not.equal(error, null)
|
await Outgoing(logger, config, xmpp, 'user', 'destination', 'message', 'type', 'unknownCode')
|
||||||
sinon.assert.notCalled(reqSpy)
|
should.fail(0, 1, 'Exception not thrown')
|
||||||
done()
|
} catch (error) {
|
||||||
})
|
error.message.should.equal('There is no webhook with code "unknownCode"')
|
||||||
|
}
|
||||||
|
sinon.assert.notCalled(reqSpy)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('POST with basic authorization and JSON content-type and reply message to XMPP', () => {
|
describe('POST with basic authorization and JSON content-type and reply message to XMPP', () => {
|
||||||
it('Should send basic authentication and JSON content-type in header and send an XMPP message', (done) => {
|
it('Should send basic authentication and JSON content-type in header and send an XMPP message', async () => {
|
||||||
Outgoing(logger, config, xmpp, 'user', 'destination', 'This a first message', 'type', 'w1', (error, response, body) => {
|
let result
|
||||||
should.equal(error, null)
|
try {
|
||||||
sinon.assert.calledOnce(reqSpy)
|
result = await Outgoing(logger, config, xmpp, 'user', 'destination', 'This a first message', 'type', 'basic-json-reply')
|
||||||
const req = reqSpy.args[0][0]
|
} catch (error) {
|
||||||
const bodyReq = JSON.parse(reqSpy.args[0][2])
|
should.fail(0, 1, 'Exception is thrown')
|
||||||
req.headers.authorization.should.equal('Basic dXNlcjM6M3Bhc3M=')
|
}
|
||||||
req.headers['content-type'].should.equal('application/json')
|
result.should.equal('Message sent. There is a reply to send back in chat destination: This is a reply')
|
||||||
bodyReq.from.should.equal('user')
|
sinon.assert.calledOnce(reqSpy)
|
||||||
bodyReq.channel.should.equal('destination')
|
const req = reqSpy.args[0][0]
|
||||||
bodyReq.message.should.equal('This a first message')
|
const bodyReq = JSON.parse(reqSpy.args[0][2])
|
||||||
sinon.assert.calledOnce(xmppSendStub)
|
req.headers.authorization.should.equal('Basic dXNlcjM6M3Bhc3M=')
|
||||||
const xmppSendArgs = xmppSendStub.args[0]
|
req.headers['content-type'].should.equal('application/json')
|
||||||
xmppSendArgs[0].should.equal('destination')
|
bodyReq.from.should.equal('user')
|
||||||
xmppSendArgs[1].should.equal('This is a reply')
|
bodyReq.channel.should.equal('destination')
|
||||||
xmppSendArgs[2].should.equal('type')
|
bodyReq.message.should.equal('This a first message')
|
||||||
done()
|
sinon.assert.calledOnce(xmppSendStub)
|
||||||
})
|
const xmppSendArgs = xmppSendStub.args[0]
|
||||||
|
xmppSendArgs[0].should.equal('destination')
|
||||||
|
xmppSendArgs[1].should.equal('This is a reply')
|
||||||
|
xmppSendArgs[2].should.equal('type')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('POST with bearer authorization and JSON content-type', () => {
|
describe('POST with bearer authorization and form-urlencoded content-type', () => {
|
||||||
it('Should send basic authentication in header', (done) => {
|
it('Should send bearer authentication and form-urlencoded content-type in header', async () => {
|
||||||
Outgoing(logger, config, xmpp, 'user', 'destination', 'This a second message', 'type', 'w2', (error, response, body) => {
|
let result
|
||||||
should.equal(error, null)
|
try {
|
||||||
sinon.assert.calledOnce(reqSpy)
|
result = await Outgoing(logger, config, xmpp, 'user', 'destination', 'This a second message', 'type', 'bearer-form')
|
||||||
const req = reqSpy.args[0][0]
|
} catch (error) {
|
||||||
const bodyReq = decodeURIComponent(reqSpy.args[0][2])
|
should.fail(0, 1, 'Exception is thrown')
|
||||||
req.headers.authorization.should.equal('Bearer abcdefgh')
|
}
|
||||||
req.headers['content-type'].should.equal('application/x-www-form-urlencoded')
|
result.should.equal('Message sent')
|
||||||
bodyReq.should.equal('from=user&message=This a second message&channel=destination')
|
sinon.assert.calledOnce(reqSpy)
|
||||||
done()
|
const req = reqSpy.args[0][0]
|
||||||
})
|
const bodyReq = decodeURIComponent(reqSpy.args[0][2])
|
||||||
|
req.headers.authorization.should.equal('Bearer abcdefgh')
|
||||||
|
req.headers['content-type'].should.equal('application/x-www-form-urlencoded')
|
||||||
|
bodyReq.should.equal('from=user&message=This a second message&channel=destination')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('POST without authorization', () => {
|
describe('POST without authorization', () => {
|
||||||
it('Should not send authorization in header and handle 401', (done) => {
|
it('Should not send authorization in header, handle 401 and throw an exception', async () => {
|
||||||
Outgoing(logger, config, xmpp, 'user', 'destination', 'This a second message', 'type', 'w3', (error, response, body) => {
|
try {
|
||||||
should.not.equal(error, null)
|
await Outgoing(logger, config, xmpp, 'user', 'destination', 'message', 'type', 'protected')
|
||||||
sinon.assert.calledOnce(reqSpy)
|
should.fail(0, 1, 'Exception not thrown')
|
||||||
done()
|
} catch (error) {
|
||||||
})
|
error.message.should.equal('HTTP error: 401')
|
||||||
|
}
|
||||||
|
sinon.assert.calledOnce(reqSpy)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('POST with HTTP error', () => {
|
describe('POST with HTTP error', () => {
|
||||||
it('Should handle error', (done) => {
|
it('Should handle error and throw an exception', async () => {
|
||||||
Outgoing(logger, config, xmpp, 'user', 'destination', 'This a second message', 'type', 'w4', (error, response, body) => {
|
try {
|
||||||
should.not.equal(error, null)
|
await Outgoing(logger, config, xmpp, 'user', 'destination', 'This a second message', 'type', 'request-error')
|
||||||
sinon.assert.calledOnce(reqSpy)
|
should.fail(0, 1, 'Exception not thrown')
|
||||||
done()
|
} catch (error) {
|
||||||
})
|
error.message.should.equal('error in request')
|
||||||
|
}
|
||||||
|
sinon.assert.calledOnce(reqSpy)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue