acpc_table_manager 1.0.9 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/acpc_proxy +5 -1
- data/exe/acpc_table_manager +5 -1
- data/lib/acpc_table_manager/config.rb +16 -4
- data/lib/acpc_table_manager/maintainer.rb +81 -8
- data/lib/acpc_table_manager/simple_logging.rb +1 -1
- data/lib/acpc_table_manager/table_queue.rb +19 -14
- data/lib/acpc_table_manager/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5d135a405ab862b042bc72b5bc5f9171e3bd0ed
|
4
|
+
data.tar.gz: 0ee34a84a44f500946fdab2e8b08945b0ce09366
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c0d1bee251f1d5bc040c6feb568cc278ef5fcbef42f020199ab5dea64ebb89c0a92ed7e440ffa6a67a210da187d1e4810ac7fb849e063803b5bc1bd40877d8d
|
7
|
+
data.tar.gz: a13cab8ef8c26b889577d05094bed698b00ceca9f02bba5b34c137f8fe73dd2534ffdefd2dd0d8e4e4c835905753a975d00862c9d3db36733aff9bf1b1fb2812
|
data/exe/acpc_proxy
CHANGED
@@ -44,8 +44,12 @@ unless match.running? && !match.finished?
|
|
44
44
|
raise OptionParser::ArgumentError.new("Match \"#{options[:match_id]}\" is not running or has already finished.")
|
45
45
|
end
|
46
46
|
|
47
|
+
Signal.trap("INT") { exit }
|
48
|
+
Signal.trap("TERM") { exit }
|
49
|
+
|
47
50
|
begin
|
48
51
|
proxy = AcpcTableManager::Proxy.start match
|
52
|
+
proxy.log __method__, options
|
49
53
|
loop do
|
50
54
|
message = AcpcTableManager.redis.blpop(
|
51
55
|
"#{AcpcTableManager.config.player_action_channel_prefix}#{options[:match_id]}",
|
@@ -78,5 +82,5 @@ rescue => e
|
|
78
82
|
},
|
79
83
|
Logger::Severity::ERROR
|
80
84
|
)
|
81
|
-
|
85
|
+
AcpcTableManager.notify e # Send an email notification
|
82
86
|
end
|
data/exe/acpc_table_manager
CHANGED
@@ -30,6 +30,10 @@ CONFIG_FILE = options[:table_manager_config]
|
|
30
30
|
|
31
31
|
AcpcTableManager.load! CONFIG_FILE
|
32
32
|
table_manager = AcpcTableManager::Maintainer.new
|
33
|
+
|
34
|
+
Signal.trap("INT") { exit }
|
35
|
+
Signal.trap("TERM") { exit }
|
36
|
+
|
33
37
|
loop do
|
34
38
|
begin
|
35
39
|
message = AcpcTableManager.redis.blpop("table-manager", :timeout => AcpcTableManager.config.maintenance_interval_s)
|
@@ -64,6 +68,6 @@ loop do
|
|
64
68
|
},
|
65
69
|
Logger::Severity::ERROR
|
66
70
|
)
|
67
|
-
|
71
|
+
AcpcTableManager.notify e
|
68
72
|
end
|
69
73
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'json'
|
3
3
|
require 'mongoid'
|
4
|
+
require 'moped'
|
4
5
|
require 'rusen'
|
5
6
|
require 'contextual_exceptions'
|
6
7
|
require 'acpc_dealer'
|
@@ -18,9 +19,9 @@ module AcpcTableManager
|
|
18
19
|
THIS_MACHINE = Socket.gethostname
|
19
20
|
DEALER_HOST = THIS_MACHINE
|
20
21
|
|
21
|
-
attr_reader :file, :log_directory, :my_log_directory, :match_log_directory
|
22
|
+
attr_reader :file, :log_directory, :my_log_directory, :match_log_directory, :proxy_pids_file
|
22
23
|
|
23
|
-
def initialize(file_path, log_directory_, match_log_directory_, interpolation_hash)
|
24
|
+
def initialize(file_path, log_directory_, match_log_directory_, proxy_pids_file_, interpolation_hash)
|
24
25
|
@file = file_path
|
25
26
|
JSON.parse(File.read(file_path)).each do |constant, val|
|
26
27
|
define_singleton_method(constant.to_sym) do
|
@@ -30,6 +31,7 @@ module AcpcTableManager
|
|
30
31
|
@log_directory = log_directory_
|
31
32
|
@match_log_directory = match_log_directory_
|
32
33
|
@my_log_directory = File.join(@log_directory, 'acpc_table_manager')
|
34
|
+
@proxy_pids_file = proxy_pids_file_
|
33
35
|
@logger = Logger.from_file_name(File.join(@my_log_directory, 'config.log'))
|
34
36
|
end
|
35
37
|
|
@@ -124,6 +126,9 @@ module AcpcTableManager
|
|
124
126
|
@@config_file = nil
|
125
127
|
def self.config_file() @@config_file end
|
126
128
|
|
129
|
+
@@notifier = nil
|
130
|
+
def self.notifier() @@notifier end
|
131
|
+
|
127
132
|
def self.load_config!(config_data, yaml_directory = File.pwd)
|
128
133
|
interpolation_hash = {
|
129
134
|
pwd: yaml_directory,
|
@@ -137,6 +142,7 @@ module AcpcTableManager
|
|
137
142
|
config['table_manager_constants'],
|
138
143
|
config['log_directory'],
|
139
144
|
config['match_log_directory'],
|
145
|
+
config['proxy_pids_file'],
|
140
146
|
interpolation_hash
|
141
147
|
)
|
142
148
|
@@exhibition_config = ExhibitionConfig.new(
|
@@ -145,7 +151,11 @@ module AcpcTableManager
|
|
145
151
|
Logger.from_file_name(File.join(@@config.my_log_directory, 'exhibition_config.log'))
|
146
152
|
)
|
147
153
|
|
148
|
-
|
154
|
+
# Moped.logger = Logger.from_file_name(File.join(@@config.log_directory, 'moped.log'))
|
155
|
+
# Mongoid.logger = Logger.from_file_name(File.join(@@config.log_directory, 'mongoid.log'))
|
156
|
+
# TODO: These should be set in configuration files
|
157
|
+
Moped.logger.level = ::Logger::FATAL
|
158
|
+
Mongoid.logger.level = ::Logger::FATAL
|
149
159
|
Mongoid.load!(config['mongoid_config'], config['mongoid_env'].to_sym)
|
150
160
|
|
151
161
|
if config['error_report']
|
@@ -156,6 +166,8 @@ module AcpcTableManager
|
|
156
166
|
Rusen.settings.sections = config['error_report']['sections'] || [:backtrace]
|
157
167
|
Rusen.settings.email_prefix = config['error_report']['email_prefix'] || '[ERROR] '
|
158
168
|
Rusen.settings.smtp_settings = config['error_report']['smtp']
|
169
|
+
|
170
|
+
@@notifier = Rusen
|
159
171
|
else
|
160
172
|
@@config.log(__method__, {warning: "Email reporting disabled. Please set email configuration to enable this feature."}, Logger::Severity::WARN)
|
161
173
|
end
|
@@ -182,7 +194,7 @@ module AcpcTableManager
|
|
182
194
|
end
|
183
195
|
|
184
196
|
def self.notify(exception)
|
185
|
-
|
197
|
+
@@notifier.notify(exception) if @@notifier
|
186
198
|
end
|
187
199
|
|
188
200
|
def self.initialized?
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
require_relative 'dealer'
|
2
3
|
require_relative 'match'
|
3
4
|
|
@@ -8,36 +9,103 @@ module AcpcTableManager
|
|
8
9
|
class Maintainer
|
9
10
|
include SimpleLogging
|
10
11
|
|
12
|
+
def self.proxy_pids(pids_file)
|
13
|
+
if !File.exists?(pids_file)
|
14
|
+
File.open(pids_file, 'w') do |pids_file|
|
15
|
+
yield pids_file, {} if block_given?
|
16
|
+
end
|
17
|
+
else
|
18
|
+
File.open(pids_file, 'r+') do |pids_file|
|
19
|
+
pids = YAML.safe_load(pids_file) || {}
|
20
|
+
pids_file.seek(0, IO::SEEK_SET)
|
21
|
+
pids_file.truncate(0)
|
22
|
+
yield pids_file, pids if block_given?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.kill_orphan_proxies(pids, pids_file)
|
28
|
+
new_pids = []
|
29
|
+
pids.each do |pid_pair|
|
30
|
+
if AcpcDealer::process_exists?(pid_pair['proxy']) && !AcpcDealer::process_exists?(pid_pair['dealer'])
|
31
|
+
AcpcDealer::kill_process pid_pair['proxy']
|
32
|
+
sleep 1 # Give the process a chance to exit
|
33
|
+
|
34
|
+
if AcpcDealer::process_exists?(pid_pair['proxy'])
|
35
|
+
AcpcDealer::force_kill_process pid_pair['proxy']
|
36
|
+
sleep 1 # Give the process a chance to exit
|
37
|
+
|
38
|
+
if AcpcDealer::process_exists?(pid_pair['proxy'])
|
39
|
+
raise(
|
40
|
+
StandardError.new(
|
41
|
+
"Proxy process #{pid_pair['proxy']} couldn't be killed!"
|
42
|
+
)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
new_pids << pid_pair
|
48
|
+
end
|
49
|
+
end
|
50
|
+
new_pids
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.update_pids(pids)
|
54
|
+
pids, pids_file = proxy_pids proxy_pids_file do |pids_file, pids|
|
55
|
+
pids = kill_orphan_proxies pids, pids_file
|
56
|
+
|
57
|
+
matches_started = yield if block_given?
|
58
|
+
|
59
|
+
matches_started.each do |info|
|
60
|
+
if info
|
61
|
+
pids << {'dealer' => info[:dealer][:pid], 'proxy' => info[:proxy]}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
pids_file.write(YAML.dump(pids)) unless pids.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.proxy_pids_file() ::AcpcTableManager.config.proxy_pids_file end
|
69
|
+
|
11
70
|
def initialize(logger_ = AcpcTableManager.new_log('table_manager.log'))
|
12
71
|
@logger = logger_
|
13
|
-
|
14
72
|
@table_queues = {}
|
15
|
-
|
73
|
+
|
74
|
+
maintain!
|
16
75
|
|
17
76
|
log(__method__)
|
18
77
|
end
|
19
78
|
|
20
79
|
def enqueue_waiting_matches(game_definition_key=nil)
|
80
|
+
queues_touched = []
|
21
81
|
if game_definition_key
|
22
82
|
@table_queues[game_definition_key] ||= ::AcpcTableManager::TableQueue.new(game_definition_key)
|
23
83
|
matches_to_check = @table_queues[game_definition_key].my_matches.not_running.and.not_started.to_a
|
24
84
|
matches_to_check.each do |m|
|
25
85
|
unless @table_queues[game_definition_key].running_matches[m.id.to_s]
|
26
|
-
@table_queues[game_definition_key].enqueue!
|
86
|
+
queues_touched << @table_queues[game_definition_key].enqueue!(m.id.to_s, m.dealer_options)
|
27
87
|
end
|
28
88
|
end
|
29
89
|
else
|
30
90
|
::AcpcTableManager.exhibition_config.games.keys.each do |game_definition_key|
|
31
|
-
enqueue_waiting_matches
|
91
|
+
queues_touched += enqueue_waiting_matches(game_definition_key)
|
32
92
|
end
|
33
93
|
end
|
94
|
+
queues_touched
|
34
95
|
end
|
35
96
|
|
36
97
|
def maintain!
|
37
98
|
log __method__, msg: "Starting maintenance"
|
38
99
|
|
39
|
-
|
40
|
-
|
100
|
+
self.class().update_pids self.class().proxy_pids_file do
|
101
|
+
queues_touched = enqueue_waiting_matches
|
102
|
+
matches_started = []
|
103
|
+
queues_touched.each do |_, queue|
|
104
|
+
matches_started << queue.check_queue!
|
105
|
+
end
|
106
|
+
matches_started
|
107
|
+
end
|
108
|
+
|
41
109
|
clean_up_matches!
|
42
110
|
|
43
111
|
log __method__, msg: "Finished maintenance"
|
@@ -61,7 +129,10 @@ module AcpcTableManager
|
|
61
129
|
rescue Mongoid::Errors::DocumentNotFound
|
62
130
|
return kill_match!(match_id)
|
63
131
|
else
|
64
|
-
|
132
|
+
self.class().update_pids self.class().proxy_pids_file do
|
133
|
+
@table_queues[m.game_definition_key.to_s].enqueue! match_id, options
|
134
|
+
@table_queues[m.game_definition_key.to_s].check_queue!
|
135
|
+
end
|
65
136
|
end
|
66
137
|
end
|
67
138
|
|
@@ -71,7 +142,9 @@ module AcpcTableManager
|
|
71
142
|
rescue Mongoid::Errors::DocumentNotFound
|
72
143
|
return kill_match!(match_id)
|
73
144
|
else
|
74
|
-
|
145
|
+
self.class().update_pids self.class().proxy_pids_file do
|
146
|
+
[@table_queues[match.game_definition_key.to_s].start_proxy(match)]
|
147
|
+
end
|
75
148
|
end
|
76
149
|
end
|
77
150
|
|
@@ -5,7 +5,7 @@ require 'fileutils'
|
|
5
5
|
class Logger
|
6
6
|
# Defaults correspond to Logger#new defaults
|
7
7
|
def self.from_file_name(file_name, shift_age = 0, shift_size = 1048576)
|
8
|
-
unless File.
|
8
|
+
unless File.exist?(file_name)
|
9
9
|
FileUtils.mkdir_p File.dirname(file_name)
|
10
10
|
FileUtils.touch file_name
|
11
11
|
end
|
@@ -55,7 +55,6 @@ module AcpcTableManager
|
|
55
55
|
log(__method__, msg: "Opponents started for #{match.id.to_s}")
|
56
56
|
|
57
57
|
start_proxy match
|
58
|
-
self
|
59
58
|
end
|
60
59
|
|
61
60
|
def start_proxy(match)
|
@@ -81,6 +80,7 @@ module AcpcTableManager
|
|
81
80
|
pid: @running_matches[match.id.to_s][:proxy]
|
82
81
|
}
|
83
82
|
)
|
83
|
+
@running_matches[match.id.to_s]
|
84
84
|
end
|
85
85
|
|
86
86
|
def my_matches
|
@@ -114,7 +114,7 @@ module AcpcTableManager
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
# @return
|
117
|
+
# @return +self+
|
118
118
|
def enqueue!(match_id, dealer_options)
|
119
119
|
log(
|
120
120
|
__method__,
|
@@ -127,18 +127,18 @@ module AcpcTableManager
|
|
127
127
|
)
|
128
128
|
|
129
129
|
if @running_matches[match_id]
|
130
|
-
|
130
|
+
log(
|
131
131
|
__method__,
|
132
132
|
msg: "Match #{match_id} already started!"
|
133
133
|
)
|
134
|
+
return self
|
134
135
|
end
|
135
136
|
|
136
137
|
@matches_to_start << {match_id: match_id, options: dealer_options}
|
137
|
-
|
138
|
-
check_queue!
|
138
|
+
self
|
139
139
|
end
|
140
140
|
|
141
|
-
# @return
|
141
|
+
# @return [Array] The list of PID information about the matches that were dequeued.
|
142
142
|
def check_queue!
|
143
143
|
log __method__
|
144
144
|
|
@@ -146,11 +146,14 @@ module AcpcTableManager
|
|
146
146
|
|
147
147
|
log __method__, {num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
nil
|
149
|
+
matches_started = []
|
150
|
+
while !@matches_to_start.empty? && @running_matches.length < AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
|
151
|
+
matches_started << dequeue
|
153
152
|
end
|
153
|
+
|
154
|
+
log __method__, {matches_started: matches_started, num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
|
155
|
+
|
156
|
+
matches_started
|
154
157
|
end
|
155
158
|
|
156
159
|
# @todo Shouldn't be necessary, so this method isn't called right now, but I've written it so I'll leave it for now
|
@@ -338,8 +341,8 @@ module AcpcTableManager
|
|
338
341
|
end
|
339
342
|
|
340
343
|
# @return [Object] The match that has been started or +nil+ if none could
|
341
|
-
#
|
342
|
-
def dequeue
|
344
|
+
# be started.
|
345
|
+
def dequeue
|
343
346
|
log(
|
344
347
|
__method__,
|
345
348
|
num_matches_to_start: @matches_to_start.length
|
@@ -355,12 +358,12 @@ module AcpcTableManager
|
|
355
358
|
begin
|
356
359
|
match = Match.find match_id
|
357
360
|
rescue Mongoid::Errors::DocumentNotFound
|
358
|
-
return
|
361
|
+
return nil if @matches_to_start.empty?
|
359
362
|
else
|
360
363
|
break
|
361
364
|
end
|
362
365
|
end
|
363
|
-
return
|
366
|
+
return nil unless match_id
|
364
367
|
|
365
368
|
options = match_info[:options]
|
366
369
|
|
@@ -452,6 +455,8 @@ module AcpcTableManager
|
|
452
455
|
)
|
453
456
|
|
454
457
|
start_players! match
|
458
|
+
|
459
|
+
@running_matches[match_id]
|
455
460
|
end
|
456
461
|
end
|
457
462
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acpc_table_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Morrill
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pony
|
@@ -318,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
318
318
|
version: '0'
|
319
319
|
requirements: []
|
320
320
|
rubyforge_project:
|
321
|
-
rubygems_version: 2.
|
321
|
+
rubygems_version: 2.5.1
|
322
322
|
signing_key:
|
323
323
|
specification_version: 4
|
324
324
|
summary: Backend components to the ACPC Poker GUI Client
|