acpc_table_manager 3.0.18 → 4.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.
@@ -1,240 +0,0 @@
1
- require 'acpc_poker_types'
2
- require 'acpc_dealer'
3
- require 'timeout'
4
-
5
- require_relative 'dealer'
6
- require_relative 'opponents'
7
- require_relative 'config'
8
- require_relative 'match'
9
-
10
- require_relative 'simple_logging'
11
- using AcpcTableManager::SimpleLogging::MessageFormatting
12
-
13
- require 'contextual_exceptions'
14
- using ContextualExceptions::ClassRefinement
15
-
16
- module AcpcTableManager
17
- class TableQueue
18
- include SimpleLogging
19
-
20
- attr_reader :running_matches
21
-
22
- exceptions :no_port_for_dealer_available
23
-
24
- def initialize(game_definition_key_)
25
- @logger = AcpcTableManager.new_log 'queue.log'
26
- @game_definition_key = game_definition_key_
27
-
28
- log(
29
- __method__,
30
- game_definition_key: @game_definition_key,
31
- max_num_matches: AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
32
- )
33
- end
34
-
35
- def start_players!(match)
36
- Opponents.start(match)
37
- log(__method__, msg: "Opponents started for #{match.id}")
38
-
39
- start_proxy! match
40
- end
41
-
42
- def start_proxy!(match)
43
- command = "#{File.expand_path('../../../exe/acpc_proxy', __FILE__)} -t #{AcpcTableManager.config_file} -m #{match.id}"
44
- log(
45
- __method__,
46
- msg: "Starting proxy for #{match.id}",
47
- command: command
48
- )
49
-
50
- match.proxy_pid = Timeout.timeout(3) do
51
- pid = Process.spawn(command)
52
- Process.detach(pid)
53
- pid
54
- end
55
- match.save!
56
-
57
- log(
58
- __method__,
59
- msg: "Started proxy for \"#{match.name}\" (#{match.id})",
60
- pid: match.proxy_pid
61
- )
62
- self
63
- end
64
-
65
- def matches_to_start
66
- my_matches.queue
67
- end
68
-
69
- def my_matches
70
- Match.where(game_definition_key: @game_definition_key.to_sym)
71
- end
72
-
73
- def change_in_number_of_running_matches?
74
- prevNumMatchesRunning = Match.running(my_matches).length
75
- yield if block_given?
76
- prevNumMatchesRunning != Match.running(my_matches).length
77
- end
78
-
79
- def length
80
- matches_to_start.length
81
- end
82
-
83
- def available_special_ports
84
- if AcpcTableManager.exhibition_config.special_ports_to_dealer
85
- AcpcTableManager.exhibition_config.special_ports_to_dealer - Match.ports_in_use
86
- else
87
- []
88
- end
89
- end
90
-
91
- def check!
92
- return if length < 1
93
-
94
- my_matches_to_start = matches_to_start.to_a
95
-
96
- max_running_matches = AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
97
- check_num_running_matches = max_running_matches > 0
98
-
99
- num_running_matches = 0
100
- if check_num_running_matches
101
- num_running_matches = Match.running(my_matches).length
102
- log(
103
- __method__,
104
- num_running_matches: num_running_matches,
105
- num_matches_to_start: my_matches_to_start.length
106
- )
107
- end
108
-
109
- matches_started = []
110
- while
111
- !my_matches_to_start.empty? &&
112
- (
113
- !check_num_running_matches ||
114
- num_running_matches < max_running_matches
115
- )
116
-
117
- matches_started << dequeue(my_matches_to_start.pop)
118
- num_running_matches += 1
119
- end
120
-
121
- log(
122
- __method__,
123
- matches_started: matches_started,
124
- num_running_matches: num_running_matches,
125
- num_matches_to_start: matches_to_start.length
126
- )
127
-
128
- matches_started
129
- end
130
-
131
- protected
132
-
133
- def port(available_ports)
134
- port_ = available_ports.pop
135
- until AcpcDealer.port_available?(port_)
136
- if available_ports.empty?
137
- raise NoPortForDealerAvailable, "None of the special ports (#{available_special_ports}) are open"
138
- end
139
- port_ = available_ports.pop
140
- end
141
- unless port_
142
- raise NoPortForDealerAvailable, "None of the special ports (#{available_special_ports}) are open"
143
- end
144
- port_
145
- end
146
-
147
- def ports_to_use(special_port_requirements, available_ports = nil)
148
- ports = special_port_requirements.map do |r|
149
- if r
150
- # Slow. Only check available special ports if necessary
151
- available_ports ||= available_special_ports
152
- port(available_ports)
153
- else
154
- 0
155
- end
156
- end
157
- [ports, available_ports]
158
- end
159
-
160
- # @return [Object] The match that has been started or +nil+ if none could
161
- # be started.
162
- def dequeue(match)
163
- log(
164
- __method__,
165
- msg: "Starting dealer for match \"#{match.name}\" (#{match.id})",
166
- options: match.dealer_options
167
- )
168
-
169
- special_port_requirements = match.bot_special_port_requirements
170
-
171
- # Add user's port
172
- special_port_requirements.insert(match.seat - 1, false)
173
-
174
- ports_to_be_used, available_ports = ports_to_use(special_port_requirements)
175
-
176
- num_repetitions = 0
177
- dealer_info = nil
178
-
179
- while dealer_info.nil?
180
- log(
181
- __method__,
182
- msg: "Added #{match.id} list of running matches",
183
- available_special_ports: available_ports,
184
- special_port_requirements: special_port_requirements,
185
- :'ports_to_be_used_(zero_for_random)' => ports_to_be_used
186
- )
187
- begin
188
- dealer_info = Dealer.start(match, port_numbers: ports_to_be_used)
189
- rescue Timeout::Error => e
190
- log(
191
- __method__,
192
- { warning: "The dealer for match \"#{match.name}\" (#{match.id}) timed out." },
193
- Logger::Severity::WARN
194
- )
195
- begin
196
- ports_to_be_used, available_ports = ports_to_use(special_port_requirements, available_ports)
197
- rescue NoPortForDealerAvailable => e
198
- available_ports = available_special_ports
199
- log(
200
- __method__,
201
- { warning: "#{ports_to_be_used} ports unavailable, retrying with all special ports, #{available_ports}." },
202
- Logger::Severity::WARN
203
- )
204
- end
205
- if num_repetitions < 1
206
- sleep 1
207
- log(
208
- __method__,
209
- { warning: "Retrying with all special ports, #{available_ports}." },
210
- Logger::Severity::WARN
211
- )
212
- num_repetitions += 1
213
- else
214
- log(
215
- __method__,
216
- { warning: 'Unable to start match after retry, giving up.' },
217
- Logger::Severity::ERROR
218
- )
219
- match.unable_to_start_dealer = true
220
- match.save!
221
- raise e
222
- end
223
- end
224
- end
225
-
226
- log(
227
- __method__,
228
- msg: "Dealer started for \"#{match.name}\" (#{match.id}) with pid #{match.dealer_pid}",
229
- ports: match.port_numbers
230
- )
231
-
232
- match.ready_to_start = false
233
- match.save!
234
-
235
- start_players! match
236
-
237
- match.id
238
- end
239
- end
240
- end