Skip to content
This repository has been archived by the owner on Jan 19, 2020. It is now read-only.

Commit

Permalink
Merge b702e90 into df412c7
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed Oct 18, 2016
2 parents df412c7 + b702e90 commit e7b26d0
Show file tree
Hide file tree
Showing 20 changed files with 387 additions and 389 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015"]
}
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "airbnb-base",
"globals": {
"jest": false
}
}
16 changes: 7 additions & 9 deletions lib/__mocks__/bot.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
var Server = require('./server')
const Server = require('./server');

var mock = {
const mock = {
on: jest.fn(),
use: jest.fn(),
connectToSocket: jest.fn(),
trigger: jest.fn(),
listen: jest.fn(function() {
return new Server()
})
}
listen: jest.fn(() =>
new Server()
),
};

module.exports = function() {
return mock
}
module.exports = () => mock;
17 changes: 8 additions & 9 deletions lib/__mocks__/event.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module.exports = function(remainingListeners, args) {
return {
remainingListeners: remainingListeners,
args: args,
next: jest.fn(function(callback) {
callback()
})
}
}
module.exports = (remainingListeners, args) =>
({
remainingListeners,
args,
next: jest.fn((callback) => {
callback();
}),
});
10 changes: 5 additions & 5 deletions lib/__mocks__/server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = jest.fn(function() {
return {
module.exports = jest.fn(() =>
({
listen: jest.fn(),
use: jest.fn()
}
})
use: jest.fn(),
})
);
7 changes: 3 additions & 4 deletions lib/__mocks__/session.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module.exports = function(bot, user, client) {
return {
module.exports = (bot, user, client) =>
({
bot,
user,
client,
}
}
});
213 changes: 105 additions & 108 deletions lib/bot.js
Original file line number Diff line number Diff line change
@@ -1,133 +1,130 @@
var BodyParser = require('body-parser')
var EventEmitter = require('./event-emitter')
var Express = require('express')
var ResponseMiddleware = require('./response-middleware')
var fs = require('fs')
var request = require('request')
var uuid = require('node-uuid')
var cors = require('cors')
var Topic = require('./topic')

var staticFilesDirectory = 'public'

function Bot(name) {
this.name = name || 'bot'
this.memory = {
users: {

}
const BodyParser = require('body-parser');
const EventEmitter = require('./event-emitter');
const Express = require('express');
const ResponseMiddleware = require('./response-middleware');
const fs = require('fs');
const request = require('request');
const uuid = require('node-uuid');
const cors = require('cors');
const Topic = require('./topic');

const staticFilesDirectory = 'public';

class Bot {
constructor(name) {
this.name = name || 'bot';
this.memory = {
users: {

},
};

this.topics = {};

this.router = Express.Router();
this.eventEmitter = new EventEmitter();
this.rootTopic = new Topic();

this.eventEmitter.addListener('message_received', (message, session) => {
const context = session.getUserContext();
let topic = this.rootTopic;

if (context.currentTopic !== undefined) {
topic = this.topics[context.currentTopic];
}

topic.trigger('message_received', message, session);
});

this.eventEmitter.fallback('webhook', (req, res) => {
res.error('No webhook handlers configured');
});

this.router.use(`/${staticFilesDirectory}`, Express.static('public'));
this.router.use(cors());
this.router.use(BodyParser.json());
this.router.use(BodyParser.urlencoded());
this.router.use(new ResponseMiddleware());

this.router.get('/webhook', this.handleWebhookRequest.bind(this));
this.router.post('/webhook', this.handleWebhookRequest.bind(this));
}

this.topics = {}

this.router = Express.Router()
this.eventEmitter = new EventEmitter()
this.rootTopic = new Topic()

this.eventEmitter.addListener('message_received', function(message, session) {
handleWebhookRequest(req, res) {
this.trigger('webhook', req, res);
}

var context = session.getUserContext()
var topic = this.rootTopic
trigger(eventName, ...args) {
console.log(`${eventName} event triggered`);
this.eventEmitter.emit(eventName, ...args);
}

if (context.currentTopic != undefined) {
topic = this.topics[context.currentTopic]
// - Default to Topic -> RootTopic - Update code not to need this hack
on(eventName, handler) {
if (eventName === 'message_received') {
this.rootTopic.on(eventName, handler);
} else {
this.eventEmitter.addListener(eventName, handler);
}

topic.trigger('message_received', message, session)

}.bind(this))

this.eventEmitter.fallback('webhook', function(req, res) {
res.error('No webhook handlers configured')
}.bind(this))

this.router.use('/' + staticFilesDirectory, Express.static('public'))
this.router.use(cors())
this.router.use(BodyParser.json())
this.router.use(BodyParser.urlencoded())
this.router.use(new ResponseMiddleware())

this.router.get('/webhook', this.handleWebhookRequest.bind(this))
this.router.post('/webhook', this.handleWebhookRequest.bind(this))
}

Bot.prototype.handleWebhookRequest = function(req, res) {
this.trigger('webhook', req, res)
}

Bot.prototype.trigger = function(eventName) {
console.log(eventName +' event triggered')
this.eventEmitter.emit.apply(this.eventEmitter, arguments)
}

// - Default to Topic -> RootTopic - Update code not to need this hack
Bot.prototype.on = function(eventName, handler) {
if (eventName == 'message_received') {
this.rootTopic.on(eventName, handler)
} else {
this.eventEmitter.addListener(eventName, handler)
}
}

Bot.prototype.hears = function(pattern, handler) {
this.rootTopic.hears(pattern, handler)
}

Bot.prototype.use = function(component) {
component(this)
}

Bot.prototype.download = function(attachment, callback) {
if (attachment.url) {
this.downloadFileFromUrl(attachment.url, callback)
} else {
this.downloadFileFromData(attachment.data, callback)
hears(pattern, handler) {
this.rootTopic.hears(pattern, handler);
}
}

Bot.prototype.downloadFileFromUrl = function(url, callback) {

var filename = uuid.v4()

if (!fs.existsSync(staticFilesDirectory)){
fs.mkdirSync(staticFilesDirectory)
use(component) {
component(this);
}

var r = request(url)
var s = fs.createWriteStream(staticFilesDirectory + '/' + filename)
download(attachment, callback) {
if (attachment.url) {
this.downloadFileFromUrl(attachment.url, callback);
} else {
this.downloadFileFromData(attachment.data, callback);
}
}

r.on('response', function (res) {
res.pipe(s)
})
downloadFileFromUrl(url, callback) {
const filename = uuid.v4();

s.on('close', function() {
callback(staticFilesDirectory + '/' + filename)
})
}
if (!fs.existsSync(staticFilesDirectory)) {
fs.mkdirSync(staticFilesDirectory);
}

Bot.prototype.downloadFileFromData = function(data, callback) {
const r = request(url);
const s = fs.createWriteStream(`${staticFilesDirectory}/${filename}`);

var filename = uuid.v4()
var matches = data.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/)
var buffer = new Buffer(matches[2], 'base64')
r.on('response', (res) => {
res.pipe(s);
});

if (!fs.existsSync(staticFilesDirectory)){
fs.mkdirSync(staticFilesDirectory)
s.on('close', () => {
callback(`${staticFilesDirectory}/${filename}`);
});
}

fs.writeFile(staticFilesDirectory + '/' + filename, buffer, 'base64')
downloadFileFromData(data, callback) {
const filename = uuid.v4();
const matches = data.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
const buffer = new Buffer(matches[2], 'base64');

callback(staticFilesDirectory + '/' + filename)
}
if (!fs.existsSync(staticFilesDirectory)) {
fs.mkdirSync(staticFilesDirectory);
}

fs.writeFile(`${staticFilesDirectory}/${filename}`, buffer, 'base64');

Bot.prototype.createTopic = function(callback) {
callback(`${staticFilesDirectory}/${filename}`);
}

var topicID = Object.keys(this.topics).length
this.topics[topicID] = new Topic()
createTopic(callback) {
const topicID = Object.keys(this.topics).length;
this.topics[topicID] = new Topic();

callback(this.topics[topicID])
callback(this.topics[topicID]);

return topicID
return topicID;
}
}

module.exports = Bot
module.exports = Bot;
80 changes: 40 additions & 40 deletions lib/event-emitter.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
var Event = require('./event')

function EventEmitter() {
this.listeners = []
this.fallbacks = {}
}

EventEmitter.prototype.addListener = function(eventName, handler) {
this.listeners.push({
eventName: eventName,
handler: handler
})
}

EventEmitter.prototype.fallback = function(eventName, handler) {
this.fallbacks[eventName] = handler
}

EventEmitter.prototype.emit = function(eventName) {
var args = Array.prototype.concat.apply([], arguments).slice(1)
var eventListeners = this.listeners.filter(function(listener) {
return listener.eventName === eventName
}).map(function(listener) {
return listener.handler
})

var event = new Event(eventListeners, args)
event.next(function() {

var handler = this.fallbacks[eventName]

if (handler) {
handler.apply(this, args)
} else {
console.error('Unhandled event ' + eventName)
}
}.bind(this))

return event
const Event = require('./event');

class EventEmitter {
constructor() {
this.listeners = [];
this.fallbacks = {};
}

addListener(eventName, handler) {
this.listeners.push({
eventName,
handler,
});
}

fallback(eventName, handler) {
this.fallbacks[eventName] = handler;
}

emit(eventName, ...args) {
const eventListeners = this.listeners.filter(listener =>
listener.eventName === eventName
).map(listener =>
listener.handler
);

const event = new Event(eventListeners, args);
event.next(() => {
const handler = this.fallbacks[eventName];

if (handler) {
handler.apply(this, args);
} else {
console.error(`Unhandled event ${eventName}`);
}
});

return event;
}
}

module.exports = EventEmitter
module.exports = EventEmitter;

0 comments on commit e7b26d0

Please sign in to comment.