templates/as3/org/rubyforge/dango/DangoClientFramework.as in dango_generator-0.3.4 vs templates/as3/org/rubyforge/dango/DangoClientFramework.as in dango_generator-0.3.5

- old
+ new

@@ -1,6 +1,6 @@ - + package org.rubyforge.dango { /** * Dangoのクライアントフレームワーク本体のクラス * */ @@ -39,19 +39,16 @@ private var delay_send_timer:Timer; // 遅延送信用のタイマーの設定 private var delay_send_timer_msec:uint = 1500; // 遅延送信用のタイマーのミリ秒 private var delay_send_cache:Array = []; // 遅延送信用のキャッシュ - private var receve_count:uint = 0; // データ受信回数 - private var receive_row_cache:Array = []; // 受信データの一時保管用のキャッシュ + private var receive_cache_byta:ByteArray = new ByteArray; // 受信データの保管用のキャッシュ ByteArray + private var receive_cache_do_phase:uint = 0; // 受信データをどこまで処理してあるかのキャッシュ + private var receive_encode_type:uint = 0; // 受信データのエンコードタイプ + private var receive_data_size:uint = 0; // 受信データのデータサイズ - private var recv_not_yet_size:uint = 0; // データ受信時のキャッシュサイズ - private var recv_not_yet_str:String = ""; // データ受信時のキャッシュデータ - private var recv_wait_do_cache:Array = []; // 実行待ち受信キャッシュ - private var recv_cache_timer_msec:uint; // 受信キャッシュ用タイマーの実行間隔 - private var recv_cache_timer:Timer; // 受信キャッシュ用タイマーの追加 private var recv_do_count_no:uint = 0; // 受信実行の回数 private var recv_do_timer_msec:uint; // 受信実行用タイマーの実行間隔 private var recv_do_timer:Timer; // 受信実行用タイマーの追加 private var recv_do_last_date:Date = new Date(); // 受信キャッシュ用処理落ちチェック用 @@ -65,12 +62,16 @@ private var server_port:int; public var sid:int; /** + * DangoClientFramework * コンストラクタ * + * @param config:* + * @param disp_obj:DisplayObject = null + * @return void */ public function DangoClientFramework(config:*, disp_obj:DisplayObject = null){ // is_debug = d; // Debugモードかどうかのフラグ if(disp_obj){ @@ -147,17 +148,10 @@ // 遅延送信用タイマーの設定 var delay_send_timer:Timer = new Timer(delay_send_timer_msec, 0); // タイマーの追加 delay_send_timer.addEventListener(TimerEvent.TIMER, delay_send_callback); // イベントリスナーの発行 delay_send_timer.start(); // タイマーの作動開始 - // 受信キャッシュ用タイマーの設定(4フレームごとに動かすよう変更) - recv_cache_timer_msec = uint((1000 * 4) / frame_rate); - if(is_debug){ trace("DangoClientFramework:recv_cache_timer_msec:" + recv_cache_timer_msec); } - recv_cache_timer = new Timer(recv_cache_timer_msec, 0); // タイマーの追加 - recv_cache_timer.addEventListener(TimerEvent.TIMER, recv_cache_callback); // イベントリスナーの発行 - recv_cache_timer.start(); // タイマーの作動開始 - // 受信実行用タイマーの設定(2フレームごとに動かすよう変更) recv_do_timer_msec = uint((1000 * 2) / frame_rate); if(is_debug){ trace("DangoClientFramework:recv_do_timer_msec:" + recv_do_timer_msec); } recv_do_timer = new Timer(recv_do_timer_msec, 0); // タイマーの追加 recv_do_timer.addEventListener(TimerEvent.TIMER, recv_do_callback); // イベントリスナーの発行 @@ -166,29 +160,47 @@ // 接続完了のときに接続完了をサーバーに通知するためのハートビート送信 var hb_id:String = make_heartbeat(); this.send_action("_notice_heart_beat", { "_hb_id": hb_id}, true); // ハートビート送信 } - //接続イベントの処理 + /** + * connectHandler + * 接続イベントの処理 + * + * @param evt:Event + * @return void + */ private function connectHandler(evt:Event):void { is_connect = true; var msg:String = "DangoClientFramework:connectHandler:" + DangoUtil.now2str(); if(is_debug){ trace(msg); } } - //切断イベントの処理 + /** + * closeHandler + * 切断イベントの処理 + * + * @param evt:Event + * @return void + */ private function closeHandler(evt:Event):void { // タイマーが動いていれば止める if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } is_connect = false; var msg:String = "DangoClientFramework:closeHandler:" + DangoUtil.now2str(); if(is_debug){ trace(msg); } this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.CloseError, msg)); } - //セキュリティエラーイベントの処理 + /** + * securityErrorHandler + * セキュリティエラーイベントの処理 + * + * @param evt:Event + * @return void + */ private function securityErrorHandler(evt:SecurityErrorEvent):void { // タイマーが動いていれば止める if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } is_connect = false; @@ -196,88 +208,203 @@ if(is_debug){ trace(msg); } this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.SecurityError, msg)); } - //IOエラーイベントの処理 + /** + * ioErrorHandler + * IOエラーイベントの処理 + * + * @param evt:Event + * @return void + */ private function ioErrorHandler(evt:IOErrorEvent):void { // タイマーが動いていれば止める if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } is_connect = false; var msg:String = "DangoClientFramework:ioErrorHandler:" + DangoUtil.now2str(); if(is_debug){ trace(msg); } this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, msg)); } - // プログレスイベントの処理(呼び出し用イベントのディスパッチ) - // とにかくキャッシュに入れるだけ + /** + * socketDataHandler + * プログレスイベントの処理:実体はsocket_read_push_cache + * + * @param evt:Event + * @return void + */ private function socketDataHandler(evt:ProgressEvent):void { - receve_count ++; - if(is_debug){ trace("DangoClientFramework:socketDataHandler:" + receve_count + ":start:" + DangoUtil.now2str()); } - var byte_array:ByteArray = new ByteArray; - socket.readBytes(byte_array, 0, socket.bytesAvailable); - receive_row_cache.push([byte_array, receve_count]); + socket_read_push_cache(); } - // Event送出用 + /** + * addEventListener + * Event送出用 + * + * @param type:String + * @param listener:Function + * @param useCapture:Boolean = false + * @param priority:int = 0 + * @param useWeakReference:Boolean = false + * @return void + */ public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void{ dispatcher.addEventListener(type, listener, useCapture, priority); } + + /** + * dispatchEvent + * Event送出用 + * + * @param evt:Event + * @return Boolean + */ public function dispatchEvent(evt:Event):Boolean{ return dispatcher.dispatchEvent(evt); } + + /** + * hasEventListener + * Event送出用 + * + * @param type:String + * @return Boolean + */ public function hasEventListener(type:String):Boolean{ return dispatcher.hasEventListener(type); } + + /** + * removeEventListener + * Event送出用 + * + * @param type:String + * @param listener:Function + * @param useCapture:Boolean = false + * @return void + */ public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void{ dispatcher.removeEventListener(type, listener, useCapture); } + + /** + * willTrigger + * Event送出用 + * + * @param type:String + * @return Boolean + */ public function willTrigger(type:String):Boolean { return dispatcher.willTrigger(type); } - /** - * recv_cache_callback - * 受信データの再構成とキャッシュをする + * socket_read_push_cache + * socketDataHandlerの実体処理 + * データ受信、データのパース、実行待ちキャッシュに保存 * - * @param evt:TimerEvent + * @param void * @return void */ - public function recv_cache_callback(evt:TimerEvent):void { -// if(is_debug){ trace("DangoClientFramework:recv_cache_callback:" + DangoUtil.now2str()); } + private function socket_read_push_cache():void{ + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:" + DangoUtil.now2str()); } - if(receive_row_cache.length > 0){ - if(is_debug){ trace("DangoClientFramework:recv_cache_callback:receive_row_cache.length=" + receive_row_cache.length + ":" + DangoUtil.now2str()); } - var arr:Array = receive_row_cache.shift(); // Queueとして取り出し - var byte_array:ByteArray = arr[0]; - var recv_c:uint = arr[1]; -// if(is_debug){ trace("DangoClientFramework:recv_c=" + recv_c); } - var receive_data:Array = this.parse_notice(byte_array); + var crlf:String = ""; + var temp_byta:ByteArray = new ByteArray; + + socket.readBytes(receive_cache_byta, receive_cache_byta.length, socket.bytesAvailable); // データ読み込み + + while(true){ + // 長さ取得処理 + if(receive_cache_do_phase == 0){ + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 0:" + DangoUtil.now2str()); } + if(receive_cache_byta.length < 6){ break; } // 長さの読み込みが終わっていなければ + + try{ + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 0:start read"); } + receive_encode_type = receive_cache_byta.readByte(); // エンコードタイプ + receive_data_size = receive_cache_byta.readUnsignedInt(); // データサイズ + crlf = receive_cache_byta.readUTFBytes(1); + + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_encode_type=" + receive_encode_type); } + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_data_size=" + receive_data_size); } + + // receive_cache_bytaの不要な部分を削除 + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:length=" + receive_cache_byta.length); } + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:position=" + receive_cache_byta.position); } + + if(receive_cache_byta.length - receive_cache_byta.position > 0){ + receive_cache_byta.readBytes(temp_byta, 0, receive_cache_byta.length - receive_cache_byta.position); + receive_cache_byta = temp_byta; + receive_cache_byta.position = 0; + } else { + receive_cache_byta = new ByteArray; + } + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 0:end read:length=" + receive_cache_byta.length); } + + } catch(err:Error){ + this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "failed in DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 0")); + break; + } + + receive_cache_do_phase = 1; + } - if(recv_not_yet_size == 0){ // 未受信データが無ければ、ひとつのデータ受信が完了とみなす - if(receive_data != []){ // データが空じゃなければ処理開始 - for(var i:uint = 0; i < receive_data.length; i++){ - var notice_name:String = receive_data[i]["notice"]; - var recv_server_time:String = receive_data[i]["server_time"]; - - if(is_debug){ trace("DangoClientFramework:push recv_wait_do_cache:dango_" + notice_name + ": recv_c:" + recv_c + ":" + i + " recv_server_time:" + recv_server_time); } - recv_wait_do_cache.push([notice_name, receive_data[i], recv_server_time, recv_do_count_no]); - - recv_do_count_no ++; + // データ取得処理 + if(receive_cache_do_phase == 1){ + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 1:" + DangoUtil.now2str()); } + if(receive_cache_byta.length < receive_data_size){ break; } // データの読み込みが終わっていなければ + + try{ + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 1:start read"); } + var recv_data:String = receive_cache_byta.readUTFBytes(receive_data_size); // データ取得 + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:recv_data=" + recv_data); } + + // データのパースと実行待ち受信キャッシュにデータを入れる + var ret_obj_data:Array; + if(recv_data != "" && recv_data != "\n"){ // データが空じゃないならdecode + ret_obj_data = JSON.decode(recv_data) as Array; + for(var i:uint = 0; i < ret_obj_data.length; i++){ + var notice_name:String = ret_obj_data[i]["notice"]; + var recv_server_time:String = ret_obj_data[i]["server_time"]; + + if(is_debug){ trace("DangoClientFramework:push recv_wait_do_cache:dango_" + notice_name + " i=" + i + " recv_server_time=" + recv_server_time); } + recv_wait_do_cache.push([notice_name, ret_obj_data[i], recv_server_time, recv_do_count_no]); + recv_do_count_no ++; + if(is_debug){ trace("DangoClientFramework:pushed recv_wait_do_cache:recv_do_count_no=" + recv_do_count_no); } + } + } else { // データが空なら空データを作ってreturn + if(is_debug){ trace("DangoClientFramework:ret_obj_data is empty." + DangoUtil.now2str()); } } - } else { // データが空なら -// if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); } - if(is_debug){ trace("DangoClientFramework:receive_data is empty."); } + + // receive_cache_bytaの不要な部分を削除 + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:length=" + receive_cache_byta.length); } + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:position=" + receive_cache_byta.position); } + + if(receive_cache_byta.length - receive_cache_byta.position > 0){ + receive_cache_byta.readBytes(temp_byta, 0, receive_cache_byta.length - receive_cache_byta.position); + receive_cache_byta = temp_byta; + receive_cache_byta.position = 0; + } else { + receive_cache_byta = new ByteArray; + } + if(is_debug){ trace("DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 1:end read:length=" + receive_cache_byta.length); } + + } catch(err:Error){ + this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "failed in DangoClientFramework:socket_read_push_cache:receive_cache_do_phase == 1")); + break; } + receive_cache_do_phase = 0; } } + } /** * recv_do_callback * 受信データの実行する処理 @@ -321,11 +448,11 @@ * * @param evt:TimerEvent * @return void */ public function polling_callback(evt:TimerEvent):void { - if(is_debug){ trace("DangoClientFramework:polling_callback:" + DangoUtil.now2str() ); } +// if(is_debug){ trace("DangoClientFramework:polling_callback:" + DangoUtil.now2str() ); } if(socket.connected){ // var send_obj:Object = null; // this.send_data_to_server(send_obj); var hb_id:String = make_heartbeat(); @@ -346,12 +473,11 @@ /** * delay_send_callback * 遅延送信用タイマーコールバック * - * @param socket:Socket - * @param send_obj:Object + * @param evt:TimerEvent * @return void */ public function delay_send_callback(evt:TimerEvent):void { // if(is_debug){ trace("DangoClientFramework:delay_send_callback:evt:" + evt); } if(!is_connect){ return(void); } @@ -371,12 +497,13 @@ /** * send data to server. * クライアント側から使うサーバーへのデータ送信メソッド * - * @param socket:Socket + * @param action_name:String * @param send_obj:Object + * @param delay:Boolean=false * @return void */ public function send_action(action_name:String, send_obj:Object, delay:Boolean=false):void { if(is_debug){ trace("DangoClientFramework:send_action:start:" + action_name + ":" + DangoUtil.now2str()); } @@ -395,19 +522,18 @@ return(void); } // データをすぐ送信 this.send_data_to_server([send_obj_dup]); - if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); } +// if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); } } /** * send data to server. * フレームワーク側のデータ送信の一般処理 * - * @param socket:Socket - * @param send_obj:Object + * @param send_obj:Array * @return void */ public function send_data_to_server( send_obj:Array ):void { // if(is_debug){ trace("DangoClientFramework:send_data_to_server:send_obj=" + ObjectUtil.toString(send_obj)); } @@ -440,112 +566,16 @@ // if(is_debug){ trace("DangoClientFramework:send_obj_str:" + send_obj_str + ":" + DangoUtil.now2str()); } } /** - * receive data from server. - * データ受信のデータのパースなど - * - * @return Object - */ - public function parse_notice(byte_array:ByteArray):Array { - if(is_debug){ trace("DangoClientFramework:parse_notice:" + DangoUtil.now2str()); } - - // 変数定義 - var recv_data_orig:String = ""; - - // まず読めるデータをすべてByteArrayに入れる -// var byte_array:ByteArray = new ByteArray; -// socket.readBytes(byte_array, 0, socket.bytesAvailable); - - // 読んだデータの長さ取得 - var byte_read_size:uint = byte_array.length; - - if(recv_not_yet_size == 0){ // 未受信データが無ければ -// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size==0"); } - - if(byte_read_size < 6){ // きちんとデータが届いていなければ - this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "byte_read_size is too short.")); - return([]); - } - - // 長さを取得 - var byte_array_size:ByteArray = new ByteArray; - try{ - byte_array.readBytes(byte_array_size, 0, 5); - } catch(err:Error){ - this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "failed to byte_array.readBytes.")); - return([]); - } - - var encode_type:int = byte_array_size.readByte(); - recv_not_yet_size = byte_array_size.readUnsignedInt(); - var crlf:String = byte_array.readUTFBytes(1); - byte_read_size -= 6; -// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size=" + recv_not_yet_size); } - } - - // 読めているだけ読んで、その分recv_not_yet_sizeを減らす - if(recv_not_yet_size > byte_read_size){ -// if(is_debug){ trace("DangoClientFramework:byte_read_size=" + byte_read_size); } - recv_data_orig = byte_array.readUTFBytes(byte_read_size); - recv_not_yet_size -= byte_read_size; - }else{ -// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size=" + recv_not_yet_size); } - recv_data_orig = byte_array.readUTFBytes(recv_not_yet_size); - recv_not_yet_size = 0; - } - -// if(is_debug){ trace("DangoClientFramework:recv_data_orig:" + recv_data_orig); } - - // 全データを受信したかどうかを確認 - if(recv_not_yet_size == 0){ // 受信完了ならJSONパース - var recv_data:String = recv_not_yet_str + recv_data_orig; - recv_not_yet_str = ""; - -// if(is_debug){ trace("DangoClientFramework:recieve:data=" + ObjectUtil.toString(recv_data)); } - - var ret_obj_data:Array; - if(recv_data && recv_data != "" && recv_data != "\n"){ // データが空じゃないならdecode - ret_obj_data = JSON.decode(recv_data) as Array; - - } else { // データが空なら空データを作ってreturn - return([]); - } - - // ret_obj_dataがObjectでnoticeが存在しているかのチェック - if(!(ret_obj_data is Array) || !(ret_obj_data[0]["notice"] is String)){ -// if(!is_connect){ throw new DangoError("error:recieve data is invalid." , 29); } - throw new DangoError("error:recieve data is invalid." , 29); - } - -/* - if(ret_obj_data["notice"] == "_notice_sid"){ - if(is_debug){ trace("DangoClientFramework:recieve:_notice_sid:no response:" + receve_count + ":" + DangoUtil.now2str()); } - }else{ - var response_notice_name:String; - response_notice_name = "_response"; - if(is_debug){ trace("DangoClientFramework:sending:response:notice_name=" + ret_obj_data["notice"] + ":" + ret_obj_data["_id"] + ":" + receve_count + ":" + DangoUtil.now2str()); } - - this.send_action(response_notice_name, {"_id":ret_obj_data["_id"]}); // 受信完了確認の為に空データを送る - } -*/ - return(ret_obj_data); - - } else { // まだデータが残っているなら空を返す - recv_not_yet_str += recv_data_orig; - return([]); - } - } - - /** * dango_before_filter の雛形 * すべてのdango通知の前処理用のメソッド - * over writeすべし + * オーバーライドして使うもの * * @param evt:DangoReceiveEvent * @return void + */ protected function dango__before_filter(evt:Object):void { } - */ } }