templates/as3/org/rubyforge/dango/DangoClientFramework.as in dango_generator-0.1.0 vs templates/as3/org/rubyforge/dango/DangoClientFramework.as in dango_generator-0.2.2

- old
+ new

@@ -1,428 +1,537 @@ package org.rubyforge.dango { - /** - * Dangoのクライアントフレームワーク本体のクラス - * - */ - - import flash.net.*; - import flash.events.*; - import flash.text.*; - import flash.utils.*; - import flash.system.*; - import mx.utils.ObjectUtil; - - import com.adobe.serialization.json.JSON; - - import flash.events.IEventDispatcher; - import flash.events.EventDispatcher; - import flash.events.Event; + /** + * Dangoのクライアントフレームワーク本体のクラス + * + */ + + import flash.net.*; + import flash.events.*; + import flash.text.*; + import flash.utils.*; + import flash.system.*; + import flash.display.*; + import mx.utils.ObjectUtil; + + import com.adobe.serialization.json.JSON; + + import flash.events.IEventDispatcher; + import flash.events.EventDispatcher; + import flash.events.Event; - import org.rubyforge.dango.DangoUtil; - import org.rubyforge.dango.DangoErrorCode; + import org.rubyforge.dango.DangoUtil; + import org.rubyforge.dango.DangoErrorCode; - public class DangoClientFramework implements IEventDispatcher { + public class DangoClientFramework implements IEventDispatcher { - private var socket:Socket; //ソケット - private var dispatcher:EventDispatcher; // Event送出用 - - private var is_debug:Boolean; // Debugモードかどうかのフラグ - private var is_connect:Boolean = false; // 接続完了しているかどうか - - private var receve_count:uint = 0; // データ受信回数 - - private var recv_not_yet_size:uint = 0; // データ受信時のキャッシュ - private var recv_not_yet_str:String = ""; // データ受信時のキャッシュ - - private var polling_timer:Timer; // ポーリング(ハートビート)用タイマーの設定 - private var polling_timer_msec:uint = 5000; // ポーリング(ハートビート)用タイマーのミリ秒 - - private var delay_send_timer:Timer; // 遅延送信用のタイマーの設定 - private var delay_send_timer_msec:uint = 1500; // 遅延送信用のタイマーのミリ秒 - private var delay_send_cache:Array = []; // 遅延送信用のキャッシュ - -// private var server_host:String = "172.31.1.74"; -// private var server_host:String = "localhost"; -// private var server_port:int = 15000; - private var server_host:String; - private var server_port:int; - - public var sid:int; - - /** - * コンストラクタ - * - */ - public function DangoClientFramework(config:*, d:Boolean = false){ - is_debug = d; // Debugモードかどうかのフラグ - - // 設定ファイルの読み込み - server_host = config.server_host; - server_port = config.server_port; -// is_debug = config.debug; - is_debug = true; - - var policy_file_protocol:String = config.policy_file_protocol; -// var policy_file_port:uint = config.policy_file_port; - var policy_file_path:String = config.policy_file_path; - - - // Event送出用 - dispatcher = new EventDispatcher(this); - - // Security.sandboxType - trace("Security.sandboxType:" + Security.sandboxType); - - // policy_file -// if(!policy_file_protocol){ policy_file_protocol = "http" }; - if(!policy_file_path) { policy_file_path = "/crossdomain.xml" }; - - // ソケットの生成 - socket = new Socket(); - - // ソケットのイベントリスナーの追加 - socket.addEventListener(Event.CONNECT, connectHandler, false); - socket.addEventListener(Event.CONNECT, connectHandler, true); - socket.addEventListener(Event.CLOSE, closeHandler, false); - socket.addEventListener(Event.CLOSE, closeHandler, true); - socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, false); - socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, true); - socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false); - socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, true); - socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false); - socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, true); - trace("registered event handling."); - - // ポリシーファイルの読み込み - if(policy_file_protocol){ - var url_load_policy_file:String; -// url_load_policy_file = "xmlsocket://" + server_host + ":" + server_port; -// url_load_policy_file = "http://aiarebaba.hi-fi-net.com/crossdomain.xml"; - url_load_policy_file = "http://" + server_host + policy_file_path; - trace("url_load_policy_file=" + url_load_policy_file); - Security.loadPolicyFile(url_load_policy_file); - } - - // 接続 - try{ - trace("connectiong... host=" + server_host + " port=" + server_port); - socket.connect(server_host, server_port); - trace("connected host=" + server_host + " port=" + server_port); - } catch(err:Error){ - trace("connect error err=" + err + " name=" + err.name + " message=" + err.message); - return(void); - } - - // polling用タイマーの設定 - var polling_timer:Timer = new Timer(polling_timer_msec, 0); // タイマーの追加 - polling_timer.addEventListener(TimerEvent.TIMER, polling_callback); // イベントリスナーの発行 - polling_timer.start(); // タイマーの作動開始 - - // 遅延送信用タイマーの設定 - 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(); // タイマーの作動開始 - } - - //接続イベントの処理 - private function connectHandler(evt:Event):void { - is_connect = true; - var msg:String = "DangoClientFramework:connectHandler"; - if(is_debug){ trace(msg); } - } - - //切断イベントの処理 - private function closeHandler(evt:Event):void { - // タイマーが動いていれば止める - if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } - - is_connect = false; - var msg:String = "DangoClientFramework:closeHandler"; - if(is_debug){ trace(msg); } - this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.CloseError, msg)); - } - - //セキュリティエラーイベントの処理 - private function securityErrorHandler(evt:SecurityErrorEvent):void { - // タイマーが動いていれば止める - if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } - - is_connect = false; - var msg:String = "DangoClientFramework:securityErrorHandler:text=" + evt.text ; - - if(is_debug){ trace(msg); } - this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.SecurityError, msg)); - } - - //IOエラーイベントの処理 - private function ioErrorHandler(evt:IOErrorEvent):void { - // タイマーが動いていれば止める - if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } - - is_connect = false; - var msg:String = "DangoClientFramework:ioErrorHandler"; - if(is_debug){ trace(msg); } - this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, msg)); - } - - //プログレスイベントの処理(呼び出し用イベントのディスパッチ) - private function socketDataHandler(evt:ProgressEvent):void { - receve_count ++; - if(is_debug){ trace("DangoClientFramework:socketDataHandler:" + receve_count); } - var receive_data:Object = this.receive_notice(); - - if(recv_not_yet_size == 0){ // 未受信データが無ければ - if(receive_data != {}){ // データが空なら無視する - var notice_name:String = receive_data["notice"]; - - if(notice_name == "_notice_sid"){ // 接続直後のsid通知なら - this.sid = receive_data["_sid"]; -// if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + DangoUtil.now2str()); } - if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + receve_count); } - - } else if(notice_name == "_heart_beat"){ // heart beat通知なら - if(is_debug){ trace("DangoClientFramework:_heart_beat:" + receve_count); } - - } else { // 通常のデータならイベント発生 - if(is_debug){ trace("DangoClientFramework:dispatchEvent:dango_" + notice_name + ":" + receve_count); } - this.dispatchEvent(new DangoReceiveEvent("dango_" + notice_name, receive_data)); - } - } else { // データが空なら -// if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); } - if(is_debug){ trace("DangoClientFramework:receive_data is empty."); } - } - } - } - - // Event送出用 - public function addEventListener(type:String, listener:Function, - useCapture:Boolean = false, - priority:int = 0, - useWeakReference:Boolean = false):void{ - dispatcher.addEventListener(type, listener, useCapture, priority); - } - public function dispatchEvent(evt:Event):Boolean{ - return dispatcher.dispatchEvent(evt); - } - public function hasEventListener(type:String):Boolean{ - return dispatcher.hasEventListener(type); - } - public function removeEventListener(type:String, listener:Function, - useCapture:Boolean = false):void{ - dispatcher.removeEventListener(type, listener, useCapture); - } - public function willTrigger(type:String):Boolean { - return dispatcher.willTrigger(type); - } - - - /** - * polling_callback - * ハートビートを送る - * - * @param evt:TimerEvent - * @return void - */ - public function polling_callback(evt:TimerEvent):void { - 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 = String((new Date()).time) + String(this.sid); - if(is_debug){ trace("DangoClientFramework:send _notice_heart_beat:" + hb_id + ":" + DangoUtil.now2str()); } - this.send_action("_notice_heart_beat", { "_hb_id": hb_id}); // ハートビート送信 - } - } - - /** - * delay_send_callback - * 遅延送信用タイマーコールバック - * - * @param socket:Socket - * @param send_obj:Object - * @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); } - if(socket.connected){ - var send_obj_dup:Object; - var i:uint; - - for (i = 0; i < 5; i++) { - if(delay_send_cache.length == 0) { break; } - send_obj_dup = delay_send_cache.pop(); - // データをすぐ送信 - this.send_data_to_server(send_obj_dup); - if(is_debug){ trace("DangoClientFramework:delay_send_callback:sent:" + DangoUtil.now2str()); } - } - } - } - - /** - * send data to server. - * クライアント側から使うサーバーへのデータ送信メソッド - * - * @param socket:Socket - * @param send_obj:Object - * @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()); } - -// if(!is_connect){ throw new DangoError("error:not connect" , 29); } // 接続されていない場合はエラー - - // 送信データの作成 - var send_obj_dup:Object = ObjectUtil.copy(send_obj); - send_obj_dup["action"] = action_name; - - // delayフラグがあったり、接続がまだなら、遅延送信用のキャッシュにデータを入れる - if(delay || !is_connect){ - delay_send_cache.push(send_obj_dup); - - if(is_debug){ trace("DangoClientFramework:send_action:delay_pull:" + action_name + ":" + DangoUtil.now2str()); } - return(void); - } - - // データをすぐ送信 - this.send_data_to_server(send_obj_dup); - if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); } - } - - /** - * send data to server. - * フレームワーク側のデータ送信の一般処理 - * - * @param socket:Socket - * @param send_obj:Object - * @return void - */ - public function send_data_to_server( send_obj:Object ):void { -// if(is_debug){ trace("DangoClientFramework:send_data_to_server:send_obj=" + ObjectUtil.toString(send_obj)); } - - var type:int = 0; - - // データが空ならJSONencodeしない - var send_obj_str:String; - if(send_obj == null){ - send_obj_str = "\n"; - } else { - send_obj_str = JSON.encode(send_obj) + "\n"; - } + private var socket:Socket; //ソケット + private var dispatcher:EventDispatcher; // Event送出用 + + private var is_debug:Boolean; // Debugモードかどうかのフラグ + private var is_connect:Boolean = false; // 接続完了しているかどうか + + private var receve_count:uint = 0; // データ受信回数 + private var frame_rate:uint = 24; // デフォルトのフレームレート(想定値) + private var receive_cache:Array = []; // 受信データの一時保管用のキャッシュ + + private var recv_not_yet_size:uint = 0; // データ受信時のキャッシュサイズ + private var recv_not_yet_str:String = ""; // データ受信時のキャッシュデータ + + private var polling_timer:Timer; // ポーリング(ハートビート)用タイマーの設定 + private var polling_timer_msec:uint = 5000; // ポーリング(ハートビート)用タイマーのミリ秒 + + private var delay_send_timer:Timer; // 遅延送信用のタイマーの設定 + private var delay_send_timer_msec:uint = 1500; // 遅延送信用のタイマーのミリ秒 + private var delay_send_cache:Array = []; // 遅延送信用のキャッシュ + + private var recv_timer_msec:uint; // 受信用タイマーの実行間隔 + private var recv_timer:Timer; // 受信用タイマーの追加 + private var recv_last_date:Date = new Date(); // 受信用処理落ちチェック用 + +// private var server_host:String = "172.31.1.74"; +// private var server_host:String = "localhost"; +// private var server_port:int = 15000; + private var server_host:String; + private var server_port:int; + + public var sid:int; + + /** + * コンストラクタ + * + */ + public function DangoClientFramework(config:*, disp_obj:DisplayObject = null){ +// is_debug = d; // Debugモードかどうかのフラグ + + if(disp_obj){ + frame_rate = disp_obj.stage.frameRate; // フレームレート + } + + // 設定ファイルの読み込み + server_host = config.server_host; + server_port = config.server_port; + is_debug = config.debug; +// is_debug = true; + + var policy_file_protocol:String = config.policy_file_protocol; +// var policy_file_port:uint = config.policy_file_port; + var policy_file_path:String = config.policy_file_path; + + + // Event送出用 + dispatcher = new EventDispatcher(this); + + // Security.sandboxType + trace("Security.sandboxType:" + Security.sandboxType); + + // policy_file +// if(!policy_file_protocol){ policy_file_protocol = "http" }; + if(!policy_file_path) { policy_file_path = "/crossdomain.xml" }; + + // ソケットの生成 + socket = new Socket(); + + // ソケットのイベントリスナーの追加 + socket.addEventListener(Event.CONNECT, connectHandler, false); + socket.addEventListener(Event.CONNECT, connectHandler, true); + socket.addEventListener(Event.CLOSE, closeHandler, false); + socket.addEventListener(Event.CLOSE, closeHandler, true); + socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, false); + socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, true); + socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false); + socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, true); + socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false); + socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, true); + trace("registered event handling."); + + // ポリシーファイルの読み込み + if(policy_file_protocol){ + var url_load_policy_file:String; +// url_load_policy_file = "xmlsocket://" + server_host + ":" + server_port; +// url_load_policy_file = "http://aiarebaba.hi-fi-net.com/crossdomain.xml"; + url_load_policy_file = "http://" + server_host + policy_file_path; + trace("url_load_policy_file=" + url_load_policy_file); + Security.loadPolicyFile(url_load_policy_file); + } + + // 接続 + try{ + trace("connectiong... host=" + server_host + " port=" + server_port); + socket.connect(server_host, server_port); + trace("connected host=" + server_host + " port=" + server_port); + } catch(err:Error){ + trace("connect error err=" + err + " name=" + err.name + " message=" + err.message); + return(void); + } + + // polling用タイマーの設定 + var polling_timer:Timer = new Timer(polling_timer_msec, 0); // タイマーの追加 + polling_timer.addEventListener(TimerEvent.TIMER, polling_callback); // イベントリスナーの発行 + polling_timer.start(); // タイマーの作動開始 + + // 遅延送信用タイマーの設定 + 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(); // タイマーの作動開始 + + // fps用タイマーの設定(3フレームごとに動かすよう変更) + recv_timer_msec = uint((1000 * 3) / frame_rate); + if(is_debug){ trace("DangoClientFramework:recv_timer_msec:" + recv_timer_msec); } + recv_timer = new Timer(recv_timer_msec, 0); // タイマーの追加 + recv_timer.addEventListener(TimerEvent.TIMER, recv_callback); // イベントリスナーの発行 + recv_timer.start(); // タイマーの作動開始 + + // 接続完了のときに接続完了をサーバーに通知するためのハートビート送信 + var hb_id:String = make_heartbeat(); + this.send_action("_notice_heart_beat", { "_hb_id": hb_id}, true); // ハートビート送信 + } + + //接続イベントの処理 + private function connectHandler(evt:Event):void { + is_connect = true; + var msg:String = "DangoClientFramework:connectHandler:" + DangoUtil.now2str(); + if(is_debug){ trace(msg); } + } + + //切断イベントの処理 + 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)); + } + + //セキュリティエラーイベントの処理 + private function securityErrorHandler(evt:SecurityErrorEvent):void { + // タイマーが動いていれば止める + if(polling_timer != null && polling_timer.running){ polling_timer.stop(); } + + is_connect = false; + var msg:String = "DangoClientFramework:securityErrorHandler:text=" + evt.text + ":" + DangoUtil.now2str(); + + if(is_debug){ trace(msg); } + this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.SecurityError, msg)); + } + + //IOエラーイベントの処理 + 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)); + } + +/* + //プログレスイベントの処理(呼び出し用イベントのディスパッチ) + private function socketDataHandler(evt:ProgressEvent):void { + receve_count ++; + if(is_debug){ trace("DangoClientFramework:socketDataHandler:" + receve_count); } + var receive_data:Object = this.receive_notice(); + + if(recv_not_yet_size == 0){ // 未受信データが無ければ + if(receive_data != {}){ // データが空なら無視する + var notice_name:String = receive_data["notice"]; + + if(notice_name == "_notice_sid"){ // 接続直後のsid通知なら + this.sid = receive_data["_sid"]; +// if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + DangoUtil.now2str()); } + if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + receve_count); } + + } else if(notice_name == "_heart_beat"){ // heart beat通知なら + if(is_debug){ trace("DangoClientFramework:_heart_beat:" + receve_count); } + + } else { // 通常のデータならイベント発生 + if(is_debug){ trace("DangoClientFramework:dispatchEvent:dango_" + notice_name + ":" + receve_count); } + this.dispatchEvent(new DangoReceiveEvent("dango_" + notice_name, receive_data)); + } + } else { // データが空なら +// if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); } + if(is_debug){ trace("DangoClientFramework:receive_data is empty."); } + } + } + } +*/ + + // プログレスイベントの処理(呼び出し用イベントのディスパッチ) + // とにかくキャッシュに入れるだけ + 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_cache.push([byte_array, receve_count]); + } - var send_obj_size:int = DangoUtil.string_byte_length(send_obj_str); - -// if(is_debug){ trace("DangoClientFramework:send:" + type + ":" + send_obj_size + ":" + send_obj_str); } + // Event送出用 + public function addEventListener(type:String, listener:Function, + useCapture:Boolean = false, + priority:int = 0, + useWeakReference:Boolean = false):void{ + dispatcher.addEventListener(type, listener, useCapture, priority); + } + public function dispatchEvent(evt:Event):Boolean{ + return dispatcher.dispatchEvent(evt); + } + public function hasEventListener(type:String):Boolean{ + return dispatcher.hasEventListener(type); + } + public function removeEventListener(type:String, listener:Function, + useCapture:Boolean = false):void{ + dispatcher.removeEventListener(type, listener, useCapture); + } + public function willTrigger(type:String):Boolean { + return dispatcher.willTrigger(type); + } + + + /** + * recv_callback + * フレームレート単位で動く処理(キャッシュにデータがあればデータ受信) + * + * @param evt:TimerEvent + * @return void + */ + public function recv_callback(evt:TimerEvent):void { + if(is_debug){ trace("DangoClientFramework:recv_callback:" + DangoUtil.now2str()); } + + // 前回から時間がかかりすぎている(処理落ち仕掛けている場合は)スキップ + var start_date:Date = new Date(); + if(is_debug){ trace("DangoClientFramework:recv_last_date.time=" + recv_last_date.time + " start_date.time=" + start_date.time); } + if(recv_last_date.time > start_date.time - (recv_timer_msec * 1.5)){ + if(receive_cache.length > 0){ +// while(receive_cache.length > 0){ + if(is_debug){ trace("DangoClientFramework:recv_callback:receive_cache.length=" + receive_cache.length + ":" + DangoUtil.now2str()); } + var arr:Array = receive_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.receive_notice(byte_array); + + 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"]; + + if(notice_name == "_notice_sid"){ // 接続直後のsid通知なら + this.sid = receive_data[i]["_sid"]; + if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + " recv_c:" + recv_c); } + + } else if(notice_name == "_heart_beat"){ // heart beat通知なら + if(is_debug){ trace("DangoClientFramework:_heart_beat: recv_c:" + recv_c); } + + } else { // 通常のデータならイベント発生 + if(is_debug){ trace("DangoClientFramework:dispatchEvent:dango_" + notice_name + ": recv_c:" + recv_c + ":" + i); } + this.dispatchEvent(new DangoReceiveEvent("dango_" + notice_name, receive_data[i])); + } + } + } else { // データが空なら + // if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); } + if(is_debug){ trace("DangoClientFramework:receive_data is empty."); } + } + } + +/* + // 処理に時間がかかりすぎている場合は、スキップさせる(while用) + if(is_debug){ trace("DangoClientFramework:recv_callback:end_date:" + DangoUtil.now2str()); } + var end_date:Date = new Date(); + if(start_date.time < end_date.time - recv_timer_msec){ + if(is_debug){ trace("DangoClientFramework:break"); } + break; + } +*/ + } + } + + recv_last_date = new Date(); + } + + /** + * polling_callback + * ハートビート用タイマーコールバック + * + * @param evt:TimerEvent + * @return void + */ + public function polling_callback(evt:TimerEvent):void { + 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(); +// if(is_debug){ trace("DangoClientFramework:send _notice_heart_beat:" + hb_id + ":" + DangoUtil.now2str()); } + this.send_action("_notice_heart_beat", { "_hb_id": hb_id}); // ハートビート送信 + } + } + + /** + * polling_callback + * ハートビートの作成 + * + * @return String + */ + public function make_heartbeat():String { + return(String((new Date()).time) + String(this.sid)); + } + + /** + * delay_send_callback + * 遅延送信用タイマーコールバック + * + * @param socket:Socket + * @param send_obj:Object + * @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); } + if(socket.connected){ + var send_obj_dup:Array; + var i:uint; + + for (i = 0; i < 5; i++) { + if(delay_send_cache.length == 0) { break; } + send_obj_dup = delay_send_cache.pop(); + // データをすぐ送信 + this.send_data_to_server(send_obj_dup); + if(is_debug){ trace("DangoClientFramework:delay_send_callback:sent:" + DangoUtil.now2str()); } + } + } + } + + /** + * send data to server. + * クライアント側から使うサーバーへのデータ送信メソッド + * + * @param socket:Socket + * @param send_obj:Object + * @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()); } + +// if(!is_connect){ throw new DangoError("error:not connect" , 29); } // 接続されていない場合はエラー + + // 送信データの作成 + var send_obj_dup:Object = ObjectUtil.copy(send_obj); + send_obj_dup["action"] = action_name; + send_obj_dup["_return_id"] = (new Date()).time; + + // delayフラグがあったり、接続がまだなら、遅延送信用のキャッシュにデータを入れる + if(delay || !is_connect){ + delay_send_cache.push([send_obj_dup]); + + if(is_debug){ trace("DangoClientFramework:send_action:delay_pull:" + action_name + ":" + DangoUtil.now2str()); } + return(void); + } + + // データをすぐ送信 + this.send_data_to_server([send_obj_dup]); + if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); } + } + + /** + * send data to server. + * フレームワーク側のデータ送信の一般処理 + * + * @param socket:Socket + * @param send_obj:Object + * @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)); } + + var type:int = 0; + + // データが空ならJSONencodeしない + var send_obj_str:String; + if(send_obj == null){ + send_obj_str = "\n"; + } else { + send_obj_str = JSON.encode(send_obj) + "\n"; + } - // 長さ送信 - var byte_array:ByteArray = new ByteArray; - byte_array.writeByte(type); - byte_array.writeUnsignedInt(send_obj_size); + var send_obj_size:int = DangoUtil.string_byte_length(send_obj_str); + +// if(is_debug){ trace("DangoClientFramework:send:" + type + ":" + send_obj_size + ":" + send_obj_str); } - socket.writeBytes(byte_array, 0, 5); - socket.writeUTFBytes("\n"); - socket.flush(); + // 長さ送信 + var byte_array:ByteArray = new ByteArray; + byte_array.writeByte(type); + byte_array.writeUnsignedInt(send_obj_size); - // データ送信 - socket.writeUTFBytes(send_obj_str); - socket.flush(); - -// if(is_debug){ trace("DangoClientFramework:send_obj_str:" + send_obj_str + ":" + DangoUtil.now2str()); } - } - - /** - * receive data from server. - * フレームワーク側のデータ受信の一般処理 - * - * @return Object - */ - public function receive_notice():Object { - if(is_debug){ trace("DangoClientFramework:receive_notice:" + receve_count + ":" + DangoUtil.now2str()); } + socket.writeBytes(byte_array, 0, 5); + socket.writeUTFBytes("\n"); + socket.flush(); - // 変数定義 - var recv_data_orig:String = ""; - var bytes_available:uint; - - // まず読めるデータをすべて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 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:Object; - if(recv_data && recv_data != "" && recv_data != "\n"){ // データが空じゃないならdecode - ret_obj_data = JSON.decode(recv_data) as Object; - - } else { // データが空なら空データを作ってreturn - ret_obj_data = {}; - return(ret_obj_data); - } - - // ret_obj_dataがObjectでnoticeが存在しているかのチェック - if(!(ret_obj_data is Object) || !(ret_obj_data["notice"] is String)){ - if(!is_connect){ 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({}); - } - } - - } + // データ送信 + socket.writeUTFBytes(send_obj_str); + socket.flush(); + +// if(is_debug){ trace("DangoClientFramework:send_obj_str:" + send_obj_str + ":" + DangoUtil.now2str()); } + } + + /** + * receive data from server. + * フレームワーク側のデータ受信の一般処理 + * + * @return Object + */ + public function receive_notice(byte_array:ByteArray):Array { + if(is_debug){ trace("DangoClientFramework:receive_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 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([]); + } + } + + } }