Twilio Studioいらず？プラモデルの様にコールフローをつくる方法

# はじめに
Twilioは、電話をAPIで制御できる素晴らしいプラットフォームです。

とても便利なプラットフォームなのですが、
ユーザと対話させつつ外部システムと連携させたコールフローを作ろうと思ったら、
自分でサーバを用意し、Twilioが提供するヘルパーライブラリを学んでプログラムを書く必要がありました。

本記事では、プログラムを書かないでも手軽にコールフローが作れる方法を紹介します。

# コールフロー
AWSインスタンスを操作するシンプルなヘルプデスクのコールフローを作ってみます。
下図のようなコールフローです。
![qiita-twilio-callflow.png](https://qiita-image-store.s3.amazonaws.com/0/133603/3da26ccc-9823-409f-6258-fc441e47c2e4.png)


# フローを作る
フローが簡単に作れるところを見てもらいたいので、3分クッキング方式で、最初に使う部品（ノード）を全てキャンバスに置いてから、フローにしていきます。

![take4.gif](https://qiita-image-store.s3.amazonaws.com/0/133603/05f2b226-907a-620c-88f9-7043f537162b.gif)

このようにGUIで部品と部品をつないでいくだけでフローは出来上がりです。あとは部品の設定をすれば完成です。
各部品の役割は次の通りです。

|部品|名前|説明|
|:----:|:----:|:----:|
|![2017-12-06 13_58_44-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/75570c34-705a-34fd-420a-a16cc5591c57.png)|**Voice In**|Twilioから着信を受付けます|
|![2017-12-06 13_59_02-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/bd30eb50-7e36-cc67-4e30-27914e5dca43.png)|**Call**|TwilioにTwiMLを返します|
|![2017-12-06 13_59_21-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/1430ff21-99b8-5912-e6bb-ca69efc20bb0.png)|**Command**|リモートサーバにSSHログインしてコマンドを実行し、結果を返します|
|![2017-12-06 13_59_47-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/70589bf4-d97d-b477-a3a9-9a1b83b98f66.png)|**Switch**|条件分岐を作ります|
|![2017-12-06 14_04_15-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/9222cd15-ef60-d5eb-80dd-9a051d9895f3.png)|**Change**|変数を設定・加工します|
|![2017-12-06 14_00_26-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/bfd607b4-00a8-5a36-1c44-68415263f122.png)|**Link**|離れているノードを接続します|
|![2017-12-06 13_59_36-frontops-18512bPCzo57HToAD.tmp - FrontOps.png](https://qiita-image-store.s3.amazonaws.com/0/133603/55b0f60d-f447-55f2-2b1e-c5d74219fbd2.png)|**inject**|起動時処理をおこないます|

# 完成したフロー
設定が完了したフロー全体がこちらです。

![qiita-twilio-callflow-all.png](https://qiita-image-store.s3.amazonaws.com/0/133603/f6aa0d50-397e-0484-c3e5-c81ce255be44.png)

* 部品の設定内容については、後述のAppendixを見てください。


# フローを公開する
設定を終えたフローを[FrontOps](https://frontops.exhands.org/)でデプロイすると、すぐにTwilioからの着信を受けて動かすことができます。
構成は以下のようになります。

![qiita-twilio-callflow-design.png](https://qiita-image-store.s3.amazonaws.com/0/133603/13312561-b2f8-4908-8ddc-f6707fa0650a.png)

* 設定の中で、[Ngrok](https://ngrok.com/)を使ってURLを取得し、Twilioのコールバックに指定しています。
* [Ngrok](https://ngrok.com/)は、NATやファイヤーウォール下にあるローカルアプリをインターネットに公開できるサービスです。[FrontOps](https://frontops.exhands.org/)に組み込まれていて、URL取得とTwilioのコールバック設定が簡単におこなえます。

# 動作概要

1. ユーザが電話すると、Twilioがコールバック設定したURLにリクエストを投げます。
1. [FrontOps](https://frontops.exhands.org/)はリクエストを受けると、コールフローの**Voice In**ノードからフローを開始します。
1. コールフローの各ノードの間を**msg**オブジェクトが受け渡しされていきます。
1. **Call**ノードでは、生成したTwiMLをTwilioにレスポンスとして戻し、Twilioからの次のリクエストを待ちます。

# まとめ
PC一台で、簡単にコールフローを作って動かすことができました。

* プログラムを書かないでコールフローを作成することができました
* PC上で作成したコールフローを、そのままTwilioと連携させて動作させることができました

# 最後に
[FrontOps](https://frontops.exhands.org)を使ってコールフローを作ると、Twilioの電話APIを使う敷居がだいぶさがったのではないでしょうか

今回のコールフローの中で、リモートサーバにSSHログインしてコマンド実行を組み込んでいますが、このことについて、ちょっと考えてみてください。

これができるということは、・・・つまり、なんでもできるということです。

例えば今回の例では、認証番号を決め打ちにしましたが、
サーバ内のテキストファイルを`grep`してチェックしたり、
LDAPを検索してチェックしたりも自由自在です。

インフラエンジニアの方など、
コマンドライン操作は得意だけど、プログラミングが得意ではない人にとって、
電話がプログラミング不要でコマンドライン操作と連携させることができるこの例が、新しい可能性を探る参考になれば幸いです。


# Appendix: 設定説明

## 使ったもの
* Twilioアカウント、電話番号
* AWS CLIが使えるサーバ
    * SSHでログインできて、`aws configure` の設定が完了していること
    * 参考 [AWS CLI の設定](http://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-getting-started.html)
* [FrontOps](https://frontops.exhands.org)（セルフサービスを作れる一次対応ツール）

## 着信～認証
1. 名乗った後に認証番号の入力を促すTwiMLを設定します。
    * `{{{twilioVoiceUrl}}}`は自動で設定されます。
1. Twilioから送られたデータは`msg.payload`に入ります。
1. ユーザが入力した値は`msg.payload.Digits` に入ります。
1. 認証番号は**1234**としています。

![qiita-twilio-callflow-1c.png](https://qiita-image-store.s3.amazonaws.com/0/133603/dca8d30a-2347-776f-3bad-452ae7337395.png)



## メニュー
認証に成功したらメニューを案内して、選択されるのを待ちます。

![qiita-twilio-callflow-2c.png](https://qiita-image-store.s3.amazonaws.com/0/133603/70444241-ac3f-defe-621e-473451acd356.png)



## 「1」が押された場合
1. AWS CLIでインスタンス状態を取得します。
mustacheにより`{{{instanceId}}}`は`msg.instanceId`で展開されます。
`running`や`stopped`といった状態だけわかればいいので、`query`で出力を絞り込んでいます。

    ```bash:
aws ec2 describe-instances --output text --instance-ids {{{instanceId}}} \
    --query "Reservations[0].Instances[0].Status.Name"
```
コマンドの実行結果は、`msg.payload`に 

    ```json:
{
  stdout: "stopped",
  stderr: "",
  code: 0
}
``` 
という形で保存されます。

1. コマンド実行完了を報告するTwiMLを設定します。
mustacheにより`{{{payload.stdout}}}`は`msg.payload.stdout`で展開されます。
手抜きしてコマンドの出力をそのまま読み上げに使っています。

![qiita-twilio-callflow-3b.png](https://qiita-image-store.s3.amazonaws.com/0/133603/80cfa67e-62a9-5bce-dd4b-67e82273b34c.png)


## 「2」が押された場合
1. AWS CLIでインスタンスを起動します。mustacheにより`{{{instanceId}}}`は`msg.instanceId`で展開されます。

    ```bash:
aws ec2 start-instances --instance-ids {{{instanceId}}}
```

1. コマンド実行完了を報告するTwiMLを設定します。

![qiita-twilio-callflow-4b.png](https://qiita-image-store.s3.amazonaws.com/0/133603/aa713a25-9c40-d366-d19f-de4aef30d6ed.png)

## 「3」が押された場合
1. AWS CLIでインスタンスを停止させます。mustacheにより`{{{instanceId}}}`は`msg.instanceId`で展開されます。

    ```bash:
aws ec2 stop-instances --instance-ids {{{instanceId}}}
```

1. コマンド実行完了を報告するTwiMLを設定します。

![qiita-twilio-callflow-5b.png](https://qiita-image-store.s3.amazonaws.com/0/133603/f4af4f26-79e9-4c76-ebd3-63422d019512.png)


## 「その他」が押された場合
1. 終了の挨拶をして、電話を切断するTwiMLを設定します。
![qiita-twilio-callflow-6b.png](https://qiita-image-store.s3.amazonaws.com/0/133603/48f2800d-92f6-764f-cdfa-0bc7a83f15aa.png)