enebularを使ってSkyWayの利用量を取得するSlack botを作ってみた

enebularを利用して、SkyWayのダッシュボード相当の情報が取得できるAPI（以下、SkyWay API）を叩くslack botを作りました。

# enebularで作成したフロー全体

enebularで作成した全体的なフローは以下のとおりです。

<img width="917" alt="flow.png" src="https://qiita-image-store.s3.amazonaws.com/0/6651/1867b503-2349-491d-26c1-8ef4b3da5c5a.png">


全体的な処理の流れはこんな感じです。

1. Slackで利用量を取得するAPIKEY情報をつぶやきenebularでキャッチ
2. SkyWay APIを叩くために必要な認証Tokenを取得
3. 2で取得した認証Tokenを利用して、SkyWayのアプリケーション一覧を取得
4. 3の情報から当該APIKEYのUsage（利用量）を抽出
5. 4の情報をSlackに送信

SkyWay APIの具体的な利用法は[SkyWay公式チュートリアル](
https://webrtc.ecl.ntt.com/ecl-api-tutorial.html)で確認してください。また、Enterprise Edition限定で、Community Editionでは残念ながら利用できません。

叩いてみるとこんな感じになります。正しいAPIKEYの場合は、Usageの情報を返します。ダッシュボードで閲覧できるデータと同一です。APIKEYが存在しない場合は怒られます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/6651/28cd00bf-8ead-a90e-ccb6-4c9a522a6a35.png)

* APIKEYはダミーです。

# enebularの各ノードの処理を解説

では、各ノードで何をやっているか具体的に解説してきます。

## Slack Bot In ノード

まずは、SlackでBotを作成します。詳しい作成方法は割愛しますが、お使いのワークスペースで、Custom IntegrationsからBotsを作成してください。

<img width="1061" alt="スクリーンショット 2018-12-05 20.41.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/6651/ad42d845-6043-8323-0b0f-25c695d3c617.png">

enebularではSlack Bot In ノードを追加します。設定項目は以下のとおりです。

|設定項目|値|
|:--|:--|
|Bot API Token|Slackで発行されたAPI Tokenをセット|
|Channel|SlackのChannelを限定したい場合に指定|
|Name|enebular上の表示名なので任意|

これだけでSlackからのデータを受け取ることができます。debug ノードをくっつけて動作確認してみてください。めっちゃ簡単ですね。

* 以後、Name項目は省略します

## function ノード（グローバル変数にAPIKEYをセット）

function ノードはJavaScriptによって、受信データに関する処理が書けるノードです。Slack In ノードでSlackから利用量を取得するAPIKEYの情報を入手しているので、ここで一旦グローバル変数（という言い方でいいんでしょうか）にその値をセットしておきます。これで、他のノードから自由に利用することができるようになります。コードはこんな感じです。

```js
global.set('apikey',msg.payload);
return msg;
```

msg.payloadには、Slack In ノードでSlackから受け取ったメッセージが格納されています。それをapikeyというキーでセットします。

## template ノード(POSTデータの設定)

ここからが、SkyWay APIを叩く処理となります。まずは、APIを叩くために必要な認証トークンを取得します。認証トークンを取得するためのAPIはPOSTでリクエストする必要があります。このノードではリクエストするデータを設定します。

|設定項目|値|
|:--|:--|
|設定先|msg.payload|
|形式|平文|

- テンプレート

```json
{  
  "auth": {
      "identity": {
          "methods": [
              "password"
          ],
          "password": {
              "user": {
                  "domain": {
                      "id": "default"
                  },
                  "name": "API鍵",
                  "password": "API秘密鍵"
              }
          }
       },
          "scope": {
              "project": {
                  "id": "テナントID"
              }
          }

  }
}
```

API鍵、API秘密鍵、テナントIDについては[SkyWay公式チュートリアル](
https://webrtc.ecl.ntt.com/ecl-api-tutorial.html)で確認してください。

このノードでPOSTする際のBodyが完成しました。

## http requestノード(認証Tokenの取得)

認証トークン取得のためのPOSTリクエスを行います。設定内容は以下のとおりです。

|設定項目|値|
|:--|:--|
|メソッド|POST|
|URL|https://keystone-xxx-ecl.api.ntt.com/v3/auth/tokens|
|出力形式|JSON|

URLのxxxはリージョンコードが入ります。詳しくは[SkyWay公式チュートリアル](
https://webrtc.ecl.ntt.com/ecl-api-tutorial.html)を御覧下さい。
値はJSONで返ってくるため、出力形式はJSONにします。

## functionノード(認証Tokenの取り出し)

JSONで値が返ってきたら認証Tokeを取り出します。functionノードで処理を書きます。

- コード

```javascript
var headers = msg.headers;
return msg = {
  payload: headers['x-subject-token']
};
```
実はレスポンスとして返ってきたbodyの情報は全く利用しません。`x-subject-token`というヘッダが認証Tokenとなるため、これを取り出して後から使えるように、msg.payloadに格納しておきます。

この時のポイントは`return msg={}`です。つまり、msgの内容を全クリアしてpayloadに値を設定します。これをやらないと、msg objectには今までのデータが全て残ったままになるので、後続のノードの処理でエラーが出てしまいます。例えば、以下のような、POSTリクエスのレスポンスがmsg.headersに残ったままになっています。

```json
{"date":"Fri, 07 Dec 2018 14:14:43 GMT","content-type":"application/json","content-length":"xxxxx","connection":"keep-alive","vary":"X-Auth-Token","x-openstack-request-id":"xxxxx","x-subject-token":"xxxxx","ecl-transaction-id":"xxxx","set-cookie":["xxxxx; Path=/"],"x-node-red-request-node":"xxxxx"}
```

## template ノード(X-Auth-Tokenの設定)

ではいよいよ、Usage（利用量）を取得します。SkyWay APIでは、リクエストエッダーに認証Tokenを設定してリクエストする必要があります。まずは、先程取得した認証Tokenをリクエストエッダーに設定します。

|設定項目|値|
|:--|:--|
|設定先|msg.headers.X-Auth-Token|
|形式|Mustacheテンプレート|
|テンプレート|{{payload}}|

テンプレートエンジンを利用して、前のノードでmsg.payloadに格納した認証Tokenを設定します。地味にハマるポイントは、`msg.payload`ではなく、`payload`と書かなければならないことです。

## http requestノード(アプリケーション一覧の取得)

SkyWay APIでアプリケーション一覧を取得するためのGETリクエスを行います。設定内容は以下のとおりです。

|設定項目|値|
|:--|:--|
|メソッド|GET|
|URL|https://webrtc-xxx-ecl.api.ntt.com/tenants/5170682da8d14f13b8ae4fd3ae2e9886/apps/?expandApps=true|
|出力形式|JSON|

URLの詳細については、認証Tokenのときと同じく、[SkyWay公式チュートリアル](
https://webrtc.ecl.ntt.com/ecl-api-tutorial.html)を御覧下さい。
こちらも値はJSONで返ってくるため、出力形式はJSONにします。

このリクエストでは作成済みの全てのアプリケーションの情報が取得できます。APIKEYをSlackで渡しましたが、SkyWay APIにはAPIKEYをキーに必要な情報を取得するAPIは用意されていないため、全部取得して後ほど検索します。

## function ノード(該当するAPIKEYのusageを抽出)

取得したアプリケーション一覧のJSONから該当のAPIKEYのUsageを抽出します。

- コード

```javascript
var applist = msg.payload;
msg.payload = 'そんなAPIKEYはないよ！';
applist.forEach(function(app){
    if(app.apikey == global.get('apikey')){
        var usagesArray = Object.entries(app.usage_summary);
        msg.payload = '利用状況がわかりました！\n'
        usagesArray.forEach(function(usage){
            msg.payload += usage[0] + ' ' + 'シグナリング: ' + usage[1].signaling + '回 / TURN: ' + usage[1].turn + 'GB / SFU: ' + usage[1].sfu +'GB\n'
        });
    }
})
return msg; 
```

ポイントは最初にグローバル変数に入れておいたAPIKEYの情報を比較するしている部分です。複数のアプリケーションから該当のアプリケーションを選び、その中から更にUsageを取り出します。APIKEYが存在しない場合はその旨を返します。結果はmsg.payloadに格納しておきます。

## Slack Bot Out ノード(SlackへのOutput)

取得したUsageをSlackに返します。設定はSlack Bot In ノードと全く一緒ですが、一応書いておきます。

|設定項目|値|
|:--|:--|
|Bot API Token|Slackで発行されたAPI Tokenをセット|
|Channel|SlackのChannelを限定したい場合に指定|

msg.payloadに格納されたデータをそのままSlackに送ってくれます。これで一連のフローは完結です。

## デバッグ用ノード

補足として、超初心者向けにデバッグに役立つノードをご紹介します。

- Inject ノード
    - SlackからのInputの代わりに値をパイプラインに流し込むことができます。
- Debug ノード
    - 任意の時点の出力形式をデバッグウィンドウに表示することができます。

この2つを使うことで、Slackを使うこと無く動作確認が可能です。JavaScriptのデバッグでconsole.logを仕込んで値を見るようなイメージですね。

# 最後に

これでSlack bot作成は終了です。
ちなみに、enebularもNode-REDも今回はじめて触りました。ですので、enebularを初めて触った当たり障りのない感想を書いておきます。

- ドキュメントがわかりやすい
- Slack botがめっちゃ手軽に作れて感動したｗ
- 最初herokuへのFlow Deploymentに失敗しまくって原因が分からなかったけど、次の日にはうまくいくようになった
    - ググると、わりとそういう事があるっぽい？
    - Heroku ボタンのgithubブランチがmasterじゃなかったりしたし…
- Flow Deploymentの概念が最初そもそも理解できなかった（頭悪いだけかも…
    - enebularごとデプロイされるということを理解するまでに時間がかかった
    - Webサービスを作るならherokuとかにデプロイする必要がありそうだけど、Botならあえてデプロイしなくてもいいのかなという印象…いや、まてまて本来の用途はIoT向けですよね。
- enebularのフロー編集画面はアクセスが有っても、タイムアウトで強制終了する
    - せめて何らかのアクションをするたびにタイムアウトを延長してほしい
    - 追記: [enebular-editor](https://docs.enebular.com/en/enebulareditor/)を使うと回避できます
- これは自業自得だけど、http requestのURLをコピペで入力したら先頭に半角スペースが入っていてハマった
- Publish Flowしようと思ったけど、秘密鍵等の情報を削除するのが面倒で今回はやめておいた。そういう事がシステムに的にできるようになると嬉しい（ひょっとしてフローにべた書きしちゃだめなんだろうか…）
- 次回はなにかノードを自作してみたい

以上です。