やったこと
slack を社内でも使いたいけどセキュリティなどの都合で使えないので、slack クローンの Rocket.Chat を最近導入しました。
irc をメインで使っていた(使っている)ので、現状でも irc 側に発言するメンバーとかがいたりします。発言が散らばるし、その時ネットワークに繋がってたら見落とすし…ってことで、irc の内容を Rocket.Chat に転送できるようにしました。
本題に入る前に…前置き
Qiita初投稿です。これまで読む専でしたが、
- アウトプットする事でスキルアップしたい!
- Rocket.Chat に関するノウハウ少ないしみんなに貢献したい!
という思いから記事を書いてます。Docker や coffeescript(javascript) に関しても初心者です。
なので、『記事の構成が クソ 良くないね』、『Dockerfile
はこう書くべき』、『coffeescript
はこう書くと良い』、『そもそも別の方法で簡単に実現できるんだけど』などなど 厳しい 温かいコメントをお待ちしています!
動作イメージ
こんな感じで動作します。
全体構成イメージ
- IRC Server は外部に存在してます。
- Rocket.Chat は公式の docker イメージを使用。
インストール手順は公式ドキュメントに従って実施してます。 - hubotは@jpshadowappsさんの公開されているdocker イメージを使わせて頂きました。勝手ながらありがとうございました!
ざっくりシーケンス
事前準備
- Rocket.Chat 管理者で bot ユーザーを作成しておいてください。
ソースコードの前に注意点
- REST API は β版 なので、ある日仕様が変更になるかもしれません。
- 例外処理とかセキュリティ的なあれとか考えられていません(初心者過ぎて)。この記事を参考にする場合は自己責任でお願いします。あるいはゴリゴリと改造してください。
(そして僕に教えてくだs
今度こそソースコード
github リポジトリ
github に Dockerfile と CoffeeScript をアップしました。
README.md
も後ほど更新します!
Dockerfile
以下の変数を自分の環境に合わせて設定して下さい。
環境変数名 | 説明 |
---|---|
HUBOT_IRC_NICK | IRC 側に表示される bot のニックネーム |
HUBOT_IRC_SERVER | 接続先 IRC サーバ |
HUBOT_IRC_ROOMS | 接続チャンネル |
http_proxy, no_proxy | プロキシ環境下で必要に応じて使用 |
FROM goldeneggg/hubot-irc
MAINTAINER 17number
# set hubot irc environment
# HUBOT_IRC_SERVER and HUBOT_IRC_ROOMS must be indicated by `docker run -e ...`
ENV HUBOT_IRC_NICK relaybot
ENV HUBOT_IRC_UNFLOOD true
ENV HUBOT_IRC_SERVER=<IRC SERVER IP ADDR>
ENV HUBOT_IRC_ROOMS="#ircroom1,#ircroom2"
# ENV http_proxy=http://proxyuser:proxypw@your.proxy.com:<proxyport>/
# ENV no_proxy="localhost,127.0.0.1,172.17.0.1"
# install pkgs
WORKDIR /root/mybot
RUN set -x && \
npm install request --save && \
npm install iconv --save && \
npm install
# HTTP Listener listen port 9980
ENV PORT 9980
EXPOSE 9980
ADD ircforward.coffee /root/mybot/scripts/ircforward.coffee
# run redis-server and hubot("-a irc")
EXPOSE 6379
RUN /etc/init.d/redis-server start
ENTRYPOINT ["bin/hubot", "-a", "irc"]
CMD ["--name", "ircbot"]
coffeescript
こちらも同様に自分の環境に合わせて設定して下さい。
変数名 | 説明 |
---|---|
dstip | Rocket.Chat が動作しているサーバ(コンテナ) |
botusername | Rocket.Chat に追加した bot ユーザー名 |
botuserpw | Rocket.Chat に追加した bot ユーザーのパスワード |
loginrooms | ircroom と rcroom をセットで設定。 ircroom : IRC 側の転送元チャンネル名 rcroom : Rocket.Chat 側の転送先チャンネル名 |
# Description:
# Forwards irc messages to Rocket.Chat.
#
# Parameters
dstip = "172.17.0.1:3000"
baseurl = "http://#{dstip}/api"
botusername = "yourbotname"
botuserpw = "yourbotpw"
loginrooms = [
{"ircroom": "#ircroom1"
"rcroom": "rocketchatroom1"},
{"ircroom": "#ircroom2"
"rcroom": "rocketchatroom2"},
"ircroom": "endofroom"
"rcroom": "endofroom"
]
request = require 'request'
module.exports = (robot) ->
robot.hear /(.*)/i, (msg) ->
# Get Token
request.post
url: "#{baseurl}/login"
form:
user: "#{botusername}"
password: "#{botuserpw}"
, (err, response, body) ->
throw err if err
if response.statusCode is not 200
msg.send "err(get token)"
exit 1
logindata = JSON.parse(body)
token = logindata.data.authToken
userid = logindata.data.userId
# Get Rooms
request
url: "#{baseurl}/publicRooms"
headers:
'X-Auth-Token': token
'X-User-Id': userid
, (err, response, body) ->
throw err if err
if response.statusCode is not 200
msg.send "err(get rooms)"
exit 1
userroom = msg.message.user.room
for roominfo, roomindex in loginrooms
if roominfo['ircroom'] is userroom
break
roomdata = JSON.parse(body)
for room, index in roomdata.rooms
if room.name is loginrooms[roomindex]["rcroom"]
roomid = room._id
break
# Join Room
request.post
url: "#{baseurl}/rooms/#{roomid}/join"
headers:
'X-Auth-Token': token
'X-User-Id': userid
, (err, response, body) ->
throw err if err
if response.statusCode is not 200
msg.send "err(join rooms)"
exit 1
# Convert Msg
Iconv = require('iconv').Iconv
jis2utf = new Iconv('ISO-2022-JP', 'UTF-8')
utf_msg = jis2utf.convert(msg.message.text).toString()
username = msg.message.user.name
userroom = msg.message.user.room
# Forward Msg
request.post
url: "#{baseurl}/rooms/#{roomid}/send"
headers:
'X-Auth-Token': token
'X-User-Id': userid
json:
msg: "#{userroom}: (#{username}) #{utf_msg}"
, (err, response, body) ->
throw err if err
if response.statusCode is not 200
msg.send "err(forward msg)"
exit 1
# Logout
request
url: "#{baseurl}/logout"
headers:
'X-Auth-Token': token
'X-User-Id': userid
, (err, response, body) ->
throw err if err
if response.statusCode is 200
else
msg.send "err(logout)"
コマンド実行例
$ git clone https://github.com/17number/irc-forward-rocketchat.git
$ cd irc-forward-rocketchat
$ vi Dockerfile
$ vi ircforward.coffee
$ docker build --tag=irc-forward-hubot .
$ docker run -t -d irc-forward-hubot
イケてない点
- エラー処理、例外処理が考慮できてない
Docker, CoffeScript, Hubot 全てにおいてにわか過ぎて… - 関数分割できてない
同上 - 設定値を外部ファイルなどにできてない
おかげさまで同じような設定をDockerfile
とCoffeeScript
の両方に入れないと… - IRC 側のチャンネル設定を変更するのに
Docker build
からしないといけない
苦労した点
- docker 使ったことない
Qiita で ROM ってた(死語?)だけで触るのは初めて。 - coffescript/javascript 知らない
- hubot もふわっとしか分かってない
- 素敵なデバッグ方法が分からない
CoffeeScript が間違ってて、コンテナ再起動後に即死にした時とか、どうやってデバッグするのですか…?後でググッてみます。 - Rocket.Chat に関する参考ページが少ない
日本語ページばっかり探してましたが、英語をまじめに勉強しろってことですかね。 - 絶対他にもあるので、思い出したら追記します!!
参考にしたページ
以下のページには大変お世話になりました!理解しきれていない点も多々ありますが、今回のものを作る際に参考にさせてもらいました。掲載順には特に意図はありません。あと分類がうまくできているかも怪しい
CoffeeScript
- CoffeeScript
- CoffeeScript 言語リファレンス - sappari wiki
- CoffeeScript基礎文法最速マスター | 株式会社インフィニットループ技術ブログ
- CoffeeScript入門(前編) ― CoffeeScriptの基本構文 - Build Insider
- CoffeeScript入門(後編) ― 関数/オブジェクト指向構文/即時関数 - Build Insider
- CoffeeScriptベストプラクティス集 Node.jsアプリケーション編(2) (1/4):CodeZine(コードジン)
- CoffeeScriptによるモダンなWebアプリケーション開発連載一覧:CodeZine(コードジン)
- CoffeeScript入門メモ - Qiita
- Node.jsで、取得したWebページをUTF-8へ自動変換する - Qiita
Hubot(と CoffeeScript)
- hubotスクリプトの書き方とサンプル集 | mitc
- Hubot + CoffeeScript ではじめるやわらかプログラミング入門 · GitHub
- #15 「人体錬成に近いものの仕方、もしくはhubotの使い方」tech.kayac.com Advent Calendar 2012 | tech.kayac.com - KAYAC engineers' blog
- hubotで快適BOT生活
- hubot-ircではmsg.replyのリプライ先が変わるので注意 | おおたの物置
- ircにhubotを登場させる - 今からお前んちこいよ
- Hubot+IRCの文字化けを解決する - GeekFactory
- 第4回 Hubotのスクリプトを書いてみる:GitHub社謹製! bot開発・実行フレームワーク「Hubot」|gihyo.jp … 技術評論社
- 第5回 実用的なHubotのスクリプトを書いてみる:GitHub社謹製! bot開発・実行フレームワーク「Hubot」|gihyo.jp … 技術評論社
Docker
- docker コマンド チートシート - Qiita
- IRC+HubotをDockerでサクッと試す - Qiita
- コンテナに入りたい?それ docker exec でできるよ - Qiita
- docker-composeを使うと複数コンテナの管理が便利に - Qiita
- fig/docker-compose事始め - Qiita
- Dockerfile の書き方「私的」なベストプラクティス - ようへいの日々精進XP
- https://hub.docker.com/r/rocketchat/rocket.chat/
- プログラマのためのDocker超入門 01.仮想化 - Qiita