Posted at

Elixir - Hedwig Responderを書く

More than 1 year has passed since last update.

この記事は リクルートライフスタイル Advent Calendar 2016 の3日目の記事です。


はじめに

ビューティ開発Tの@shotatです。

今回は「Elixir製botフレームワークのHedwigのResponder作成」について書きます。

bot作成は普通にHubot使うのが一番楽なんですが、Elixirを書きたいがためにHedwigを使っていきます。

正直Elixir力は全然高くないので、間違った箇所があればご指摘いただけると幸いです。


Hedwigについて

https://github.com/hedwig-im/hedwig

冒頭にも書きましたがElixir製のbotフレームワークです。


Hedwig is a chat bot, highly inspired by GitHub's Hubot.


と、READMEに書いてある通り、書き方は非常にHubotに似ています。

Hubotを使ったことがあり、最低限のElixirの知識があれば基本的な対話の実装はできます。

Slackで動かすまでの日本語のチュートリアル的なものは以下の記事にまとめています。

Elixir製Hubot風BotフレームワークのHedwigでSlack Botを作る - Memento memo.


Responderを作る

Responderは「pingと呟くとPONGを返す」みたいなscriptのことです。

ドキュメントを読むとResponderはbot appの lib/responders/xxxxx.ex に直接書けばいいんですが、どうせなら外部モジュールに切り出してプラグインっぽくしたいので、今回はそれをやりました。

以下のHedwigのawesomeリポジトリを参考にしました。

https://github.com/enilsen16/awesome-hedwig

先月くらいまではResponders欄に2件いた気がするんですが、現時点で再確認したら半減していました。Hedwig界のエコシステムはまだまだ黎明期と言えるので、自作のモジュールを作成するチャンスです。


作ったもの

https://github.com/shotat/hedwig_github

hoge.png

<bot_name>: github <repository_name> とreplyを送るとマッチしたGitHubのリポジトリ + スター数を送ってくれます。極稀に役に立っています。

昨今においてはコンプライアンス遵守の重要性が叫ばれているため、なんとなくモザイク処理をしておきました。


作り方

とりあえず mix new でプロジェクトを作成します。

次に mix.exs にhedwigと必要なライブラリ系をつっこみます。 tentacat はGitHubのAPI wrapperです。


mix.exs

  def application do

[applications: [
:hedwig,
:tentacat,
],
mod: {HedwigGithub, []}]
end

...

defp deps do
[
{:tentacat, "~> 0.5"},
{:hedwig, "~> 1.0.0-rc.4"}
]
end


lib/<app_name>/responders/<responder_name>.ex にResponderを実装していきます。


github.ex

defmodule HedwigGithub.Responders.Github do

use Hedwig.Responder

@usage """
hedwig: github <repository name> - Respond with GitHub url with stars count.
"""

respond ~r/github(?: +)(.+)/i, msg do
%{matches: %{1 => q}} = msg
reply msg, search_repository(q)
end

def search_repository(repository_name) do
client = Tentacat.Client.new
params = %{
q: repository_name,
per_page: 1,
}
options = [ pagination: :none ]

response = Tentacat.get "search/repositories", client, params, options
case response do
%{"incomplete_results" => false, "items" => [item | _]} ->
parse_item(item)
_ ->
"?"
end
end

defp parse_item(item) do
%{"html_url" => url, "stargazers_count" => stars} = item
"#{url} :star: #{stars}"
end
end


あまり本筋とは関係ないですが、実装当時Tentacatのsearchモジュールが怪しい挙動をしていたので直接getを呼んでいます。Tentacat使った意味の7割くらいが消えています。


Responderを使う側の実装

https://github.com/shotat/hedwig_github のREADMEに書きました。

とりあえず mix.exs で依存定義してReponderのリストに追加すれば動きます。


まとめ

結構端折ってしまいましたが、Repositoryを覗いて頂ければ同じように作成できるかと思います。

Elixir自体書き味の良い言語なので、botあたりの簡単なところから初めつつ、こっそりプロダクトコードに突っ込んでいきたいです。


おまけ: deploy周り

素のElixirだと対応してるPaaSが存在しないので、Dockerを使います。

Dockerfile の例は以下です。

FROM elixir

RUN mkdir /app
COPY . /app/
WORKDIR /app
RUN mix local.hex --force
RUN mix deps.get && mix compile

CMD ["mix", "run", "--no-halt"]

こんな感じでDockerコンテナで動くようにしておけばGAE等で簡単に運用できます。便利な世の中ですね。