SlackとIRCを相互リレーする話

この記事は [Slack Advent Calendar 2014 - Qiita](http://qiita.com/advent-calendar/2014/slack/) の 13日目の記事です。

皆さん、Slack使ってますか？ 非エンジニアにも使いやすくて、ログの検索やファイルのアップロードもできてbotとの親和性の高いSlack、最高にイケてるサービスだと思います。

ただ、このSlackを導入していくにあたって、自分が務めている会社では一つ障壁がありました。それは、

**エンジニアの圧倒的なIRC文化**

です。エンジニアはどんな仕事をするにあたってもとにかくIRC。みんなZNCを立てていたり、IRC上のチャットオペレーションでリリースフローやデプロイをしてくれるボットまでいたりするという現状。

この状況が、IRCからSlackへの移行を難しくしていました。また、Slackの便利さに釣られてSlack移行してしまった人が現れたせいで、今度はIRCサイドとSlackサイドに別れてコミュニケーションの断絶が発生してしまったり、非常にゆゆしき状態になっていました。

そのためその状況を打開すべきツールを作りました。それが、

[ircslackrelay](https://github.com/sifue/ircslackrelay) 

です。

現在、社内の30以上のチャンネルがSlackとIRCで相互リレーされています。ライセンスは、MITライセンスにて公開中で、Scalaで書かれており、Java 7以上が動くマシンであればどのようなプラットフォームでもビルドして動かすことができます。


## ircslackrelayについて

基本的な機能としては、

- IRCの発言をircslackrelayというボットがAPI経由でSlackに発言
- Slackの発言をIRCアダプタ経由で取得してIRCに発言

という機能を提供しています。webhookの機能を利用していないので、無料でSlackを運用されているというチームでも問題なく利用することができます。すでにひと月以上再起動無しで稼働することを確認しています。


## それぞれの見え方

![スクリーンショット 2014-12-12 22.07.47.png](https://qiita-image-store.s3.amazonaws.com/0/2382/0bda89c3-5647-959d-0fad-ec77103dec1c.png)

このような感じになります。

## アーキテクチャ

![スクリーンショット 2014-12-12 22.54.11.png](https://qiita-image-store.s3.amazonaws.com/0/2382/7ac3f6c2-62cb-7c37-713b-3489b1473046.png)

以上の図のように社内にプライベートなIRCがあり、社内の適当なサーバーにてこのircslackrelayを置くことによって相互リレーをすることを想定しています。


## 行った工夫
1. SlackのIRCアダプタは1週間に1回ぐらい切断するためリトライ再接続機構を用意した
2. IRC側のnicknameをSlack側の絵文字形式(小文字化してコロンで囲む)にすることで顔サムネとして絵文字登録可能にした
3. IRC上では呼び出しにハイライトしないように最初のnicknameの文字の後にゼロサイズスペースを挿入した
4. Slack側にないIRCのnoticeの表現をアンダースコアで囲む斜体の表現として相互翻訳した

以上のような工夫をすることで、相互にリレーしても違和感のなく、IRCとSlackのそれぞれの文化を融合させています。

## つらいこと
基本このサービスの運用には誰かのslackのアカウントが必要です。またそのアカウントから作成されるIRCアダプターのパスワードとAPIのトークンも利用するため、その個人のアカウントの制約を受けることになります。

具体的に言うとAPIに1秒1投制限があるため、1人のアカウントで流量の大きな沢山のチャンネルをリレーすることはできません。そのため1秒1投を超えているかどうかは内部的にセマフォで制御しており、バッファリングして必ず1秒1投のペースでAPIを叩くようになっています。

なおこの問題はSlackを有料でつかったからといって解消されません。


## 利用しているライブラリ
- sirc
- akka-acotor
- dispatch

以上のライブラリを利用させてもらいました。このおかげでとても簡単に書くことができました。

## 使い方

[ircslackrelay/README.md](https://github.com/sifue/ircslackrelay/blob/master/README.md)

に英語訳がありますが、日本語で説明させてもらいます。

### Java 7以上をインストール
[Oracle JDK](http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html)
ここから自分のプラットフォームにあったJDKをダウンロードしてインストールしてください。Java 8 でも問題なく動きます。

### SBTをインストール
[sbt](http://www.scala-sbt.org/)、このdownloadのページから、バイナリをインストールするなり、brewやportでインストールするなりして、インストール手順にそってsbtをインストールをします。

### ビルド
```
git clone git@github.com:sifue/ircslackrelay.git
cd ircslackrelay
sbt assembly
```
以上を実行して待つと、

```
target/scala-2.11/ircslackrelay-assembly-X.X.X.jar
```
というファイルがビルドされますので適当な場所に移動してください。

### 設定ファイル
ircslackrelay_template.confをコピーして、ircslackrelay.confをircslackrelay-assembly-X.X.X.jarと同じフォルダに置きます。
そして内容を編集して、

```
irc.address="irchostname.com"
irc.nickname="ircslackrelay"
irc.username="ircslackrelay"
irc.password=""
irc.port=6667
irc.use_ssl=false
irc.charset="UTF-8"
slack.irc.address="hostname.irc.slack.com"
slack.irc.nickname="fuga"
slack.irc.username="fuga"
slack.irc.password="hege.k314df9aKefaj"
slack.irc.port=6667
slack.irc.use_ssl=true
slack.irc.charset="UTF-8"
slack.api.username="ircslackrelay"
slack.api.token="aaaaa-999999999-99999999-9999999-99999999"
slack.api.icon_url="https://pbs.twimg.com/profile_images/2193228277/scalachan.jpg"
relays = [
  {
    irc_channel: "#irc_channel_1"
    slack_channel: "#slack_channel_1"
  },
  {
    irc_channel: "#irc_channel_2"
    slack_channel: "#slack_channel_2"
  },
  {
    irc_channel: "#irc_channel_3"
    slack_channel: "#slack_channel_3"
  }
]
```

以上の内容を入力します。IRCのアダプタの設定用の情報は、[gateways](https://my.slack.com/account/gateways)より、API tokenの情報は、[slack api](https://api.slack.com/)より取得できます。

なお、irc.nicknameはIRC上の名前なので、| などの短い名前にすると表示上スッキリします。またirc.usernameはbotを動かしている人のnicknameを入れておくとよいでしょう。
またslack.api.icon_urlはデフォルトではスカラちゃんになっているので、好きなキャラクターのアイコンに、slack.api.usernameもそのキャラクターの名前にしておくとより良いと思います。

なおuse_sslと書いていますが、内部的にはtlsを利用しています。

### 起動方法
```
java -jar -server ircslackrelay-assembly-X.X.X.jar
```
を実行することでircslackrelayを動かすことができます。なお、デーモン化する方法はもってないので、screenやtmuxやnohopコマンドで動かすか、windowsならばサービスに起動するbatchを登録することで対応してください。

## 便利な機能

### herokuで動かす
[iwag](https://github.com/iwag) さんが作ってくださいました。

```
heroku create # git remote add heroku dokku@dokku.me:myrelay 
cp ircslackrelay_template.conf ircslackrelay.conf
vi ircslackrelay.conf
git add -f ircslackrelay.conf
git commit -m "ircslackrelay.conf"
git push heroku master
```

で行けるようです。(自分は試していません…)

### システムコマンドを利用する
- noname コマンド

"noname> "の後に何かしらの発言をすると、その発言者のnameを省いて登録してくれます。これによって、何かしらの文字列で始まるコマンドで、IRCやSlack上でbotを運用している時にそれを動かすことができます。

弊社ではiPhoneのSlackクライアントからIRCのbotにコマンドを送ってデプロイなどをすることもできます。

- ping コマンド

"ircslackrelayping>"と入力することで、

```
pong, booted by boot_user_name
```

のように起動しているOS上のユーザーの名前を表示してくれます。誰が立てたircslackrelayなのかすぐ調べたい時に便利です。


# 最後に

やはりIRCとSlackでシステムが違いすぎて困るという部分もあります。例えば@channelとかとカジュアルに書くと、チャンネルの全員にメールが飛ぶなどの問題です。その辺のトラブルが起きる度に何かしらの対策を考えなくてはいけません。特にIRCのbotが気づかないうちにSlack側に大きな影響をあたえることもあり、それらについては見つかる度に対策を考えてはいけないなと思っています。

また深刻なのは、Slackに本移行した際に、Slackが1週間に一度ぐらい障害で繋がらなくなるという問題がおきたりすることです。そういった場合にこのIRCとの共運用は、Slackが落ちていてもIRCで仕事の話を進めることができるため非常に便利な回避策となります。

このようなことがあるので個人的には、Slackは便利だけれどもIRCとの共存やSlackのインターフェースとしてのIRCの活用はまだまだ活躍の余地はあるなと思っています。

なお、

[sifue/ircslackrelay](https://github.com/sifue/ircslackrelay) 

では皆様の温かいプルリクエストをお待ちしております。

長くなりましたが、最後までお読みいただきありがとうございました。