Coding fun – message all the things

Today we actually make the bot interact, it will start to post messages to Spark.

We’ve setup nginx to listen, setup nodejs to actually listen and grab incoming spark messages.  We’ve setup a search to imgur, returning a text link, now we’re going to send it right back where it came from.

First I’m going to detail and explain the postMessage routine within the spark module:

var postMessage = (link, messageDetail, callback) => {
 var sparkAPI = 'https://api.ciscospark.com/v1/messages/';

 var postData = {
  files: [link]
 };

 if (messageDetail.roomType === 'group') {
  postData.roomId = messageDetail.roomId;
 } else {
  postData.toPersonId = messageDetail.personId;
 }

 var options = {
  url: sparkAPI,
  headers: {
   'Authorization': 'Bearer <YOUR TOKEN>'
  },
  body: postData,
  json: true
 };

 request.post(options, (err, res, body) => {
  if (!err) {
   callback(body);
  }
 });
};

Starting from the top

var postMessage = (link, messageDetail, callback) => {

Standard function definition, we’re passing in the string for the imgur link to an image, the details of the message that spark sent us(important for later), and the callback function we want to handle this with

 var sparkAPI = 'https://api.ciscospark.com/v1/messages/';

 var postData = {
  files: [link]
 };

Two variables, one to define the API of spark we’re working with.

The second variable will be the body of the document we send.  Post methods send any data inside the body of the document(with various encodings, see the link for details on that).  In our case we’re stating the files variable will be an array with our link.  We could send multiple files this way.  The array can also contain binary file data, but it’s convenient that we can pass it a url and it will fetch it within the spark client.

 if (messageDetail.roomType === 'group') {
  postData.roomId = messageDetail.roomId;
 } else {
  postData.toPersonId = messageDetail.personId;
 }

We passed in messageDetail so we could determine where the message came from.  If it came from a room, a group message, we need to reply back to that room.  Otherwise we reply back to the user that directly messaged us.

var options = {
 url: sparkAPI,
 headers: {
  'Authorization': 'Bearer <YOUR TOKEN>'
 },
 body: postData,
 json: true
};

Defining the options that will be passed to the request module.  This is just gathering all the data and flags we want to send.  Remember each authorization token is unique to spark’s bot, so fill yours in above.

I’ve also specified we’re sending pre-formatted json data, other languages (python) don’t work in native json so we’d need to pre-convert before using this.  NodeJS does, so happily it’s just set the flag and forget it.

request.post(options, (err, res, body) => {
 if (!err) {
  callback(body);
 }
});

Finally post the message to spark, returning whatever information the call gives us back (via a callback!).

Now let’s see it in context of our master server app

var botName = 'ImgurBot';

app.all('/spark', (req, res) => {
 res.send();
 spark.getMessage(req.body.data.id, (messageDetail) => {
  if (messageDetail.personEmail !== botName + '@sparkbot.io') {
   if (messageDetail.roomType === 'group') {
   // Check if the bot is mentioned, if not ignore this
   if (messageDetail.text.split(' ')[0] === botName) {
    // Strip off the @ reference to the Bot
    msgText = messageDetail.text.split(' ').slice(1).join(' ');
    imgur.search(msgText, (link) => {
     spark.postMessage(link, messageDetail, (msgId) => {
      console.log(msgId);
     });
    });
   } else {
    imgur.search(messageDetail.text, (link) => {
     spark.postMessage(link, messageDetail, (msgId) => {
      console.log(msgId);
     });
    });
   }
  }
 });
});

Most of this is self explanatory, there is one thing I’ll highlight below:

var botName = 'ImgurBot';

if (messageDetail.personEmail !== botName + '@sparkbot.io') {
 if (messageDetail.roomType === 'group') {
   // Check if the bot is mentioned, if not ignore this
   if (messageDetail.text.split(' ')[0] === botName) {
     // Strip off the @ reference to the Bot
     msgText = messageDetail.text.split(' ').slice(1).join(' ');

One of the spark restrictions is that Bots in group chats will only receive messages where they are mentioned.  This logic is checking for that.  First you have to define a variable with your bot’s name, make sure this matches including case.

We first check to ensure the message we just received, is not the message the bot just sent(that was a fun one to learn, recursion strikes again!).  Spark will append @sparkbot.io to any message with the bot, so in my case all it’s messages are from ImgurBot@sparkbot.io

Third we check if it’s a group message or not.  This is important because if it is our bot’s name will be the first word of the message.  We know this is true due to the requirement that bot’s be @mentioned within group messages(otherwise our script wouldn’t get any data in the first place).

If it is, we strip off the botName at the beginning (with a sanity check first) and create a new variable called msgText that contains everything else.

In the next post we’ll detail catching specific commands within msgText to allow the bot to do other things(like delete it’s own messages), but for now that’s the meat and potatoes that Imgur needs to search with.

We then search, post the message, and log the results.

At this point we are 4 callbacks deep:

app.all -> getMessage -> search -> postMessage

When you draw these out like above, you can really see how the power of a callback can write your program flow for you.

The power of a modular design like this, we can substitute anything we want for search(maybe doing weather data?  Maybe looking at an NMS for status on a device?).

One very common use for bots like this is in Network Operations, having your NMS alert you and send a message to spark.  In this way you aren’t worrying about email, and can potentially write scripts to interact via Chat (chatops) to acknowledge and potentially get more detail on alerts.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s