bots
Version:
Build robust networks of bots that can react to events
190 lines (163 loc) • 5.74 kB
text/coffeescript
# The main `Bot` class that all robots are created from, this contains the
# main functions for assembling a bot.
{EventEmitter} = require 'events'
request = require 'request'
fs = require 'fs'
# Get the current version from `package.json`.
exports.version = JSON.parse(fs.readFileSync(__dirname + "/../package.json")).version
# Factory method for creating a new `Bot` instance. Accepts a name
# argument, which is the name given to the bot.
#
# var bots = require('bots');
#
# var coolbot = bots.createBot('coolbot 1.0.0');
#
exports.createBot = (name) ->
new Bot name
# The `Bot` class, inherits from `EventEmitter` so it can notify plugins of
# certain lifecycle events.
exports.Bot = class Bot extends EventEmitter
# Creates a new `Bot` with the given name. Sets up the bot ready to be
# configured.
constructor: (@name) ->
@handlers = []
@interfaces = []
@descriptions = {}
setup: (nickname, callback) ->
if typeof(nickname) is 'function'
callback = nickname
else
@nickname = nickname
callback @desc, @hear
# Adds a description of a piece of the robots functionality, this is used
# for the robots builtin `help` phrase.
#
# * **phrase** - The String representing the phase the bot recognises.
# * **functionality** - The String describing the phrase (optional).
#
# #### Example
#
# bot.desc('image me THING', 'Get a random image of THING');
#
desc: (phrase, functionality) =>
@descriptions[phrase] = functionality
# Add a `pattern` to the robots repotoire. This is matched against incoming
# messages and if they match then the message is passed to `callback`.
#
# * **pattern** - The RegEx to match against the message body.
# * **callback** - The Function to be invoked when the pattern is matched.
#
# #### Example
#
# bot.hear(/ping/, function(message) {
# message.say('PONG');
# });
#
hear: (pattern, callback) =>
@handlers.push [pattern, callback]
# Add an interface to the robot. This is allows the 'bot to communicate
# with the outside world. See the `Cli` and `XMPP` interfaces for examples,
# the interface should inherit from EventEmitter, and emit a `message`
# event when there is a new message on the interface.
#
# var bots = require('bots');
# var coolbot = bots.createBot('coolbot 1.0.0');
# coolbot.use(bots.cli());
#
use: (interface) ->
@interfaces.push interface
interface.on 'message', @dispatch
# Dispatches an incoming message to any handlers that match the message
# body. This can be used to fake message to the bot, useful for testing
# the bot. Takes a `message` object with `body` and `say` properties.
#
# coolbot.dispatch({
# message: 'ping',
# say: function(text, callback) {
# console.log(text);
# callback();
# }
# });
#
dispatch: (message) =>
for pair in @handlers
if @nickname
continue unless message.body.match(new RegExp("^#{@nickname}"))
[ pattern, handler ] = pair
handler.call(@, message) if message.match = message.body.match(pattern)
# Start the bot up, calls listen on the registered interfaces. This registers
# the **help** phrase that the bot will always repond to. Emits a `start`
# event when setup is complete.
#
# coolbot.on('start', function() {
# console.log("coolbot started");
# });
# coolbot.start();
#
start: ->
interface.listen() for interface in @interfaces
@hear /help/, @help
@emit 'start'
stop: (finished) ->
console.log "\nStopping #{@name}"
closing = @interfaces.length
for interface in @interfaces
interface.close ->
finished() if --closing is 0
# Reset the bot's `handlers` and `descriptions`, note this does not stop
# the registered interfaces from listening.
reset: (callback) ->
@handlers = []
@descriptions = []
callback?()
# Helper method for making a `GET` request, proxies to the `request`
# method.
get: (uri, body, callback) ->
@request('GET', uri, body, callback)
# Helper method for making a `POST` request, proxies to the `request`
# method.
post: (uri, body, callback) ->
@request('POST', uri, body, callback)
# Handler for the default help action, gathers all of the registered
# descriptions and sends a message describing each action.
help: (message) ->
if Object.keys(@descriptions).length is 0
return message.say "I do not have any actions yet."
message.say "I listen for the following…", =>
for phrase, functionality of @descriptions
if functionality
output = phrase + ": " + functionality
else
output = phrase
message.say output
# Helper to make http requests, tries to automatically handle JSON input and
# output.
request: (method, uri, body, callback) ->
options = { method: method, uri: uri }
options.headers = { 'User-Agent': @name }
if typeof(body) is 'function' and not callback
callback = body
body = null
if typeof body is 'string'
options.body = body
else
options.json = body
request options, (err, response, body) ->
try
body = JSON.parse body
catch e
# Ignore and pass through the raw body.
callback? body, response
# Command line interface.
exports.cli = ->
Cli = require './interfaces/cli'
new Cli
# Campfire interface.
exports.campfire = (args...) ->
Campfire = require './interfaces/campfire'
new Campfire args...
# XMPP interface.
exports.xmpp = (args...) ->
Xmpp = require './interfaces/xmpp'
new Xmpp args...
exports.generate = require './generator'