2016年1月14日木曜日

【Slack】botでも作ってみるか 後編

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

前回に引き続き、ちょっと緩急話題としてSlackのbotを作成中です。

前半:Slackbot

ネットでSlackのbotを調べると最初に出てくるのはコレですね。Slackbot。

詳細は省きますが、簡単に言えば「特定の文字列をSlackに投稿すると特定文字列を返却する」というもの。

testとして作ってみたところ、書くと以下のようになりました。
「test」と書き込むと反応して特定文字列が戻ってくる。


馬鹿馬鹿しいわ!!

とは正にこのことですが、これがSlack関連のbotの半分を端的に表していると言えるでしょう。
つまり、「Slackに投稿した文字列をトリガーに特定の処理を行う」というものです。

これと外部システムを組み合わせるとそれなりの機能が実現出来ますね。

  1. Slackに秘密コマンドを投稿する。
  2. 投稿された秘密コマンド文字列を検知して自作のSlackbotが起動。
  3. Slackbotの処理にて、外部にHTTPリクエストを投げる。
  4. HTTPリクエストを以てサーバ処理のトリガーとなり、本格的な処理が開始。

こんなことが出来るわけですよ。
「本格的な処理」については、現場毎の需要にてご自由にどうぞ。

例えば、お店の売上がいつも気になる社長さんとかいるとしますよね。
そういう時に「本日の売上情報を送信しろ」というコマンドをSlackに投げると、
上記のフローで業務サーバで集計処理が走り、結果を社長さんのスマホに送るとか。

その気になれば「自爆スイッチ」とかもSlackでチョイチョイっと作れるわけですよ。
こりゃ危険だ!!

後半:WebAPI処理

上記は「Slackへの投稿をキーにSlack内で処理が起動する」というものでしたね。
これが半分。

では残り半分はと言うと、「外部システムからSlackに文字列を投入する」というものです。
今回の話はこっちがメイン。

Slackは人がログインして手で入力しなくても、WebAPI経由でシステムで投稿することが出来るのです。
ですから、常駐バッチが常にデータを集計して定期的にSlackに上げる、というやり方が出来ます。

上記の売上が気になる社長さんの例で作りますと、


  1. 業務サーバで1時間おきにバッチが起動し、その日の売上を集計する。
  2. 集計結果はSlackのWebAPIを経由してSlackに投稿する。
  3. 社長さんはSlackに投稿された報告を読む。


こっちの方が合理的ですよね。

前述の「前半:Slackbot」の利用方法もそれなりに使い方があるとは思いますが、私の業務界隈を考えると、
どちらかと言うと「後半:外部処理」みたいに一方的な定期報告の方が需要が多い気がします。

ところでこのやり方、実はSlackを使わなくてもメール送信すれば済む話ですよね。
でも、一日に何十何百もメールを受信したく無いという需要もあると思います。

つまり、

  • 定期報告は一応欲しいけど、だからってメールを大量に送り付けられても困る。
  • 常に確認必須の重要な情報じゃない。ただ、偶に観たい時に観れる程度にデータが届いていればいいんだ。

このくらいのゆる~い情報収集にSlackは便利です。

WebAPIの実現方法


では、そのWebAPIとはどういうものかをご説明しましょう。

まず、公式サイトはこちらです。


そこから辿ると「API Methods」というのがあって、それがこちら。


どうやらWebAPIベースで「チャット投稿」「履歴参照」「プロフィール変更」とか殆ど全部出来てしまうようです。

Slackスマホアプリを自分で作ろうと思っても出来るようになっている。

こうやってWebAPIを幅広く提供したのが今日のSlackの反映なのですね。

「Slackを使いたければ俺達の作った公式アプリを使え!!」ではなく、「全部公開しています。どうぞどうぞ、ご自由に」とオープンにした結果、世界中のエンジニアがこぞってSlackbotを作り、一大勢力を築き上げたわけです。
こういう開放的な姿勢は素晴らしいですね!!

さて、今回は基本中の基本である「チャット投稿」を実行します。

まず、上記「Slack Web API」のサイトから、自分用のbot用の識別トークンを取得します。
ページの下の方にあるので、軽くササッと発行して下さい。


くれぐれも漏洩させないようにご注意を。

次に、チャット投稿のメソッドである「chat.postMessage」の仕様を参考にHTTPリクエスト送信ロジックを構築。




まあ、早い話が単なるHTML送信ですから、極論を言えばJavaとかRubyとかでロジックを組まずともブラウザのURLに文字列を打ち込めば投稿完了するくらい簡単なものです。
リクエスト文字列としては以下のような例となります。


  • https://<あなたのドメイン>.slack.com/api/chat.postMessage?token=<あなたのトークン>&channel=%23general&text=Hello&username=tacybot


本当にこれだけ。これで「hello」というメッセージが#generlに届きます。
リクエストの形式は正式にはPostですが実はgetでも普通に動いちゃう。単純です。

注意点はURLEncodeすることくらいですね。
エンコードを忘れると文字化けして投稿してしまうので注意です。

以上です。

このように特にサンプルを示す必要があるような特段の技術は存在しないのですが、一応、私が作ったJavaソースを張っておきます。


/**
 * Slack送信
 *
 * @author Tacy
 */
public class RequestSlack {

 /** logger */
 private Logger logger = Logger.getLogger(RequestSlack.class.getName());

 /** BASE_URL */
 private static String BASE_URL =
   "https://tacy.slack.com/api/chat.postMessage?token=%s&channel=%s&username=tacy";

 /** トークン */
 private static String TOKEN = "tacy_token";

 /** 送信先の部屋 */
 private static String CHANNEL = "%23genera";

 /**
  * メッセージを送信する。
  * 
  * @param message 送信メッセージ
  * @throws IOException
  */
 public void sendMessage(String message) throws IOException {

  logger.fine("Slack送信:開始");

  String url = String.format(BASE_URL, TOKEN, CHANNEL);

  requestPost(url, URLEncoder.encode(String.format("text=%s", message)));

  logger.fine("Slack送信:開始");

 }

 /**
  * メッセージをPost送信する。
  * 
  * @param urlStr 送信先URL
  * @param postMessage 送信メッセージ(URLエンコード済み)
  * @throws IOException
  */
 public void requestPost(String urlStr, String postMessage) throws IOException {

  logger.fine("requestPost:開始");

  logger.info("リクエストを送信します。:" + urlStr);

  // サーバへ接続する
  HttpURLConnection connection = null;
  DataOutputStream os = null;
  BufferedReader br = null;

  try {

   URL url = new URL(urlStr);

   connection = (HttpURLConnection) url.openConnection();

   connection.setDoInput(true);
   connection.setDoOutput(true);

   // キャッシュを使用しない
   connection.setUseCaches(false);

   // HTTPストリーミングを有効にする
   connection.setChunkedStreamingMode(0);

   connection.setRequestMethod("POST");

   PrintStream ps = null;

   try {

    ps = new PrintStream(connection.getOutputStream());
    ps.print(postMessage);

   } finally {

    if (ps != null) {
     ps.close();
    }
   }

   // レスポンスを受信する
   int responseCode = connection.getResponseCode();

   if (responseCode != HttpURLConnection.HTTP_OK) {

    throw new IOException("post送信に失敗しました。responseCode=" + responseCode);

   }

  } finally {

   if (br != null) {
    br.close();
   }
   if (os != null) {
    os.flush();
    os.close();
   }
   if (connection != null) {
    connection.disconnect();
   }

   logger.fine("requestPost:終了");
  }

 }
}

支援ライブラリ:Hubot


上記は既に存在しているJavaシステムからSlackにデータを投入するソースの一部なのでJavaになっていますが、
単品で動かすbotを作るなら、もっと軽量なスクリプト言語で作った方がSlackっぽくてお洒落かもしれませんね。

その為のSlack向けBot開発用ライブラリとして有名なのはHubotでしょう。



HubotとNode.jsを使って簡単にbotをリリースしていくのも楽しいかもしれませんね。
逆に「既に違う言語でシステムが動いているんだけど……」「Androidアプリから送りたい」みたいな人は、上記のとおり単にHTTPリクエストを送るだけの話ですのでササッと作ればOK。

実に柔軟な対応が可能となっています。

終わりに


Slackはシンプルではありますが高い拡張性を持っています。
上手く使いこなせればとても会社の役に立ちそうですね。

では、本年度もブログ更新頑張ります。
今後とも宜しくお願い致します。

0 件のコメント:

コメントを投稿