Skip to content

Commit

Permalink
added License; updated Readme.md to its first version; added messenge…
Browse files Browse the repository at this point in the history
…r_bot_tests; added error throwing and tested for them in messenger. Doing it for others now
  • Loading branch information
John-David Wuarin committed Aug 1, 2016
1 parent 315f55f commit 596a14c
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 104 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 IBM

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
242 changes: 167 additions & 75 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,72 @@
Bot framework
---
# Botmaster

This is a lightweight bot framework that can be used for creating bots on a variety of different platforms.
Botmaster is an opinionated lightweight chatbot framework. Botmaster is platform agnostic, which means that in its current state, developers can have bots running on Facebook Messenger, Twitter DM and Telegram with just one integration.

Its purpose is to minimise the amount of code developers have to write in order to create a 1-on-1 conversational chatbot that works on multiple different platforms. It does so by defining a standard with respect to what format messages take and how 1-on-1 conversations occur.

## install

```bash
npm install --save botmaster
```

## how so use botmaster
## Quick start
```js
const botmaster = new Botmaster(botmasterSettings);

// settings stuff
const Botmaster = require('botmaster');
const config = require('./tests/config.js')

const messengerSettings = {
credentials: {
verifyToken: 'YOUR verifyToken',
pageToken: 'YOUR pageToken',
fbAppSecret: 'YOUR fbAppSecret'
},
webhookEndpoint: '/webhook1234', // botmaster will mount this webhook on https://Your_Domain_Name/messenger/webhook1234
};

const twitterSettings = {
consumerKey: 'YOUR consumerKey',
consumerSecret: 'YOUR consumerSecret',
accessToken: 'YOUR accessToken',
accessTokenSecret: 'YOUR accessTokenSecret',
}
}

const botsSettings = [{ messenger: messengerSettings },
{ twitter: twitterSettings }];

const botmasterSettings = {
botsSettings: botsSettings,
// by default botmaster will start an express server that listens on port 3000
// you can pass in a port argument here to change this default setting:
port: 3001
}

const botmaster = new Botmaster(settings);

// actual code
botmaster.on('update', (bot, update) => {
bot.sendMessage({
recipient: {
id: update.sender.id,
},
message: {
text: 'Well right back at you!',
text: 'Right back at you!', // yes, this bot doesn't really do anything smart
},
});
});

botmaster.on('error', (bot, err) => {
console.log(err.stack);
console.log('there was an error');
});
```

As you can see here, the Botmaster constructor takes a botmasterSettigns argument.
## Getting set up

As you can see here, the Botmaster constructor takes a botmasterSettings argument.
This object is of the following form:

```js
Expand All @@ -36,52 +77,137 @@ botmasterSettings = {
sessionStore: sessionStore // optional. Define if you will be dealing with sessions
}
```
Here is a full example assuming you are not running your own express server. If you are, see example right below this one

## Without own server object (speaking with both a telegram and a messenger bot)
botsSettings look something like what you saw in the quick start example:

```js
const express = require('express');
const Botmaster = require('botmaster');
const botsSettings = [{ messenger: messengerSettings },
{ twitter: twitterSettings },
{ twitter: otherTwitterSettings }];
```

const telegramSettings = {
I.e. it is an array of single key objects. Where you specify the type as the key of each object and the settings is is the value. Here I show that you can define multiple bots of the same type at once (twitter ones in this example). As you surely guessed, each different platform will expect different credentials. So platform specific settings will differ.

### Getting set up with Messenger

We've seen a messenger settings object looks like:

const messengerSettings = {
credentials: {
authToken: process.env.TELEGRAM_TEST_TOKEN,
verifyToken: 'YOUR verifyToken',
pageToken: 'YOUR pageToken',
fbAppSecret: 'YOUR fbAppSecret'
},
// !! botmaster will mount your webhooks on /<botType>/webhookEndpoint.
// so in this case, it will mount it on: /telegram/webhook1234.
// If using localtunnel as specified below the whole path will be:
// https://botmastersubdomain.localtunnel.me/telegram/webhook1234/
webhookEndpoint: '/webhook1234/',
webhookEndpoint: '/webhook1234'
};

const messengerSettings = {
credentials: {
verifyToken: process.env.MESSENGER_VERIFY_TOKEN,
pageToken: process.env.MESSENGER_PAGE_TOKEN,
fbAppSecret: process.env.FACEBOOK_APP_SECRET,
If you don't already have these, follow the steps **1-4** on the Facebook Messenger guide:
https://developers.facebook.com/docs/messenger-platform/quickstart

In step 2, where you setup your webhook, no need to code anything. Just specify the webhook, enter any secure string you want as a verify token and copy that value in the settings object.

If you are not too sure how webhooks work and/or how to get it to run locally, go to the section about webhooks.

### Getting set up with Telegram
https://core.telegram.org/bots for an intro.
https://core.telegram.org/bots/api for all the doc.

### Getting set up with Twitter

We've also seen a twitter settings object looks like:

const twitterSettings = {
consumerKey: 'YOUR consumerKey',
consumerSecret: 'YOUR consumerSecret',
accessToken: 'YOUR accessToken',
accessTokenSecret: 'YOUR accessTokenSecret',
}
}

Twitter setup is slightly more cumbersome than the two other ones. Because in Twitter you have to create an actual account and not a page or a bot, you'll have to do a few more steps.

1. Setting up the bot account
* Just create a standard account as you would any other. Name it as you want
* navigate to your security and privacy settings (click on your image profile > settings > privacy and security settings)
* scroll to the bottom of the page and make sure "Receive Direct Messages from anyone" is ticked. (currently this has to be done because of Twitter's rules concerning DMs, where in order to send a DM to someone, they have to be following you).

2. Setting up the app
*


## Message format

Standardization is at the heart of Botmaster. The framework was really created for that purpose. This means that messages coming from any platform have to have the same format.

In order to do that, the Facebook Messenger message format was chosen and adopted. This means that when your botmaster object receives an 'update' event from anywhere (twitter, telegram or Messenger as of this writing), you can be sure that it will be of the same format as a similar message that would come from Messenger.

### incoming messages
Typically, it would look something like this for a message with an image attachment. Independant of what platform the message comes from:

```js
{
raw: <platform_specific_raw_update>,
sender: {
id: <id_of_sender>
},
webhookEndpoint: '/webhook1234/',
recipient: {
id: <id_of_the_recipent> // will typically be the bot's id
},
timestamp: <unix_miliseconds_timestamp>,
message: {
mid: <message_id>,
seq: <message_sequence_id>,
attachments: [
{
type: 'image',
payload: {
url: 'https://scontent.xx.fbcdn.net/v/.....'
}
}
]
}
};
```

const botsSettings = [{ telegram: telegramSettings },
{ messenger: messengerSettings }];
const botmasterSettings = { botsSettings: botsSettings } // will start on port 3000 unless specified otherwise
This allows developers to handle these messages in on place only rather than doing it in multiple ones.

const botmaster = new Botmaster(botmasterSettings);
### outgoing messages
...

botmaster.on('update', (bot, update) => {
bot.sendMessage({
recipient: {
id: update.sender.id,
},
message: {
text: 'Well right back at you!',
},
});
});
### buttons
...

## sessions

## webhooks

### On a local machine:

Simply install localtunnel on local machine

```bash
npm install -g localtunnel
```

Then run the localtunnel with a predetermined subdomain. e.g:

```bash
lt -p 3000 -s botmastersubdomain //for example
```

-l is for the localhost we want to point to. -p is the port and -s is the subdomain we want.
In this case, your url will be: http://botmastersubdomain.localtunnel.me.

So if you specified messenger's webhook endpoint to, say, /messenger/webhook1234/, you will have to set up the webhook for your demo app at:

https://botmastersubdomain.localtunnel.me/messenger/webhook1234/
(localtunnel provides both an http and https url. But messenger requires an https one)


## Using Botmaster with your own express() object

Here's an example on how to do so:

```js
const express = require('express');
const app = express();
Expand All @@ -93,10 +219,6 @@ const telegramSettings = {
credentials: {
authToken: process.env.TELEGRAM_TEST_TOKEN,
},
// !! botmaster will mount your webhooks on /<botType>/webhookEndpoint.
// so in this case, it will mount it on: /telegram/webhook1234.
// If using localtunnel as specified below the whole path will be:
// https://botmastersubdomain.localtunnel.me/telegram/webhook1234/
webhookEndpoint: '/webhook1234/',
};

Expand All @@ -117,9 +239,7 @@ const botmasterSettings = {
app: app,
}

const botmasterSettings =

const botmaster = new Botmaster(botsSettings, app);
const botmaster = new Botmaster(botmasterSettings);

botmaster.on('update', (bot, update) => {
bot.sendMessage({
Expand All @@ -140,35 +260,7 @@ app.listen(port, '0.0.0.0', () => {
});
```

See the examples folder for examples on how to use botmaster


## You will need to set up the a bot on telegram. See this page:
https://core.telegram.org/bots for an intro;
https://core.telegram.org/bots/api for all the doc.

## For the facebook Messenger bot, follow this guide to set up the bot:
https://developers.facebook.com/docs/messenger-platform/quickstart


## Dealing with webhooks on local machine:

Simply install localtunnel on local machine

```bash
npm install -g localtunnel
```

Then run the localtunnel with a predetermined subdomain. e.g:
## More examples

```bash
lt -p 3000 -s botmastersubdomain //for example
```
Checkout the examples folder for cool examples of how to use botmaster

-l is for the localhost we want to point to. -p is the port and -s is the subdomain we want.
In this case, your url will be: http://botmastersubdomain.localtunnel.me.

So if you specified messenger's webhook endpoint to, say, /messenger/webhook1234/, you will have to set up the webhook for your demo app at:

https://botmastersubdomain.localtunnel.me/messenger/webhook1234/
(localtunnel provides both an http and https url. But messenger requires an https one)
4 changes: 1 addition & 3 deletions botmaster_or_botkit_readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ Although it might seem at first glance like the two frameworks (and other simila

Botkit was initially created to allow developers to easily build bots of all types that would be available on Slack. Although it now allows developers to build bots for twilio IP messaging and Facebook Messenger too. It was first published in December 2015

Botmaster, no the other hand, is an opinionated lightweight framework created after answering the following question: How can I minimise the amount of code a developer has to write in order to create a 1-on-1 conversational chatbot that works on multiple different platforms. It was first published to Github on August 2016.
Botmaster, on the other hand, is an opinionated lightweight framework created after answering the following question: How can I minimise the amount of code a developer has to write in order to create a 1-on-1 conversational chatbot that works on multiple different platforms. It was first published to Github on August 2016.

Due to the differences in application intents between both frameworks, the design differs in many ways.

### Main differences
---

Message format
---
Expand Down
41 changes: 35 additions & 6 deletions lib/bot_types/base_bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,45 @@ const EventEmitter = require('events');
class BaseBot extends EventEmitter {
constructor(settings) {
super();
this.credentials = settings.credentials;
if (settings.sessionStore) {
this.type = 'baseBot';
this.requiresWebhook = false;
this.requiredCredentials = [];
}

/**
* Just validating the settings and throwing errors or warnings
* where appropriate.
*/
__validateSettings(settings) {
if (typeof settings !== 'object') {
throw new TypeError(`ERROR: settings must be object, got + ${typeof settings}`);
}

if (!settings.credentials) {
throw new Error('ERROR: no credentials specified for the bot');
} else {
this.credentials = settings.credentials;
}

if (!settings.sessionStore) {
console.log('WARNING: starting bot without sessionStore');
} else {
this.sessionStore = settings.sessionStore;
}
// for the channels implemented with webhooks
if (settings.webhookEndpoint) {
this.webhookEndpoint = settings.webhookEndpoint;

for (const credentialName of this.requiredCredentials) {
if (!this.credentials[credentialName]) {
throw new Error(`ERROR: bots of type ${this.type} are expected to have ${credentialName} credentials`);
}
}

this.__createMountPoints();
if (this.requiresWebhook) {
if (!settings.webhookEndpoint) {
throw new Error(`ERROR: bots of type ${this.type} must be defined with webhookEndpoint in their settings`);
} else {
this.webhookEndpoint = settings.webhookEndpoint;
}
}
}

/**
Expand Down
Loading

0 comments on commit 596a14c

Please sign in to comment.