[II] 関数定義
ここでは、次の2種類の処理を行っています。
- プッシュメッセージをバックグラウンドスクリプトからgaedirectのChannelサーバに送信
- ユーザPCのローカルストレージへHTML5のWeb SQLを使用してアクセス
(F) プッシュメッセージをバックグラウンドスクリプトからChannelサーバに送信
リスト3 多機能チャットプログラム-2 (channelHtl5.htm)
01 | //(F) 開始: Channel APIでのサーバプッシュメッセージをバックグラウンドで送信 |
02 | function up_to_channel(lat, lon){ |
03 | var uname = $("#uname").val(); |
04 | var uemail = $("#uemail").val(); |
05 | var umsg = $("#umsg").val(); |
06 | var utime = setutime1(); |
07 | var id = "uname,uemail,umsg,lat,lon,utime"; //(1) |
08 | var val = uname+"<p>"+uemail+"<p>"+umsg+"<p>"+lat+"<p>"+lon+"<p>"+utime; //(2) |
09 | var que = "kind="+kind+"&clientId="+clientId+"&id="+id+"&val="+val; |
10 | worker2.postMessage(que); //(3) |
12 | //(F) 終了:Channel APIでのサーバプッシュメッセージをバックグラウンドで送信 |
13 | //(G) 開始:ローカルストレージへのアクセス |
14 | function add_local(e){ //(4) |
15 | var listno = e.target.id; //(5) |
16 | if (listno.substr(0, 1) != 'u') { //(6) |
17 | var uname = $('#' + 'uname' + listno).text(); //(7) |
18 | var uemail = $('#' + 'uemail' + listno).text(); |
19 | var utime = $('#' + 'utime' + listno).text().substr(3); //(8) |
20 | var lon = $('#' + 'lon' + listno).text().split(":")[1]; //(9) |
21 | var lat = $('#' + 'lat' + listno).text().split(":")[1]; //(10) |
22 | var umsg = $('#' + 'umsg' + listno).text(); //(11) |
23 | var uval = uname + "<i>" + uemail + "<i>" + utime + "<i>" + lat + "<i>" + lon + "<i>" + umsg; |
24 | var ukey1 = uemail.split("@")[0]; //(12) |
25 | var ukey = ukey1 + utime; //(13) |
26 | db.transaction(function(tx) { |
27 | tx.executeSql('CREATE TABLE IF NOT EXISTS lcheck(key TEXT PRIMARY KEY, uname text, uemail text, lat text, lon text, utime text, umsg text)',[]); //(14) |
29 | tx.executeSql('INSERT INTO lcheck VALUES(?,?,?,?,?,?,?)', [ukey,uname,uemail,lat,lon,utime,umsg], //(15) |
32 | $("#status").text("OK"+res); //(16) |
35 | $("#status").text("Err"+error.message); //(17) |
40 | function rev_local() { //(18) |
41 | db.transaction(function(tx) { |
42 | tx.executeSql('SELECT * FROM lcheck', [], function(tx, res) { |
43 | var len = res.rows.length; //(19) |
44 | listno = 0; seqno=len; |
45 | $("#splist").html(""); |
46 | for(var i=0; i<len; i++) { //(20) |
47 | var row = res.rows.item(i); //(21) |
48 | splist(listno++, row.uname, row.uemail, row.lat, row.lon, row.utime, row.umsg); //(22) |
53 | function del_local(){ //(23) |
54 | db.transaction(function(tx) { |
55 | tx.executeSql('DELETE FROM lcheck', [], |
57 | var pnode = document.getElementById("splist"); |
58 | for (var i =pnode.childNodes.length-1; i>=0; i--) { |
59 | pnode.removeChild(pnode.childNodes[i]); //(24) |
63 | $("#status").text("err"+error.message); |
67 | //(G) 終了:ローカルストレージへのアクセス |
(F)の処理は、Channelサーバへのデータ送信で呼び出されるup_to_ channel関数の処理内容です。この関数では、チャット画面入力データと書き込み時間の取得を行ったあと、(1)で送信データのプロパティ名を指定していますが、例えばここで
1 | var id = "uname,uemail,te:umsg,lat,lon,utime"; |
とすれば、送信されたメッセージ(umsg)をプロパティ長で最大1メガバイトまでの長さでBigbaleに書き込むことができるようになります。(2)で送信データを指定しkind名やクライアントID(clientId) を追加して送信データをクエリ変数形式で整えたあと、(3)のワーカオブジェクト(worker2)のpostMessageメソッドでバックグラウンドスクリプトに処置を依頼しています。このような処理方式にすることによって、Channelサーバへのデータ送信を行っている間も、フォアグラウンドのJavaScriptでは並行してUI操作の処理を継続することができます。
・Web Workersを使用したChannelサーバへのデータ送信
postMessageの実効によってバックグラウンドスクリプトの実行が開始されますが、バックグラウンドで実行されるスクリプトはリスト4のようになっています。
リスト4 非同期通信用のワーカスクリプト(tworker.js)
1 | onmessage = function(e) { (W1) |
2 | var xhr = new XMLHttpRequest(); (W2) |
3 | xhr.open("post", "/channelapi", false); (W3) |
4 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); |
7 | var res = xhr.responseText; (W6) |
8 | postMessage("送信完了: "+res); (W7) |
リスト4は非同期通信を使用してChannelサーバにデータを送信するワーカスクリプトですが、ワーカスクリプト内ではライブラリは使用できないため、すべてJavaScriptの言語機能として備わっているステートメントを使用して記述する必要があります。リストではAjaxのPOST同期型の通信を行っていますが、今では殆どの場合に非同期通信でライブラリを使用しており、生のAjax非同期通信コード記述は使用されることも少なくなっているため、ここで簡単に処理内容を解説します。
Ajaxの非同期通信
Ajaxの非同期通信では最初に非同期通信用のオブジェクトを生成する必要があり、これは(W2)で行っています。その後(W3)のopenメソッドで通信をオープンしていますが、第一引数ではPOSTメソッドでの通信であることを指定し、第二引数ではweb.xmlに記述されているgaedirectのChannelサーバアドレスの指定、そして第3引数では同期型の通信を指定しています。
ここで、非同期通信で同期型という事を奇異に感じる方もいるかと思いますが、Ajaxでの非同期通信は「画面遷移と同期しない」という意味で、通信を行う時に、HTMLのフォームを使用したサーバ通信のように画面遷移を発生しない、画面表示はそのままで送受信を完了させる、という意味です。そしてその画面遷移を発生させない通信には、非同期型と同期型があり、同期通信を行う場合は、openメソッドの第三引数にfalseを指定します。
(W4)ではHTTPヘッダに追加する情報を指定していますが、POST通信ではHTTPデータ送信のペイロード(HTTPプロトコルのデータ本体)にデータをセットして送信するため、そのデータフォーマットをサーバに知らせる為に、この指定が必要になります。GETメソッドの場合は、ペイロードは空のままなので、指定の必要は有りません。
以上の準備の後、(W5)のsendメソッドでデータを送信します。引数に指定する送信データには、フォアグラウンドスリプト(リスト2の(17))から送られたパラメータを使用していますが、リスト4ではワーカオブジェクト(e)として受け取っており、そこからデータ部分を e.data で取得して、この値を送信データにしています。
同期型の場合は、sendメソッドを抜けた状態でサーバからのレスポンス受信を完了しているので、この値を(W6)で変数resにセットし、(W7)のpostMessageでフォアグラウンドのスクリプトに渡しています。リスト2では、(20)でワーカからメッセージが送られてくるとonmessageイベントから匿名関数が呼び出されて、送られてきたメッセージをdataプロパティで受け取っています。
ただしここで受け取るメッセージは、Channelサーバに送信されているメッセージではなく、送信の完了を知らせるステータスメッセージです。
(G) ローカルストレージへのアクセス
ローカルストレージへのアクセスでは、HTML5の Web SQL Database を使用して、表示されるメッセージのJavaScriptからローカルストレージへの書き込みや、全件参照、全件削除を行っています。
[チェックボックスクリックでローカルストレージ書き込み]
リスト3(4)のadd_local関数でローカルストレージへの書き込みを行っています。add_local関数は、図13のように、表示される書込み一覧の左端にあるチェックボックスをチェックしたときに呼び出されます。チェックすることによってadd_localが呼び出され、(5)でチェックしたメッセージの行番号が取得されます。但し、イベントはチェックボックス以外のフィールドをクリックした場合にも発生するため、その中からチェックボックスのクリックだけを選択しているのが(6)の処理です。
その後(7)~(11)で書きこまれたメッセージと位置情報(緯度、経度)と書込み時間を取得しています。それぞれの行データには、その項目毎に 「項目フィールドID値+行番号(listno)」のID値がアサインされているので、(7)以下のような記述で値を取得できる訳です。ここで(9)~(10)では、取得された値に split(":")[1]を適用していますが、これは一覧表示時に、例えば経度であれば、「"緯度:"+lon」の形でデータ表示されているので、前半の "緯度:"の部分を除くために行っています。
書き込み用のキー作成
(12)と(13)では、ローカルストレージ書き込み用のレコードキーを作成しています。
(12)では、ユーザが入力したメールアドレスの「@」から前の部分を取り出し、(13)でそれに書き込み時間を追加したものをキーとしています、これによってキー値だけから誰が何時書き込んだものかを知ることができ、またキー値がユニークであるという必須要件も満たすことができる訳です。
ローカルストレージ書き込み
そのあとはWeb SQLを使用したローカルストレージ書き込みを(15)で行っていますが、その前に最初の書き込みでテーブルがまだ存在しない場合のために(14)でテーブル生成を行っています。SQLについては標準的な構文ですので省略しますが、(16)と(17)のステータス表示では、Web SQL からのレスポンスをそのまま表示しています。
[ローカルストレージ書き込みデータの全件参照]
(18)のrev_localはローカルストレージに書き込まれたデータの参照処理を行っています。参照は全件参照で行われ、SQLについては前にも見てきていますが、(19)で受信データのレコード数を取得し、(20)のfor文でレコード数に対応した表示処理を(21)と(22)で行っています、ここでrev_local はクラウド上のBigtableデータを参照・表示する場合も使用される共通ルーチンになっています。
[ローカルストレージ書き込みデータの全件削除]
(23)のdel_localではローカルストレージ書き込みデータを全件削除しています。全件削除についても前に見てきていますが、書き込みノードの削除では、(24)のremoveChildでDOMノード操作を使用した処理になっています。