acpc_table_manager 2.2.3 → 3.0.0
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.
- 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
|