Slack/Mattermost(以降、まとめてSlack)のbotといえばHubotが有名だ。
Hubotはcoffeescriptで書かれているのだが、botのためだけに新しい言語を覚えるのも面倒。
加えてHubotを動作させるにはnpmが必要。
ちょっとそこまでは…。
Pythonなら普段使いで最初から環境は作ってあるし、楽だし。
そう思っていろいろと調べてみた。
Slackのbotに必要なことは?
Slackのbotに必要なのは、端的に以下の二つ。
1. Slackからのデータ送信を受ける。
2. Slackへ何かをする。
1.は、HTTP POSTでやってくるので、POSTを受けることさえできればよい。
2.は、例えばSlack上で何かの発言をすることだが、こちらはcurl(Pythonならrequests)でも使えば簡単にできる。
PythonでHTTP POSTを受けるには?
Flask である。
Flaskとはごくごく軽量なwebフレームワークである。
驚くくらい簡単にwebサーバを作ることができる。
もちろんPOSTを受けるのもすぐにできる。
以下、説明。
Flaskのインストール
pipでもなんでも、好きなものを使ってインストールせい。
Flaskのテスト
以下のようなスクリプトを書く。
適当な名前で保存する。
flask.pyとかはやめようね。
#!/usr/local/bin/python
from flask import Flask
app = Flask ( __name__ )
@ app . route ( '/' )
def welcome ( ) :
html = '<html><title>welcome</title>'
html = html + '<body>welcome</body></html>'
return html
if __name__ == '__main__' :
app . debug = True
app . run ( host = '0.0.0.0' )
上記のapp.route(‘/’)とは、ルーティング。
ルートディレクトリ(’/’)へのアクセスがあったら、次のdef welcome()が(デコレートによって)呼ばれる、ということである。
上記の場合、welcomeと表示するhtmlが返る。
app.debug = Trueについては後述。
app.run(host=’0.0.0.0)のhost=…の記述により、サーバを外部に公開することになる。
テストスクリプトの実行
$ python . / flasktest . py
* Running on http : //0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active !
* Debugger pin code : 213 - 546 - 048
localhostのポート5000でサーバが立ち上がったと分かる。
ブラウザでアクセスして「welcome」と表示されればよい。
ところで、app.debut = Trueだが、スクリプトを書き換えると、自動的に再読み込みをしてくれる。
実際のログは以下。
* Detected change in '/usr/home/doe/py/flasktest.py' , reloading
* Restarting with stat
* Debugger is active !
激烈に便利な機能なので、開発中は有効にしておくこと。
SlackからのPOSTを受ける。
先ほどのスクリプト冒頭のimportを以下のように変更。
from flask import Flask , request
さらに以下を追加。
@ app . route ( '/matter' , methods = [ 'POST' ] )
def post ( ) :
print request . form
上記のようにしておいて、Slack側のOutgoing Webhookで、呼び出すURLに「http://<あなたのサーバのアドレス>:5000/matter」を指定する。
Slack側からwebhookを呼び出してみると、POSTされた内容がログに表示されるはず。
なお、def post()が何も返さないのでエラーは出るが気にしない。
以下が例。
ImmutableMultiDict ( [ ( 'user_id' , u 'xxxxx' ) , ( 'channel_id' , u 'xxxxx' ) , ( 'timestamp' , u '1414562326' ) , ( 'team_id' , u 'xxxx' ) , ( 'trigger_word' , u 'test' ) , ( 'channel_name' , u 'off-topic' ) , ( 'token' , u 'xxxtokenxxx' ) , ( 'text' , u 'test' ) , ( 'team_domain' , u 'xxxx' ) , ( 'user_name' , u 'xxxx' ) ] )
つまりPOSTの内容はディクショナリになっている。
Slackへ応答を返そう
Slackへ応答を返す場合には、POSTでもらった中にあるtokenが必要である。
応答文、tokenのディクショナリを作っておいて、それをjsonに変換し、返してやればよい。
Mattermostの場合、tokenのキーは’MATTERMOST_TOKEN’
先ほどのスクリプトを最終的に以下のようにする。
(わざわざjsonをimportしているが、Flaskにもそういう機能がある気がしてならない)
これでSlackから通知を受けると、「You said <トリガーワード>」という応答がSlackへ帰る。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/local/bin/python
from flask import Flask , request
import requests
import json
app = Flask ( __name__ )
@ app . route ( '/' )
def welcome ( ) :
html = '<html><title>welcome</title>'
html = html + '<body>welcome</body></html>'
return html
@ app . route ( '/matter' , methods = [ 'POST' ] )
def post ( ) :
postdic = request . form
incomeText = postdic [ 'text' ]
token = postdic [ 'token' ]
text = 'You said ' + incomeText
payload = {
'text' : text ,
'MATTERMOST_TOKEN' : token }
json_payload = json . dumps ( payload )
return json_payload
if __name__ == '__main__' :
app . debug = True
app . run ( host = '0.0.0.0' )
あとはどんどん膨らませていけばよい。
【補遺】slackのoutgoing webhooks
slackでのwebhooks設定方法を示す。
webでいうと、左下のAppsからBrowse Appsを選び、outgoins WebHooksを探す
Add Configurationで設定へ。
webhooksを投げる条件を設定する。以下の3つ。
指定のチャンネルで発言したら
特定のトリガーワードを発言したら
特定のチャンネルで特定のトリガーワードを発言したら
1.はChannelで、2.はTrigger Word(s)で指定する。
3の場合には1.2.の両方を指定する。
上記条件に合致したらwebhooksを投げるURLを「URL(s)」で指定。
そのときのTokenは記載の通り。
webhooksで飛んでくるデータは以下の通り。json「ではない」ことに注意。
token=qFosSxxxxxxxxERh1Jfdy5
team_id=T0009
team_domain=example
channel_id=C0000000000
channel_name=test
timestamp=1355517523.000005
user_id=U0000000000
user_name=Steve
text=googlebot: What is the air-speed velocity of an unladen swallow?
trigger_word=googlebot: