2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
はじめに
本記事は、Twilio Syncを使うプログラミングサンプルとなります。
複数のブラウザ(PC、スマホ等)で同期を取りながら、いずれかの端末の変更結果を他の端末にPushします。
準備
- Twilioアカウント(トライアルアカウントでも可能です)
- ブラウザ(スマホ、PC)
Twilio Sync
- Twilio Sync
- 複数のデバイス間で情報を同期させるためのサービス
- WebSocketやSocket.ioのようなリアルタイム通信プラットフォーム
- Syncは、受け取ったデータをTwilio上に保存してから配信する
- Sync上のデータは、明示的に削除しない限り消えない
- 月10,000アクションまでは無料、それ以降は1000アクション単位で1.5円
- Documents / Lists / Maps / Message Streams の4種類のデータを扱うことが可能
- 各オブジェクトにはACLを設定することが可能
Documentsオブジェクト
- 単一のJSON形式オブジェクト
- 1データのサイズは最大16KB
- 単純な値のPUB/SUBに向いている
- 履歴を取るような使い方には向いていない
- JavaScript SDKを使うと、Documentオブジェクトの生成、更新、購読、削除が可能
- サーバーサイドのREST API経由でも管理可能
- Documentsオブジェクトの利用例
- コールセンターでオペレータの稼働確認などに利用
例:Documentsオブジェクトの生成
client.document('user_prefs').then(function(doc) {
doc.set({
foregroundColor: "#ffff00",
backgroundColor: "#ff0000"
});
});
すでに、user_prefsオブジェクトが存在する場合は、そのオブジェクトが上書きされます。
例:Documentsオブジェクトの更新
client.document('user_prefs').then(function(doc) {
doc.update({foregroundColor: "#ff0000"});
});
user_prefsに、別のKey/Value(例えば、backgroundColor)があった場合、その値は更新されません。
例:Documentsオブジェクトの読み込み
client.document('user_prefs').then(function(doc) {
console.log(doc.value);
});
例:Documentsオブジェクトの更新を購読する
syncClient.document("user_prefs").then(function(doc) {
doc.on("updated",function(data) {
console.log(data);
});
});
例:Documentsオブジェクトの削除
syncClient.document("user_prefs").then(function(doc) {
doc.removeDocument().then(function() {
console.log('Document removed.');
});
});
ハンズオン
Documentsオブジェクトを使ったデバイス同期
シナリオ
SyncのDocumentsオブジェクトを利用して、複数ブラウザで同期を行うサイトを作成してみます。
SyncのJavaScript Clientを利用します。
手順1. Syncサービスの作成と、API KeyとAPI Tokenの発行
まずは、新しいSyncサービスを作成し、API KeyとAPI Tokenを発行します。
- 管理コンソールのスライドメニューから、DEVELOPER TOOLSの中のSyncを選択します。
- Syncメニューの中からServicesを選択します。
- 赤い**+**アイコンを押して、新しいSyncサービスを作成します。
- **新規Sync Servceに名前をつけます。**ダイアログが表示されるので、名前欄に「SyncBrowser」と入力し、Createボタンを押します。
- SERVICE SID(ISから始まる文字列)をメモ帳に保存しておきます。
- Syncメニューの**< Back**をクリックして、Syncサービスの一覧画面に戻ります。
- Syncメニューのツールを選択し、APIキーの一覧が表示されるのを確認します。
- Create API Keyボタンを押すか、**+**アイコンを押して、新しいAPI Keyを作成します。
- 名前欄に「SyncBrowser」と入力し、キータイプは「Standard」を選択します。
- APIキーを作成するボタンを押します。
- 表示されるSID(SKから始まる文字列)と、SECRETに表示されている文字列の両方をメモ帳に保存します。
- **完了しました!**のチェックボックスにチェックを入れて、終了ボタンを押します。
手順2. アクセストークン発行用Functionの作成
Syncを利用するためには、先程作成したAPIキーを使って、アクセストークンを動的に生成する必要があります。
今回は、Functionsを使って、Syncサービスのアクセストークンを生成してみましょう。
- 管理コンソールから、Runtime > Functions > Configureを選択します。
- Environmental Variablesの赤い**+**ボタンを3回押して、KEY/VALUE欄を3つ追加します。
- それぞれのKEY/VALUEを以下のように設定します。
KEY | VALUE |
---|---|
SYNC_SERVICE_SID | ISから始まるSyncサービスのSID |
TWILIO_API_KEY | SKから始まるAPIキー |
TWILIO_API_SECRET | APIキーとセットで設定されたSECRET |
- Saveボタンを押して設定を保存します。
- RuntimeメニューのFunctions > Manageを選択します。
- 赤い**+**アイコンをクリックして、新しいFunctionを生成します。
- テンプレートの一覧からBlankを選択して、Createボタンを押します。
- FUNCTION NAMEに「SyncToken」と入力し、PATHには、「/sync-token」と入力します。
- ACCESS CONTROLのチェックは外しておきます。
- CODE欄に書かれているコードを以下のコードに置き換えます。
exports.handler = function(context, event, callback) {
const ACCOUNT_SID = context.ACCOUNT_SID;
const SERVICE_SID = context.SYNC_SERVICE_SID;
const API_KEY = context.TWILIO_API_KEY;
const API_SECRET = context.TWILIO_API_SECRET;
const IDENTITY = context.DOMAIN_NAME;
const AccessToken = Twilio.jwt.AccessToken;
const SyncGrant = AccessToken.SyncGrant;
const syncGrant = new SyncGrant({
serviceSid: SERVICE_SID
});
const accessToken = new AccessToken(
ACCOUNT_SID,
API_KEY,
API_SECRET
);
accessToken.addGrant(syncGrant);
accessToken.identity = IDENTITY;
callback(null, {
token: accessToken.toJwt()
});
};
- Saveボタンを押して、デプロイされるのを待ちます。
- デプロイが完了したら、PATH欄のURLをコピーして、別のブラウザタブで実行してみます。
- JSON形式の長い文字列が表示されたら、トークンの生成は成功です。
手順3. HTMLファイルのアップロード
では次に、ブラウザに表示するHTMLファイルを準備します。
- 以下のURLからZIPファイルをダウンロードします。
https://sapphire-donkey-2666.twil.io/assets/SyncBrowser.zip
- ダウンロードしたZIPファイルを解凍し、2つのファイルがあることを確認します。
- index.html
- index.js
- 管理コンソールのRuntime > Assetsを選択します。
- **+**アイコンを押して、index.htmlを選択します。MAKE PRIVATEのチェックは外しておきます。
- Uploadボタンを押して、アップロードを完了します(デプロイが完了するまで待ちます)。
- 同様に、index.jsもアップロードします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sync Browser</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery読み込み -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- BootstrapのJS読み込み -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
<script src="https://media.twiliocdn.com/sdk/js/sync/releases/0.8.4/twilio-sync.min.js"></script>
<script src="./index.js?version=1.04"></script>
</head>
<body>
<h3>押されたボタンの状況を同期します</h3>
<button id="btn1" type="button" class="btn btn-primary">ボタン1</button>
<button id="btn2" type="button" class="btn btn-warning">ボタン2</button>
<button id="btn3" type="button" class="btn btn-danger">ボタン3</button>
<p>
<div id="result"></div>
</p>
</body>
</html>
let syncDoc, syncClient;
$(function() {
// Twilio Sync Tokenの取得
$.getJSON('../sync-token', function (tokenResponse) {
// Sync Clientの初期化
syncClient = new Twilio.Sync.Client(tokenResponse.token, { logLevel: 'info' });
console.log(tokenResponse.token);
syncClient.document('SyncBrowser')
.then(function(doc) {
// グローバル変数に格納
syncDoc = doc;
// Syncからメッセージが届いた場合のイベント
syncDoc.on('updated', event => {
text = event.value.text;
console.log(`Sync updated. ${text}`);
// 画面を更新
$('#result').html(text);
});
})
.catch(function(error) {
console.log(error);
});
// Token Expire対策
syncClient.on('tokenAboutToExpire', () => {
$.getJSON('../sync-token', function (tokenResponse) {
syncClient.updateToken(tokenResponse.token);
console.log('Sync token updated.');
});
});
});
$('#btn1').on('click', function() {
setSyncDoc("ボタン1が押されました");
});
$('#btn2').on('click', function() {
setSyncDoc("ボタン2が押されました");
});
$('#btn3').on('click', function() {
setSyncDoc("ボタン3が押されました");
});
function setSyncDoc(text) {
const value = {
text: text,
};
syncDoc.set(value);
console.log('Sync publish.');
};
});
<重要> index.jsのように、Assetsに格納されたコンテンツ(今回の場合は、index.html)から参照されるコンテンツだけを更新してAssetsにアップロードし直しても、キャッシュが効いてしまうので新しいコンテンツが反映されません。そのため、今回の例のように、呼び出すコンテンツに「?ver=1.xx」のようにバージョンを振るなどして、index.htmlとindex.jsの両方をアップロードするとキャッシュされないようになります。
手順5. テスト
- 管理コンソールのAssestの一覧画面から、アップロードしたindex.htmlのURLをコピーします。
- 新しいブラウザタブを開き、今のURLを実行します。
- ボタンを押すと、メッセージが表示されることを確認します。
- さらに複数のタブで上記URLを開き、どれかの画面でボタンを押すと、他のタブにも反映されることを確認します。