Skip to content

Commit

Permalink
PubNub as webhook transmitter to avoid firewall issues. Description i…
Browse files Browse the repository at this point in the history
…n example4.md and working template in templates folder
  • Loading branch information
ralfschiffert committed Oct 29, 2019
1 parent 5007a9f commit 9909860
Show file tree
Hide file tree
Showing 11 changed files with 2,102 additions and 1 deletion.
105 changes: 105 additions & 0 deletions docs/example4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
## Example #4 Using PubNub
An inbound, internet reachable port, is required for the Webex Teams API to notify
Flint of webhook events. This is not always easy or possible.

The standard way to handle firewall tunneling is via a tool like ngrok or a web server in the DMZ.
Here we use a different approach. We are using a PubNub server as a way to transmit the webhook event to
the flint application, which uses a PubNub client to receive the event. PubNub uses whatever mechanism is best suited to reach the PubHub nodes.

There is a PubNub function you need to deploy at PubNub. It's in the file pubnub-function.js.
Check their tutorial here:
https://www.pubnub.com/tutorials/pubnub-functions/
Configure the function to run 'On Request'

Once you configured your PubNub function (block) you should copy the URL and configure it as WebhookRecipientURL
in your environment. You also need to configure the PubnubSubscribeKey in your environment so the client
can subscribe to the channel. As channel name we used webex since flint registers for webhooks with
resource:all event: all ( we also publish to webex.${resource} and webex.${resource}.${event} so you can use
PubNubs channel wildcards if you want. See here https://www.pubnub.com/developers/tech/key-concepts/stream-controller/wildcard-subscribe/)

When PubNub receives the event it will invoke the function that then sends the event along the channel.
Flint spawns a bot for every space/room and will cross check based on the roomId to which bot the message
belongs.

If you want a different additional bot configured, you must use a different WebhookRecipientURL and
PubnubSubscribeKey Key.

You should check the temaplates folder for a working example.
```js
"use strict";

var Flint = require('node-flint');
var webhook = require('node-flint/webhook');
var path = require('path');
var PubNub = require('pubnub');
var config = require(path.join(__dirname, 'config.js'));
var when = require('when');


// instantiate thje pubnub object
var pubnub = new PubNub ({
subscribeKey : config.pubnubSubscribeKey
})

// pubnub status listener
// we use it here for the initialization and then remove ourselves
let statusListener = {
status: (s) => {
if (s.category === "PNConnectedCategory") {
// res is from the closure
this.res("fullfilled my init promise for pubnub");
}
}
}




let messageListener = {
message: (m) => {
webhook(flint)(m.message);
}
}



function checkInit() {
return new Promise( (res,rej) => {
statusListener.__proto__.res = res;
const initTimeSecs = 5;
// give 3 second init time
setTimeout(() => {
rej("resolved")
}, initTimeSecs * 1000)

pubnub.addListener(statusListener);
})
}

// init flint
var flint = new Flint(config);

checkInit()
.then( (a) => { pubnub.removeListener(statusListener) })
.then( () => { flint.start() } )
.then( () => { flint.use(path.join(__dirname, 'flint.js')) })
.then( () => { flint.debug('Flint has started') })
.then( () => { pubnub.addListener(messageListener) })
.catch( (e) => { console.log("could not init pubnub or flint") })


// flint registers webhooks for resurce: all event: all
// so here we listen to the all all pubnub channel
pubnub.subscribe({
channels: ["webex"]
})


// gracefully shutdown (ctrl-c)
process.on('SIGINT', function() {
flint.debug('stoppping...');
flint.stop().then(function() {
process.exit();
});
});
```
4 changes: 3 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var uuid = require('uuid');
var base64 = require('js-base64').Base64;

var Utils = {};

Expand All @@ -12,7 +13,8 @@ var Utils = {};
* @returns {String} Base64 encoded string.
*/
Utils.base64encode = function(string) {
return new Buffer(string).toString('base64');
// deprecated return new Buffer(string).toString('base64');
return base64.encode(string);
};

/**
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
},
"devDependencies": {
"doctoc": "^1.3.0",
"express": "^4.16.4",
"js-base64": "^2.4.9",
"jsdoc-to-markdown": "^3.0.0"
}
}
1 change: 1 addition & 0 deletions templates/pubnub-template/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: DEBUG=flint,bot node main.js
2 changes: 2 additions & 0 deletions templates/pubnub-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#pubnub-template

12 changes: 12 additions & 0 deletions templates/pubnub-template/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
token: process.env.TOKEN,
maxPageItems: 100,
maxConcurrent: 5,
minTime: 50,
requeueCodes: [ 429, 500, 501, 502, 503 ],
requeueMinTime: 500,
removeWebhooksOnStart: true,
webhookSecret: process.env.FLYNN_APP_ID,
pubnubSubscribeKey: process.env.PubnubSubscribeKey,
webhookUrl: process.env.WebhookRecipientURL
};
7 changes: 7 additions & 0 deletions templates/pubnub-template/flint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";

module.exports = function(flint) {
flint.hears('hello', function(bot, trigger) {
bot.say('Hello %s!', trigger.personDisplayName);
});
};
76 changes: 76 additions & 0 deletions templates/pubnub-template/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"use strict";

var Flint = require('node-flint');
var webhook = require('node-flint/webhook');
var path = require('path');
var PubNub = require('pubnub');
var config = require(path.join(__dirname, 'config.js'));
var when = require('when');


// instantiate thje pubnub object
var pubnub = new PubNub ({
subscribeKey : config.pubnubSubscribeKey
})

// pubnub status listener
// we use it here for the initialization and then remove ourselves
let statusListener = {
status: (s) => {
if (s.category === "PNConnectedCategory") {
// res is from the closure
this.res("fullfilled my init promise for pubnub");
}
}
}




let messageListener = {
message: (m) => {
webhook(flint)(m.message);
}
}



function checkInit() {
return new Promise( (res,rej) => {
statusListener.__proto__.res = res;
const initTimeSecs = 5;
// give 3 second init time
setTimeout(() => {
rej("resolved")
}, initTimeSecs * 1000)

pubnub.addListener(statusListener);
})
}

// init flint
var flint = new Flint(config);

checkInit()
.then( (a) => { pubnub.removeListener(statusListener) })
.then( () => { flint.start() } )
.then( () => { flint.use(path.join(__dirname, 'flint.js')) })
.then( () => { flint.debug('Flint has started') })
.then( () => { pubnub.addListener(messageListener) })
.catch( (e) => { console.log("could not init pubnub or flint") })


// flint registers webhooks for resurce: all event: all
// so here we listen to the all all pubnub channel
pubnub.subscribe({
channels: ["webex"]
})


// gracefully shutdown (ctrl-c)
process.on('SIGINT', function() {
flint.debug('stoppping...');
flint.stop().then(function() {
process.exit();
});
});
Loading

0 comments on commit 9909860

Please sign in to comment.