UNPKG

hubot-genesys-cloud

Version:
228 lines (171 loc) 6.48 kB
try # FIXME: This is a hack for testing, otherwise instanceof doesn't work for TextMessage path = require('path') {User,Adapter,Robot,TextMessage,EnterMessage,LeaveMessage} = require path.join(module.parent.path, '..') catch {User,Adapter,Robot,TextMessage,EnterMessage,LeaveMessage} = require 'hubot' fs = require 'fs' util = require 'util' path = require 'path' {EventEmitter} = require 'events' global._ = require 'underscore' _.str = require 'underscore.string' { client, xml } = require("@xmpp/client"); middleware = require("@xmpp/middleware"); debug = require("@xmpp/debug"); global.JID = require('@xmpp/client').jid global.ltx = require('ltx') global.uuid = require './lib/uuid' config = require(path.join(process.cwd(), 'config')) global.logError = => @robot.logger.error arguments... global.log = => console.log arguments... global.debug = => console.log arguments... if process.env.HUBOT_GENESYS_CLOUD_DEBUG; class Realtime extends EventEmitter constructor: (client) -> super @client = client send: (stanza) -> debug 'stanza', 'out', stanza.toString() @client.send stanza jid: null debug: debug connected: false features: {} class GenesysCloudBot extends Adapter options = null constructor: -> super @options = config [username, domain] = @options.username.split('@') @client = client({ service: "xmpp://#{@options.host}:#{@options.port}", credentials: { authzid: @options.username, username, password: @options.password, }, }); # !!! HACK BELOW !!! All of thie is because it's # near impossible to override the host when the # connection is upgraded to TLS. @client.header = (args...) => for el in args if el.attrs.to == @options.host el.attrs.to = domain # This comes from @xmpp/client-core @client.Transport.prototype.header(args...) debug(@client, true) if process.env.HUBOT_GENESYS_CLOUD_DEBUG @realtime = new Realtime @client reconnectTryCount: 0 controllers: {} run: -> @robot.on 'error', (error) => console.error error @makeClient() @setupControllers() @realtime.on 'message', @_onMessage setupControllers: -> for fileName in fs.readdirSync __dirname + '/controllers' unless fileName.match /.*Controller(.coffee)?$/ then continue name = _.str.camelize(fileName.substring(0, fileName.indexOf('Controller'))).replace /^./, (m) -> m.toLowerCase() Controller = require "./controllers/#{fileName}" @controllers[name] = new Controller(@realtime) do (name, Controller) => for funcName, func of Controller.expose debug 'handler', 'registering exposed controller method', funcName, 'in controller', name do (funcName, func) => @realtime[funcName] = (args...) => apply = => func.apply @controllers[name], args unless @realtime.connected debug 'handle', 'deferring call to', funcName, @realtime.connected return @realtime.once 'connect', => debug 'handle', 'defer resolve', funcName apply() else apply() null for event in Controller.exposeEvents do (name, event) => @['on'+_.str.capitalize(event)] = (callback) => @on event, callback @controllers[name].on event, => @realtime.emit event, arguments... null makeClient: -> @connected = false @client.on 'error', (error) => logError error @client.on 'online', @onConnect @client.on 'offline', => log 'offline', arguments... @realtime.emit 'disconnect' @client.on 'stanza', @onStanza @client.on 'end', => @robot.logger.info 'Connection closed, attempting to reconnect' @client.reconnect() if(@client.start) @client.start().catch(console.error); onConnect: () => log '***************** online', @client.jid.toString(), @client.jid.bare().toString() @realtime.jid = @client.jid unless @realtime.connected @realtime.connected = true @emit 'connected' @realtime.emit 'connect' onStanza: (stanza) => handled = false for name, controller of @controllers for func, test of controller.constructor.stanzas do (stanza) => if test.apply(controller, [stanza]) debug 'stanza', 'handled by', "#{controller.constructor.name}.#{func}" handled = true controller[func] stanza unless handled then debug 'stanza', 'unhandled' null _send: (envelope, messages, {message_fn, preferred_to_fn}) -> for message in messages unless message then continue if (!message_fn) message_fn = (msg) => msg transformedMessage = message_fn(message) @robot.logger.debug "Sending to #{envelope.room or envelope.user?.id}: #{transformedMessage}" if (!preferred_to_fn) to = envelope.room or envelope.user?.id else to = preferred_to_fn(envelope) @realtime.sendMessage to, transformedMessage send: (envelope, messages...) -> @_send(envelope, messages, {}) emote: (envelope, messages...) -> @_send(envelope, messages, { message_fn: ((msg) => "/me #{msg}") }) reply: (envelope, messages...) -> @_send(envelope, messages, { preferred_to_fn: ((envelope) => envelope.user?.id) }) offline: => @robot.logger.debug "Received offline event", @client.connect? @client.connect() clearInterval(@keepaliveInterval) @robot.logger.debug "Received offline event" @client.connect() leaveRoom: (res) => to = res.envelope.room @robot.logger.debug 'Leaving room', to if to.match(/@conference/) @realtime.sendMessage to, 'Goodbye!', => @realtime.leaveRoom to @realtime.setInactive to else @realtime.sendMessage res.envelope.user?.id, "Sorry, I can only leave chats!" _onMessage: (msg) => if msg.from is @options.username.toLowerCase() then return if msg.body?.match /nsfw/ then return if msg.type is 'person' user = @robot.brain.userForId msg.from user.room = msg.from else user = @robot.brain.userForId msg.from user.room = msg.to @receive new TextMessage(user, msg.body) exports.use = (@robot) -> new GenesysCloudBot @robot