The Hubot msg Object

I've been playing with Hubot lately as part of allowing certain commands to be available to the engineers for deploying environments within AWS. One of the puzzles I have had is the lack of a good reference as to what all the various pieces within the msg object are within the Hubot system. I'm sure my google-fu is just really bad, but for the life of me I couldn't find a good and clear listing.

In the end (as I'm still learning coffeescript) I made a really basic Hubot module and used it to write out debug information to the console. This meant that I could then view the logs created (Hubot is a node application, so I wrap it up in an Init script so that it runs on a server 24x7) and by viewing those logs, determine what the objects within msg are.

My main objective is to ensure that commands called out by specific individuals, and occasionally only if they talk in specific rooms within Slack are catered for. This will be implemented using either hard-coded switch statements or if I really get a round tuit, stored within a database. Hubot is pretty awesome, so I can easily populate Hubot's 'brain' (or just directly check authentication) using a REST API endpoint. The world is my oyster or somesuch!

The script command is a lot easier than I thought it would be, so of course I tried writing a recursive object logging function to start with (that worked, but not 100% and was actually very messy to read). In the end, my script is really basic. You of course get to miss out on the lengthy Google searching and general coding iteration I went through to get (what at times was a good 20 lines of code) down to this one statement:

robot.respond /debug/, (msg) ->  
  console.log Object(msg)

And the output? Well, that is pretty awesome for what I needed (the below is mostly sanitised of course):

{ robot:
   { name: 'hubot',
     events: { domain: null, _events: [Object], _maxListeners: 10 },
     brain:
      { data: [Object],
        autoSave: true,
        saveInterval: [Object],
        _events: [Object] },
     alias: false,
     adapter:
      { message: [Function],
        close: [Function],
        open: [Function],
        userChange: [Function],
        brainLoaded: [Function],
        loggedIn: [Function],
        error: [Function],
        robot: [Circular],
        _events: [Object],
        options: [Object],
        client: [Object],
        self: [Object] },
     Response: [Function: Response],
     commands:
      [ 'hubot help - Displays all of the help commands that Hubot knows about.',
        'hubot help <query> - Displays all help commands that match <query>.' ],
     listeners: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
     logger: { level: 7, stream: [Object] },
     pingIntervalId: null,
     version: '2.11.1',
     server:
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        _connections: 0,
        connections: [Getter/Setter],
        _handle: [Object],
        _usingSlaves: false,
        _slaves: [],
        allowHalfOpen: true,
        httpAllowHalfOpen: false,
        timeout: 120000,
        _connectionKey: '4:0.0.0.0:8080' },
     router:
      { [Function: app]
        use: [Function],
        handle: [Function],
        listen: [Function],
        setMaxListeners: [Function: setMaxListeners],
        emit: [Function: emit],
        addListener: [Function: addListener],
        on: [Function: addListener],
        once: [Function: once],
        removeListener: [Function: removeListener],
        removeAllListeners: [Function: removeAllListeners],
        listeners: [Function: listeners],
        route: '/',
        stack: [Object],
        init: [Function],
        defaultConfiguration: [Function],
        engine: [Function],
        param: [Function],
        set: [Function],
        path: [Function],
        enabled: [Function],
        disabled: [Function],
        enable: [Function],
        disable: [Function],
        configure: [Function],
        get: [Function],
        post: [Function],
        put: [Function],
        head: [Function],
        delete: [Function],
        options: [Function],
        trace: [Function],
        copy: [Function],
        lock: [Function],
        mkcol: [Function],
        move: [Function],
        purge: [Function],
        propfind: [Function],
        proppatch: [Function],
        unlock: [Function],
        report: [Function],
        mkactivity: [Function],
        checkout: [Function],
        merge: [Function],
        'm-search': [Function],
        notify: [Function],
        subscribe: [Function],
        unsubscribe: [Function],
        patch: [Function],
        search: [Function],
        connect: [Function],
        all: [Function],
        del: [Function],
        render: [Function],
        request: [Object],
        response: [Object],
        cache: {},
        settings: [Object],
        engines: {},
        _events: [Object],
        _router: [Object],
        routes: [Object],
        router: [Getter],
        locals: [Object],
        _usedRouter: true },
     adapterName: 'slack',
     errorHandlers: [],
     onUncaughtException: [Function] },
  message:
   { user:
      { id: 'ABCDEFGHI',
        name: 'phillip',
        email_address: 'phillip@domainname',
        room: 'hubottest' },
     text: 'hubot debug',
     id: '1234567890.123456',
     done: false,
     room: 'hubottest' },
  match:
   [ 'hubot debug',
     index: 0,
     input: 'hubot debug' ],
  envelope:
   { room: 'hubottest',
     user:
      { id: 'ABCDEFGHI',
        name: 'phillip',
        email_address: 'phillip@domainname',
        room: 'hubottest' },
     message:
      { user: [Object],
        text: 'hubot debug',
        id: '1234567890.123456',
        done: false,
        room: 'hubottest' } } }

Now that I can see the bulk of the objects, I can easily reference the channel (called room and referenced as msg.message.user.room, msg.message.room, msg.envelope.room, msg.envelope.user.room or msg.envelope.message.room - so many choices!). I can reference the user.name and if I want to add some obfuscated security, I could reference the user.id. All these objects are returned in some shape or other to a Slack client, so using user.id isn't actually adding any real security...

All that said, off I go to create my commands that will call my Rundeck API and run the relevant environment jobs without even needing to log in to Rundeck itself.