【Ruby】Slack BotでReal Time Messaging APIを利用してみる

2018年7月27日Ruby,Slack

こんにちは、しきゆらです。

前回・前々回とSlackとのやり取りをさっくりと確認していました。

前回の記事

【Ruby】Slack Botことはじめ

前々回の記事

【Ruby】Slack Appことはじめ

タイトルが似ているので間違えそうですね・・・。

Slack AppがBotも含んだ広い意味でのSlack上で動くアプリ全般を表しています。

Slack BotはAppの中でもBotとして振る舞うようなアプリを指しています。

 

今回は、Slack Botでもう少し複雑なこともしたいので、RTMを利用してみます。

 

RTMとは?

タイトルにもある通り、Real Time Messaging APIの略で

Slackと常に接続し、ユーザの動きを監視して特定の行動が起こったら反応する、というようなことができるAPIです。

例えば、

  • ユーザが入力を始めたとき、通知する
  • メッセージが変更されたとき、前後の差分を表示する

などができそうです。

この辺は発想次第でなんとでもできそうですね。

 

では、実際に使って行きます。

 

 

準備

前回・前々回と同様です。

今回は、前回作成した「test_bot」をそのまま利用していきます。

別アプリとして作成する場合は、前回の記事を参考にしていただければ。

 

gemのインストール

test_botでRTMを使うためには、http以外にもgemを利用していきます。

追加するのは、以下の2つ。

EventMachineは、並列処理のためのライブラリ。

feya-websocketは、RubyでWebSocketを利用するためのライブラリと思っていただければいいかと思います。

 

RTMを利用するためにはWebSocketで接続するために、これらを利用していきます。

 

RTM APIの流れ

RTMを利用するための流れとしては、以下のとおりです。

  • https://api.slack.com/methods/rtm.start へアクセスし、WebSocketで接続するためのURLを取得する
  • 取得したURLへ接続し、流れてくる情報をもとにレスポンスをSlackへ投げる

という感じです。

 

まずは、WebSocketで接続するためのURLを取得します。

コードは以下のような感じ。

require 'http'
require 'json'
require 'eventmachine'
require 'faye/websocket'

response = HTTP.post('https://slack.com/api/rtm.start', params: {
   token: 'Tokenを貼り付け'
 })

# 取得してきたレスポンスをJSONに直す
res_json = JSON.parse(response.body)
# 接続するためのURLを確認
puts res_json['url']

 

Slack上の活動を監視

ここで取得できたURLをもとに、Slackで起こる様々な活動を監視してみます。

上記のコードを少し変更していきます。

 

require 'http'
require 'json'
require 'eventmachine'
require 'faye/websocket'

response = HTTP.post('https://slack.com/api/rtm.start', params: {
                       token: 'Tokenを貼り付けて'
                     })

res_json = JSON.parse(response.body)
puts res_json['url']

###########################
# ここより下を追加
###########################

EM.run do
  # Web Socketインスタンスの立ち上げ
  ws = Faye::WebSocket::Client.new(res_json['url'])

  #  接続が確立した時の処理
  ws.on :open do
    p [:open]
  end

  # RTM APIから情報を受け取った時の処理
  ws.on :message do |event|
    data = JSON.parse(event.data)
    p data
  end

  # 接続が切断した時の処理
  ws.on :close do |event|
    p [:close, event.code]
    ws = nil
    EM.stop
  end
end

 

これを実行してみます。

Slackで起こる活動がいろいろ流れてくるかと思います。

いくつか見てみると、「type=xxx」となっていることがわかるかと思います。

簡単に見てみると、以下のようなものがわかるかと思います。

  • helloは、接続できたときに流れてくるもの。
  • user_typingは入力が行われているときに流れてくるもの。
  • messageはメッセージが投稿されたときに流れてくるもの。

その他、様々な状態を取得できます。

これを利用して、アプリを作ると楽しいかもしれません。

 

Botアプリを拡張

今回は、特定のコメントが流れてきたら返答する、という簡単なものを作ってみます。

対応するコメントは、以下の通り。

  • おはよう
  • こんにちは
  • こんばんは
  • さようなら

挨拶をしたら、返してくれるBotです。

(実用性は無いですね・・・)

 

では、コードを更に拡張してみます。

require 'http'
require 'json'
require 'eventmachine'
require 'faye/websocket'

response = HTTP.post('https://slack.com/api/rtm.start', params: {
  token: 'Tokenを貼り付け'
})

res_json = JSON.parse(response.body)
puts res_json['url']

EM.run do
  # Web Socketインスタンスの立ち上げ
  ws = Faye::WebSocket::Client.new(res_json['url'])

  #  接続が確立した時の処理
  ws.on :open do
    p [:open]
  end

  # RTM APIから情報を受け取った時の処理
  ws.on :message do |event|
    data = JSON.parse(event.data)
    p data

    ########################### 
    # ここより下を追加 
    ###########################
    case data['text']
    when 'おはよう'
      ws.send({
        channel: data['channel'],
        type: 'message',
        text: <<~EOS
        <@#{data['user']}>さん
        おっはー。
        今日も頑張ろう。
        EOS
      }.to_json)
    when 'こんにちは'
      ws.send({
        channel: data['channel'],
        type: 'message',
        text: <<~EOS
        <@#{data['user']}>さん
        こんにちは。
        疲れてない?
        EOS
      }.to_json)
    when 'こんばんは'
      ws.send({
        channel: data['channel'],
        type: 'message',
        text: <<~EOS
        <@#{data['user']}>さん
        こんばんは。
        重役出勤ですね。
        EOS
      }.to_json)
    when 'さようなら'
      ws.send({
        channel: data['channel'],
        type: 'message',
        text: <<~EOS
        <@#{data['user']}>さん
        はい、さようなら。
        お疲れ様ー。
        EOS
      }.to_json)
    end
    ########################### 
    # ここまで追加 
    ###########################
  end

  # 接続が切断した時の処理
  ws.on :close do |event|
    p [:close, event.code]
    ws = nil
    EM.stop
  end
end

 

見慣れないコードが追加されました。

一部切り取って解説します。

case data['text'] 
when 'おはよう' 
  ws.send({
    channel: data['channel'], 
    type: 'message',
    text: <<~EOS 
    <@#{data['user']}>さん 
    おっはー。 
    今日も頑張ろう。 
    EOS 
  }.to_json)

ws.sendでWebSocketのつながっている先へデータを送ります。

送るデータは、

  • channel : 送信するチャンネル
    • data['channel’]にメッセージが投稿されたチャンネルが入るので、そこに送り返す
  • type : このデータはメッセージ投稿、という宣言
  • text : 投稿に表示するテキスト

という構成。

これをJSONに直して送信します。

 

<@#{data['user’]}>は、Slackでメンションをつけて投稿する記法です。

SlackのユーザIDを@の後につけるのですが、

dataにはメッセージの送信者が入ってくるので、そのまま利用します。

特定のユーザへメンションをつけてメッセージを送る場合は、ユーザ一覧を取得できるAPIを用いるてIDを確認する必要があります。

 

では、これを実行してみます。

うまいこと動いているようです。

例えば、分報とかで、疲れたときに戯れるBot

特定の言葉を投稿すると、一定のフォーマットで発言をまとめてくれるBot

もう少し複雑にして、本のタイトルを投稿すると、Amazonで検索してリンクを張ってくれるBot

などなど、考えるといくらでもできそうですね。

 

APIもかなりの数が提供されているので、この辺を絡めるとかなりのことができそうです。

API Methods | Slack

https://api.slack.com/methods

 

 

まとめ

3回に渡って、簡単にSlackを使ったアプリ・Botの作り方を見てみました。

これと、少しの発想があればいくらでも楽しく遊べそうですね。

 

今回は、ここまで。

おわり

Posted by しきゆら