サンプルのプログラムコード解説
[グローバル変数の初期化]
リスト2の最初の部分ではグローバル変数の初期化を行っています。このサンプルでは、画面初期化後に実行される関数、またはそれ以外の関数など多くの関数から共通に呼び出される変数やオブジェクトが多数あるので、それらは広域変数として定義しています。この中で
- (1)でkind名の指定
- (2)でワーカオブジェクトの生成
- (3)でローカルDBをオープンして、データベースオブジェクトの取得
を行っていますが、このサンプルでの指定は次のような内容になっています。
- gaedirectのChannelサーバに送信されたメッセージは、オプション指定で、kind名”chnlhtml5”のBigtableに格納される。
- このサンプルでのワーカは、非同期通信でChannelサーバにメッセージ送信を行い、スクリプト名“tworker.js” の外部JSファイルを使用する。
- サンプルで使用されるWeb SQLデータベースのDB名は”lcheck”で、サイズは1Mバイト。
WebワーカとWeb SQLではそれぞれ生成されるオブジェクト(worker2とdb)を使用して操作が行われます。
[プログラムの処理ブロック]
プログラム処理は、画面ロード時の処理として、画面を表示するまでにBigtableに既に書き込まれているメッセージを表示する(図4※画面下部のメッセージ)処理から始まっています。これはrev_remote()関数の呼び出しによって行われていますが、この関数についてはこの後の「(E) クラウドBigtable登録エンティティの参照」で見ていきますので、ここでは省略します。
※)文中に登場する図は第1回のものです。
ここでのプログラム処理は(A)から(E)まで5種類あり、すべて画面ロード後に評価されます。
(A) Channel API 初期化
Channel APIを使用するための初期化処理は、次の手順で行っています。
- (1)clientId = ""+Math.floor(Math.random()*1000000);
- Channel APIを行うWebクライアントは、必ずChannelクライアントを識別するためのユニークなID(clientID)を持つ必要があります。このサンプルではMath.randomで発生した乱数を文字列に変換してIDとしていますが、ユニークであれば何でもかまいません。
- (2)token = getToken(clientId);
- getTokenはgaedirectの関数で、引数で指定されたclientIDをChannel APIに対応しているChannelサーバ(ここではgaedirectのChannelサーバ)に送信します。Channelサーバは受信したclientIDからtokenを生成し、戻り値として返すので、それを変数tokenにセットします。
- (3)channel = goog.appengine.Channel(token);
- goog.appengine.Channelは返されたtokenを引数にとってChannelサーバにリクエストを送信します。ChannelサーバではcreateChannel() メソッドでchannelオブジェクトを生成して返すので、それを変数channelにセットします。
- (4)socket = channel.open():
- このメソッドが実行されると。ChannelサーバはクライアントとのChannelをオープし、ソケットオブジェクト(goog.appengine.Socket)を返します。Socketオブジェクトを取得したブラウザクライアントはChannelを使用したサーバプッシュ通信が可能となり、クライアント側の初期化処理は完了します。
(B)Web Storage への書き込みデータ表示
HTML5のローカルストレージアクセスでは、キー・バリュー型とSQL型の2種類が主なものです。ここではキー・バリュー型のストレージアクセスを使用して、名前とEmailをローカルストレージに書き込み、2回目の表示からは、自動表示を行って再入力が必要ないようにしています。
キー・バリュー型でのローカルストレージアクセスは簡単で、
- 書込は localStorage.キー名 = 値; で行うことができ、
- 読取は var val = localStorage.キー名 で行えます。
ここでは(5)と(6)でそれぞれ名前と、Emailアドレスの読取を行っていますが、例えば名前の書き込みデータ取得は、書き込みが有ることを確認してから localStorage.uname で行っています。なお、ローカルストレージへの書き込みはメッセージの送信時に行っていますが、この処理によって図4のように2回目以降にチャット画面を表示した時には、名前とメールアドレスが自動表示され、再入力が必要ないようにしています。
(C)テキストのドラッグ&ドロップ
図8と図9では、Weページに表示されている文章をそのままドラッグ&ドロップしてチャットメッセージに追加していますが、この処理を行っているのが、(C)の記述です。
(7)ではドラッグオーバ時のイベントリスナ処理を行い、(8)のドロップ時の処理ではドロップするメッセージ入力フィールドにキー入力などによるテキスト表示が既にある場合への対応を行なっています。(10)では入力フィールドに書きこまれているテキストを変数utmpにセットし、(9)のドロップテキストをその後に連結して(11)でメッセージフィールドに表示するようにしています。
(D) Channel API イベントハンドラの設定
Channelサーバからサーバプッシュで送られてくるステータス情報およびメッセージは、socketオブジェクトのイベントハンドラで検知されて対応する処理を行います。ステータス&メッセージの内容によって次のように分かれます。
- socket.onopen = ソケットオープン時の処理;
- socket.onmessage = プッシュメッセージ受信時の処理;
- socket.onerror = エラー発生時の処理;
- socket.onclose = ソケットクローズ時の処理;
・Channelサーバからのプッシュメッセージ受信
ここでのメインとなる処理はChannelサーバからプッシュ形式で送られてくるメッセージを受信した場合の処理で、これは(12)で行われています。
ChannelサーバからのプッシュメッセージはJSONフォーマットになっているので、(13)のjQuery関数の$.parseJSONでJSON形式の文字列を、JavaScript オブジェクト(res)に変換しています。その後、resを使用して名前から書き込み時間までの情報を取得した後(14)のsplit関数で画面上の一覧表示に追加します。追加ではDOMノード操作を使用して表示内容の先頭に追加されますが、この処理内容については(H)のsplit関数のところで解説します。
(E)ユーザインタラクション(ボタンクリック)への対応処理
(E)ブロックは、ユーザのマウス操作などによるイベントに対応する処理になっています。
・Channelサーバへのデータ送信
(15)は「書込み」ボタンのクリックによって、画面から入力されたメッセージをgaedirectのChannelサーバに送信する処理になっていますが、実際の送信処理はHTML5のバックグラウンドスクリプトからライブラリ関数を使用しない非同期通信で行われています。
通信では画面上の「位置情報OK」、「位置情報NO」のラジオボタン選択情報を変数showlocにセットし、(16)では位置情報を取得できた場合にgeolocationで位置情報を取得できるか否かを判定して、OKの場合は位置情報をそれぞれ変数にセットして、(17)のクラウドへのプッシュ情報アップロード関数up_to_channelを呼び出しています。送信データには、Geolocation APIで取得された位置情報(緯度、経度)も含まれていますが、このサンプルではスマートフォンは対象外なので、Android用のgearsに関する外部JSファイル指定と、初期設定は行われていません。
「位置情報NO」または位置情報を取得できない場合は、(18)のelse以下で位置情報に仮の値を設定し、前と同様に(19)でup_to_channelを呼び出してサーバへのプッシュメッセージのアップロード送信を行っています。
Channelサーバへのメッセージ送信はバックグラウンドのワーカスクリプトから行われ、ワーカから送信完了後のステータスメッセージが返されると(20)の匿名関数が起動されるので、その中でステータス表示を行っています。
その後(21)から(25)でクリックイベントに対応した関数呼び出しが列記されていますが、これらの処理内容については、次の関数定義で見ていきます。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- JDO APIとLow-Level APIの違いと基本CRUD処理
- Socket.IOを使ってNode.jsでリアルタイムWebアプリを開発する
- App Engineから読み取ったデータの書き込みと、スプレッドシートのUIで表示する処理
- クラウドWebサービスの概要とサンプル画面操作
- Firebaseのこれからとリアルタイムデータベースの補足説明
- Firebaseの認証機能
- expressで開発したWebアプリをeXcaleで動かす
- FirebaseプログラムをApp Engineにディプロイする
- FirebaseプログラムをCompute Engineにディプロイする
- AppsスプレッドシートとApp Engineのデータ交換を完成させる