プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Twilio 電話を受けたら録音して、メールを飛ばす

以前、こちらの記事で、 Twilio を使って受付用留守番電話を作るというのを試しました。 せっかく受付用留守電を作っても、このままだといちいち Twilio のコンソールを見ないとわからないので現実的ではないです。

ということで、こちらの記事で試したFAX受信時のメール送信と同様に、留守電に録音されたらメールを飛ばすようにしたいと思います。

留守番電話が録音されたら、メールを飛ばす

基本的な考え方は、FAXを受信したらメールを飛ばすのと同じです。

メール送信用 Function の作成

まずは、留守電があったら呼び出される Functions を作成しておきます。 内容的には、FAX送信時と大して変わりませんが、メールの添付ファイルとして指定するのが、FAXの文面ではなく、録音した音声データになります。

サンプルコードは、こちらのGist, 下記修正前のリビジョン を参照してください。

メール送信用 Function の呼び出し設定

Functions を作成したら、次は、メール送信 Function の呼び出し設定を行います。

これは、TwiML の Record 動詞recordingStatusCallback 属性を使えば、録音が利用可能となったタイミングで指定されたURLを呼び出すことで実現できます。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say language="ja-JP">録音します。録音が終了したらシャープを押してください。</Say>
  <Record action="https://handler.twilio.com/twiml/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 
          recordingStatusCallback="https://xxxxxxxxxxxxxxxxxx.twil.io/function名" />
</Response>

こうすることで、録音が終わり、そのデータが利用可能になった時点で、recordingStatusCallback で指定されたURLが呼び出されます。 なお、以前の記事と同様に、actionで指定されたURLは録音後間違いなく電話が切れるように、hugup動詞のみのTwiMLを指定します。

テスト

さあ、試しましょう。 電話をかけて、適当に録音して、メールが来ているか確認します。

メールを確認すると、

f:id:junichim:20190221145307p:plain

問題なく受信できてました。と思いきや、電話をかけてきた相手の電話番号が表示されていません。

あれ?どうなっているんや?

ということで、リファレンスを調べてみると、どうも recordingStatusCallback で送る時は、発信元の電話番号とかの情報は送られていないようです。

これってどうしたらいいんだろうか?としばし考えたのですが、よくわからなかったので、Twilio のサポートに聞いてみると、CallSid を使って通話の情報を取得してください、とのことでした。 ま、考えてみりゃそういうことか。

発信元電話番号の取得

ということで、メール送信前に、発信元電話番号を取得して、それをメールのタイトルに入れるようにします。

まず、Function が呼ばれた時に、どういう情報が送られているのかを確認します。

debug:context: {
     "ACCOUNT_SID":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"DOMAIN_NAME":"yyyyyyyy-yyyyyyyy-yyyyyyyyy.twil.io"
}
debug:event: {
     "RecordingSource":"RecordVerb"
    ,"RecordingSid":"RExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingUrl":"https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxxxxxxxxx/Recordings/RExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingStatus":"completed"
    ,"RecordingChannels":"1"
    ,"ErrorCode":"0"
    ,"CallSid":"CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingStartTime":"Sat, 16 Feb 2019 07:42:24 +0000"
    ,"AccountSid":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"RecordingDuration":"3"
}

(頭の debug:event 等はconsole.logに埋め込んだ文字です) 引数の event の中身を確認すろと、先ほど見た、 recordingStatusCallback のリファレンスの通りになっています。 そこで、この CallSid が通話を識別するSidなので、これを使って Call Resource を取得して、表示させれば良さそうです。

具体的には、Fetch a Call Resource APIを呼びます。

このAPIのリファレンスのサンプル(例えば、node.js)を見るとわかるように、このAPIを呼ぶためには、Twilio client が必要なのですが、Twilio client を生成するには AUTH_TOKEN が必要です。 なお、先ほど Function が呼ばれた際のパラメータを見てもわかるように AUTH_TOKEN は返してくれません。

そこで、 Function の引数にAUTH_TOKEN を渡すようにするために、Functions の設定を変更して、 AUTH_TOKEN を渡すようにします。

f:id:junichim:20190221150452p:plain

設定変更後、渡されたパラメータを確認すると、

debug:context:{
     "AUTH_TOKEN":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"ACCOUNT_SID":"ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ,"DOMAIN_NAME":"xxxxxxxxxxxxxxxxxxxxx"
}

のように AUTH_TOKENが渡ってきているのが確認できました。

ただし、この設定は、そのアカウント(上記の場合はサブアカウント)で管理しているすべての Function について共通のようなので、その点は少し注意が必要かもしれません。

AUTH_TOKEN が取得できるようになったので、リファレンスと同様に電話番号を取得します。 あとは、これとメール送信を Promise でつなげれば終わりです。

最終的に こちらのGist のようにして、発信元の電話番号を取得します。

確認

もう一度試します。 電話をかけて、適当に録音して、メールを確認すると、

f:id:junichim:20190221151611p:plain

こんどは、電話をかけてきた相手の電話番号も無事表示されています。

さいごに

基本的な動作は FAX の時と同じでしたが、処理の呼び出し時に受け取れるパラメータの内容が微妙に異なっているのに少しはまりました。 でも、これで、留守電も使えるようになったので、とりあえずは満足です。

QNAP Backup Station などでの『最大ダウンロード速度』の設定について

ちょっと前に設定方法がわからなかったことがあったので、今更ですがメモっと来ます。

  • 機種:QNAP TS-231P
  • QTS : 正確には覚えてませんが、たぶん 4.3.5.0728 だったはず

QNAP の Backup Station の設定で Rsync サーバーのところに 『最大ダウンロード速度を有効にする』という項目があります。

QNAP Turbo NAS Software User Manual

いまのバックアップ体制はLAN内のみなので、速度制限なんて不要だと思い、マニュアル通り0を入れたら、エラーになります。

f:id:junichim:20181218093833p:plain

不審に思って、サポートに問い合わせてみたら、

  • チェックを入れるとダウンロード速度制限が有効になる
  • ダウンロード速度制限を有効にしたくなかったら、チェックを入れるな

とのことでした。

そう言われてみれば画面の表記も機能のオン・オフのように受け取れますね。でも、ここはちょっと、マニュアル表記も見直してほしいところです(いずれにせよ、0は入力できないので)。

ともあれ、WAN経由でバックアップするとかじゃない限り、チェックなしでよさそうです。

Git で過去のコミットのメールアドレスを修正する

GitHub の設定でprivateのメールアドレスでのコミットは受け付けないように設定しています。

が、既に過去に公開したリポジトリ(避難所検索@伊勢のリポジトリ)をよく見てみたら、どうもこの設定前にコミットしたらしく、メールアドレスとして private のメールアドレスがばっちりと載ってしまっていました。

本当はよくないのですが、forkとかはされていなかったので、過去のコミットのメールアドレスを変更することにしました。 clone してくれた方にはご迷惑をおかけしてしまいますが、平にご容赦ください。

ということで、その際の作業メモです。

変更方法

ちょっと調べると過去コミットのメールアドレスの変更方法は簡単に見つかりました。git filter-branch を使えという方法です。

version control - How to change the author and committer name and e-mail of multiple commits in Git? - Stack Overflow

なかでも、GitHub が変更用のスクリプトを公開してくれているので、それを利用することにします。

https://help.github.com/articles/changing-author-info/help.github.com

ここで紹介されているスクリプトの内容を rewrite というファイルに保存して実行権限を与えておきます。

変更作業

実際の作業は、上記リンク先の説明に従って進めます。

最初にローカル上に作業用リポジトリをクローンして、作成した rewrite スクリプトを実行して Author/Commiter の書き換えを行います。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ ./rewrite
Rewrite 5127723affae8988878905cd4c88826f1ffc4614 (59/61) (17 seconds passed, remaining 0 predicted)
Ref 'refs/heads/master' was rewritten
Ref 'refs/tags/1.0beta' was rewritten
1.0beta -> 1.0beta (5127723affae8988878905cd4c88826f1ffc4614 -> 03acac1d9dd4b51aaf193e740e7ca464a362f05a)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$

git log でログを表示させると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ git log
commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, tag: 1.0beta)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

commit 65016265bd4c026bdb20edf1bd50cf47a8921573
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:51:52 2017 +0900

    現在位置の最寄りの避難所を任意のタイミングで検索できる機能を追加

commit d37b76b2a5a76061fd06a42c210e24bbe8f0ab28
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:39:59 2017 +0900

    アプリバーがスワイプで消えてしまい、元に戻せないのを修正

確かに変更されています。

これで、問題ないかと思って、push すると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Counting objects: 889, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (217/217), done.
Writing objects: 100% (889/889), 3.12 MiB | 1.20 MiB/s, done.
Total 889 (delta 427), reused 830 (delta 427)
remote: Resolving deltas: 100% (427/427), done.
remote: error: GH007: Your push would publish a private email address.
remote: You can make your email public or disable this protection by visiting:
remote: http://github.com/settings/emails
To https://github.com/junichim/ShelterAtIse.git
 + 5127723...03acac1 master -> master (forced update)
 ! [remote rejected] 1.0beta -> 1.0beta (push declined due to email privacy restrictions)
error: failed to push some refs to 'https://github.com/junichim/ShelterAtIse.git'
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$

のようにpushが失敗しました。

実は作業用リポジトリをクローンする際に、--bare オプションを付けていませんでした。なので、それが原因かと考え、一度ローカルリポジトリを消して、--bare をつけて再度実行してみます。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ ../rewrite
Rewrite 03acac1d9dd4b51aaf193e740e7ca464a362f05a (119/119) (32 seconds passed, remaining 0 predicted)
WARNING: Ref 'refs/heads/master' is unchanged
Ref 'refs/tags/1.0beta' was rewritten
1.0beta -> 1.0beta (5127723affae8988878905cd4c88826f1ffc4614 -> 03acac1d9dd4b51aaf193e740e7ca464a362f05a)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

で、pushします。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Counting objects: 1, done.
Writing objects: 100% (1/1), 150 bytes | 75.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
remote: error: GH007: Your push would publish a private email address.
remote: You can make your email public or disable this protection by visiting:
remote: http://github.com/settings/emails
To https://github.com/junichim/ShelterAtIse.git
 ! [remote rejected] 1.0beta -> 1.0beta (push declined due to email privacy restrictions)
error: failed to push some refs to 'https://github.com/junichim/ShelterAtIse.git'
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

相変わらず失敗します。何がまずいんだろうか?

しばらくあれこれ調べて考えていると、tag にも作成者があるんじゃないかな、と思い立ちました。

で、tagの情報を表示してみると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git show 1.0beta
tag 1.0beta
Tagger: mor <myprivate@email.address>
Date:   Fri Jul 7 15:30:58 2017 +0900


commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, tag: 1.0beta)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

(以下略)

当たりのようですね。tagのTaggerのところに、ばっちりprivateのメールアドレスが載ってました。

どうもこれが原因でpushに失敗していたようです。

tag の削除

tag も作成者(Tagger)が変更できるかと思って調べてみると、どうもtagについてはできないようです。 ということで、諦めて、tagについてはローカルおよびリモートで削除します。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git tag -d 1.0beta
Deleted tag '1.0beta' (was dbd1930)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --delete origin 1.0beta
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
To https://github.com/junichim/ShelterAtIse.git
 - [deleted]         1.0beta
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

そのあとに再度、pushします。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Everything up-to-date
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

問題なくpushできたようです。

最後に改めてタグを振って完了です。

振り返り

さて、上記に書いたように試行錯誤しながらいろいろとやりましたが、あとから表示されたログをよく見るとやっと状況がわかりました。

どうも最初の git push --force の段階で、masterブランチのpushは完了しており、各コミットの Author/Commiter は書き換えられて、tag の push(のみ)失敗したということのようです。 というのも、上記の途中でベアリポジトリをクローンして作業していると思いますが、rewrite しても master ブランチは書き換えが起こっていません。

つまり、この作業時点では、 Author/Commiter の書き換えのpushが失敗したと思っていたのですが、(リモートリポジトリの)状態としては、各コミットの Author/Commiter は書き換えられ、古いコミットに紐づいている tag が残っているという中途半端な状況になっていたようです。

たまたま確認用にこのタイミングでリモートリポジトリをクローンして、ログを見ていたのですが、それを見ると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/check/ShelterAtIse$ git log
commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, origin/master, origin/HEAD)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

commit 65016265bd4c026bdb20edf1bd50cf47a8921573
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:51:52 2017 +0900

    現在位置の最寄りの避難所を任意のタイミングで検索できる機能を追加

commit d37b76b2a5a76061fd06a42c210e24bbe8f0ab28
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:39:59 2017 +0900

    アプリバーがスワイプで消えてしまい、元に戻せないのを修正

のようにAuthorが変更されていますが、タグについては、

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/check/ShelterAtIse$ git show 1.0beta
tag 1.0beta
Tagger: mor <myprivate@email.address>
Date:   Fri Jul 7 15:30:58 2017 +0900


commit 5127723affae8988878905cd4c88826f1ffc4614 (tag: 1.0beta)
Author: mor <myprivate@email.address>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

(以下略)

と private のメールアドレスを持ち、Author変更前のコミット(ハッシュ値 5127723)を指していました。

Author変更スクリプトに書かれている git filter-branch のオプションを調べると --tag-name-filter cat は tag を新しいコミットに付け替えてくれるというオプションのようです。実際、作業途中で git show 1.0beta とタグの情報を見たときには、tagのメールアドレスはprivateのものですが、指しているコミットはAuthor更新後のもの(ハッシュ値 03acac1)となっていました。

で、最後にリモートからタグを消したことでこの状態が解消したんだと思います。

GitHub の設定で private メールアドレスのコミットを禁止しているので、ローカルでは tag 自体は新しいコミットを指すように付け替えられたけど、pushができなかったので、リモート上の tag は古いコミットを指しているままという、こんなややこしい状況になったんでしょうね。

まとめ

というわけで、

  • 過去コミットのメールアドレスを変更する際に、
  • GitHub の private アドレスのコミット禁止設定をしている場合は、
  • 最初から tag を消しておいて、
  • Author/Commiter の変更作業をする

というのが無難なようです。

表示されるメッセージはちゃんと読め、ということですね。あー、めんどくさかった。