dango_generator 0.1.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,428 +1,537 @@
|
|
1
1
|
|
2
2
|
package org.rubyforge.dango {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
3
|
+
/**
|
4
|
+
* Dangoのクライアントフレームワーク本体のクラス
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
|
8
|
+
import flash.net.*;
|
9
|
+
import flash.events.*;
|
10
|
+
import flash.text.*;
|
11
|
+
import flash.utils.*;
|
12
|
+
import flash.system.*;
|
13
|
+
import flash.display.*;
|
14
|
+
import mx.utils.ObjectUtil;
|
15
|
+
|
16
|
+
import com.adobe.serialization.json.JSON;
|
17
|
+
|
18
|
+
import flash.events.IEventDispatcher;
|
19
|
+
import flash.events.EventDispatcher;
|
20
|
+
import flash.events.Event;
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
import org.rubyforge.dango.DangoUtil;
|
23
|
+
import org.rubyforge.dango.DangoErrorCode;
|
23
24
|
|
24
|
-
|
25
|
+
public class DangoClientFramework implements IEventDispatcher {
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
//
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
// var send_obj:Object = null;
|
230
|
-
// this.send_data_to_server(send_obj);
|
231
|
-
|
232
|
-
var hb_id:String = String((new Date()).time) + String(this.sid);
|
233
|
-
if(is_debug){ trace("DangoClientFramework:send _notice_heart_beat:" + hb_id + ":" + DangoUtil.now2str()); }
|
234
|
-
this.send_action("_notice_heart_beat", { "_hb_id": hb_id}); // ハートビート送信
|
235
|
-
}
|
236
|
-
}
|
237
|
-
|
238
|
-
/**
|
239
|
-
* delay_send_callback
|
240
|
-
* 遅延送信用タイマーコールバック
|
241
|
-
*
|
242
|
-
* @param socket:Socket
|
243
|
-
* @param send_obj:Object
|
244
|
-
* @return void
|
245
|
-
*/
|
246
|
-
public function delay_send_callback(evt:TimerEvent):void {
|
247
|
-
// if(is_debug){ trace("DangoClientFramework:delay_send_callback:evt:" + evt); }
|
248
|
-
if(!is_connect){ return(void); }
|
249
|
-
if(socket.connected){
|
250
|
-
var send_obj_dup:Object;
|
251
|
-
var i:uint;
|
252
|
-
|
253
|
-
for (i = 0; i < 5; i++) {
|
254
|
-
if(delay_send_cache.length == 0) { break; }
|
255
|
-
send_obj_dup = delay_send_cache.pop();
|
256
|
-
// データをすぐ送信
|
257
|
-
this.send_data_to_server(send_obj_dup);
|
258
|
-
if(is_debug){ trace("DangoClientFramework:delay_send_callback:sent:" + DangoUtil.now2str()); }
|
259
|
-
}
|
260
|
-
}
|
261
|
-
}
|
262
|
-
|
263
|
-
/**
|
264
|
-
* send data to server.
|
265
|
-
* クライアント側から使うサーバーへのデータ送信メソッド
|
266
|
-
*
|
267
|
-
* @param socket:Socket
|
268
|
-
* @param send_obj:Object
|
269
|
-
* @return void
|
270
|
-
*/
|
271
|
-
public function send_action(action_name:String, send_obj:Object, delay:Boolean=false):void {
|
272
|
-
if(is_debug){ trace("DangoClientFramework:send_action:start:" + action_name + ":" + DangoUtil.now2str()); }
|
273
|
-
|
274
|
-
// if(!is_connect){ throw new DangoError("error:not connect" , 29); } // 接続されていない場合はエラー
|
275
|
-
|
276
|
-
// 送信データの作成
|
277
|
-
var send_obj_dup:Object = ObjectUtil.copy(send_obj);
|
278
|
-
send_obj_dup["action"] = action_name;
|
279
|
-
|
280
|
-
// delayフラグがあったり、接続がまだなら、遅延送信用のキャッシュにデータを入れる
|
281
|
-
if(delay || !is_connect){
|
282
|
-
delay_send_cache.push(send_obj_dup);
|
283
|
-
|
284
|
-
if(is_debug){ trace("DangoClientFramework:send_action:delay_pull:" + action_name + ":" + DangoUtil.now2str()); }
|
285
|
-
return(void);
|
286
|
-
}
|
287
|
-
|
288
|
-
// データをすぐ送信
|
289
|
-
this.send_data_to_server(send_obj_dup);
|
290
|
-
if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); }
|
291
|
-
}
|
292
|
-
|
293
|
-
/**
|
294
|
-
* send data to server.
|
295
|
-
* フレームワーク側のデータ送信の一般処理
|
296
|
-
*
|
297
|
-
* @param socket:Socket
|
298
|
-
* @param send_obj:Object
|
299
|
-
* @return void
|
300
|
-
*/
|
301
|
-
public function send_data_to_server( send_obj:Object ):void {
|
302
|
-
// if(is_debug){ trace("DangoClientFramework:send_data_to_server:send_obj=" + ObjectUtil.toString(send_obj)); }
|
303
|
-
|
304
|
-
var type:int = 0;
|
305
|
-
|
306
|
-
// データが空ならJSONencodeしない
|
307
|
-
var send_obj_str:String;
|
308
|
-
if(send_obj == null){
|
309
|
-
send_obj_str = "\n";
|
310
|
-
} else {
|
311
|
-
send_obj_str = JSON.encode(send_obj) + "\n";
|
312
|
-
}
|
27
|
+
private var socket:Socket; //ソケット
|
28
|
+
private var dispatcher:EventDispatcher; // Event送出用
|
29
|
+
|
30
|
+
private var is_debug:Boolean; // Debugモードかどうかのフラグ
|
31
|
+
private var is_connect:Boolean = false; // 接続完了しているかどうか
|
32
|
+
|
33
|
+
private var receve_count:uint = 0; // データ受信回数
|
34
|
+
private var frame_rate:uint = 24; // デフォルトのフレームレート(想定値)
|
35
|
+
private var receive_cache:Array = []; // 受信データの一時保管用のキャッシュ
|
36
|
+
|
37
|
+
private var recv_not_yet_size:uint = 0; // データ受信時のキャッシュサイズ
|
38
|
+
private var recv_not_yet_str:String = ""; // データ受信時のキャッシュデータ
|
39
|
+
|
40
|
+
private var polling_timer:Timer; // ポーリング(ハートビート)用タイマーの設定
|
41
|
+
private var polling_timer_msec:uint = 5000; // ポーリング(ハートビート)用タイマーのミリ秒
|
42
|
+
|
43
|
+
private var delay_send_timer:Timer; // 遅延送信用のタイマーの設定
|
44
|
+
private var delay_send_timer_msec:uint = 1500; // 遅延送信用のタイマーのミリ秒
|
45
|
+
private var delay_send_cache:Array = []; // 遅延送信用のキャッシュ
|
46
|
+
|
47
|
+
private var recv_timer_msec:uint; // 受信用タイマーの実行間隔
|
48
|
+
private var recv_timer:Timer; // 受信用タイマーの追加
|
49
|
+
private var recv_last_date:Date = new Date(); // 受信用処理落ちチェック用
|
50
|
+
|
51
|
+
// private var server_host:String = "172.31.1.74";
|
52
|
+
// private var server_host:String = "localhost";
|
53
|
+
// private var server_port:int = 15000;
|
54
|
+
private var server_host:String;
|
55
|
+
private var server_port:int;
|
56
|
+
|
57
|
+
public var sid:int;
|
58
|
+
|
59
|
+
/**
|
60
|
+
* コンストラクタ
|
61
|
+
*
|
62
|
+
*/
|
63
|
+
public function DangoClientFramework(config:*, disp_obj:DisplayObject = null){
|
64
|
+
// is_debug = d; // Debugモードかどうかのフラグ
|
65
|
+
|
66
|
+
if(disp_obj){
|
67
|
+
frame_rate = disp_obj.stage.frameRate; // フレームレート
|
68
|
+
}
|
69
|
+
|
70
|
+
// 設定ファイルの読み込み
|
71
|
+
server_host = config.server_host;
|
72
|
+
server_port = config.server_port;
|
73
|
+
is_debug = config.debug;
|
74
|
+
// is_debug = true;
|
75
|
+
|
76
|
+
var policy_file_protocol:String = config.policy_file_protocol;
|
77
|
+
// var policy_file_port:uint = config.policy_file_port;
|
78
|
+
var policy_file_path:String = config.policy_file_path;
|
79
|
+
|
80
|
+
|
81
|
+
// Event送出用
|
82
|
+
dispatcher = new EventDispatcher(this);
|
83
|
+
|
84
|
+
// Security.sandboxType
|
85
|
+
trace("Security.sandboxType:" + Security.sandboxType);
|
86
|
+
|
87
|
+
// policy_file
|
88
|
+
// if(!policy_file_protocol){ policy_file_protocol = "http" };
|
89
|
+
if(!policy_file_path) { policy_file_path = "/crossdomain.xml" };
|
90
|
+
|
91
|
+
// ソケットの生成
|
92
|
+
socket = new Socket();
|
93
|
+
|
94
|
+
// ソケットのイベントリスナーの追加
|
95
|
+
socket.addEventListener(Event.CONNECT, connectHandler, false);
|
96
|
+
socket.addEventListener(Event.CONNECT, connectHandler, true);
|
97
|
+
socket.addEventListener(Event.CLOSE, closeHandler, false);
|
98
|
+
socket.addEventListener(Event.CLOSE, closeHandler, true);
|
99
|
+
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, false);
|
100
|
+
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler, true);
|
101
|
+
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, false);
|
102
|
+
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler, true);
|
103
|
+
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, false);
|
104
|
+
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, true);
|
105
|
+
trace("registered event handling.");
|
106
|
+
|
107
|
+
// ポリシーファイルの読み込み
|
108
|
+
if(policy_file_protocol){
|
109
|
+
var url_load_policy_file:String;
|
110
|
+
// url_load_policy_file = "xmlsocket://" + server_host + ":" + server_port;
|
111
|
+
// url_load_policy_file = "http://aiarebaba.hi-fi-net.com/crossdomain.xml";
|
112
|
+
url_load_policy_file = "http://" + server_host + policy_file_path;
|
113
|
+
trace("url_load_policy_file=" + url_load_policy_file);
|
114
|
+
Security.loadPolicyFile(url_load_policy_file);
|
115
|
+
}
|
116
|
+
|
117
|
+
// 接続
|
118
|
+
try{
|
119
|
+
trace("connectiong... host=" + server_host + " port=" + server_port);
|
120
|
+
socket.connect(server_host, server_port);
|
121
|
+
trace("connected host=" + server_host + " port=" + server_port);
|
122
|
+
} catch(err:Error){
|
123
|
+
trace("connect error err=" + err + " name=" + err.name + " message=" + err.message);
|
124
|
+
return(void);
|
125
|
+
}
|
126
|
+
|
127
|
+
// polling用タイマーの設定
|
128
|
+
var polling_timer:Timer = new Timer(polling_timer_msec, 0); // タイマーの追加
|
129
|
+
polling_timer.addEventListener(TimerEvent.TIMER, polling_callback); // イベントリスナーの発行
|
130
|
+
polling_timer.start(); // タイマーの作動開始
|
131
|
+
|
132
|
+
// 遅延送信用タイマーの設定
|
133
|
+
var delay_send_timer:Timer = new Timer(delay_send_timer_msec, 0); // タイマーの追加
|
134
|
+
delay_send_timer.addEventListener(TimerEvent.TIMER, delay_send_callback); // イベントリスナーの発行
|
135
|
+
delay_send_timer.start(); // タイマーの作動開始
|
136
|
+
|
137
|
+
// fps用タイマーの設定(3フレームごとに動かすよう変更)
|
138
|
+
recv_timer_msec = uint((1000 * 3) / frame_rate);
|
139
|
+
if(is_debug){ trace("DangoClientFramework:recv_timer_msec:" + recv_timer_msec); }
|
140
|
+
recv_timer = new Timer(recv_timer_msec, 0); // タイマーの追加
|
141
|
+
recv_timer.addEventListener(TimerEvent.TIMER, recv_callback); // イベントリスナーの発行
|
142
|
+
recv_timer.start(); // タイマーの作動開始
|
143
|
+
|
144
|
+
// 接続完了のときに接続完了をサーバーに通知するためのハートビート送信
|
145
|
+
var hb_id:String = make_heartbeat();
|
146
|
+
this.send_action("_notice_heart_beat", { "_hb_id": hb_id}, true); // ハートビート送信
|
147
|
+
}
|
148
|
+
|
149
|
+
//接続イベントの処理
|
150
|
+
private function connectHandler(evt:Event):void {
|
151
|
+
is_connect = true;
|
152
|
+
var msg:String = "DangoClientFramework:connectHandler:" + DangoUtil.now2str();
|
153
|
+
if(is_debug){ trace(msg); }
|
154
|
+
}
|
155
|
+
|
156
|
+
//切断イベントの処理
|
157
|
+
private function closeHandler(evt:Event):void {
|
158
|
+
// タイマーが動いていれば止める
|
159
|
+
if(polling_timer != null && polling_timer.running){ polling_timer.stop(); }
|
160
|
+
|
161
|
+
is_connect = false;
|
162
|
+
var msg:String = "DangoClientFramework:closeHandler:" + DangoUtil.now2str();
|
163
|
+
if(is_debug){ trace(msg); }
|
164
|
+
this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.CloseError, msg));
|
165
|
+
}
|
166
|
+
|
167
|
+
//セキュリティエラーイベントの処理
|
168
|
+
private function securityErrorHandler(evt:SecurityErrorEvent):void {
|
169
|
+
// タイマーが動いていれば止める
|
170
|
+
if(polling_timer != null && polling_timer.running){ polling_timer.stop(); }
|
171
|
+
|
172
|
+
is_connect = false;
|
173
|
+
var msg:String = "DangoClientFramework:securityErrorHandler:text=" + evt.text + ":" + DangoUtil.now2str();
|
174
|
+
|
175
|
+
if(is_debug){ trace(msg); }
|
176
|
+
this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.SecurityError, msg));
|
177
|
+
}
|
178
|
+
|
179
|
+
//IOエラーイベントの処理
|
180
|
+
private function ioErrorHandler(evt:IOErrorEvent):void {
|
181
|
+
// タイマーが動いていれば止める
|
182
|
+
if(polling_timer != null && polling_timer.running){ polling_timer.stop(); }
|
183
|
+
|
184
|
+
is_connect = false;
|
185
|
+
var msg:String = "DangoClientFramework:ioErrorHandler:" + DangoUtil.now2str();
|
186
|
+
if(is_debug){ trace(msg); }
|
187
|
+
this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, msg));
|
188
|
+
}
|
189
|
+
|
190
|
+
/*
|
191
|
+
//プログレスイベントの処理(呼び出し用イベントのディスパッチ)
|
192
|
+
private function socketDataHandler(evt:ProgressEvent):void {
|
193
|
+
receve_count ++;
|
194
|
+
if(is_debug){ trace("DangoClientFramework:socketDataHandler:" + receve_count); }
|
195
|
+
var receive_data:Object = this.receive_notice();
|
196
|
+
|
197
|
+
if(recv_not_yet_size == 0){ // 未受信データが無ければ
|
198
|
+
if(receive_data != {}){ // データが空なら無視する
|
199
|
+
var notice_name:String = receive_data["notice"];
|
200
|
+
|
201
|
+
if(notice_name == "_notice_sid"){ // 接続直後のsid通知なら
|
202
|
+
this.sid = receive_data["_sid"];
|
203
|
+
// if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + DangoUtil.now2str()); }
|
204
|
+
if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + ":" + receve_count); }
|
205
|
+
|
206
|
+
} else if(notice_name == "_heart_beat"){ // heart beat通知なら
|
207
|
+
if(is_debug){ trace("DangoClientFramework:_heart_beat:" + receve_count); }
|
208
|
+
|
209
|
+
} else { // 通常のデータならイベント発生
|
210
|
+
if(is_debug){ trace("DangoClientFramework:dispatchEvent:dango_" + notice_name + ":" + receve_count); }
|
211
|
+
this.dispatchEvent(new DangoReceiveEvent("dango_" + notice_name, receive_data));
|
212
|
+
}
|
213
|
+
} else { // データが空なら
|
214
|
+
// if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); }
|
215
|
+
if(is_debug){ trace("DangoClientFramework:receive_data is empty."); }
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
*/
|
220
|
+
|
221
|
+
// プログレスイベントの処理(呼び出し用イベントのディスパッチ)
|
222
|
+
// とにかくキャッシュに入れるだけ
|
223
|
+
private function socketDataHandler(evt:ProgressEvent):void {
|
224
|
+
receve_count ++;
|
225
|
+
if(is_debug){ trace("DangoClientFramework:socketDataHandler:" + receve_count + ":start:" + DangoUtil.now2str()); }
|
226
|
+
var byte_array:ByteArray = new ByteArray;
|
227
|
+
socket.readBytes(byte_array, 0, socket.bytesAvailable);
|
228
|
+
receive_cache.push([byte_array, receve_count]);
|
229
|
+
}
|
313
230
|
|
314
|
-
|
315
|
-
|
316
|
-
|
231
|
+
// Event送出用
|
232
|
+
public function addEventListener(type:String, listener:Function,
|
233
|
+
useCapture:Boolean = false,
|
234
|
+
priority:int = 0,
|
235
|
+
useWeakReference:Boolean = false):void{
|
236
|
+
dispatcher.addEventListener(type, listener, useCapture, priority);
|
237
|
+
}
|
238
|
+
public function dispatchEvent(evt:Event):Boolean{
|
239
|
+
return dispatcher.dispatchEvent(evt);
|
240
|
+
}
|
241
|
+
public function hasEventListener(type:String):Boolean{
|
242
|
+
return dispatcher.hasEventListener(type);
|
243
|
+
}
|
244
|
+
public function removeEventListener(type:String, listener:Function,
|
245
|
+
useCapture:Boolean = false):void{
|
246
|
+
dispatcher.removeEventListener(type, listener, useCapture);
|
247
|
+
}
|
248
|
+
public function willTrigger(type:String):Boolean {
|
249
|
+
return dispatcher.willTrigger(type);
|
250
|
+
}
|
251
|
+
|
252
|
+
|
253
|
+
/**
|
254
|
+
* recv_callback
|
255
|
+
* フレームレート単位で動く処理(キャッシュにデータがあればデータ受信)
|
256
|
+
*
|
257
|
+
* @param evt:TimerEvent
|
258
|
+
* @return void
|
259
|
+
*/
|
260
|
+
public function recv_callback(evt:TimerEvent):void {
|
261
|
+
if(is_debug){ trace("DangoClientFramework:recv_callback:" + DangoUtil.now2str()); }
|
262
|
+
|
263
|
+
// 前回から時間がかかりすぎている(処理落ち仕掛けている場合は)スキップ
|
264
|
+
var start_date:Date = new Date();
|
265
|
+
if(is_debug){ trace("DangoClientFramework:recv_last_date.time=" + recv_last_date.time + " start_date.time=" + start_date.time); }
|
266
|
+
if(recv_last_date.time > start_date.time - (recv_timer_msec * 1.5)){
|
267
|
+
if(receive_cache.length > 0){
|
268
|
+
// while(receive_cache.length > 0){
|
269
|
+
if(is_debug){ trace("DangoClientFramework:recv_callback:receive_cache.length=" + receive_cache.length + ":" + DangoUtil.now2str()); }
|
270
|
+
var arr:Array = receive_cache.shift(); // Queueとして取り出し
|
271
|
+
var byte_array:ByteArray = arr[0];
|
272
|
+
var recv_c:uint = arr[1];
|
273
|
+
if(is_debug){ trace("DangoClientFramework:recv_c=" + recv_c); }
|
274
|
+
var receive_data:Array = this.receive_notice(byte_array);
|
275
|
+
|
276
|
+
if(recv_not_yet_size == 0){ // 未受信データが無ければ
|
277
|
+
if(receive_data != []){ // データが空なら無視する
|
278
|
+
for(var i:uint = 0; i < receive_data.length; i++){
|
279
|
+
var notice_name:String = receive_data[i]["notice"];
|
280
|
+
|
281
|
+
if(notice_name == "_notice_sid"){ // 接続直後のsid通知なら
|
282
|
+
this.sid = receive_data[i]["_sid"];
|
283
|
+
if(is_debug){ trace("DangoClientFramework:this.sid=" + this.sid + " recv_c:" + recv_c); }
|
284
|
+
|
285
|
+
} else if(notice_name == "_heart_beat"){ // heart beat通知なら
|
286
|
+
if(is_debug){ trace("DangoClientFramework:_heart_beat: recv_c:" + recv_c); }
|
287
|
+
|
288
|
+
} else { // 通常のデータならイベント発生
|
289
|
+
if(is_debug){ trace("DangoClientFramework:dispatchEvent:dango_" + notice_name + ": recv_c:" + recv_c + ":" + i); }
|
290
|
+
this.dispatchEvent(new DangoReceiveEvent("dango_" + notice_name, receive_data[i]));
|
291
|
+
}
|
292
|
+
}
|
293
|
+
} else { // データが空なら
|
294
|
+
// if(is_debug){ trace("DangoClientFramework:receive_data is empty." + DangoUtil.now2str()); }
|
295
|
+
if(is_debug){ trace("DangoClientFramework:receive_data is empty."); }
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
/*
|
300
|
+
// 処理に時間がかかりすぎている場合は、スキップさせる(while用)
|
301
|
+
if(is_debug){ trace("DangoClientFramework:recv_callback:end_date:" + DangoUtil.now2str()); }
|
302
|
+
var end_date:Date = new Date();
|
303
|
+
if(start_date.time < end_date.time - recv_timer_msec){
|
304
|
+
if(is_debug){ trace("DangoClientFramework:break"); }
|
305
|
+
break;
|
306
|
+
}
|
307
|
+
*/
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
recv_last_date = new Date();
|
312
|
+
}
|
313
|
+
|
314
|
+
/**
|
315
|
+
* polling_callback
|
316
|
+
* ハートビート用タイマーコールバック
|
317
|
+
*
|
318
|
+
* @param evt:TimerEvent
|
319
|
+
* @return void
|
320
|
+
*/
|
321
|
+
public function polling_callback(evt:TimerEvent):void {
|
322
|
+
if(is_debug){ trace("DangoClientFramework:polling_callback:" + DangoUtil.now2str() ); }
|
323
|
+
if(socket.connected){
|
324
|
+
// var send_obj:Object = null;
|
325
|
+
// this.send_data_to_server(send_obj);
|
326
|
+
|
327
|
+
var hb_id:String = make_heartbeat();
|
328
|
+
// if(is_debug){ trace("DangoClientFramework:send _notice_heart_beat:" + hb_id + ":" + DangoUtil.now2str()); }
|
329
|
+
this.send_action("_notice_heart_beat", { "_hb_id": hb_id}); // ハートビート送信
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
/**
|
334
|
+
* polling_callback
|
335
|
+
* ハートビートの作成
|
336
|
+
*
|
337
|
+
* @return String
|
338
|
+
*/
|
339
|
+
public function make_heartbeat():String {
|
340
|
+
return(String((new Date()).time) + String(this.sid));
|
341
|
+
}
|
342
|
+
|
343
|
+
/**
|
344
|
+
* delay_send_callback
|
345
|
+
* 遅延送信用タイマーコールバック
|
346
|
+
*
|
347
|
+
* @param socket:Socket
|
348
|
+
* @param send_obj:Object
|
349
|
+
* @return void
|
350
|
+
*/
|
351
|
+
public function delay_send_callback(evt:TimerEvent):void {
|
352
|
+
// if(is_debug){ trace("DangoClientFramework:delay_send_callback:evt:" + evt); }
|
353
|
+
if(!is_connect){ return(void); }
|
354
|
+
if(socket.connected){
|
355
|
+
var send_obj_dup:Array;
|
356
|
+
var i:uint;
|
357
|
+
|
358
|
+
for (i = 0; i < 5; i++) {
|
359
|
+
if(delay_send_cache.length == 0) { break; }
|
360
|
+
send_obj_dup = delay_send_cache.pop();
|
361
|
+
// データをすぐ送信
|
362
|
+
this.send_data_to_server(send_obj_dup);
|
363
|
+
if(is_debug){ trace("DangoClientFramework:delay_send_callback:sent:" + DangoUtil.now2str()); }
|
364
|
+
}
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
/**
|
369
|
+
* send data to server.
|
370
|
+
* クライアント側から使うサーバーへのデータ送信メソッド
|
371
|
+
*
|
372
|
+
* @param socket:Socket
|
373
|
+
* @param send_obj:Object
|
374
|
+
* @return void
|
375
|
+
*/
|
376
|
+
public function send_action(action_name:String, send_obj:Object, delay:Boolean=false):void {
|
377
|
+
if(is_debug){ trace("DangoClientFramework:send_action:start:" + action_name + ":" + DangoUtil.now2str()); }
|
378
|
+
|
379
|
+
// if(!is_connect){ throw new DangoError("error:not connect" , 29); } // 接続されていない場合はエラー
|
380
|
+
|
381
|
+
// 送信データの作成
|
382
|
+
var send_obj_dup:Object = ObjectUtil.copy(send_obj);
|
383
|
+
send_obj_dup["action"] = action_name;
|
384
|
+
send_obj_dup["_return_id"] = (new Date()).time;
|
385
|
+
|
386
|
+
// delayフラグがあったり、接続がまだなら、遅延送信用のキャッシュにデータを入れる
|
387
|
+
if(delay || !is_connect){
|
388
|
+
delay_send_cache.push([send_obj_dup]);
|
389
|
+
|
390
|
+
if(is_debug){ trace("DangoClientFramework:send_action:delay_pull:" + action_name + ":" + DangoUtil.now2str()); }
|
391
|
+
return(void);
|
392
|
+
}
|
393
|
+
|
394
|
+
// データをすぐ送信
|
395
|
+
this.send_data_to_server([send_obj_dup]);
|
396
|
+
if(is_debug){ trace("DangoClientFramework:send_action:end:" + action_name + ":" + DangoUtil.now2str()); }
|
397
|
+
}
|
398
|
+
|
399
|
+
/**
|
400
|
+
* send data to server.
|
401
|
+
* フレームワーク側のデータ送信の一般処理
|
402
|
+
*
|
403
|
+
* @param socket:Socket
|
404
|
+
* @param send_obj:Object
|
405
|
+
* @return void
|
406
|
+
*/
|
407
|
+
public function send_data_to_server( send_obj:Array ):void {
|
408
|
+
// if(is_debug){ trace("DangoClientFramework:send_data_to_server:send_obj=" + ObjectUtil.toString(send_obj)); }
|
409
|
+
|
410
|
+
var type:int = 0;
|
411
|
+
|
412
|
+
// データが空ならJSONencodeしない
|
413
|
+
var send_obj_str:String;
|
414
|
+
if(send_obj == null){
|
415
|
+
send_obj_str = "\n";
|
416
|
+
} else {
|
417
|
+
send_obj_str = JSON.encode(send_obj) + "\n";
|
418
|
+
}
|
317
419
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
byte_array.writeUnsignedInt(send_obj_size);
|
420
|
+
var send_obj_size:int = DangoUtil.string_byte_length(send_obj_str);
|
421
|
+
|
422
|
+
// if(is_debug){ trace("DangoClientFramework:send:" + type + ":" + send_obj_size + ":" + send_obj_str); }
|
322
423
|
|
323
|
-
|
324
|
-
|
325
|
-
|
424
|
+
// 長さ送信
|
425
|
+
var byte_array:ByteArray = new ByteArray;
|
426
|
+
byte_array.writeByte(type);
|
427
|
+
byte_array.writeUnsignedInt(send_obj_size);
|
326
428
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
// if(is_debug){ trace("DangoClientFramework:send_obj_str:" + send_obj_str + ":" + DangoUtil.now2str()); }
|
332
|
-
}
|
333
|
-
|
334
|
-
/**
|
335
|
-
* receive data from server.
|
336
|
-
* フレームワーク側のデータ受信の一般処理
|
337
|
-
*
|
338
|
-
* @return Object
|
339
|
-
*/
|
340
|
-
public function receive_notice():Object {
|
341
|
-
if(is_debug){ trace("DangoClientFramework:receive_notice:" + receve_count + ":" + DangoUtil.now2str()); }
|
429
|
+
socket.writeBytes(byte_array, 0, 5);
|
430
|
+
socket.writeUTFBytes("\n");
|
431
|
+
socket.flush();
|
342
432
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
433
|
+
// データ送信
|
434
|
+
socket.writeUTFBytes(send_obj_str);
|
435
|
+
socket.flush();
|
436
|
+
|
437
|
+
// if(is_debug){ trace("DangoClientFramework:send_obj_str:" + send_obj_str + ":" + DangoUtil.now2str()); }
|
438
|
+
}
|
439
|
+
|
440
|
+
/**
|
441
|
+
* receive data from server.
|
442
|
+
* フレームワーク側のデータ受信の一般処理
|
443
|
+
*
|
444
|
+
* @return Object
|
445
|
+
*/
|
446
|
+
public function receive_notice(byte_array:ByteArray):Array {
|
447
|
+
if(is_debug){ trace("DangoClientFramework:receive_notice:" + DangoUtil.now2str()); }
|
448
|
+
|
449
|
+
// 変数定義
|
450
|
+
var recv_data_orig:String = "";
|
451
|
+
|
452
|
+
// まず読めるデータをすべてByteArrayに入れる
|
453
|
+
// var byte_array:ByteArray = new ByteArray;
|
454
|
+
// socket.readBytes(byte_array, 0, socket.bytesAvailable);
|
455
|
+
|
456
|
+
// 読んだデータの長さ取得
|
457
|
+
var byte_read_size:uint = byte_array.length;
|
458
|
+
|
459
|
+
if(recv_not_yet_size == 0){ // 未受信データが無ければ
|
460
|
+
// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size==0"); }
|
461
|
+
|
462
|
+
if(byte_read_size < 6){ // きちんとデータが届いていなければ
|
463
|
+
this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "byte_read_size is too short."));
|
464
|
+
return([]);
|
465
|
+
}
|
466
|
+
|
467
|
+
// 長さを取得
|
468
|
+
var byte_array_size:ByteArray = new ByteArray;
|
469
|
+
try{
|
470
|
+
byte_array.readBytes(byte_array_size, 0, 5);
|
471
|
+
} catch(err:Error){
|
472
|
+
this.dispatchEvent(new DangoErrorEvent("DangoError", DangoErrorCode.IOError, "failed to byte_array.readBytes."));
|
473
|
+
return([]);
|
474
|
+
}
|
475
|
+
|
476
|
+
var type:int = byte_array_size.readByte();
|
477
|
+
recv_not_yet_size = byte_array_size.readUnsignedInt();
|
478
|
+
var crlf:String = byte_array.readUTFBytes(1);
|
479
|
+
byte_read_size -= 6;
|
480
|
+
// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size=" + recv_not_yet_size); }
|
481
|
+
}
|
482
|
+
|
483
|
+
// 読めているだけ読んで、その分recv_not_yet_sizeを減らす
|
484
|
+
if(recv_not_yet_size > byte_read_size){
|
485
|
+
// if(is_debug){ trace("DangoClientFramework:byte_read_size=" + byte_read_size); }
|
486
|
+
recv_data_orig = byte_array.readUTFBytes(byte_read_size);
|
487
|
+
recv_not_yet_size -= byte_read_size;
|
488
|
+
}else{
|
489
|
+
// if(is_debug){ trace("DangoClientFramework:recv_not_yet_size=" + recv_not_yet_size); }
|
490
|
+
recv_data_orig = byte_array.readUTFBytes(recv_not_yet_size);
|
491
|
+
recv_not_yet_size = 0;
|
492
|
+
}
|
493
|
+
|
494
|
+
// if(is_debug){ trace("DangoClientFramework:recv_data_orig:" + recv_data_orig); }
|
495
|
+
|
496
|
+
// 全データを受信したかどうかを確認
|
497
|
+
if(recv_not_yet_size == 0){ // 受信完了ならJSONパース
|
498
|
+
var recv_data:String = recv_not_yet_str + recv_data_orig;
|
499
|
+
recv_not_yet_str = "";
|
500
|
+
|
501
|
+
// if(is_debug){ trace("DangoClientFramework:recieve:data=" + ObjectUtil.toString(recv_data)); }
|
502
|
+
|
503
|
+
var ret_obj_data:Array;
|
504
|
+
if(recv_data && recv_data != "" && recv_data != "\n"){ // データが空じゃないならdecode
|
505
|
+
ret_obj_data = JSON.decode(recv_data) as Array;
|
506
|
+
|
507
|
+
} else { // データが空なら空データを作ってreturn
|
508
|
+
return([]);
|
509
|
+
}
|
510
|
+
|
511
|
+
// ret_obj_dataがObjectでnoticeが存在しているかのチェック
|
512
|
+
if(!(ret_obj_data is Array) || !(ret_obj_data[0]["notice"] is String)){
|
513
|
+
// if(!is_connect){ throw new DangoError("error:recieve data is invalid." , 29); }
|
514
|
+
throw new DangoError("error:recieve data is invalid." , 29);
|
515
|
+
}
|
516
|
+
|
517
|
+
/*
|
518
|
+
if(ret_obj_data["notice"] == "_notice_sid"){
|
519
|
+
if(is_debug){ trace("DangoClientFramework:recieve:_notice_sid:no response:" + receve_count + ":" + DangoUtil.now2str()); }
|
520
|
+
}else{
|
521
|
+
var response_notice_name:String;
|
522
|
+
response_notice_name = "_response";
|
523
|
+
if(is_debug){ trace("DangoClientFramework:sending:response:notice_name=" + ret_obj_data["notice"] + ":" + ret_obj_data["_id"] + ":" + receve_count + ":" + DangoUtil.now2str()); }
|
524
|
+
|
525
|
+
this.send_action(response_notice_name, {"_id":ret_obj_data["_id"]}); // 受信完了確認の為に空データを送る
|
526
|
+
}
|
527
|
+
*/
|
528
|
+
return(ret_obj_data);
|
529
|
+
|
530
|
+
} else { // まだデータが残っているなら空を返す
|
531
|
+
recv_not_yet_str += recv_data_orig;
|
532
|
+
return([]);
|
533
|
+
}
|
534
|
+
}
|
535
|
+
|
536
|
+
}
|
428
537
|
}
|
@@ -13,10 +13,23 @@ package org.rubyforge.dango {
|
|
13
13
|
|
14
14
|
// Arrayから特定アイテムを削除した結果を返す
|
15
15
|
public static function array_delete(arr:Array, delete_item:*):Array {
|
16
|
+
|
17
|
+
// filterメソッドだと「ABC データは破損しているため、境界外の読み取りが試行されました。」が
|
18
|
+
// Flashバージョンによって出るのでforループで作り直し
|
19
|
+
/*
|
16
20
|
var filter_function:Function = function filter_function(item:*, idx:int, arr:Array):Boolean {
|
17
21
|
return(item != delete_item);
|
18
22
|
};
|
19
23
|
return(arr.filter(filter_function));
|
24
|
+
*/
|
25
|
+
var temp_arr:Array = [];
|
26
|
+
for (var i:uint = 0; i < arr.length; i ++) {
|
27
|
+
var item:* = arr[i];
|
28
|
+
if (item != delete_item){
|
29
|
+
temp_arr.push(item);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
return(temp_arr);
|
20
33
|
}
|
21
34
|
|
22
35
|
// Stringのバイト数を返す
|
@@ -76,9 +89,21 @@ package org.rubyforge.dango {
|
|
76
89
|
ret_object[String(arr_split_equal[0])] = String(arr_split_equal[1]);
|
77
90
|
// trace("4"+i);
|
78
91
|
}
|
79
|
-
|
92
|
+
|
80
93
|
return(ret_object);
|
81
94
|
}
|
82
95
|
|
96
|
+
// parametersからflashvarsを分解してobjectに入れて返す
|
97
|
+
public static function get_flashvars(app:Object):Object {
|
98
|
+
var flash_vars:Object = {};
|
99
|
+
var value:String;
|
100
|
+
for (var key:String in app.parameters) {
|
101
|
+
value = app.parameters[key];
|
102
|
+
flash_vars[key] = value;
|
103
|
+
}
|
104
|
+
|
105
|
+
return(flash_vars);
|
106
|
+
}
|
107
|
+
|
83
108
|
}
|
84
109
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
server:
|
2
2
|
# host: "localhost" # 接続制限ホスト "0.0.0.0"にすれば全接続オッケイ
|
3
3
|
host: "0.0.0.0" # 接続制限ホスト "0.0.0.0"にすれば全接続オッケイ
|
4
|
-
max_connections:
|
4
|
+
max_connections: 10
|
5
5
|
log_file: log/dango_development.log
|
6
6
|
log_level: DEBUG
|
7
7
|
log_max_size: 100000000
|
@@ -13,7 +13,7 @@ server:
|
|
13
13
|
debug: true # スレッド終了時に全体停止する
|
14
14
|
policy_file_request: true # <policy-file-request/>要求に答える(Flashでクロスドメイン処理を行う)
|
15
15
|
|
16
|
-
check_dango_process_cmd: 'cmd /c "D: && cd D:\
|
16
|
+
check_dango_process_cmd: 'cmd /c "D: && cd D:\dango_sample_chat\trunk\rails && ruby script/dango_server"'
|
17
17
|
|
18
18
|
send_receive_sleep_interval_sec: 0.2 # データ送信時のタイムアウトチェック間隔秒
|
19
19
|
send_receive_timeout_default_sec: 5.0 # データ送受信時のデフォルトタイムアウト秒数
|
@@ -1,3 +1,31 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
server:
|
2
|
+
# host: "localhost" # 接続制限ホスト "0.0.0.0"にすれば全接続オッケイ
|
3
|
+
host: "0.0.0.0" # 接続制限ホスト "0.0.0.0"にすれば全接続オッケイ
|
4
|
+
max_connections: 100
|
5
|
+
log_file: log/dango_production.log
|
6
|
+
log_level: DEBUG
|
7
|
+
log_max_size: 100000000
|
8
|
+
log_shift_age: 99
|
9
|
+
gserver_log_file: log/dango_gserver_production.log
|
10
|
+
shared_database_manager: MemoryStore
|
11
|
+
backdoor_host: "127.0.0.1"
|
12
|
+
thread_sync: true # trueにすると各スレッドが同時動作しなくなる。falseの場合は自分で排他処理を書く場合
|
13
|
+
debug: true # スレッド終了時に全体停止する
|
14
|
+
policy_file_request: true # <policy-file-request/>要求に答える(Flashでクロスドメイン処理を行う)
|
15
|
+
|
16
|
+
check_dango_process_cmd: 'cmd /c "D: && cd D:\dango_sample_chat\trunk\rails && ruby script/dango_server"'
|
17
|
+
|
18
|
+
send_receive_sleep_interval_sec: 0.2 # データ送信時のタイムアウトチェック間隔秒
|
19
|
+
send_receive_timeout_default_sec: 5.0 # データ送受信時のデフォルトタイムアウト秒数
|
20
|
+
send_timeout_sec: 4.0 # データ送受信時の送信のタイムアウト秒数
|
21
|
+
heart_beat_interval_sec: 10.0 # S=>Cのheart beatの送信間隔秒数
|
22
|
+
heart_beat_response_wait_sec: 10.0 # S=>Cのheart beatの返信待ち秒数
|
23
|
+
|
24
|
+
network:
|
25
|
+
host: localhost
|
26
|
+
port: 15000
|
27
|
+
# port: 5140
|
28
|
+
|
29
|
+
client:
|
30
|
+
# host: 172.31.1.74
|
3
31
|
|
@@ -3,16 +3,19 @@
|
|
3
3
|
puts "Booting DangoServer..."
|
4
4
|
require File.dirname(__FILE__) + '/../config/boot'
|
5
5
|
|
6
|
+
require "yaml"
|
7
|
+
require "getoptlong"
|
6
8
|
|
7
9
|
# 環境によるコンフィグ読み込み
|
8
|
-
require "yaml"
|
9
10
|
env = ENV['RAILS_ENV'] || 'development'
|
11
|
+
env = ARGV[0] if ARGV[0]
|
10
12
|
config = YAML.load(open("dango/config/#{env}.yml", "rb"){|fh| fh.read})
|
13
|
+
puts "environment=#{env}"
|
11
14
|
|
12
|
-
#
|
13
|
-
require 'getoptlong.rb'
|
15
|
+
# コマンドラインオプション取得
|
14
16
|
opt_parser = GetoptLong.new
|
15
17
|
|
18
|
+
# コマンドラインオプションによるコンフィグの上書き
|
16
19
|
options_arr = ["dango"]
|
17
20
|
config["server"].each{|k, v| options_arr.push("server:#{k}") }
|
18
21
|
config["network"].each{|k, v| options_arr.push("network:#{k}") }
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dango_generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
platform:
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keisuke Minami
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2008-03-26 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
102
|
requirements: []
|
103
103
|
|
104
104
|
rubyforge_project: dango
|
105
|
-
rubygems_version: 0.
|
105
|
+
rubygems_version: 1.0.1
|
106
106
|
signing_key:
|
107
107
|
specification_version: 2
|
108
108
|
summary: dango_generator
|