Our thoughts, knowledge, insights and opinions

Introducing Scala Slack Bot

Slack

Motivation

In Scalac we believe that communication is essential in IT and that projects with inefficient information sharing are doomed to fail. Fortunately for us it doesn’t always mean that putting people in one place is the only way. More often it’s about creating the right spirit for exchanging knowledge and providing ways to do so. As in Scalac we are very often working remotely, we had to come up with a tool to help us communicate. We tried few different products for communication, but in the end we switched to Slack. We are using it for around a year now and are pleased with the rich experience it offers.

But our ambitions don’t stop here. As we are a medium size company we strive for maximum efficiency. We are eager to automate as much of the process as possible, so our employees can spend their time focusing on tasks requiring creativity and accountability. As we are hiring the best people, we don’t want them to do boring and repeatable busywork.

It’s not always an easy process. You have to face technical difficulties and convince people to trust the new tools.

How is Slack helping us automate? It’s done via Integrations. Slack Integrations contain apps for many useful services as Google Hangouts, Github, Crashlytics or Google Docs. Unfortunately for us it’s not enough … we would like to have a central hub with all our tools, so they have a common interface and are easily accessible. This is where Real Time Messaging API (provided by Slack) and Scala Slack Bot (hacked together by us) come in.

The following sections are a step by step guide on how to setup a custom integration for Slack using Scala Slack Bot.

Configure Slack

First, let’s start with configuring the integration in Slack. First go to https://XXX.slack.com/services/new (where XXX is the name of your organization). There you can browse all the existing integrations. Search for “Bots” option and click “View” button. Give the new bot a name and click “Add Bot Integration”. After that you will be taken to a page with a detailed view of your new bot. The most important thing is to generate and save the API Token. We will need it for later!

You should see something like this

New-Bot

First Steps

Now let’s start with the Scala side of things. Create a new Scala application using sbt. Having this in place open your build.sbt and add

Also open your src/main/resources/application.conf file and add the API token we got from Slack as follows

[application.conf]

The value of websocket.key can be any Base64 encoded value. It will be used by the bot to identify websocket connection.

Having the needed libs in place we can create a starting point for our app.

[BotRunner.scala]

As Scala Slack Bot is written on top of Akka, we need to create an ActorSystem in which the bots will run first. Also we shouldn’t forget to close them properly using sys.addShutdownHook(shutdown()). Now we can start tinkering with our bots. The heart of the bot system is the ScalaBotActor class that takes few parameters: BotModules instance, a MessageEventBus for communication, reference to master class and an ActorRef pointing to UserStorage actor. You don’t have to worry about all of that now. Just concentrate on BotBundle.

A note on architecture. As Slack limit the amount of integrations you can use, we decided on the following approach. We integrate a single application with Slack, so only one slot is used and you are free to add third-party integrations. On the other hand this application may hold multiple bot modules, each providing a distinct feature. Those modules are created by instances of BotModules trait.

[BotRunner.scala]

The body of a BotModules instance is very simple. It defines one function registerModules which is responsible for initializing actor instances. One thing to notice here is that the actors share the same instance of MessageEventBus (passed as a parameter for easier testing) and all have readable actor names.

In our example we start three modules. The CommandsRecognizerBot is a handy utility actor, invisible from the outside, that will translate raw Slack messages for us into a more useful Command class. HelpBot is the Slack’s counterpart of Linux man command - it presents users with options and descriptions for commands. The CalculatorBot is a dummy bot, that we will write on our own.

Calculator bot

OK, let’s create our first bot. This one will be a simple Clojure-style calculator.

[CalculatorBot.scala]

Let’s elaborate on this a little. The AbstractBot class is a thin wrapper around Akka’s Actor class providing few useful utility methods for bot authors and constraints a Bot should meet. There are three things a bot should do:

  • he should use a MessageEventBus for communication
  • he should define a help method for maintainers and user
  • and he should provide an act method, which behaves roughly the same way as receive in an ordinary actor

The first thing you might notice in this draft is help being a String => OutboundMessage function. OutboundMessage represents a message that will be sent back to Slack. It takes two parameters: on what channel to send and what to send. Having this basic understanding we can move to implementing the act method. We can do that as follows.

[CalculatorBot.scala]

As you can see this is not far from Akka. The only difference is that we match on Command instances provided to us by CommandsRecognizerBot. This class carries three values. The first is the command name without the leading ‘command’ character ($ be default), and List[String] of the arguments (without the leading command) and the raw message (so we can, for instance, extract the channel id). After matching a request we perform some computations, form an OutboundMessage and pass it to publish for sending. Simple as that.

There are few things to consider when writing a new bot. We find it useful to communicate with end users as much as possible about the failures and when a command can’t be matched (for instance it’s lacking params). You don’t have to extend AbstractBot, but it’s recommended in most cases. If you are in need for creating an internal bot able to communicate with Slack consider using IncomingMessageListener directly, but proceed with caution.

For more examples you can check the bots we are using. The source is available here.

Using the bot

The command above should start the bot. After all components start successfully, the bot will get online as on the screen.

Bot-online

Now we can send a few Direct Messages to the bot:

  $calc + 1 2 3 10
  $calc / 10 2
  $calc && 1

The bot will also listen on all channels that he has been invited to. If you think that this “console command” style of communication is not for you, you can also mention the bot and pass the command without the leading character.

  @calculator: calc + 1 2 3

Summary

Bender

In Scalac we have a strong belief that in the future all redundant tasks will be automated and the done by efficient, specialized robots working on behalf of humans. So people will be able to focus on creative tasks and those tasks that require taking responsibility. We are far from there, yet I’m in the opinion that Slack Bot presented to you above is a step into the future.

You like this post? Want to stay updated? Follow us on Twitter or subscribe to our Feed.