acpc_table_manager 2.2.3 → 3.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 +7 -10
- data/exe/acpc_table_manager +5 -12
- data/lib/acpc_table_manager/config.rb +1 -1
- data/lib/acpc_table_manager/dealer.rb +9 -5
- data/lib/acpc_table_manager/maintainer.rb +8 -220
- data/lib/acpc_table_manager/match.rb +119 -20
- data/lib/acpc_table_manager/match_slice.rb +1 -0
- data/lib/acpc_table_manager/opponents.rb +27 -5
- data/lib/acpc_table_manager/proxy.rb +27 -18
- data/lib/acpc_table_manager/table_queue.rb +49 -280
- data/lib/acpc_table_manager/utils.rb +10 -1
- data/lib/acpc_table_manager/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7ccf8130e5686e105baea868fb25168df10a64b
|
4
|
+
data.tar.gz: 48a25e5be4a4d5fc18b2c4e96044e7f40f5b30d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b26c482c1625469524e338fee40457b0efae1ea24521252f0fa45edf64b7e31bb44939d52b5347fca0812daf608e712bb4c29161d84742e5171b2fb943c9c0c
|
7
|
+
data.tar.gz: c163fbf0a7717da2dc35e389e5892fbb8e7a1d27102b0b9733894ff16584ef181830bf733d9add44e68f0c20feff0d226b19707e5a2c1b7d4468a6b7564be3c7
|
data/exe/acpc_proxy
CHANGED
@@ -71,6 +71,8 @@ begin
|
|
71
71
|
proxy.play! action
|
72
72
|
end
|
73
73
|
last_message_received = Time.now
|
74
|
+
elsif !proxy.users_turn_to_act?
|
75
|
+
last_message_received = Time.now
|
74
76
|
elsif (
|
75
77
|
AcpcTableManager.config.proxy_timeout_s &&
|
76
78
|
(
|
@@ -82,16 +84,11 @@ begin
|
|
82
84
|
# @todo Allow different behaviour on timeout
|
83
85
|
proxy.play_check_fold!
|
84
86
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
'params' => {
|
91
|
-
AcpcTableManager.config.match_id_key => options[:match_id]
|
92
|
-
}
|
93
|
-
}.to_json
|
94
|
-
)
|
87
|
+
match = AcpcTableManager::Match.find options[:match_id]
|
88
|
+
if proxy.match_ended? or !match.dealer_running?
|
89
|
+
match.proxy_pid = -1
|
90
|
+
match.dealer_pid = -1
|
91
|
+
match.save!
|
95
92
|
exit
|
96
93
|
end
|
97
94
|
end
|
data/exe/acpc_table_manager
CHANGED
@@ -4,6 +4,7 @@ require 'acpc_table_manager'
|
|
4
4
|
require 'redis'
|
5
5
|
require 'json'
|
6
6
|
require 'optparse'
|
7
|
+
require 'acpc_table_manager/match'
|
7
8
|
|
8
9
|
|
9
10
|
ARGV << '-h' if ARGV.empty?
|
@@ -42,25 +43,17 @@ loop do
|
|
42
43
|
table_manager.log(__method__, {data: data})
|
43
44
|
|
44
45
|
case data['request']
|
45
|
-
when AcpcTableManager.config.
|
46
|
-
table_manager.enqueue_match!(
|
47
|
-
data['params'][AcpcTableManager.config.match_id_key],
|
48
|
-
data['params'][AcpcTableManager.config.options_key]
|
49
|
-
)
|
46
|
+
when AcpcTableManager.config.check_matches
|
50
47
|
when AcpcTableManager.config.kill_match
|
51
|
-
|
48
|
+
match = AcpcTableManager::Match.quiet_find data['params'][AcpcTableManager.config.match_id_key]
|
49
|
+
if match then match.kill_proxy! end
|
52
50
|
when 'reload'
|
53
51
|
AcpcTableManager.load! CONFIG_FILE
|
54
|
-
when AcpcTableManager.config.check_match
|
55
|
-
table_manager.check_match data['params'][AcpcTableManager.config.match_id_key]
|
56
|
-
when AcpcTableManager.config.delete_irrelevant_matches_request_code
|
57
|
-
table_manager.clean_up_matches!
|
58
52
|
else
|
59
53
|
raise StandardError.new("Unrecognized request: #{data['request']}")
|
60
54
|
end
|
61
|
-
else
|
62
|
-
table_manager.maintain!
|
63
55
|
end
|
56
|
+
table_manager.maintain!
|
64
57
|
rescue => e
|
65
58
|
table_manager.log(
|
66
59
|
__method__,
|
@@ -61,7 +61,7 @@ module AcpcTableManager
|
|
61
61
|
instance_variable_get("@#{constant}".to_sym)
|
62
62
|
end
|
63
63
|
end
|
64
|
-
unless
|
64
|
+
unless special_ports_to_dealer
|
65
65
|
@special_ports_to_dealer = []
|
66
66
|
log(__method__, {adding: {method: 'special_ports_to_dealer', value: @special_ports_to_dealer}})
|
67
67
|
define_singleton_method(:special_ports_to_dealer) do
|
@@ -15,21 +15,22 @@ module Dealer
|
|
15
15
|
|
16
16
|
# @return [Hash<Symbol, Object>] The dealer information
|
17
17
|
# @note Saves the actual port numbers used by the dealer instance in +match+
|
18
|
-
def self.start(
|
18
|
+
def self.start(match, port_numbers: nil)
|
19
19
|
@logger ||= ::AcpcTableManager.new_log 'dealer.log'
|
20
|
-
log __method__,
|
20
|
+
log __method__, match: match
|
21
21
|
|
22
22
|
dealer_arguments = {
|
23
|
-
match_name:
|
23
|
+
match_name: match.sanitized_name,
|
24
24
|
game_def_file_name: Shellwords.escape(match.game_definition_file_name),
|
25
25
|
hands: Shellwords.escape(match.number_of_hands),
|
26
26
|
random_seed: Shellwords.escape(match.random_seed.to_s),
|
27
27
|
player_names: match.player_names.map { |name| Shellwords.escape(name.gsub(/\s+/, '_')) }.join(' '),
|
28
|
-
options:
|
28
|
+
options: match.dealer_options
|
29
29
|
}
|
30
30
|
|
31
31
|
log __method__, {
|
32
32
|
match_id: match.id,
|
33
|
+
match_name: match.name,
|
33
34
|
dealer_arguments: dealer_arguments,
|
34
35
|
log_directory: ::AcpcTableManager.config.match_log_directory,
|
35
36
|
port_numbers: port_numbers,
|
@@ -44,11 +45,14 @@ module Dealer
|
|
44
45
|
)
|
45
46
|
end
|
46
47
|
|
47
|
-
match.
|
48
|
+
match.dealer_pid = dealer_info[:pid]
|
49
|
+
match.port_numbers = dealer_info[:port_numbers].map { |e| e.to_i }
|
48
50
|
match.save!
|
49
51
|
|
50
52
|
log __method__, {
|
51
53
|
match_id: match.id,
|
54
|
+
match_name: match.name,
|
55
|
+
dealer_pid: match.dealer_pid,
|
52
56
|
saved_port_numbers: match.port_numbers
|
53
57
|
}
|
54
58
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require_relative 'dealer'
|
3
3
|
require_relative 'match'
|
4
|
+
require_relative 'table_queue'
|
4
5
|
|
5
6
|
require_relative 'simple_logging'
|
6
7
|
using AcpcTableManager::SimpleLogging::MessageFormatting
|
@@ -9,239 +10,26 @@ module AcpcTableManager
|
|
9
10
|
class Maintainer
|
10
11
|
include SimpleLogging
|
11
12
|
|
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_process_if_running(pid)
|
28
|
-
begin
|
29
|
-
AcpcDealer::kill_process pid
|
30
|
-
sleep 1 # Give the process a chance to exit
|
31
|
-
|
32
|
-
if AcpcDealer::process_exists?(pid)
|
33
|
-
AcpcDealer::force_kill_process pid
|
34
|
-
sleep 1 # Give the process a chance to exit
|
35
|
-
|
36
|
-
if AcpcDealer::process_exists?(pid)
|
37
|
-
yield if block_given?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
rescue Errno::ESRCH
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.kill_orphan_proxies(pids, pids_file)
|
45
|
-
new_pids = []
|
46
|
-
pids.each do |pid_pair|
|
47
|
-
proxy_running = AcpcDealer::process_exists?(pid_pair['proxy'])
|
48
|
-
if proxy_running && AcpcDealer::process_exists?(pid_pair['dealer'])
|
49
|
-
new_pids << pid_pair
|
50
|
-
elsif proxy_running
|
51
|
-
kill_process_if_running pid_pair['proxy'] do
|
52
|
-
raise(
|
53
|
-
StandardError.new(
|
54
|
-
"Proxy process #{pid_pair['proxy']} couldn't be killed!"
|
55
|
-
)
|
56
|
-
)
|
57
|
-
end
|
58
|
-
else
|
59
|
-
kill_process_if_running pid_pair['dealer'] do
|
60
|
-
raise(
|
61
|
-
StandardError.new(
|
62
|
-
"Dealer process #{pid_pair['dealer']} couldn't be killed!"
|
63
|
-
)
|
64
|
-
)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
new_pids
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.update_pids(pids)
|
72
|
-
pids, pids_file = proxy_pids proxy_pids_file do |pids_file, pids|
|
73
|
-
pids = kill_orphan_proxies pids, pids_file
|
74
|
-
|
75
|
-
matches_started = yield if block_given?
|
76
|
-
|
77
|
-
matches_started.each do |info|
|
78
|
-
if info
|
79
|
-
pids << {'dealer' => info[:dealer][:pid], 'proxy' => info[:proxy]}
|
80
|
-
end
|
81
|
-
end
|
82
|
-
pids_file.write(YAML.dump(pids)) unless pids.empty?
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.proxy_pids_file() ::AcpcTableManager.config.proxy_pids_file end
|
87
|
-
|
88
13
|
def initialize(logger_ = AcpcTableManager.new_log('table_manager.log'))
|
89
14
|
@logger = logger_
|
90
|
-
@table_queues = {}
|
91
|
-
|
92
|
-
maintain!
|
93
|
-
|
94
15
|
log(__method__)
|
95
|
-
end
|
96
16
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
@table_queues[game_definition_key] ||= ::AcpcTableManager::TableQueue.new(game_definition_key)
|
101
|
-
matches_to_check = @table_queues[game_definition_key].my_matches.not_running.and.not_started.to_a
|
102
|
-
matches_to_check.each do |m|
|
103
|
-
unless @table_queues[game_definition_key].running_matches[m.id.to_s]
|
104
|
-
queues_touched << @table_queues[game_definition_key].enqueue!(m.id.to_s, m.dealer_options)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
else
|
108
|
-
::AcpcTableManager.exhibition_config.games.keys.each do |game_definition_key|
|
109
|
-
queues_touched += enqueue_waiting_matches(game_definition_key)
|
110
|
-
end
|
17
|
+
@table_queues = {}
|
18
|
+
::AcpcTableManager.exhibition_config.games.keys.each do |game_definition_key|
|
19
|
+
@table_queues[game_definition_key] = ::AcpcTableManager::TableQueue.new(game_definition_key)
|
111
20
|
end
|
112
|
-
|
21
|
+
maintain!
|
113
22
|
end
|
114
23
|
|
115
24
|
def maintain!
|
116
25
|
log __method__, msg: "Starting maintenance"
|
117
26
|
|
118
|
-
self.class().update_pids self.class().proxy_pids_file do
|
119
|
-
queues_touched = enqueue_waiting_matches
|
120
|
-
matches_started = []
|
121
|
-
queues_touched.each do |queue|
|
122
|
-
matches_started << queue.check_queue!
|
123
|
-
end
|
124
|
-
matches_started
|
125
|
-
end
|
126
|
-
|
127
|
-
clean_up_matches!
|
128
|
-
|
129
|
-
log __method__, msg: "Finished maintenance"
|
130
|
-
end
|
131
|
-
|
132
|
-
def kill_match!(match_id)
|
133
|
-
log(__method__, match_id: match_id)
|
134
|
-
|
135
27
|
@table_queues.each do |key, queue|
|
136
|
-
log(__method__, {queue: key
|
137
|
-
|
138
|
-
queue.kill_match!(match_id)
|
28
|
+
log(__method__, {queue: key})
|
29
|
+
queue.check!
|
139
30
|
end
|
140
|
-
end
|
141
31
|
|
142
|
-
|
143
|
-
::AcpcTableManager::Match.delete_matches_older_than! 1.day
|
144
|
-
end
|
145
|
-
|
146
|
-
def enqueue_match!(match_id, options)
|
147
|
-
begin
|
148
|
-
m = ::AcpcTableManager::Match.find match_id
|
149
|
-
rescue Mongoid::Errors::DocumentNotFound
|
150
|
-
|
151
|
-
log(
|
152
|
-
__method__,
|
153
|
-
{
|
154
|
-
msg: "Match not found",
|
155
|
-
match_id: match_id
|
156
|
-
},
|
157
|
-
Logger::Severity::ERROR
|
158
|
-
)
|
159
|
-
|
160
|
-
return kill_match!(match_id)
|
161
|
-
else
|
162
|
-
self.class().update_pids self.class().proxy_pids_file do
|
163
|
-
@table_queues[m.game_definition_key.to_s].enqueue! match_id, options
|
164
|
-
@table_queues[m.game_definition_key.to_s].check_queue!
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def start_proxy!(match_id)
|
170
|
-
begin
|
171
|
-
match = ::AcpcTableManager::Match.find match_id
|
172
|
-
rescue Mongoid::Errors::DocumentNotFound
|
173
|
-
|
174
|
-
log(
|
175
|
-
__method__,
|
176
|
-
{
|
177
|
-
msg: "Match not found",
|
178
|
-
match_id: match_id
|
179
|
-
},
|
180
|
-
Logger::Severity::ERROR
|
181
|
-
)
|
182
|
-
|
183
|
-
return kill_match!(match_id)
|
184
|
-
else
|
185
|
-
self.class().update_pids self.class().proxy_pids_file do
|
186
|
-
[@table_queues[match.game_definition_key.to_s].start_proxy(match)]
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def check_match(match_id)
|
192
|
-
log(__method__, {match_id: match_id})
|
193
|
-
begin
|
194
|
-
match = ::AcpcTableManager::Match.find match_id
|
195
|
-
rescue Mongoid::Errors::DocumentNotFound
|
196
|
-
log(
|
197
|
-
__method__,
|
198
|
-
{
|
199
|
-
msg: "Match \"#{match_id}\" doesn't exist! Killing match.",
|
200
|
-
match_id: match_id
|
201
|
-
},
|
202
|
-
Logger::Severity::ERROR
|
203
|
-
)
|
204
|
-
return kill_match!(match_id)
|
205
|
-
end
|
206
|
-
unless @table_queues[match.game_definition_key.to_s].running_matches[match_id]
|
207
|
-
log(
|
208
|
-
__method__,
|
209
|
-
{
|
210
|
-
msg: "Match \"#{match_id}\" in seat #{match.seat} doesn't have a proxy! Killing match.",
|
211
|
-
match_id: match_id,
|
212
|
-
match_name: match.name,
|
213
|
-
last_updated_at: match.updated_at,
|
214
|
-
running?: match.running?,
|
215
|
-
last_slice_viewed: match.last_slice_viewed,
|
216
|
-
last_slice_present: match.slices.length - 1
|
217
|
-
},
|
218
|
-
Logger::Severity::ERROR
|
219
|
-
)
|
220
|
-
return kill_match!(match_id)
|
221
|
-
end
|
222
|
-
proxy_pid = @table_queues[match.game_definition_key.to_s].running_matches[match_id][:proxy]
|
223
|
-
|
224
|
-
log __method__, {
|
225
|
-
match_id: match_id,
|
226
|
-
running?: proxy_pid && AcpcDealer::process_exists?(proxy_pid)
|
227
|
-
}
|
228
|
-
|
229
|
-
unless proxy_pid && AcpcDealer::process_exists?(proxy_pid)
|
230
|
-
log(
|
231
|
-
__method__,
|
232
|
-
{
|
233
|
-
msg: "The proxy for match \"#{match_id}\" in seat #{match.seat} isn't running! Killing match.",
|
234
|
-
match_id: match_id,
|
235
|
-
match_name: match.name,
|
236
|
-
last_updated_at: match.updated_at,
|
237
|
-
running?: match.running?,
|
238
|
-
last_slice_viewed: match.last_slice_viewed,
|
239
|
-
last_slice_present: match.slices.length - 1
|
240
|
-
},
|
241
|
-
Logger::Severity::ERROR
|
242
|
-
)
|
243
|
-
kill_match!(match_id)
|
244
|
-
end
|
32
|
+
log __method__, msg: "Finished maintenance"
|
245
33
|
end
|
246
34
|
end
|
247
35
|
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
1
|
require 'mongoid'
|
2
|
+
require 'zaru'
|
3
3
|
|
4
4
|
require 'acpc_poker_types/game_definition'
|
5
5
|
require 'acpc_poker_types/match_state'
|
6
|
+
require 'acpc_dealer'
|
6
7
|
|
7
8
|
require_relative 'match_slice'
|
8
9
|
require_relative 'config'
|
@@ -32,34 +33,86 @@ class Match
|
|
32
33
|
scope :inactive, ->(lifespan) do
|
33
34
|
started.and.old(lifespan)
|
34
35
|
end
|
36
|
+
scope :active_between, ->(lifespan, reference_time=Time.now) do
|
37
|
+
started.and.where(
|
38
|
+
{ 'slices.updated_at' => { '$gt' => (reference_time - lifespan)}}
|
39
|
+
).and.where(
|
40
|
+
{ 'slices.updated_at' => { '$lt' => reference_time}}
|
41
|
+
)
|
42
|
+
end
|
35
43
|
scope :with_slices, ->(has_slices) do
|
36
44
|
where({ 'slices.0' => { '$exists' => has_slices }})
|
37
45
|
end
|
38
46
|
scope :started, -> { with_slices(true) }
|
39
47
|
scope :not_started, -> { with_slices(false) }
|
40
|
-
scope :
|
41
|
-
where(is_running: is_running)
|
42
|
-
end
|
43
|
-
scope :running, -> { with_running_status(true) }
|
44
|
-
scope :not_running, -> { with_running_status(false) }
|
45
|
-
scope :running_or_started, -> { any_of([running.selector, started.selector]) }
|
48
|
+
scope :ready_to_start, -> { where(ready_to_start: true) }
|
46
49
|
|
47
50
|
class << self
|
48
|
-
|
49
|
-
|
51
|
+
# @todo Move to AcpcDealer
|
52
|
+
def kill_process_if_running(pid)
|
53
|
+
begin
|
54
|
+
AcpcDealer::kill_process pid
|
55
|
+
sleep 1 # Give the process a chance to exit
|
56
|
+
|
57
|
+
if AcpcDealer::process_exists?(pid)
|
58
|
+
AcpcDealer::force_kill_process pid
|
59
|
+
sleep 1 # Give the process a chance to exit
|
60
|
+
|
61
|
+
if AcpcDealer::process_exists?(pid)
|
62
|
+
yield if block_given?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
rescue Errno::ESRCH
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def id_exists?(match_id, matches=all)
|
70
|
+
matches.where(id: match_id).exists?
|
71
|
+
end
|
72
|
+
|
73
|
+
def quiet_find(match_id)
|
74
|
+
begin
|
75
|
+
match = Match.find match_id
|
76
|
+
rescue Mongoid::Errors::DocumentNotFound
|
77
|
+
nil
|
78
|
+
end
|
50
79
|
end
|
51
80
|
|
52
81
|
# Almost scopes
|
53
|
-
def
|
54
|
-
|
82
|
+
def running(matches=all)
|
83
|
+
matches.select { |match| match.running? }
|
84
|
+
end
|
85
|
+
def not_running(matches=all)
|
86
|
+
matches.select { |match| !match.running? }
|
87
|
+
end
|
88
|
+
def finished(matches=all)
|
89
|
+
matches.select { |match| match.finished? }
|
55
90
|
end
|
56
91
|
def unfinished(matches=all)
|
57
92
|
matches.select { |match| !match.finished? }
|
58
93
|
end
|
59
|
-
def started_and_unfinished
|
94
|
+
def started_and_unfinished
|
60
95
|
started.to_a.select { |match| !match.finished? }
|
61
96
|
end
|
62
97
|
|
98
|
+
def ports_in_use(matches=all)
|
99
|
+
running(matches).inject([]) { |ports, m| ports += m.port_numbers }
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return The matches to be started (have not been started and not
|
103
|
+
# currently running) ordered from newest to oldest.
|
104
|
+
def start_queue(matches=all)
|
105
|
+
not_running(matches.not_started.and.ready_to_start.desc(:updated_at))
|
106
|
+
end
|
107
|
+
|
108
|
+
def kill_all_orphan_processes!(matches=all)
|
109
|
+
matches.each { |m| m.kill_orphan_processes! }
|
110
|
+
end
|
111
|
+
|
112
|
+
def kill_all_orphan_proxies!(matches=all)
|
113
|
+
matches.each { |m| m.kill_orphan_proxy! }
|
114
|
+
end
|
115
|
+
|
63
116
|
# Schema
|
64
117
|
def include_name
|
65
118
|
field :name
|
@@ -163,7 +216,10 @@ class Match
|
|
163
216
|
field :port_numbers, type: Array
|
164
217
|
field :random_seed, type: Integer, default: new_random_seed
|
165
218
|
field :last_slice_viewed, type: Integer, default: -1
|
166
|
-
field :
|
219
|
+
field :dealer_pid, type: Integer, default: -1
|
220
|
+
field :proxy_pid, type: Integer, default: -1
|
221
|
+
field :ready_to_start, type: Boolean, default: false
|
222
|
+
field :unable_to_start_dealer, type: Boolean, default: false
|
167
223
|
field :dealer_options, type: String, default: (
|
168
224
|
[
|
169
225
|
'-a', # Append logs with the same name rather than overwrite
|
@@ -206,6 +262,10 @@ class Match
|
|
206
262
|
end
|
207
263
|
|
208
264
|
# Initializers
|
265
|
+
def set_dealer_options!(options)
|
266
|
+
self.dealer_options = (options.split(' ').map { |o| Shellwords.escape o }.join(' ') || '')
|
267
|
+
self
|
268
|
+
end
|
209
269
|
def set_name!(name_ = self.name_from_user)
|
210
270
|
name_from_user_ = name_.strip
|
211
271
|
self.name = name_from_user_
|
@@ -230,6 +290,7 @@ class Match
|
|
230
290
|
set_name!.set_seat!.set_game_definition_file_name!.set_game_definition_hash!
|
231
291
|
self.opponent_names ||= self.class().default_opponent_names(game_info['num_players'])
|
232
292
|
self.number_of_hands ||= 1
|
293
|
+
self.ready_to_start = true
|
233
294
|
save!
|
234
295
|
self
|
235
296
|
end
|
@@ -278,14 +339,14 @@ class Match
|
|
278
339
|
def no_limit?
|
279
340
|
@is_no_limit ||= game_def.betting_type == AcpcPokerTypes::GameDefinition::BETTING_TYPES[:nolimit]
|
280
341
|
end
|
281
|
-
def started?
|
282
|
-
|
283
|
-
end
|
284
|
-
def
|
285
|
-
|
342
|
+
def started?() !self.slices.empty? end
|
343
|
+
def finished?() started? && self.slices.last.match_ended? end
|
344
|
+
def running?() dealer_running? && proxy_running? end
|
345
|
+
def dealer_running?
|
346
|
+
self.dealer_pid >= 0 && AcpcDealer::process_exists?(self.dealer_pid)
|
286
347
|
end
|
287
|
-
def
|
288
|
-
self.
|
348
|
+
def proxy_running?
|
349
|
+
self.proxy_pid >= 0 && AcpcDealer::process_exists?(self.proxy_pid)
|
289
350
|
end
|
290
351
|
def all_slices_viewed?
|
291
352
|
self.last_slice_viewed >= (self.slices.length - 1)
|
@@ -346,5 +407,43 @@ class Match
|
|
346
407
|
self.class().where(name: self.name).ne(name_from_user: self.name).map { |m| m.seat }
|
347
408
|
)
|
348
409
|
end
|
410
|
+
def sanitized_name
|
411
|
+
Zaru.sanitize!(Shellwords.escape(self.name.gsub(/\s+/, '_')))
|
412
|
+
end
|
413
|
+
def kill_dealer!
|
414
|
+
self.class().kill_process_if_running(self.dealer_pid) do
|
415
|
+
raise(
|
416
|
+
StandardError.new(
|
417
|
+
"Dealer process #{self.dealer_pid} couldn't be killed!"
|
418
|
+
)
|
419
|
+
)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def defunkt?()
|
424
|
+
(started? and !running? and !finished?) || self.unable_to_start_dealer
|
425
|
+
end
|
426
|
+
|
427
|
+
def kill_proxy!
|
428
|
+
self.class().kill_process_if_running(self.proxy_pid) do
|
429
|
+
raise(
|
430
|
+
StandardError.new(
|
431
|
+
"Proxy process #{self.proxy_pid} couldn't be killed!"
|
432
|
+
)
|
433
|
+
)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def kill_orphan_proxy!
|
438
|
+
kill_proxy! if proxy_running? && !dealer_running?
|
439
|
+
end
|
440
|
+
|
441
|
+
def kill_orphan_processes!
|
442
|
+
if dealer_running? && !proxy_running?
|
443
|
+
kill_dealer!
|
444
|
+
elsif proxy_running && !dealer_running?
|
445
|
+
kill_proxy!
|
446
|
+
end
|
447
|
+
end
|
349
448
|
end
|
350
449
|
end
|
@@ -2,6 +2,7 @@ require 'timeout'
|
|
2
2
|
require 'process_runner'
|
3
3
|
require_relative 'config'
|
4
4
|
require_relative 'simple_logging'
|
5
|
+
require 'fileutils'
|
5
6
|
|
6
7
|
module AcpcTableManager
|
7
8
|
module Opponents
|
@@ -10,20 +11,41 @@ module Opponents
|
|
10
11
|
@logger = nil
|
11
12
|
|
12
13
|
# @return [Array<Integer>] PIDs of the opponents started
|
13
|
-
def self.start(
|
14
|
+
def self.start(match)
|
14
15
|
@logger ||= ::AcpcTableManager.new_log 'opponents.log'
|
15
|
-
|
16
|
+
|
17
|
+
opponents = match.bots(AcpcTableManager.config.dealer_host)
|
18
|
+
log __method__, num_opponents: opponents.length
|
19
|
+
|
20
|
+
if opponents.empty?
|
21
|
+
raise StandardError.new("No opponents found to start for \"#{match.name}\" (#{match.id.to_s})!")
|
22
|
+
end
|
23
|
+
|
24
|
+
opponents_log_dir = File.join(AcpcTableManager.config.log_directory, 'opponents')
|
25
|
+
FileUtils.mkdir(opponents_log_dir) unless File.directory?(opponents_log_dir)
|
26
|
+
|
27
|
+
bot_start_commands = opponents.map do |name, info|
|
28
|
+
{
|
29
|
+
args: [info[:runner], info[:host], info[:port]],
|
30
|
+
log: File.join(opponents_log_dir, "#{match.name}.#{match.id}.#{name}.log")
|
31
|
+
}
|
32
|
+
end
|
16
33
|
|
17
34
|
bot_start_commands.map do |bot_start_command|
|
18
35
|
log(
|
19
36
|
__method__,
|
20
37
|
{
|
21
|
-
bot_start_command_parameters: bot_start_command,
|
22
|
-
command_to_be_run: bot_start_command.join(' ')
|
38
|
+
bot_start_command_parameters: bot_start_command[:args],
|
39
|
+
command_to_be_run: bot_start_command[:args].join(' ')
|
23
40
|
}
|
24
41
|
)
|
25
42
|
pid = Timeout::timeout(3) do
|
26
|
-
ProcessRunner.go(
|
43
|
+
ProcessRunner.go(
|
44
|
+
bot_start_command[:args].map { |e| e.to_s },
|
45
|
+
{
|
46
|
+
[:err, :out] => [bot_start_command[:log], File::CREAT|File::WRONLY]
|
47
|
+
}
|
48
|
+
)
|
27
49
|
end
|
28
50
|
log(
|
29
51
|
__method__,
|
@@ -26,6 +26,7 @@ class Proxy
|
|
26
26
|
|
27
27
|
proxy = new(
|
28
28
|
match.id,
|
29
|
+
match.sanitized_name,
|
29
30
|
AcpcDealer::ConnectionInformation.new(
|
30
31
|
match.port_numbers[match.seat - 1],
|
31
32
|
::AcpcTableManager.config.dealer_host
|
@@ -43,12 +44,14 @@ class Proxy
|
|
43
44
|
# @todo Reduce the # of params
|
44
45
|
#
|
45
46
|
# @param [String] match_id The ID of the match in which this player is participating.
|
47
|
+
# @param [String] match_name The name of the match in which this player is participating.
|
46
48
|
# @param [DealerInformation] dealer_information Information about the dealer to which this bot should connect.
|
47
49
|
# @param [GameDefinition, #to_s] game_definition A game definition; either a +GameDefinition+ or the name of the file containing a game definition.
|
48
50
|
# @param [String] player_names The names of the players in this match.
|
49
51
|
# @param [Integer] number_of_hands The number of hands in this match.
|
50
52
|
def initialize(
|
51
53
|
match_id,
|
54
|
+
match_name,
|
52
55
|
dealer_information,
|
53
56
|
users_seat,
|
54
57
|
game_definition,
|
@@ -56,7 +59,7 @@ class Proxy
|
|
56
59
|
number_of_hands=1,
|
57
60
|
must_send_ready=false
|
58
61
|
)
|
59
|
-
@logger = AcpcTableManager.new_log File.join('proxies', "#{match_id}.#{users_seat}.log")
|
62
|
+
@logger = AcpcTableManager.new_log File.join('proxies', "#{match_name}.#{match_id}.#{users_seat}.log")
|
60
63
|
|
61
64
|
log __method__, {
|
62
65
|
dealer_information: dealer_information,
|
@@ -87,11 +90,13 @@ class Proxy
|
|
87
90
|
def next_hand!
|
88
91
|
log __method__
|
89
92
|
|
90
|
-
@player_proxy.
|
91
|
-
|
93
|
+
if @player_proxy.hand_ended?
|
94
|
+
@player_proxy.next_hand! do |players_at_the_table|
|
95
|
+
update_database! players_at_the_table
|
92
96
|
|
93
|
-
|
94
|
-
|
97
|
+
yield players_at_the_table if block_given?
|
98
|
+
end
|
99
|
+
end
|
95
100
|
|
96
101
|
log(
|
97
102
|
__method__,
|
@@ -107,27 +112,31 @@ class Proxy
|
|
107
112
|
# Player action interface
|
108
113
|
# @see PlayerProxy#play!
|
109
114
|
def play!(action, fast_forward = false)
|
110
|
-
log __method__, action: action
|
115
|
+
log __method__, users_turn_to_act?: @player_proxy.users_turn_to_act?, action: action
|
111
116
|
|
112
|
-
|
117
|
+
if @player_proxy.users_turn_to_act?
|
118
|
+
action = PokerAction.new(action) unless action.is_a?(PokerAction)
|
113
119
|
|
114
|
-
|
115
|
-
|
120
|
+
@player_proxy.play! action do |players_at_the_table|
|
121
|
+
update_database! players_at_the_table, fast_forward
|
116
122
|
|
117
|
-
|
118
|
-
|
123
|
+
yield players_at_the_table if block_given?
|
124
|
+
end
|
119
125
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
126
|
+
log(
|
127
|
+
__method__,
|
128
|
+
{
|
129
|
+
users_turn_to_act?: @player_proxy.users_turn_to_act?,
|
130
|
+
match_ended?: @player_proxy.match_ended?
|
131
|
+
}
|
132
|
+
)
|
133
|
+
end
|
127
134
|
|
128
135
|
self
|
129
136
|
end
|
130
137
|
|
138
|
+
def users_turn_to_act?() @player_proxy.users_turn_to_act? end
|
139
|
+
|
131
140
|
def play_check_fold!
|
132
141
|
log __method__
|
133
142
|
if @player_proxy.users_turn_to_act?
|
@@ -23,8 +23,6 @@ module AcpcTableManager
|
|
23
23
|
|
24
24
|
def initialize(game_definition_key_)
|
25
25
|
@logger = AcpcTableManager.new_log 'queue.log'
|
26
|
-
@matches_to_start = []
|
27
|
-
@running_matches = {}
|
28
26
|
@game_definition_key = game_definition_key_
|
29
27
|
|
30
28
|
log(
|
@@ -34,31 +32,17 @@ module AcpcTableManager
|
|
34
32
|
max_num_matches: AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
|
35
33
|
}
|
36
34
|
)
|
37
|
-
|
38
|
-
# Clean up old matches
|
39
|
-
my_matches.running_or_started.each do |m|
|
40
|
-
m.delete
|
41
|
-
end
|
42
35
|
end
|
43
36
|
|
44
37
|
def start_players!(match)
|
45
|
-
|
46
|
-
|
47
|
-
if opponents.empty?
|
48
|
-
force_kill_match! match.id.to_s
|
49
|
-
raise StandardError.new("No opponents found to start for #{match.id.to_s}! Killed match.")
|
50
|
-
end
|
51
|
-
|
52
|
-
Opponents.start(
|
53
|
-
*opponents.map { |name, info| [info[:runner], info[:host], info[:port]] }
|
54
|
-
)
|
38
|
+
Opponents.start(match)
|
55
39
|
log(__method__, msg: "Opponents started for #{match.id.to_s}")
|
56
40
|
|
57
|
-
start_proxy match
|
41
|
+
start_proxy! match
|
58
42
|
end
|
59
43
|
|
60
|
-
def start_proxy(match)
|
61
|
-
command = "
|
44
|
+
def start_proxy!(match)
|
45
|
+
command = "#{File.expand_path('../../../exe/acpc_proxy', __FILE__)} -t #{AcpcTableManager.config_file} -m #{match.id.to_s}"
|
62
46
|
log(
|
63
47
|
__method__,
|
64
48
|
{
|
@@ -67,265 +51,75 @@ module AcpcTableManager
|
|
67
51
|
}
|
68
52
|
)
|
69
53
|
|
70
|
-
|
54
|
+
match.proxy_pid = Timeout::timeout(3) do
|
71
55
|
pid = Process.spawn(command)
|
72
56
|
Process.detach(pid)
|
73
57
|
pid
|
74
58
|
end
|
59
|
+
match.save!
|
75
60
|
|
76
61
|
log(
|
77
62
|
__method__,
|
78
63
|
{
|
79
|
-
msg: "Started proxy for #{match.id.to_s}",
|
80
|
-
pid:
|
64
|
+
msg: "Started proxy for \"#{match.name}\" (#{match.id.to_s})",
|
65
|
+
pid: match.proxy_pid
|
81
66
|
}
|
82
67
|
)
|
83
|
-
|
68
|
+
self
|
84
69
|
end
|
85
70
|
|
71
|
+
def matches_to_start() Match.start_queue(my_matches) end
|
72
|
+
|
86
73
|
def my_matches
|
87
74
|
Match.where(game_definition_key: @game_definition_key.to_sym)
|
88
75
|
end
|
89
76
|
|
90
77
|
def change_in_number_of_running_matches?
|
91
|
-
prevNumMatchesRunning =
|
78
|
+
prevNumMatchesRunning = Match.running(my_matches).length
|
92
79
|
yield if block_given?
|
93
|
-
prevNumMatchesRunning !=
|
94
|
-
end
|
95
|
-
|
96
|
-
def length
|
97
|
-
@matches_to_start.length
|
80
|
+
prevNumMatchesRunning != Match.running(my_matches).length
|
98
81
|
end
|
99
82
|
|
100
|
-
def
|
101
|
-
@running_matches.values.inject([]) do |ports, m|
|
102
|
-
if m[:dealer] && m[:dealer][:port_numbers]
|
103
|
-
m[:dealer][:port_numbers].each { |n| ports << n.to_i }
|
104
|
-
end
|
105
|
-
ports
|
106
|
-
end
|
107
|
-
end
|
83
|
+
def length() matches_to_start.length end
|
108
84
|
|
109
85
|
def available_special_ports
|
110
86
|
if AcpcTableManager.exhibition_config.special_ports_to_dealer
|
111
|
-
AcpcTableManager.exhibition_config.special_ports_to_dealer - ports_in_use
|
87
|
+
AcpcTableManager.exhibition_config.special_ports_to_dealer - Match.ports_in_use
|
112
88
|
else
|
113
89
|
[]
|
114
90
|
end
|
115
91
|
end
|
116
92
|
|
117
|
-
|
118
|
-
def enqueue!(match_id, dealer_options)
|
93
|
+
def check!
|
119
94
|
log(
|
120
95
|
__method__,
|
121
96
|
{
|
122
|
-
|
123
|
-
|
124
|
-
game_definition_key: @game_definition_key,
|
125
|
-
max_num_matches: AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
|
97
|
+
num_running_matches: Match.running(my_matches).length,
|
98
|
+
num_matches_to_start: matches_to_start.length
|
126
99
|
}
|
127
100
|
)
|
128
101
|
|
129
|
-
if @running_matches[match_id]
|
130
|
-
log(
|
131
|
-
__method__,
|
132
|
-
msg: "Match #{match_id} already started!"
|
133
|
-
)
|
134
|
-
else
|
135
|
-
@matches_to_start << {match_id: match_id, options: dealer_options}
|
136
|
-
end
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
|
-
# @return [Array] The list of PID information about the matches that were dequeued.
|
141
|
-
def check_queue!
|
142
|
-
log __method__
|
143
|
-
|
144
|
-
kill_matches!
|
145
|
-
|
146
|
-
log __method__, {num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
|
147
|
-
|
148
102
|
matches_started = []
|
149
|
-
while
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
log __method__, {matches_started: matches_started, num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
|
154
|
-
|
155
|
-
matches_started
|
156
|
-
end
|
157
|
-
|
158
|
-
# @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
|
159
|
-
def fix_running_matches_statuses!
|
160
|
-
log __method__
|
161
|
-
my_matches.running do |m|
|
162
|
-
if !(@running_matches[m.id.to_s] && AcpcDealer::dealer_running?(@running_matches[m.id.to_s][:dealer]))
|
163
|
-
m.is_running = false
|
164
|
-
m.save
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def kill_match!(match_id)
|
170
|
-
return unless match_id
|
171
|
-
|
172
|
-
begin
|
173
|
-
match = Match.find match_id
|
174
|
-
rescue Mongoid::Errors::DocumentNotFound
|
175
|
-
else
|
176
|
-
match.is_running = false
|
177
|
-
match.save!
|
178
|
-
end
|
179
|
-
|
180
|
-
match_info = @running_matches[match_id]
|
181
|
-
if match_info
|
182
|
-
@running_matches.delete(match_id)
|
183
|
-
end
|
184
|
-
@matches_to_start.delete_if { |m| m[:match_id] == match_id }
|
185
|
-
|
186
|
-
if match_info && match_info[:dealer] && match_info[:proxy].nil? then
|
187
|
-
kill_dealer!(match_info[:dealer])
|
188
|
-
end
|
189
|
-
kill_proxy!(match_info[:proxy]) if match_info && match_info[:proxy]
|
190
|
-
|
191
|
-
log __method__, match_id: match_id, msg: 'Match successfully killed'
|
192
|
-
end
|
193
|
-
|
194
|
-
def force_kill_match!(match_id)
|
195
|
-
log __method__, match_id: match_id
|
196
|
-
kill_match! match_id
|
197
|
-
::AcpcTableManager::Match.delete_match! match_id
|
198
|
-
log __method__, match_id: match_id, msg: 'Match successfully deleted'
|
199
|
-
end
|
200
|
-
|
201
|
-
protected
|
202
|
-
|
203
|
-
def kill_dealer!(dealer_info)
|
204
|
-
log(
|
205
|
-
__method__,
|
206
|
-
pid: dealer_info[:pid],
|
207
|
-
was_running?: true,
|
208
|
-
dealer_running?: AcpcDealer::dealer_running?(dealer_info)
|
103
|
+
while (
|
104
|
+
!matches_to_start.empty? &&
|
105
|
+
Match.running(my_matches).length < AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
|
209
106
|
)
|
210
|
-
|
211
|
-
if AcpcDealer::dealer_running? dealer_info
|
212
|
-
AcpcDealer.kill_process dealer_info[:pid]
|
213
|
-
|
214
|
-
sleep 1 # Give the dealer a chance to exit
|
215
|
-
|
216
|
-
log(
|
217
|
-
__method__,
|
218
|
-
pid: dealer_info[:pid],
|
219
|
-
msg: 'After TERM signal',
|
220
|
-
dealer_still_running?: AcpcDealer::dealer_running?(dealer_info)
|
221
|
-
)
|
222
|
-
|
223
|
-
if AcpcDealer::dealer_running?(dealer_info)
|
224
|
-
AcpcDealer.force_kill_process dealer_info[:pid]
|
225
|
-
sleep 1
|
226
|
-
|
227
|
-
log(
|
228
|
-
__method__,
|
229
|
-
pid: dealer_info[:pid],
|
230
|
-
msg: 'After KILL signal',
|
231
|
-
dealer_still_running?: AcpcDealer::dealer_running?(dealer_info)
|
232
|
-
)
|
233
|
-
|
234
|
-
if AcpcDealer::dealer_running?(dealer_info)
|
235
|
-
raise(
|
236
|
-
StandardError.new(
|
237
|
-
"Dealer process #{dealer_info[:pid]} couldn't be killed!"
|
238
|
-
)
|
239
|
-
)
|
240
|
-
end
|
241
|
-
end
|
107
|
+
matches_started << dequeue
|
242
108
|
end
|
243
|
-
end
|
244
109
|
|
245
|
-
def kill_proxy!(proxy_pid)
|
246
110
|
log(
|
247
111
|
__method__,
|
248
|
-
|
249
|
-
|
250
|
-
|
112
|
+
{
|
113
|
+
matches_started: matches_started,
|
114
|
+
num_running_matches: Match.running(my_matches).length,
|
115
|
+
num_matches_to_start: matches_to_start.length
|
116
|
+
}
|
251
117
|
)
|
252
118
|
|
253
|
-
|
254
|
-
AcpcDealer.kill_process proxy_pid
|
255
|
-
|
256
|
-
sleep 1 # Give the proxy a chance to exit
|
257
|
-
|
258
|
-
log(
|
259
|
-
__method__,
|
260
|
-
pid: proxy_pid,
|
261
|
-
msg: 'After TERM signal',
|
262
|
-
proxy_still_running?: AcpcDealer::process_exists?(proxy_pid)
|
263
|
-
)
|
264
|
-
|
265
|
-
if AcpcDealer::process_exists?(proxy_pid)
|
266
|
-
AcpcDealer.force_kill_process proxy_pid
|
267
|
-
sleep 1
|
268
|
-
|
269
|
-
log(
|
270
|
-
__method__,
|
271
|
-
pid: proxy_pid,
|
272
|
-
msg: 'After KILL signal',
|
273
|
-
proxy_still_running?: AcpcDealer::process_exists?(proxy_pid)
|
274
|
-
)
|
275
|
-
|
276
|
-
if AcpcDealer::process_exists?(proxy_pid)
|
277
|
-
raise(
|
278
|
-
StandardError.new(
|
279
|
-
"Proxy process #{proxy_pid} couldn't be killed!"
|
280
|
-
)
|
281
|
-
)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def kill_matches!
|
288
|
-
log __method__
|
289
|
-
|
290
|
-
unless AcpcTableManager.config.match_lifespan_s < 0
|
291
|
-
Match.running.and.old(AcpcTableManager.config.match_lifespan_s).each do |m|
|
292
|
-
log(
|
293
|
-
__method__,
|
294
|
-
{
|
295
|
-
old_running_match_id_being_killed: m.id.to_s
|
296
|
-
}
|
297
|
-
)
|
298
|
-
|
299
|
-
kill_match! m.id.to_s
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
running_matches_array = @running_matches.to_a
|
304
|
-
running_matches_array.each_index do |i|
|
305
|
-
match_id, match_info = running_matches_array[i]
|
306
|
-
|
307
|
-
unless (
|
308
|
-
AcpcDealer::dealer_running?(match_info[:dealer]) &&
|
309
|
-
Match.id_exists?(match_id)
|
310
|
-
)
|
311
|
-
log(
|
312
|
-
__method__,
|
313
|
-
{
|
314
|
-
match_id_being_killed: match_id
|
315
|
-
}
|
316
|
-
)
|
317
|
-
|
318
|
-
kill_match! match_id
|
319
|
-
end
|
320
|
-
end
|
321
|
-
@matches_to_start.delete_if do |m|
|
322
|
-
!Match.id_exists?(m[:match_id])
|
323
|
-
end
|
119
|
+
matches_started
|
324
120
|
end
|
325
121
|
|
326
|
-
|
327
|
-
@matches_to_start.any? { |m| m[:match_id] == match_id }
|
328
|
-
end
|
122
|
+
protected
|
329
123
|
|
330
124
|
def port(available_ports_)
|
331
125
|
port_ = available_ports_.pop
|
@@ -344,38 +138,21 @@ module AcpcTableManager
|
|
344
138
|
# @return [Object] The match that has been started or +nil+ if none could
|
345
139
|
# be started.
|
346
140
|
def dequeue
|
141
|
+
my_matches_to_start = matches_to_start
|
347
142
|
log(
|
348
143
|
__method__,
|
349
|
-
num_matches_to_start:
|
144
|
+
num_matches_to_start: my_matches_to_start.length
|
350
145
|
)
|
351
|
-
return nil if
|
352
|
-
|
353
|
-
match_info = nil
|
354
|
-
match_id = nil
|
355
|
-
match = nil
|
356
|
-
loop do
|
357
|
-
match_info = @matches_to_start.shift
|
358
|
-
match_id = match_info[:match_id]
|
359
|
-
begin
|
360
|
-
match = Match.find match_id
|
361
|
-
rescue Mongoid::Errors::DocumentNotFound
|
362
|
-
return nil if @matches_to_start.empty?
|
363
|
-
else
|
364
|
-
break
|
365
|
-
end
|
366
|
-
end
|
367
|
-
return nil unless match_id
|
146
|
+
return nil if my_matches_to_start.empty?
|
368
147
|
|
369
|
-
|
148
|
+
match = my_matches_to_start.pop
|
370
149
|
|
371
150
|
log(
|
372
151
|
__method__,
|
373
|
-
msg: "Starting dealer for match #{
|
374
|
-
options:
|
152
|
+
msg: "Starting dealer for match \"#{match.name}\" (#{match.id})",
|
153
|
+
options: match.dealer_options
|
375
154
|
)
|
376
155
|
|
377
|
-
@running_matches[match_id] ||= {}
|
378
|
-
|
379
156
|
special_port_requirements = match.bot_special_port_requirements
|
380
157
|
|
381
158
|
# Add user's port
|
@@ -386,28 +163,23 @@ module AcpcTableManager
|
|
386
163
|
if r then port(available_ports_) else 0 end
|
387
164
|
end
|
388
165
|
|
389
|
-
match.is_running = true
|
390
|
-
match.save!
|
391
|
-
|
392
166
|
num_repetitions = 0
|
393
|
-
|
167
|
+
dealer_info = nil
|
168
|
+
|
169
|
+
while dealer_info.nil? do
|
394
170
|
log(
|
395
171
|
__method__,
|
396
|
-
msg: "Added #{
|
172
|
+
msg: "Added #{match.id} list of running matches",
|
397
173
|
available_special_ports: available_ports_,
|
398
174
|
special_port_requirements: special_port_requirements,
|
399
175
|
:'ports_to_be_used_(zero_for_random)' => ports_to_be_used
|
400
176
|
)
|
401
177
|
begin
|
402
|
-
|
403
|
-
options,
|
404
|
-
match,
|
405
|
-
port_numbers: ports_to_be_used
|
406
|
-
)
|
178
|
+
dealer_info = Dealer.start(match, port_numbers: ports_to_be_used)
|
407
179
|
rescue Timeout::Error => e
|
408
180
|
log(
|
409
181
|
__method__,
|
410
|
-
{warning: "The dealer for match #{
|
182
|
+
{warning: "The dealer for match \"#{match.name}\" (#{match.id}) timed out."},
|
411
183
|
Logger::Severity::WARN
|
412
184
|
)
|
413
185
|
begin
|
@@ -433,31 +205,28 @@ module AcpcTableManager
|
|
433
205
|
else
|
434
206
|
log(
|
435
207
|
__method__,
|
436
|
-
{warning: "Unable to start match after retry,
|
208
|
+
{warning: "Unable to start match after retry, giving up."},
|
437
209
|
Logger::Severity::ERROR
|
438
210
|
)
|
439
|
-
|
211
|
+
match.unable_to_start_dealer = true
|
212
|
+
match.save!
|
440
213
|
raise e
|
441
214
|
end
|
442
215
|
end
|
443
216
|
end
|
444
217
|
|
445
|
-
begin
|
446
|
-
match = Match.find match_id
|
447
|
-
rescue Mongoid::Errors::DocumentNotFound => e
|
448
|
-
kill_match! match_id
|
449
|
-
raise e
|
450
|
-
end
|
451
|
-
|
452
218
|
log(
|
453
219
|
__method__,
|
454
|
-
msg: "Dealer started for #{
|
220
|
+
msg: "Dealer started for \"#{match.name}\" (#{match.id}) with pid #{match.dealer_pid}",
|
455
221
|
ports: match.port_numbers
|
456
222
|
)
|
457
223
|
|
224
|
+
match.ready_to_start = false
|
225
|
+
match.save!
|
226
|
+
|
458
227
|
start_players! match
|
459
228
|
|
460
|
-
|
229
|
+
match.id
|
461
230
|
end
|
462
231
|
end
|
463
232
|
end
|
@@ -22,7 +22,16 @@ module AcpcTableManager
|
|
22
22
|
|
23
23
|
def self.interpolate_all_strings(value, interpolation_hash)
|
24
24
|
if value.is_a?(String)
|
25
|
-
|
25
|
+
# $VERBOSE and $DEBUG change '%''s behaviour
|
26
|
+
_v = $VERBOSE
|
27
|
+
$VERBOSE = false
|
28
|
+
r = begin
|
29
|
+
value % interpolation_hash
|
30
|
+
rescue ArgumentError
|
31
|
+
value
|
32
|
+
end
|
33
|
+
$VERBOSE = _v
|
34
|
+
r
|
26
35
|
elsif value.respond_to?(:each)
|
27
36
|
each_key_value_pair(value) do |k, v|
|
28
37
|
value[k] = interpolate_all_strings(v, interpolation_hash)
|
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: 3.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: 2016-
|
11
|
+
date: 2016-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pony
|