SlackクローンのMattermostのWindows版を動かす

# はじめに
SlackのBotを作成して業務を改善する記事をみて、会社で試してみようと思ったのですがセキュリティ的にSlackを導入するわけにもいかず、そんな中でSlackクローンのMattermostがBotにも対応していることを知りました。
しかし、MattermostサーバーはLinuxとDockerしかなく、会社で使えるのはWindows Server 2008R2しかありません。

下記サイトで[公式な非公式](https://docs.mattermost.com/install/prod-windows-2012.html)でWindows版が存在することを知り、インストールしてみました。
[チャットシステムはMattermostに落ち着いた](https://patchrocket.blogspot.jp/2017/02/mattermost.html)

## 環境
Mattermost(公式な非公式)側で動作を確認しているのはWindows 10 Pro 64bitとWindows Server 2012 Standardですが、会社ではWindows Server 2008R2、自宅ではWindows 10 Home 64bitで動作確認しました。

### 会社

  * Windows Server 2008R2
  * Apache Ver 2.4.20
  * PHP Ver 7.1
  * MySQL Ver 5.7.12
  * Mattermost Ver 3.6.2

[簡易グループウェア スケジュールWeb「LiteScl.oda」の導入](http://qiita.com/yaju/items/cf68c6c58e3eefd49fcd)と同環境

### 自宅

  * Windows 10 Home 64bit
  * XAMPP for Windows 7.1.1([XAMPPのダウンロード](https://www.apachefriends.org/download.html))
  *  Mattermost Ver 3.6.2

# 導入方法
導入については、Windows 10 Home 64bitでの説明をしていきます。Windows Server 2008R2ではXAMPPを使わないが基本的な考え方は同じとなります。

【追記 2017/12/02】
Windows 10 Homeは、Fall Creators Updateで、WSL(Windows Subsystem for Linux)が使えるようになったのでLinux版でもいいし、Windows 10 Proの方はDockerが使えるのでそっちのほうが導入が楽そうです。
[WSL(Bash on Windows)でDockerを使用する](https://qiita.com/yoichiwo7/items/0b2aaa3a8c26ce8e87fe)
[slackクローンのmattermostをdockerで立てて使うメモ](https://qiita.com/suzukihi724/items/4d38c720ba2b62c668bc)

## Mattermostのインストール
2017/04/16時点の最新Windows向けビルドは以下から取得。バージョンは3.6.2となります。
[https://releases.mattermost.com/X.X.X/mattermost-team-X.X.X-windows-amd64.zip](https://releases.mattermost.com/3.6.2/mattermost-team-3.6.2-windows-amd64.zip)
ダウンロードが終わったら解凍して任意の場所へ配置。今回は「C:\mattermost」としました。

最新版バージョンの確認は下記記事を参考にするといいでしょう。
[windowsにMattermost on Bitnamiをしてみる](http://hajimeruse.wp-x.jp/mattermost/install-mattermost-on-bitnami/)

## Apacheのhttpd.conf の編集
IISでポート「80」を使用しているため、XAMPPコントロールパネルのApacheの「config」ボタンでhttpd.confファイルが開くのでポートを「1080」に2ヶ所変更します。

```bash:httpd.conf
#Listen 80
Listen 1080

#ServerName localhost:80
ServerName localhost:1080
```
ApacheとMySQLのActionsの「Start」ボタンをクリックします。正常に開始されると「Stop」ボタンに名称が切り替わります。
![xampp_conrolpanel.png](https://qiita-image-store.s3.amazonaws.com/0/14053/1583567d-887e-b404-66f0-5382852e58ab.png)

## MySQLにデータベースを作成
MySQLの「Admin」ボタンをクリックしてphpMyAdminにアクセスさせますが、ポート「80」から「1080」に変更しているためエラーとなります。URLにポート番号「:1080」を付けて再度アクセスしてください。「 http://localhost:1080/phpmyadmin/ 」

左ペインのNewから「mattermost」を作成します。
![xampp_phpMyAdmin.png](https://qiita-image-store.s3.amazonaws.com/0/14053/cbee9c2e-12f2-9f8d-0e68-da083ab3c32b.png)

## Mattermostの設定変更
C:\mattermost\config\config.json ファイルをエディタで開きます。
「SqlSettings」の中の「DataSource」を「SQLユーザ名:パスワード@tcp(接続先サーバ:3306)/データベース名?charset=utf8mb4,utf8」とします。
「LocalizationSettings」の中の「DefaultServerLocale」「DefaultClientLocale」を日本語にするため、「en」から「ja」に書き換えます。

```bash:config.json
    "SqlSettings": {
        "DataSource": "root:@tcp(localhost:3306)/mattermost?charset=utf8mb4,utf8",

    "LocalizationSettings": {
        "DefaultServerLocale": "ja",
        "DefaultClientLocale": "ja",
```
## Mattermostの実行

1. 「コマンドプロンプト」を開きます。
2. 「cd C:\mattermost\bin\」でカレントディレクトリを変更します。
3. 「platform.exe」を入力してEnterキーを押します。

![platform.png](https://qiita-image-store.s3.amazonaws.com/0/14053/758febed-48ce-a514-b2b0-68468db8e190.png)

ちなみにコンテンツ配信サーバーもMattermost側が持っているため、Apacheはデータベース作成後は不要となります。
しかし、今回はBotをローカル上のPHPで作成するのでApacheはそのまま使用します。

サーバが起動したら「 http://localhost:8065 」にアクセスします。　
![mattermost_start.png](https://qiita-image-store.s3.amazonaws.com/0/14053/abca1b26-932c-8f2b-5402-ef06d2686ebd.png)

### Windowsサービス化
現状ではコマンドプロンプト画面が表示されたままなので、Windowsサービス化に変換する方法があります。
[Windowsアプリをサービス化してサインイン前に起動！](http://ascii.jp/elem/000/000/933/933079/index-2.html)

NSSM (Non-Sucking Service Manager)の最新版を[ダウンロード](https://nssm.cc/download)します。
あとは下記サイトを参考にしてください。
[Establish a Windows Service](https://docs.mattermost.com/install/prod-windows-2012.html)
[Mattermostをバックグラウンド（windows サービス）で実行する](http://hajimeruse.wp-x.jp/mattermost/mattermost-windows-service/)
 
## Mattermostの初期設定
アカウントやチームを作成します。下記サイトを参照してください。
今回チーム名は「shizudev」で作成しています。
[SlackクローンのMattermostを使ってみる - 導入、初期設定編-](http://qiita.com/terukizm/items/4a4016d8ec5a21856e4f)

# Mattermostの使い方
[Mattermostの使い方(基本編)](http://qiita.com/maruTA-bis5/items/297db90f85d8ff94a119)

# 外部システムとの連携
Mattermostには「統合機能(Integrations)」と呼ばれる機能があり、外部システムとの連携を行うことができます。
![mattermost_integrations.png](https://qiita-image-store.s3.amazonaws.com/0/14053/51e3c59f-c4d3-a720-3b57-32ed7b87385e.png)


## 事前準備
「システムコンソール」をクリックします。
![mattermost_systemconsole.png](https://qiita-image-store.s3.amazonaws.com/0/14053/dc598d34-7c96-436a-1557-cde1798f950f.png)


システムコンソールの統合機能「カスタム統合機能」の設定にて「統合機能によるユーザー名の上書きを許可する」と「統合機能によるプロフィール画像アイコンの上書きを許可する」を「有効」にします。
![mattermost_custom.png](https://qiita-image-store.s3.amazonaws.com/0/14053/ce974b83-95de-b633-37ee-c1ca06a8aa22.png)


## 内向きのウェブブック(Incoming WebHooks)
他システムからMattermostに通知するために使います。
「内向きのウェブブックを追加する」をクリックして内向きのウェブブックを作成します。
![mattermost_incoming.png](https://qiita-image-store.s3.amazonaws.com/0/14053/5aef01d0-ac88-51ac-d155-b45ed952349a.png)


セットアップが成功するとURLが提示されます。
![mattermost_incoming2.png](https://qiita-image-store.s3.amazonaws.com/0/14053/5b4951b7-54b4-34b5-b811-4801385c7047.png)

### 動作確認
curlコマンドで動作確認できます。
気を付けるのは、コマンドプロンプトでは2重引用符はエスケープが必要です。
また、Shift-JISなので文字化けしてエラー内容が不明です。
「螟夜Κ縺九ｉ縺ｮ繝・・繧ｿ繧定ｧ｣譫舌〒縺阪∪縺帙ｓ」→「外部からのデータを解析できません」を意味します。
UTF-8を使いたいなら「Git Bash」を使うといいでしょう。

```bat:curl
C:\Tool>curl -i -X POST -d "payload={\"text\": \"Hello\"}" http://localhost:8065/hooks/wowkfcb3btbn8q3dide81sru6r
HTTP/1.1 200 OK
Content-Type: text/plain
X-Request-Id: 8r18qwapqjbr581pk4wexsyq8h
X-Version-Id: 3.6.0.3.6.2.451e3d2a5f97ab986196a2ab3559e7d6
Date: Sun, 16 Apr 2017 13:59:53 GMT
Content-Length: 2

ok
```
日本語メッセージを送信するとShift-JISのため文字化けするので、「nkf」を使ってUTF-8に変換させます。
[nkfツールで文字コードを変換する（Windows編）](http://www.atmarkit.co.jp/ait/articles/1301/25/news092.html)

```bat
C:\Tool>echo {"text":"こんにちは"}| nkf -w | curl -i -X POST --data-urlencode payload@- http://localhost:8065/hooks/wowkfcb3btbn8q3dide81sru6r
HTTP/1.1 200 OK
Content-Type: text/plain
X-Request-Id: jie8wjy91b8ymxai5ketn8uhmr
X-Version-Id: 3.6.0.3.6.2.451e3d2a5f97ab986196a2ab3559e7d6
Date: Sun, 16 Apr 2017 16:07:56 GMT
Content-Length: 2

ok
```
### 動作確認
最初はnkfを使わなかったため文字化けしましたが、nkfで変換することで文字化けを解消できました。
![mattermost_incoming3.png](https://qiita-image-store.s3.amazonaws.com/0/14053/c17502b1-fae0-3a79-1815-fc791e740c09.png)

## 外向きのウェブブック(Outgoing Webhooks)
Mattermostから他システムを呼び出して、その結果をもらいます。
「外向きのウェブブックを追加する」をクリックして外向きのウェブブックを作成します。
下記サイトを参考にしました。
[超簡単！MattermostにBOTを追加する - ビビビッ](http://vivibit.net/mattermost_bot/)

トリガーコマンドは「echo」でパラメーターのワードをそのまま返すBOTとなります。
![mattermost_outgoing.png](https://qiita-image-store.s3.amazonaws.com/0/14053/04551e0d-6dcf-b1d0-5aa8-d04af377cd4e.png)

セットアップが成功するとトークンが提示されます。
![mattermost_outgoing2.png](https://qiita-image-store.s3.amazonaws.com/0/14053/18400b31-1d6f-a63f-2306-b095a28d7fcc.png)


下記スクリプトを「C:\xampp\htdocs\bot\echo.php」に作成しました。
(参考元と違い、トークンチェックやアイコン指定は省略しています。)

```php:echo.php
<?php
header("Content-Type: application/json; charset=utf-8");

$text   = $_POST['text'];
$query  = preg_split('/[\s\x{3000}]/u',$text,2);
$q  = $query[1];
$name   = 'echo';

echo json_encode(array("username" => $name, "text" => $q));
```

### 動作確認
「echo 動く」を入力して、BOTが「動く」を返してくれました。

![mattermost_outgoing3.png](https://qiita-image-store.s3.amazonaws.com/0/14053/151121e5-3be6-7a5a-c3af-e0e882f46314.png)

## スラッシュコマンド(Slash Command)
Mattermostから拡張コマンドとして外部APIを呼び出して、その結果をもらいます。
「スラッシュコマンドを追加する」をクリックしてスラッシュコマンドを作成します。

今回は時刻を返すスラッシュコマンド「/now」にしました。
![mattermost_slash.png](https://qiita-image-store.s3.amazonaws.com/0/14053/aa604adf-63a8-e2d3-8b7b-889c54ae109e.png)

セットアップが成功するとトークンが提示されます。
![mattermost_slash2.png](https://qiita-image-store.s3.amazonaws.com/0/14053/096c92d3-8d81-0dc2-bb42-5b86ceb8f908.png)

C:\xampp\htdocs\bot\now.php に作成しました。

``` php:now.php
<?php
date_default_timezone_set('Asia/Tokyo');
$tm = date("H:i:s");

header('Content-type: application/json');
$payload = json_encode(array('response_type' => 'in_channel', 'text' => $tm));
echo $payload;
```

### 動作確認
スラッシュコマンド「/now」を入力します。
※スラッシュコマンドを作成時に「自動補完」にチェックを入れておくと「/now」が自動補完リストに表示されます。

BOTが時刻を返してくれました。
![mattermost_slash3.png](https://qiita-image-store.s3.amazonaws.com/0/14053/e3a17bdf-1fb7-d47f-dcc6-51c6190f81e2.png)

## 嵌ったこと
外向きのウェブブックとスラッシュコマンド用のBOTを作成したものの、エラー「execute_command.failed_empty」などが出るなりして動作しませんでした。
プログラム内容は問題ないのでWindows版が悪いのかと思い、TensorFlow用のDocker環境があったのでDocker版を入れてみたのですが、結果は同じでした。
それではと本場のSlackに自分だけのチームを作成して外向きのウェブブックとスラッシュコマンドを動かしたところ、外向きのウェブブックは正常に動作し、スラッシュコマンドはJSONの値がそのまま表示されました。
JSONの値がそのまま表示されるってことは、一体どういうことなんだろうと。普段やらないことをやったことと言えば、UTF-8なのでBOMを付けたことくらいです。
そこで「PHP BOM」で検索してみたところ、「[PHPのechoにBOMが混入するのを防ぐ](http://blog.xin9le.net/entry/2015/02/05/230332)」の記事に気になることが書かれていました。
>結論から言うと、実行コードが書いてある .php ファイルが BOM 付きの UTF-8 で保存されている場合、echo した結果に BOM が乗ります。どうしてこんな動きをするのかはサッパリですが、実際そうなります。なので BOM が付かない形式の UTF-8 で .php ファイルを保存すれば解決します。

また、「[PHP スクリプトは BOM 付き UTF-8 で書いてはいけない](http://web.archive.org/web/20140410014600/http://www.revulo.com:80/blog/20090129.html)」にはPHPならではとのこと。
>他の言語なら、こういう変な現象は起きないのでしょうけれど、 PHP は HTML 内に埋め込むスクリプト言語、という側面があるので、これは仕方ないんでしょうね。

BOMなしで保存し直したところ、外向きのウェブブックとスラッシュコマンド用のBOTが正常に動作するようになりました。

# さいごに
セキュリティ面で外部インターネットに繋げるSlackを使うことには抵抗があるけど、Slackのようなことはしてみたいといった場合に「Mattermost」はとてもいいクローンです。
公式にはサポートはしていないとはいえ、Windows版を使えるのでWindows Serverしか環境が無いところで導入してみるといいでしょう。