dango 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +13 -0
- data/README.txt +47 -0
- data/lib/dango/client_framework.rb +260 -0
- data/lib/dango/framework_base.rb +247 -0
- data/lib/dango/monitor/dango_monitor_client.rb +66 -0
- data/lib/dango/script/dango_server.rb +42 -0
- data/lib/dango/server_framework.rb +661 -0
- data/lib/dango/shared/memory_store.rb +91 -0
- data/lib/dango/tasks/dango_rake.rb +38 -0
- data/lib/dango/version.rb +9 -0
- data/setup.rb +1585 -0
- data/test/test_dango.rb +13 -0
- data/test/test_helper.rb +2 -0
- metadata +67 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
#!ruby -Ku
|
2
|
+
|
3
|
+
=begin
|
4
|
+
= Dangoサーバーのメンテナンス用モニタ
|
5
|
+
=end
|
6
|
+
|
7
|
+
#$LOAD_PATH.push("../../../../svn/rubyforge/dango/lib")
|
8
|
+
|
9
|
+
#gem "dango"
|
10
|
+
|
11
|
+
require 'dango/client_framework' # コネクションサーバーフレームワークの呼び出し
|
12
|
+
|
13
|
+
#
|
14
|
+
|
15
|
+
# メインクラス
|
16
|
+
class DangoMonitorClient < DangoClientFramework
|
17
|
+
ConnTimeout = 6
|
18
|
+
|
19
|
+
def initialize()
|
20
|
+
super(ENV['RAILS_ENV'])
|
21
|
+
end
|
22
|
+
|
23
|
+
public
|
24
|
+
|
25
|
+
# 起動処理
|
26
|
+
def cs_client_init
|
27
|
+
# ログ出力情報
|
28
|
+
@connection_client_log_file = "log/dango_monitor_#{ENV['RAILS_ENV']}.log"
|
29
|
+
@connection_client_log_level = Logger::DEBUG
|
30
|
+
end
|
31
|
+
|
32
|
+
# アクセサの定義
|
33
|
+
# 読み込みのみ
|
34
|
+
attr_reader(:is_session_closed)
|
35
|
+
|
36
|
+
# サーバーの全情報取得
|
37
|
+
def get_all_info
|
38
|
+
cs_logger.debug "DangoMonitorClient:get_all_info"
|
39
|
+
begin
|
40
|
+
ret_obj = cs_client_send_receive_data('monitor_all_info', {})
|
41
|
+
rescue DangoFrameworkConnectionError
|
42
|
+
raise("monitor_all_info Connection error")
|
43
|
+
rescue DangoFrameworkTimeoutError
|
44
|
+
raise("monitor_all_info Timeout error")
|
45
|
+
end
|
46
|
+
raise("code is not 0 (faild). :code=#{ret_obj['code']}") if ret_obj['code'] != 0
|
47
|
+
ret_obj['all_info']
|
48
|
+
end
|
49
|
+
|
50
|
+
# サーバーのデータリロード
|
51
|
+
def server_reload
|
52
|
+
cs_logger.debug "DangoMonitorClient:server_reload"
|
53
|
+
begin
|
54
|
+
ret_obj = cs_client_send_receive_data('monitor_server_reload', {})
|
55
|
+
rescue DangoFrameworkConnectionError
|
56
|
+
raise("monitor_server_reload Connection error")
|
57
|
+
rescue DangoFrameworkTimeoutError
|
58
|
+
raise("monitor_server_reload Timeout error")
|
59
|
+
end
|
60
|
+
raise("code is not 0 (faild). :code=#{ret_obj['code']}") if ret_obj['code'] != 0
|
61
|
+
ret_obj['all_info']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!ruby -Ku
|
2
|
+
|
3
|
+
#module Dango
|
4
|
+
require 'yaml'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
require 'dango/server_framework'
|
8
|
+
|
9
|
+
# require RAILS_ROOT + '/config/boot'
|
10
|
+
require RAILS_ROOT + '/config/environment'
|
11
|
+
|
12
|
+
# 環境によるコンフィグ読み込み
|
13
|
+
env = ENV['RAILS_ENV'] || 'development'
|
14
|
+
|
15
|
+
config = YAML.load(open("dango/config/#{env}.yml", "rb"){|fh| fh.read})
|
16
|
+
|
17
|
+
# serverファイル名一覧を取得
|
18
|
+
load_files = []
|
19
|
+
glob_str = 'dango/server/*.rb'
|
20
|
+
Dir.glob(glob_str) do |srv_file|
|
21
|
+
load_files.push({:file=>srv_file, :mtime=>File.mtime(srv_file)})
|
22
|
+
end
|
23
|
+
|
24
|
+
# ファイル名順にソート
|
25
|
+
load_files = load_files.sort_by{|f| f[:file] }
|
26
|
+
#p load_files
|
27
|
+
|
28
|
+
# config['load_files'] = load_files
|
29
|
+
|
30
|
+
# config:cache_classesによる処理分け
|
31
|
+
# if config['server']['cache_classes'] == true
|
32
|
+
# load_files.each do |f|
|
33
|
+
# require f[:file]
|
34
|
+
# end
|
35
|
+
# else
|
36
|
+
load_files.each do |f|
|
37
|
+
load f[:file]
|
38
|
+
end
|
39
|
+
# end
|
40
|
+
|
41
|
+
DangoServer.start(config)
|
42
|
+
#end
|
@@ -0,0 +1,661 @@
|
|
1
|
+
#!ruby -Ku
|
2
|
+
|
3
|
+
=begin
|
4
|
+
= コネクション型サーバーフレームワーク
|
5
|
+
=end
|
6
|
+
|
7
|
+
require 'gserver'
|
8
|
+
require 'ipaddr'
|
9
|
+
|
10
|
+
require "dango/framework_base"
|
11
|
+
|
12
|
+
# フレームワーククラス
|
13
|
+
class DangoServerFramework
|
14
|
+
include DangoFrameworkModule
|
15
|
+
|
16
|
+
SendReceiveSleepIntervalSec = 0.1 # データ送信後の順の際のタイムアウトチェック間隔秒
|
17
|
+
|
18
|
+
# cs_client_send_receive_data用の共有メモリ
|
19
|
+
def send_receive_shared_init
|
20
|
+
@send_receive_shared = SharedMemoryStore.new
|
21
|
+
end
|
22
|
+
def send_receive_shared
|
23
|
+
@send_receive_shared
|
24
|
+
end
|
25
|
+
|
26
|
+
class DangoGServer < GServer
|
27
|
+
def initialize(parent, *args)
|
28
|
+
@parent = parent
|
29
|
+
super(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def serve(sock)
|
33
|
+
@parent.thread_main(sock)
|
34
|
+
end
|
35
|
+
|
36
|
+
def connecting(sock)
|
37
|
+
@parent.connecting(sock)
|
38
|
+
end
|
39
|
+
|
40
|
+
def disconnecting(sock)
|
41
|
+
@parent.disconnecting(sock)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(config)
|
46
|
+
@config = config
|
47
|
+
|
48
|
+
@gserver = nil # Gserver用の変数
|
49
|
+
@server_reload = nil # サーバーのリロード用フラグ
|
50
|
+
|
51
|
+
# SIGINT の捕捉
|
52
|
+
Signal.trap(:INT) do
|
53
|
+
puts "shutdown"
|
54
|
+
exit!
|
55
|
+
end
|
56
|
+
|
57
|
+
# サーバー開始
|
58
|
+
server_start()
|
59
|
+
|
60
|
+
loop do # 待ちで無限ループに入る
|
61
|
+
sleep 3
|
62
|
+
# p( Time.now.to_s + ":#{@server_reload.inspect}")
|
63
|
+
check_reload_class()
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader(:log_file, :shared) # 読み書き
|
68
|
+
|
69
|
+
# 起動用のインスタンスメソッド
|
70
|
+
def self.start(config = {})
|
71
|
+
self.new(config)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# サーバー開始処理
|
76
|
+
def server_start()
|
77
|
+
set_server_variables() # 各種サーバー仕様の変数設定
|
78
|
+
shared_init() # 共有メモリを初期化
|
79
|
+
notice_shared_init() # 通知共有メモリを初期化
|
80
|
+
socket_list_init() # ソケット一覧を初期化
|
81
|
+
mutex_socket_list_init(cs_logger()) # ソケット毎用のmutexを初期化
|
82
|
+
send_receive_shared_init() # データ送受信用の共有メモリ初期化
|
83
|
+
cs_server_init() # 初期設定読み込み
|
84
|
+
|
85
|
+
cs_logger.debug("===== server initialize =====") # loggerの準備
|
86
|
+
cs_logger.debug("port=#{@connection_server_port}")
|
87
|
+
cs_logger.debug("host=#{@connection_server_host}")
|
88
|
+
cs_logger.debug("max_connections=#{@connection_server_max_connections}")
|
89
|
+
|
90
|
+
@gserver = DangoGServer.new(self, @connection_server_port,
|
91
|
+
@connection_server_host,
|
92
|
+
@connection_server_max_connections)
|
93
|
+
@gserver.audit = true # Turn logging on.
|
94
|
+
@gserver.start
|
95
|
+
end
|
96
|
+
|
97
|
+
# サーバーのループ時のクラス読み直し処理
|
98
|
+
def check_reload_class()
|
99
|
+
begin
|
100
|
+
# @config:cache_classesによる処理分け
|
101
|
+
# if @config['server']['cache_classes'] != true
|
102
|
+
|
103
|
+
# ロードファイルの変更確認
|
104
|
+
# changed = false
|
105
|
+
# @config['load_files'].each do |f|
|
106
|
+
# this_mtime = File.mtime(f[:file])
|
107
|
+
# if this_mtime > f[:mtime]
|
108
|
+
# f[:mtime] = this_mtime
|
109
|
+
# changed = true
|
110
|
+
# end
|
111
|
+
# end
|
112
|
+
|
113
|
+
# 変更していたら
|
114
|
+
# changed = nil
|
115
|
+
# if changed
|
116
|
+
if @server_reload
|
117
|
+
@server_reload = nil
|
118
|
+
|
119
|
+
puts "-- stopping server"
|
120
|
+
|
121
|
+
# 強制的に接続しているsocketをクローズ
|
122
|
+
cs_logger.debug "socket_list.keys:#{socket_list.keys.inspect}"
|
123
|
+
socket_list.keys.each do |sk|
|
124
|
+
cs_logger.debug "sk:#{socket_list[sk].inspect}"
|
125
|
+
socket_list[sk].close if ! socket_list[sk].closed?
|
126
|
+
socket_list[sk]
|
127
|
+
end
|
128
|
+
|
129
|
+
# サーバーを停止
|
130
|
+
@gserver.shutdown
|
131
|
+
@gserver.stop
|
132
|
+
while(!@gserver.stopped?) do
|
133
|
+
sleep 1
|
134
|
+
puts "waiting... #{@gserver.stopped?}"
|
135
|
+
cs_logger.debug "waiting... #{@gserver.stopped?} #{@gserver.connections}"
|
136
|
+
end
|
137
|
+
|
138
|
+
@gserver = nil
|
139
|
+
|
140
|
+
puts "-- stopped server"
|
141
|
+
|
142
|
+
# GCを行う
|
143
|
+
GC.start
|
144
|
+
|
145
|
+
# サーバーファイルを読み直し
|
146
|
+
puts "-- reload classes"
|
147
|
+
tmp_verbose = $VERBOSE
|
148
|
+
$VERBOSE = nil
|
149
|
+
|
150
|
+
# serverファイル名一覧を取得
|
151
|
+
load_files = []
|
152
|
+
glob_str = 'dango/server/*.rb'
|
153
|
+
Dir.glob(glob_str) do |srv_file|
|
154
|
+
load_files.push({:file=>srv_file, :mtime=>File.mtime(srv_file)})
|
155
|
+
end
|
156
|
+
|
157
|
+
# ファイル名順にソート
|
158
|
+
load_files = load_files.sort_by{|f| f[:file] }
|
159
|
+
load_files.each do |f|
|
160
|
+
begin
|
161
|
+
load f[:file]
|
162
|
+
rescue Exception
|
163
|
+
p $!.class
|
164
|
+
p $!.message
|
165
|
+
p $!.backtrace
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
$VERBOSE = tmp_verbose
|
170
|
+
|
171
|
+
# サーバーを再度起動
|
172
|
+
puts "-- start server"
|
173
|
+
server_start() # サーバー開始
|
174
|
+
end
|
175
|
+
# end
|
176
|
+
rescue Exception
|
177
|
+
cs_logger.error "#{$!.class}:#{$!.message}\n#{$!.backtrace.pretty_inspect}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# gserver接続開始処理
|
182
|
+
def connecting(sock)
|
183
|
+
cs_logger.debug "connecting:sock=#{sock}"
|
184
|
+
end
|
185
|
+
|
186
|
+
# gserver接続開始処理
|
187
|
+
def disconnecting(port)
|
188
|
+
cs_logger.debug "disconnecting:port=#{port}"
|
189
|
+
end
|
190
|
+
|
191
|
+
# gserverのserveメソッド:スレッド開始処理
|
192
|
+
def thread_main(sock)
|
193
|
+
cs_logger.debug "thread_main:start"
|
194
|
+
cs_logger.debug "#{sock} is accepted. key=#{Thread.current.object_id}"
|
195
|
+
|
196
|
+
begin
|
197
|
+
session[:session_id] = Thread.current.object_id
|
198
|
+
socket_list.add(session[:session_id], sock)
|
199
|
+
mutex_socket_list.add(session[:session_id])
|
200
|
+
|
201
|
+
sock.binmode
|
202
|
+
sock.sync = true
|
203
|
+
|
204
|
+
cs_connect() # 接続時メソッド呼び出し
|
205
|
+
|
206
|
+
# メインループ入り
|
207
|
+
loop do
|
208
|
+
if sock.closed?
|
209
|
+
cs_logger.debug "#{sock.inspect}:sock is closed..."
|
210
|
+
break
|
211
|
+
end
|
212
|
+
|
213
|
+
cs_logger.debug "start cs_receive_data"
|
214
|
+
ret_obj = nil
|
215
|
+
# mutex_socket_list.synchronize(session[:session_id]) do
|
216
|
+
ret_obj = cs_receive_data(sock) # データ受信処理
|
217
|
+
# end
|
218
|
+
cs_logger.debug "finished cs_receive_data"
|
219
|
+
|
220
|
+
if ret_obj != {} # 受信データがあれば
|
221
|
+
if !(ret_obj && ret_obj["action"]) # actionが無い場合はエラー
|
222
|
+
cs_logger.error "no action error:#{ret_obj.inspect}"
|
223
|
+
raise(DangoFrameworkError, "no action error")
|
224
|
+
end
|
225
|
+
|
226
|
+
# アクション名
|
227
|
+
action_name = ret_obj["action"].to_s
|
228
|
+
cs_logger.debug "action_name=#{action_name}"
|
229
|
+
|
230
|
+
if action_name == 'monitor_all_info' # メンテナンスアクション名なら
|
231
|
+
cs_check_monitor_error(sock, "return_monitor_all_info")
|
232
|
+
cs_server_monitor_all_info()
|
233
|
+
elsif action_name == 'monitor_server_reload' # メンテナンスアクション名なら
|
234
|
+
cs_check_monitor_error(sock, "return_monitor_server_reload")
|
235
|
+
cs_server_monitor_server_reload()
|
236
|
+
else # メンテナンスコマンド以外のユーザーアクション名なら
|
237
|
+
begin
|
238
|
+
__send__("cs_receive_#{action_name}", ret_obj)
|
239
|
+
rescue NoMethodError
|
240
|
+
@recv_fail_count += 1 if @recv_fail_count # 受信失敗回数カウント
|
241
|
+
cs_logger.error "not find action #{action_name}:#{error_message($!, 'u')}"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
rescue DangoFrameworkConnectionError
|
248
|
+
@recv_fail_count += 1 if @recv_fail_count # 受信失敗回数カウント
|
249
|
+
cs_logger.debug "connection error. \n#{error_message($!, 'u')}"
|
250
|
+
|
251
|
+
rescue Exception
|
252
|
+
cs_logger.error "#{error_message($!, 'u')}"
|
253
|
+
|
254
|
+
ensure
|
255
|
+
cs_logger.debug "#{sock.inspect} is gone"
|
256
|
+
|
257
|
+
begin
|
258
|
+
cs_close() # 接続解除時に呼び出されるメソッド
|
259
|
+
rescue
|
260
|
+
cs_logger.error "#{error_message($!, 'u')}"
|
261
|
+
ensure
|
262
|
+
socket_list.delete(Thread.current.object_id) # ソケットリストから削除
|
263
|
+
sock.close # ソケットを閉じる
|
264
|
+
|
265
|
+
cs_logger.debug "#{sock.inspect} is gone 2"
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# 各種サーバー仕様の変数設定
|
272
|
+
def set_server_variables()
|
273
|
+
# 変数の初期設定
|
274
|
+
@connection_server_port = @config['network']['port'] || 15000
|
275
|
+
@connection_server_host = @config['server']['host'] || "localhost"
|
276
|
+
@connection_server_max_connections = @config['server']['max_connections'] || 10
|
277
|
+
@log_file = @config['server']['log_file'] || ""
|
278
|
+
|
279
|
+
log_level_hash = {
|
280
|
+
"FATAL" => Logger::FATAL,
|
281
|
+
"ERROR" => Logger::ERROR,
|
282
|
+
"WARN" => Logger::WARN,
|
283
|
+
"INFO" => Logger::INFO,
|
284
|
+
"DEBUG" => Logger::DEBUG,
|
285
|
+
}
|
286
|
+
@log_level = log_level_hash.find do |level|
|
287
|
+
level == @config['server']['log_level']
|
288
|
+
end
|
289
|
+
@log_level = @connection_server_log_level || Logger::DEBUG
|
290
|
+
|
291
|
+
@start_time = Time.now # サーバー起動時間
|
292
|
+
@recv_count = 0 # 受信回数
|
293
|
+
@send_count = 0 # 送信回数
|
294
|
+
@recv_fail_count = 0 # 受信失敗回数
|
295
|
+
@send_fail_count = 0 # 送信失敗回数
|
296
|
+
end
|
297
|
+
|
298
|
+
def cs_server_init # 初期設定
|
299
|
+
end
|
300
|
+
|
301
|
+
# コンフィグのshared_database_managerによる使用クラスの選択
|
302
|
+
def select_shared_database_manager()
|
303
|
+
if @config['server']['shared_database_manager'] == 'MemoryStore'
|
304
|
+
SharedMemoryStore.new
|
305
|
+
else
|
306
|
+
SharedMemoryStore.new
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# 共有メモリ
|
311
|
+
def shared_init
|
312
|
+
@shared = select_shared_database_manager()
|
313
|
+
end
|
314
|
+
def shared
|
315
|
+
@shared
|
316
|
+
end
|
317
|
+
|
318
|
+
# 通知共有メモリ
|
319
|
+
|
320
|
+
def notice_shared_init
|
321
|
+
# @notice_shared = NoticeShared.new(self)
|
322
|
+
@notice_shared = select_shared_database_manager()
|
323
|
+
|
324
|
+
class << @notice_shared ## 各種メソッド追加
|
325
|
+
def initialize2(parent)
|
326
|
+
@parent = parent
|
327
|
+
self[:notice_list] = {}
|
328
|
+
end
|
329
|
+
|
330
|
+
def init_key(key) # そのキーを作成する
|
331
|
+
if self[:notice_list].has_key?(key) || key == :notice_list # キーがすでにあるか予約語なら
|
332
|
+
raise(DangoFrameworkError, "notice_list already has key. key=#{key.inspect}")
|
333
|
+
end
|
334
|
+
|
335
|
+
self.transaction(:notice_list) do |notice_list|
|
336
|
+
notice_list[key] = []
|
337
|
+
notice_list
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def add_connectable(key, session_id) # 接続許可にする
|
342
|
+
if !self[:notice_list].has_key?(key) # キーがなければ
|
343
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
344
|
+
end
|
345
|
+
|
346
|
+
self.transaction(:notice_list) do |notice_list|
|
347
|
+
notice_list[key] << session_id
|
348
|
+
notice_list
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def remove_connectable(key, session_id) # 接続を不許可にする
|
353
|
+
if !self[:notice_list].has_key?(key) # キーがなければ
|
354
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
355
|
+
end
|
356
|
+
|
357
|
+
self.transaction(:notice_list) do |notice_list|
|
358
|
+
notice_list[key].delete(session_id)
|
359
|
+
notice_list
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def get_connectables(key) # 接続許可一覧を返す
|
364
|
+
if !self[:notice_list].has_key?(key) # キーがなければ
|
365
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
366
|
+
end
|
367
|
+
|
368
|
+
self[:notice_list][key]
|
369
|
+
end
|
370
|
+
|
371
|
+
def notice_change(key, value) # 変更時に通知する変更
|
372
|
+
if !self[:notice_list].has_key?(key) # キーがなければ
|
373
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
374
|
+
end
|
375
|
+
|
376
|
+
self[key] = value
|
377
|
+
|
378
|
+
@parent.cs_logger.debug "self.get_connectables(key):#{self.get_connectables(key).inspect}"
|
379
|
+
|
380
|
+
self.get_connectables(key).each do |session_id|
|
381
|
+
@parent.cs_server_send_data(session_id, "notice_shared_#{key}".to_sym, value)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
def not_notice_change(key, value) # 変更時に通知しない変更
|
386
|
+
if !self[:notice_list].has_key?(key) # キーがなければ
|
387
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
388
|
+
end
|
389
|
+
|
390
|
+
self[key] = value
|
391
|
+
end
|
392
|
+
|
393
|
+
def []=(key, value) # データの変更
|
394
|
+
if key != :notice_list && !self[:notice_list].has_key?(key) # キーがなければ
|
395
|
+
raise(DangoFrameworkError, "notice_list not has key. key=#{key.inspect}")
|
396
|
+
end
|
397
|
+
|
398
|
+
super(key, value) # データの変更
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
def notice_shared
|
404
|
+
@notice_shared
|
405
|
+
end
|
406
|
+
|
407
|
+
# セッション
|
408
|
+
class Session < Hash
|
409
|
+
end
|
410
|
+
def session
|
411
|
+
Thread.current[:session] = Session.new if !Thread.current[:session]
|
412
|
+
Thread.current[:session]
|
413
|
+
end
|
414
|
+
|
415
|
+
# ソケットとIDの対応
|
416
|
+
class SocketList
|
417
|
+
def initialize
|
418
|
+
@sl_hash = Hash.new
|
419
|
+
@sl_mutex = Mutex.new
|
420
|
+
end
|
421
|
+
def keys()
|
422
|
+
@sl_mutex.synchronize do
|
423
|
+
@sl_hash.keys
|
424
|
+
end
|
425
|
+
end
|
426
|
+
def delete(key)
|
427
|
+
@sl_mutex.synchronize do
|
428
|
+
@sl_hash.delete(key)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
def add(key, sock)
|
432
|
+
@sl_mutex.synchronize do
|
433
|
+
raise("already exist key(#{key})") if @sl_hash.has_key?(key)
|
434
|
+
raise("sock(#{sock.ins}) is not Socket") if sock.kind_of?(Socket)
|
435
|
+
@sl_hash[key] = sock
|
436
|
+
end
|
437
|
+
end
|
438
|
+
def [](key)
|
439
|
+
@sl_mutex.synchronize do
|
440
|
+
raise("not exist key(#{key})") if ! @sl_hash.has_key?(key)
|
441
|
+
@sl_hash[key]
|
442
|
+
end
|
443
|
+
end
|
444
|
+
def []=(key, sock)
|
445
|
+
@sl_mutex.synchronize do
|
446
|
+
raise("not exist key(#{key})") if ! @sl_hash.has_key?(key)
|
447
|
+
raise("sock(#{sock.class}) is not Socket") if sock.kind_of?(Socket)
|
448
|
+
@sl_hash[key] = sock
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
def socket_list_init
|
453
|
+
@socket_list = SocketList.new
|
454
|
+
end
|
455
|
+
def socket_list
|
456
|
+
@socket_list
|
457
|
+
end
|
458
|
+
|
459
|
+
# ソケット毎用のmutex
|
460
|
+
class MutexSocketList
|
461
|
+
def initialize(cs_logger)
|
462
|
+
@cs_logger = cs_logger
|
463
|
+
@msl_hash = Hash.new
|
464
|
+
end
|
465
|
+
def keys()
|
466
|
+
@msl_hash.keys
|
467
|
+
end
|
468
|
+
def delete(key)
|
469
|
+
@msl_hash.delete(key)
|
470
|
+
end
|
471
|
+
def add(key)
|
472
|
+
@msl_hash[key] = Mutex.new
|
473
|
+
end
|
474
|
+
# def [](key)
|
475
|
+
# raise("not exist key(#{key})") if ! @msl_hash.has_key?(key)
|
476
|
+
## add(key) if @msl_hash.has_key?(key)
|
477
|
+
# @msl_hash[key]
|
478
|
+
# end
|
479
|
+
def synchronize(key)
|
480
|
+
raise("not exist key(#{key})") if ! @msl_hash.has_key?(key)
|
481
|
+
@cs_logger.debug("mutex_socket_list starting synchronize. key=#{key}")
|
482
|
+
ret = nil
|
483
|
+
@msl_hash[key].synchronize do
|
484
|
+
@cs_logger.debug("mutex_socket_list started synchronize. key=#{key}")
|
485
|
+
ret = yield
|
486
|
+
@cs_logger.debug("mutex_socket_list finished synchronize. key=#{key}")
|
487
|
+
end
|
488
|
+
ret
|
489
|
+
end
|
490
|
+
end
|
491
|
+
def mutex_socket_list_init(cs_logger)
|
492
|
+
@mutex_sock_list = MutexSocketList.new(cs_logger) # ソケット毎用のmutex
|
493
|
+
end
|
494
|
+
def mutex_socket_list
|
495
|
+
@mutex_sock_list
|
496
|
+
end
|
497
|
+
|
498
|
+
# 接続時に呼び出されるメソッド
|
499
|
+
def cs_connect; end
|
500
|
+
|
501
|
+
# 接続解除時に呼び出されるメソッド
|
502
|
+
def cs_close; end
|
503
|
+
|
504
|
+
|
505
|
+
# サーバーの暗号化処理
|
506
|
+
def cs_server_send_encrypt(str) # 継承用
|
507
|
+
str
|
508
|
+
end
|
509
|
+
def cs_send_encrypt(str) # フレームワークから呼ばれる部分
|
510
|
+
cs_server_send_encrypt(str)
|
511
|
+
end
|
512
|
+
|
513
|
+
# サーバーの復号化処理
|
514
|
+
def cs_server_receive_decrypt(str) # 継承用
|
515
|
+
str
|
516
|
+
end
|
517
|
+
def cs_receive_decrypt(str) # フレームワークから呼ばれる部分
|
518
|
+
cs_server_receive_decrypt(str)
|
519
|
+
end
|
520
|
+
|
521
|
+
# サーバーからクライアントへのデータ送信
|
522
|
+
def cs_server_send_data(session_id, notice_name, send_obj, options = {})
|
523
|
+
cs_logger.debug "cs_server_send_data(#{session_id.inspect}, #{notice_name.inspect}, #{send_obj.inspect}, #{options.inspect})"
|
524
|
+
|
525
|
+
timeout = options[:timeout] || 6
|
526
|
+
dtype = options[:type] || 0
|
527
|
+
|
528
|
+
sock = socket_list[session_id]
|
529
|
+
raise(DangoFrameworkError, "not found session_id=#{session_id}") if !sock
|
530
|
+
raise(DangoFrameworkConnectionError, "socket closed. s_id=#{session_id}") if sock.closed?
|
531
|
+
|
532
|
+
cs_logger.debug "cs_server_send_data:sending data notice_name=#{notice_name.inspect}"
|
533
|
+
send_obj_dup = send_obj.deep_dup
|
534
|
+
send_obj_dup["notice"] = notice_name.to_s
|
535
|
+
|
536
|
+
# データ送信時にクライアントからのレスポンスを確認する(Flashのバグらしきもの対策)
|
537
|
+
if notice_name.to_s =~ /^return_/
|
538
|
+
cs_send_data(sock, send_obj_dup, :type=>dtype) # データ送信
|
539
|
+
cs_logger.debug "cs_server_send_data:finish send data notice_name=#{notice_name.inspect}\n"
|
540
|
+
else
|
541
|
+
Thread.start do
|
542
|
+
mutex_socket_list.synchronize(session_id) do
|
543
|
+
send_receive_shared[notice_name] = nil
|
544
|
+
|
545
|
+
receive_thread = nil
|
546
|
+
end_reserved_time = Time.now + timeout
|
547
|
+
|
548
|
+
# 戻ってきたデータのチェック
|
549
|
+
notice_name_sym = (notice_name.class == Symbol) ? (":"+notice_name.to_s) : ('"'+notice_name+'"')
|
550
|
+
instance_method_name = "cs_receive_response_#{notice_name}"
|
551
|
+
expr = <<-EOF
|
552
|
+
def self.#{instance_method_name}(ret_obj)
|
553
|
+
cs_logger.debug "ret_obj:" + ret_obj.inspect
|
554
|
+
send_receive_shared[#{notice_name_sym}] = ret_obj
|
555
|
+
end
|
556
|
+
cs_logger.debug "defined:#{instance_method_name}"
|
557
|
+
EOF
|
558
|
+
instance_eval expr
|
559
|
+
|
560
|
+
# タイムアウトチェック
|
561
|
+
(timeout.to_f / SendReceiveSleepIntervalSec).to_i.times do
|
562
|
+
raise(DangoFrameworkTimeoutError, "timeout:#{notice_name}") if Time.now > end_reserved_time
|
563
|
+
|
564
|
+
# 送信スレッドが開始していなければ開始
|
565
|
+
if !receive_thread
|
566
|
+
receive_thread = Thread.start do
|
567
|
+
cs_send_data(sock, send_obj_dup, :type=>dtype) # データ送信
|
568
|
+
cs_logger.debug "cs_server_send_data:finish send data notice_name=#{notice_name.inspect}\n"
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
# 戻ってきたデータがあれば
|
573
|
+
if send_receive_shared[notice_name]
|
574
|
+
cs_logger.debug "notice_name:#{send_receive_shared[notice_name].inspect}"
|
575
|
+
break
|
576
|
+
end
|
577
|
+
|
578
|
+
cs_logger.debug "sleep:#{SendReceiveSleepIntervalSec}"
|
579
|
+
sleep SendReceiveSleepIntervalSec # スリープ
|
580
|
+
end
|
581
|
+
|
582
|
+
if !send_receive_shared[notice_name] # 戻ってきたデータがあるかどうかチェック
|
583
|
+
raise(DangoFrameworkError, "received data is none")
|
584
|
+
end
|
585
|
+
|
586
|
+
remove_method(instance_method_name) # 定義したインスタンスメソッドを削除しておく
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
self
|
592
|
+
end
|
593
|
+
|
594
|
+
# メンテナンスコマンド:エラーの場合
|
595
|
+
def cs_check_monitor_error(sock, return_command)
|
596
|
+
peerhost, peeraddr = sock.peeraddr[2, 2]
|
597
|
+
backdoor_host = @config['server']['backdoor_host']
|
598
|
+
match = false
|
599
|
+
if peerhost == backdoor_host # ホスト名で書いてある時の一致確認
|
600
|
+
match = true
|
601
|
+
else
|
602
|
+
begin # IPアドレスの一致確認
|
603
|
+
match = true if IPAddr.new(peeraddr) == IPAddr.new(backdoor_host)
|
604
|
+
rescue
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
if !match
|
609
|
+
send_obj = {'code'=>1, 'message'=>"error your ip address"}
|
610
|
+
cs_server_send_data(session[:session_id], return_command, send_obj, :type=>2)
|
611
|
+
raise(DangoFrameworkError)
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
# メンテナンスコマンド:サーバーからクライアントへのデータ送信
|
616
|
+
def cs_server_monitor_all_info()
|
617
|
+
all_info = {
|
618
|
+
'shareds' => shared.to_hash,
|
619
|
+
'socket_list' => socket_list.keys,
|
620
|
+
|
621
|
+
'server_start_time' => @start_time.strftime("%Y-%m-%d %H:%M:%S"),
|
622
|
+
'up_time' => Time.now - @start_time,
|
623
|
+
|
624
|
+
'recv_count' => @recv_count, # 受信回数
|
625
|
+
'send_count' => @send_count, # 送信回数
|
626
|
+
'recv_fail_count' => @recv_fail_count, # 受信失敗回数
|
627
|
+
'send_fail_count' => @send_fail_count, # 送信失敗回数
|
628
|
+
# 'dummy' => "dummy "*1000, # ダミー情報
|
629
|
+
}
|
630
|
+
|
631
|
+
send_obj = {'code'=>0, 'all_info'=>all_info}
|
632
|
+
cs_server_send_data(session[:session_id], 'return_monitor_all_info', send_obj, :type=>2)
|
633
|
+
end
|
634
|
+
|
635
|
+
# メンテナンスコマンド:サーバーからクライアントへのデータ送信
|
636
|
+
def cs_server_monitor_server_reload()
|
637
|
+
cs_logger.debug "cs_server_monitor_server_reload"
|
638
|
+
@server_reload = true
|
639
|
+
cs_logger.debug "@server_reload=#{@server_reload.inspect}"
|
640
|
+
send_obj = {'code'=>0, 'message'=>'success'}
|
641
|
+
cs_server_send_data(session[:session_id], 'return_monitor_server_reload', send_obj, :type=>2)
|
642
|
+
end
|
643
|
+
|
644
|
+
# 必要に応じて追加するメソッド
|
645
|
+
def method_missing(name, *args)
|
646
|
+
if name.to_s =~ /^cs_receive_action_notice_shared_(.+)/ # 共有メモリ変更通知なら
|
647
|
+
key = $1
|
648
|
+
method_action_notice_shared(key, name, *args)
|
649
|
+
else
|
650
|
+
# raise(NameError, "method not found. #{name.inspect} #{args.inspect}")
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
def method_action_notice_shared(key, name, *args) # 共有メモリ変更通知のメソッド
|
655
|
+
cs_logger.debug "method_name:#{name}"
|
656
|
+
send_obj = args[0]
|
657
|
+
notice_shared.notice_change(key.to_sym, send_obj)
|
658
|
+
end
|
659
|
+
|
660
|
+
end
|
661
|
+
|