dango 0.0.1
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.
- 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
|
+
|