Code Monkey home page Code Monkey logo

slackbot-router's Introduction

slackbot-router

Clojars Project

slackbot-router is a small routing library for Slack bots, organizing incoming message tests and reply-generators into tables. Incoming messages are handled asynchronously.

Installation

Add the following dependency to your project.clj file:

[jcorrado/slackbot-router "0.1.1"]

Usage

Bot Setup

A Slack bot is a web application designed to handle events surfaced by a configured Slack workspace. Slack offers two patterns: the Real Time Messaging API and the simpler Events API; I have only used the latter.

Here is a fragment of a Compojure app that shows the basic idea. Our message routing rules are in message-table, detailed below.

You will need to configure Ring, via project.clj to use your init and handler fns.

(defproject mybot "0.1.0"
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [jcorrado/slackbot-router "0.1.1"]
                 ;; ...]
  :ring {:init mybot.handler/init
         :handler mybot.handler/app})

A simple mybot.handler fragment with the basic idea.

(def events-c (chan 100))

(defn slack-event-handler
  [req]
  (let [event (:body req)]
    (try
      (response (slackbot-router.core/route-event event events-c))
      (catch java.lang.Exception e
        (println "Unknown Slack message type:" (.getMessage e))
        ;; We always reply 200 to incoming Slack events
        (response "OK")))))

(defroutes app
  (POST "/slack-event" [body] slack-event-handler))

(defn init
  []
  (go-loop []
    (let [msg (<! events-c)]
      (if-let [reply (slackbot-router.core/route-message message-table msg)]
       	;;
        ;; The incoming message passed a test in our routinge table
        ;; and the associated reply generator returned non-nil - do
        ;; something with that here.
        ;;
        ))
    (recur)))

Routing Table Design

A table consists of two-element vectors. The first element is a test function, to which the message is passed. If that test returns anything truthy, that returned value is passed to the second element: the reply-generating function. A typical design would have that reply, in turn, posted to Slack. However that's outside of the domain of slackbot-router.

Here is a very simple table, with a single route.

(def basic-table
  [(fn [msg] (= (:text msg) "!ping"))
   (fn [_] "!pong")])

This simple test-text/reply-text pattern is common enough to warrant a macro, which also supports a regular expression.

(def basic-table
  [(text-match "!ping" "!pong")
   (text-match #"(?i)^.*deploy(ing)? (to )?prod(uction)?"
               "*leeeroy jeeenkins!!1* :hotdog:")])

The return of a successful test is passed to the associated reply generating function.

(def boromir-table
  [(text-match "Who is Boromir?" "High Warden of the White Tower")

   [(fn [msg]
      (if-let [[_ deed] (re-matches #"(?i)!boromir\s+(.+?)\s*$" (:text msg))]
        deed))
    (fn [deed]
      (format "*One does not simply %s*" deed))]])]

You may nest tables, breaking your routes apart.

(def message-table
  [basic-table
   boromir-table]))

slackbot-router flattens the nested tables and tests, in sequence, from the top.

License

Copyright © 2018 Jereme Corrado

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

slackbot-router's People

Contributors

jcorrado avatar

slackbot-router's Issues

Can event type tests be handled by spec?

;; TODO - Now that we're using Spec, these feel redundant.
(defn- verification-event?
"Is event a Slack verification challenge?"
[ev]
(if (= (:type ev) "url_verification")
ev))
(defn- message-event?
"Is event a Slack message? We filter out bot messages."
[ev]
(if (and (= (:type ev) "event_callback")
(= (get-in ev [:event :type]) "message")
(not= (get-in ev [:event :subtype]) "bot_message"))
ev))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.