1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* This file contains functionality relating to the official BZFlag match servers for the league |
4
|
|
|
* |
5
|
|
|
* @package BZiON\Models |
6
|
|
|
* @license https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
include_once DOC_ROOT . "/includes/bzfquery.php"; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* A BZFlag server |
13
|
|
|
* @package BZiON\Models |
14
|
|
|
*/ |
15
|
|
|
class Server extends UrlModel implements NamedModel |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* The name of the server |
19
|
|
|
* @var string |
20
|
|
|
*/ |
21
|
|
|
protected $name; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* The domain of the server |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
protected $domain; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* The port of the server |
31
|
|
|
* @var int |
32
|
|
|
*/ |
33
|
|
|
protected $port; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* The id of the country the server is located in |
37
|
|
|
* @var int |
38
|
|
|
*/ |
39
|
|
|
protected $country; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* The id of the owner of the server |
43
|
|
|
* @var int |
44
|
|
|
*/ |
45
|
|
|
protected $owner; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Whether the server is listed on the public list server |
49
|
|
|
* @var bool |
50
|
|
|
*/ |
51
|
|
|
protected $online; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* The server's bzfquery information |
55
|
|
|
* @var array |
56
|
|
|
*/ |
57
|
|
|
protected $info; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* The ID of the API key assigned to this server |
61
|
|
|
* @var ApiKey |
62
|
|
|
*/ |
63
|
|
|
protected $api_key; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* The date of the last bzfquery of the server |
67
|
|
|
* @var TimeDate |
68
|
|
|
*/ |
69
|
|
|
protected $updated; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Whether or not this server is capable of hosting official matches. |
73
|
|
|
* |
74
|
|
|
* @var bool |
75
|
|
|
*/ |
76
|
|
|
protected $is_official_server; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Whether or not this server is dedicated to being a replay server. |
80
|
|
|
* |
81
|
|
|
* @var bool |
82
|
|
|
*/ |
83
|
|
|
protected $is_replay_server; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Whether or not this server has been marked as "inactive" and is only kept for historical purposes. |
87
|
|
|
* |
88
|
|
|
* @var bool |
89
|
|
|
*/ |
90
|
|
|
protected $is_inactive; |
91
|
|
|
|
92
|
|
|
const DELETED_COLUMN = 'is_deleted'; |
93
|
|
|
const TABLE = "servers"; |
94
|
|
|
|
95
|
|
|
const CREATE_PERMISSION = Permission::ADD_SERVER; |
96
|
|
|
const EDIT_PERMISSION = Permission::EDIT_SERVER; |
97
|
|
|
const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_SERVER; |
98
|
|
|
const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_SERVER; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* {@inheritdoc} |
102
|
|
|
*/ |
103
|
|
|
protected function assignResult($server) |
104
|
|
|
{ |
105
|
|
|
$this->name = $server['name']; |
106
|
|
|
$this->domain = $server['domain']; |
107
|
|
|
$this->port = $server['port']; |
108
|
|
|
$this->country = $server['country']; |
109
|
|
|
$this->owner = $server['owner']; |
110
|
|
|
$this->online = $server['online']; |
111
|
|
|
$this->info = unserialize($server['info']); |
112
|
|
|
$this->api_key = ApiKey::get($server['api_key']); |
113
|
|
|
$this->updated = TimeDate::fromMysql($server['updated']); |
114
|
|
|
$this->is_official_server = $server['is_official_server']; |
115
|
|
|
$this->is_replay_server = $server['is_replay_server']; |
116
|
|
|
$this->is_inactive = $server['is_inactive']; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Update the server with current bzfquery information |
121
|
|
|
* return self |
122
|
|
|
*/ |
123
|
|
|
public function forceUpdate() |
124
|
|
|
{ |
125
|
|
|
$this->info = bzfquery($this->getAddress()); |
126
|
|
|
$this->updated = TimeDate::now(); |
127
|
|
|
$this->online = !isset($this->info['error']); |
128
|
|
|
|
129
|
|
|
$this->db->execute( |
130
|
|
|
"UPDATE servers SET info = ?, online = ?, updated = UTC_TIMESTAMP() WHERE id = ?", |
131
|
|
|
array(serialize($this->info), $this->online, $this->id) |
132
|
|
|
); |
133
|
|
|
|
134
|
|
|
// If a server is offline, log it |
135
|
|
|
if (!$this->online) { |
136
|
|
|
if ($logger = \Service::getContainer()->get('logger')) { |
137
|
|
|
$id = $this->getId(); |
138
|
|
|
$address = $this->getAddress(); |
139
|
|
|
$reason = $this->info['error']; |
140
|
|
|
|
141
|
|
|
$logger->notice("Connection to server #$id ($address) failed: $reason"); |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return $this; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Checks if the server is online (listed on the public list server) |
150
|
|
|
* @return bool Whether the server is online |
151
|
|
|
*/ |
152
|
|
|
public function isOnline() |
153
|
|
|
{ |
154
|
|
|
return $this->online; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Checks if the server has players |
159
|
|
|
* @return bool Whether the server has any players |
160
|
|
|
*/ |
161
|
|
|
public function hasPlayers() |
162
|
|
|
{ |
163
|
|
|
return $this->info['numPlayers'] > 0; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Gets the number of players on the server |
168
|
|
|
* @return int The number of players |
169
|
|
|
*/ |
170
|
|
|
public function numPlayers() |
171
|
|
|
{ |
172
|
|
|
return (isset($this->info['numPlayers'])) ? $this->info['numPlayers'] : 0; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Gets the players on the server |
177
|
|
|
* @return array The players on the server |
178
|
|
|
*/ |
179
|
|
|
public function getPlayers() |
180
|
|
|
{ |
181
|
|
|
if (isset($this->info['player'])) { |
182
|
|
|
return $this->info['player']; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return array(); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Checks if the last update is older than or equal to the update interval |
190
|
|
|
* @return bool Whether the information is older than the update interval |
191
|
|
|
*/ |
192
|
|
|
public function staleInfo() |
193
|
|
|
{ |
194
|
|
|
$update_time = $this->updated->copy(); |
195
|
|
|
$update_time->modify(Service::getParameter('bzion.miscellaneous.update_interval')); |
196
|
|
|
|
197
|
|
|
return TimeDate::now() >= $update_time; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* The ApiKey assigned to this server |
202
|
|
|
* |
203
|
|
|
* @return \CachedModel|int|null|static |
204
|
|
|
*/ |
205
|
|
|
public function getApiKey() |
206
|
|
|
{ |
207
|
|
|
return $this->api_key; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Gets the server's ip address |
212
|
|
|
* @return string The server's ip address |
213
|
|
|
*/ |
214
|
|
|
public function getServerIp() |
215
|
|
|
{ |
216
|
|
|
return $this->info['ip']; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Get the server's name |
221
|
|
|
* @return string |
222
|
|
|
*/ |
223
|
|
|
public function getName() |
224
|
|
|
{ |
225
|
|
|
return $this->name; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Get the domain of the server |
230
|
|
|
* |
231
|
|
|
* @return string The server's domain |
232
|
|
|
*/ |
233
|
|
|
public function getDomain() |
234
|
|
|
{ |
235
|
|
|
return $this->domain; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Get the port of the server |
240
|
|
|
* |
241
|
|
|
* @return int The port number |
242
|
|
|
*/ |
243
|
|
|
public function getPort() |
244
|
|
|
{ |
245
|
|
|
return $this->port; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Get the server's IP address or hostname |
250
|
|
|
* @return string |
251
|
|
|
*/ |
252
|
|
|
public function getAddress() |
253
|
|
|
{ |
254
|
|
|
return $this->domain . ":" . $this->port; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Get when the server information was last updated |
259
|
|
|
* @return TimeDate |
260
|
|
|
*/ |
261
|
|
|
public function getUpdated() |
262
|
|
|
{ |
263
|
|
|
return $this->updated->copy(); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Get the country the server is in |
268
|
|
|
* @return Country The country the server is located in |
269
|
|
|
*/ |
270
|
|
|
public function getCountry() |
271
|
|
|
{ |
272
|
|
|
return Country::get($this->country); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Get the owner of the server |
277
|
|
|
* @return Player |
278
|
|
|
*/ |
279
|
|
|
public function getOwner() |
280
|
|
|
{ |
281
|
|
|
return Player::get($this->owner); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Get the number of matches that have occurred on this server |
286
|
|
|
* |
287
|
|
|
* @return int |
288
|
|
|
*/ |
289
|
|
|
public function getMatchCount() |
290
|
|
|
{ |
291
|
|
|
$qb = new MatchQueryBuilder('Match', [ |
292
|
|
|
'columns' => [ |
293
|
|
|
'server' => 'server_id' |
294
|
|
|
] |
295
|
|
|
]); |
296
|
|
|
$query = $qb |
297
|
|
|
->where('server')->equals($this->getId()) |
298
|
|
|
->active() |
299
|
|
|
->count() |
300
|
|
|
; |
301
|
|
|
|
302
|
|
|
return $query; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Returns the amount of time passed since the server was last updated |
307
|
|
|
* @return TimeDate |
308
|
|
|
*/ |
309
|
|
|
public function getLastUpdate() |
310
|
|
|
{ |
311
|
|
|
return $this->updated; |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Get whether or not this server is only kept for historical purposes. |
316
|
|
|
* |
317
|
|
|
* The server is now "retired" or no longer used but is **not** soft deleted. |
318
|
|
|
* |
319
|
|
|
* @return bool |
320
|
|
|
*/ |
321
|
|
|
public function isInactive() |
322
|
|
|
{ |
323
|
|
|
return (bool)$this->is_inactive; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Get whether or not this server is capable of hosting official matches |
328
|
|
|
* |
329
|
|
|
* @return bool |
330
|
|
|
*/ |
331
|
|
|
public function isOfficialServer() |
332
|
|
|
{ |
333
|
|
|
return (bool)$this->is_official_server; |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Get whether or not this server is dedicated to serving replays. |
338
|
|
|
* |
339
|
|
|
* @return bool |
340
|
|
|
*/ |
341
|
|
|
public function isReplayServer() |
342
|
|
|
{ |
343
|
|
|
return (bool)$this->is_replay_server; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* Set the name of the server |
348
|
|
|
* |
349
|
|
|
* @param string $name The new name of the server |
350
|
|
|
* |
351
|
|
|
* @return self |
352
|
|
|
*/ |
353
|
|
|
public function setName($name) |
354
|
|
|
{ |
355
|
|
|
return $this->updateProperty($this->name, 'name', $name); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* Set the address of the server |
360
|
|
|
* |
361
|
|
|
* @param string $address The new address of the server |
362
|
|
|
* |
363
|
|
|
* @deprecated Use setDomain() and setPort() instead |
364
|
|
|
* |
365
|
|
|
* @return self |
366
|
|
|
*/ |
367
|
|
|
public function setAddress($address) |
368
|
|
|
{ |
369
|
|
|
list($domain, $port) = explode(":", $address); |
370
|
|
|
|
371
|
|
|
$this->setDomain($domain); |
372
|
|
|
$this->setPort($port); |
373
|
|
|
|
374
|
|
|
return $this; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
/** |
378
|
|
|
* Set the domain of the server |
379
|
|
|
* |
380
|
|
|
* @param $domain string The new domain of the server |
381
|
|
|
* |
382
|
|
|
* @return self |
383
|
|
|
*/ |
384
|
|
|
public function setDomain($domain) |
385
|
|
|
{ |
386
|
|
|
return $this->updateProperty($this->domain, 'domain', $domain); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Set the port of the server |
391
|
|
|
* |
392
|
|
|
* @param $port int The new port of the server |
393
|
|
|
* |
394
|
|
|
* @return self |
395
|
|
|
*/ |
396
|
|
|
public function setPort($port) |
397
|
|
|
{ |
398
|
|
|
return $this->updateProperty($this->port, 'port', $port); |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* Set the id of the owner of the server |
403
|
|
|
* |
404
|
|
|
* @param int $ownerId The ID of the new owner of the server |
405
|
|
|
* |
406
|
|
|
* @return self |
407
|
|
|
*/ |
408
|
|
|
public function setOwner($ownerId) |
409
|
|
|
{ |
410
|
|
|
return $this->updateProperty($this->owner, 'owner', $ownerId); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
/** |
414
|
|
|
* Set the id of the country of the server |
415
|
|
|
* |
416
|
|
|
* @param int $countryId The ID of the new country of the server |
417
|
|
|
* |
418
|
|
|
* @return self |
419
|
|
|
*/ |
420
|
|
|
public function setCountry($countryId) |
421
|
|
|
{ |
422
|
|
|
return $this->updateProperty($this->country, 'country', $countryId); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* Set this server's inactivity status. |
427
|
|
|
* |
428
|
|
|
* @param bool $inactive |
429
|
|
|
* |
430
|
|
|
* @return static |
431
|
|
|
*/ |
432
|
|
|
public function setInactive($inactive) |
433
|
|
|
{ |
434
|
|
|
return $this->updateProperty($this->is_inactive, 'is_inactive', $inactive); |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Set the official match capabilities of this server. |
439
|
|
|
* |
440
|
|
|
* @param bool $matchServer |
441
|
|
|
* |
442
|
|
|
* @return static |
443
|
|
|
*/ |
444
|
|
|
public function setOfficialServer($matchServer) |
445
|
|
|
{ |
446
|
|
|
return $this->updateProperty($this->is_official_server, 'is_official_server', $matchServer); |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
/** |
450
|
|
|
* Set the replay status of this server. |
451
|
|
|
* |
452
|
|
|
* @param bool $replayServer |
453
|
|
|
* |
454
|
|
|
* @return static |
455
|
|
|
*/ |
456
|
|
|
public function setReplayServer($replayServer) |
457
|
|
|
{ |
458
|
|
|
return $this->updateProperty($this->is_replay_server, 'is_replay_server', $replayServer); |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* Add a new server |
463
|
|
|
* |
464
|
|
|
* @param string $name The name of the server |
465
|
|
|
* @param string $domain The domain of the server (e.g. server.com) |
466
|
|
|
* @param string $port The port of the server (e.g. 5154) |
467
|
|
|
* @param int $countryID The ID of the country |
468
|
|
|
* @param int $ownerID The ID of the server owner |
469
|
|
|
* |
470
|
|
|
* @return Server An object that represents the sent message |
471
|
|
|
*/ |
472
|
|
|
public static function addServer($name, $domain, $port, $countryID, $ownerID) |
473
|
|
|
{ |
474
|
|
|
$key = ApiKey::getKeyByOwner($ownerID); |
475
|
|
|
|
476
|
|
|
$server = self::create([ |
477
|
|
|
'name' => $name, |
478
|
|
|
'domain' => $domain, |
479
|
|
|
'port' => $port, |
480
|
|
|
'country' => $countryID, |
481
|
|
|
'owner' => $ownerID, |
482
|
|
|
'api_key' => $key->getId(), |
483
|
|
|
], 'updated'); |
484
|
|
|
$server->forceUpdate(); |
485
|
|
|
|
486
|
|
|
return $server; |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
/** |
490
|
|
|
* Get a query builder for servers |
491
|
|
|
* |
492
|
|
|
* @throws Exception |
493
|
|
|
* |
494
|
|
|
* @return QueryBuilderFlex |
495
|
|
|
*/ |
496
|
|
|
public static function getQueryBuilder() |
497
|
|
|
{ |
498
|
|
|
return QueryBuilderFlex::createForModel(Server::class) |
|
|
|
|
499
|
|
|
->setNameColumn('name') |
500
|
|
|
; |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* {@inheritdoc} |
505
|
|
|
*/ |
506
|
|
View Code Duplication |
public static function getActiveModels(QueryBuilderFlex &$qb) |
|
|
|
|
507
|
|
|
{ |
508
|
|
|
$qb |
509
|
|
|
->whereNot(self::DELETED_COLUMN, '=', self::DELETED_VALUE) |
510
|
|
|
->whereNot('is_inactive', '=', true) |
511
|
|
|
; |
512
|
|
|
|
513
|
|
|
return true; |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
/** |
517
|
|
|
* Get the Server model with the respective address |
518
|
|
|
* |
519
|
|
|
* @param string $address The address in the format of `domain:port` |
520
|
|
|
* |
521
|
|
|
* @throws \Pixie\Exception |
522
|
|
|
* @throws Exception |
523
|
|
|
* |
524
|
|
|
* @return static |
525
|
|
|
*/ |
526
|
|
|
public static function fetchFromAddress($address) |
527
|
|
|
{ |
528
|
|
|
if (strpos($address, ':') === false) { |
529
|
|
|
return Server::get(0); |
|
|
|
|
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
list($domain, $port) = explode(':', $address); |
533
|
|
|
|
534
|
|
|
$results = self::getQueryBuilder() |
535
|
|
|
->where('domain', '=', $domain) |
536
|
|
|
->where('port', '=', $port) |
537
|
|
|
->active() |
538
|
|
|
->getModels(true) |
539
|
|
|
; |
540
|
|
|
|
541
|
|
|
if (count($results) > 0) { |
542
|
|
|
return $results[0]; |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
return Server::get(0); |
|
|
|
|
546
|
|
|
} |
547
|
|
|
} |
548
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.