1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of Dedipanel project |
5
|
|
|
* |
6
|
|
|
* (c) 2010-2015 Dedipanel <http://www.dedicated-panel.net> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace DP\GameServer\GameServerBundle\Entity; |
13
|
|
|
|
14
|
|
|
use Dedipanel\PHPSeclibWrapperBundle\Connection\Exception\ScreenNotExistException; |
15
|
|
|
use Doctrine\ORM\Mapping as ORM; |
16
|
|
|
use DP\Core\MachineBundle\Entity\Machine; |
17
|
|
|
use Symfony\Component\Validator\Constraints as Assert; |
18
|
|
|
use DP\GameServer\GameServerBundle\Query\QueryInterface; |
19
|
|
|
use DP\GameServer\GameServerBundle\Query\RconInterface; |
20
|
|
|
use DP\Core\CoreBundle\Exception\NotImplementedException; |
21
|
|
|
use DP\GameServer\GameServerBundle\FTP\AbstractItem; |
22
|
|
|
use DP\GameServer\GameServerBundle\FTP\File; |
23
|
|
|
use DP\GameServer\GameServerBundle\FTP\Directory; |
24
|
|
|
use DP\Core\GameBundle\Entity\Plugin; |
25
|
|
|
use DP\Core\CoreBundle\Model\AbstractServer; |
26
|
|
|
use Symfony\Component\Validator\Mapping\ClassMetadata; |
27
|
|
|
use Symfony\Component\Validator\Context\ExecutionContextInterface; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* DP\Core\GameServer\GameServerBundle\Entity\GameServer |
31
|
|
|
* @ORM\Table(name="game_server") |
32
|
|
|
* @ORM\Entity() |
33
|
|
|
* @ORM\InheritanceType("JOINED") |
34
|
|
|
* @ORM\DiscriminatorColumn(name="discr", type="string") |
35
|
|
|
* @ORM\DiscriminatorMap({ |
36
|
|
|
* "steam" = "DP\GameServer\SteamServerBundle\Entity\SteamServer", |
37
|
|
|
* "minecraft" = "DP\GameServer\MinecraftServerBundle\Entity\MinecraftServer" |
38
|
|
|
* }) |
39
|
|
|
*/ |
40
|
|
|
abstract class GameServer extends AbstractServer |
41
|
|
|
{ |
42
|
|
|
/** |
43
|
|
|
* @var integer $id |
44
|
|
|
* |
45
|
|
|
* @ORM\Column(name="id", type="integer") |
46
|
|
|
* @ORM\Id |
47
|
|
|
* @ORM\GeneratedValue(strategy="AUTO") |
48
|
|
|
*/ |
49
|
|
|
protected $id; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var string $name |
53
|
|
|
* |
54
|
|
|
* @ORM\Column(name="name", type="string", length=32) |
55
|
|
|
*/ |
56
|
|
|
protected $name; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var integer $port |
60
|
|
|
* |
61
|
|
|
* @ORM\Column(name="port", type="integer") |
62
|
|
|
*/ |
63
|
|
|
protected $port; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var integer $maxplayers |
67
|
|
|
* |
68
|
|
|
* @ORM\Column(name="maxplayers", type="integer") |
69
|
|
|
*/ |
70
|
|
|
protected $maxplayers; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @ORM\ManyToOne(targetEntity="DP\Core\MachineBundle\Entity\Machine", inversedBy="gameServers") |
74
|
|
|
* @ORM\JoinColumn(name="machineId", referencedColumnName="id") |
75
|
|
|
*/ |
76
|
|
|
protected $machine; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @ORM\ManyToOne(targetEntity="DP\Core\GameBundle\Entity\Game", inversedBy="gameServers") |
80
|
|
|
* @ORM\JoinColumn(name="gameId", referencedColumnName="id") |
81
|
|
|
*/ |
82
|
|
|
protected $game; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @var string $rcon |
86
|
|
|
* |
87
|
|
|
* @ORM\Column(name="rconPassword", type="string", length=32) |
88
|
|
|
*/ |
89
|
|
|
protected $rconPassword; |
90
|
|
|
|
91
|
|
|
protected $query; |
92
|
|
|
protected $rcon; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @var \Doctrine\Common\Collections\ArrayCollection $plugins |
96
|
|
|
* |
97
|
|
|
* @ORM\ManyToMany(targetEntity="DP\Core\GameBundle\Entity\Plugin") |
98
|
|
|
* @ORM\JoinTable(name="gameserver_plugins", |
99
|
|
|
* joinColumns={@ORM\JoinColumn(name="server_id", referencedColumnName="id")}, |
100
|
|
|
* inverseJoinColumns={@ORM\JoinColumn(name="plugin_id", referencedColumnName="id")} |
101
|
|
|
* ) |
102
|
|
|
*/ |
103
|
|
|
private $plugins; |
104
|
|
|
|
105
|
|
|
|
106
|
|
|
public function __construct() |
107
|
|
|
{ |
108
|
|
|
$this->plugins = new \Doctrine\Common\Collections\ArrayCollection(); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Get id |
113
|
|
|
* |
114
|
|
|
* @return integer |
115
|
|
|
*/ |
116
|
|
|
public function getId() |
117
|
|
|
{ |
118
|
|
|
return $this->id; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Set machine |
123
|
|
|
* |
124
|
|
|
* @param Machine $machine |
125
|
|
|
*/ |
126
|
|
|
public function setMachine(Machine $machine) |
127
|
|
|
{ |
128
|
|
|
$this->machine = $machine; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Get machine |
133
|
|
|
* |
134
|
|
|
* @return Machine |
135
|
|
|
*/ |
136
|
|
|
public function getMachine() |
137
|
|
|
{ |
138
|
|
|
return $this->machine; |
|
|
|
|
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Set name |
143
|
|
|
* |
144
|
|
|
* @param string $name |
145
|
|
|
*/ |
146
|
|
|
public function setName($name) |
147
|
|
|
{ |
148
|
|
|
$this->name = $name; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Get name |
153
|
|
|
* |
154
|
|
|
* @return string |
155
|
|
|
*/ |
156
|
|
|
public function getName() |
157
|
|
|
{ |
158
|
|
|
return $this->name; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Set port |
163
|
|
|
* |
164
|
|
|
* @param integer $port |
165
|
|
|
*/ |
166
|
|
|
public function setPort($port) |
167
|
|
|
{ |
168
|
|
|
$this->port = $port; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Get port |
173
|
|
|
* |
174
|
|
|
* @return integer |
175
|
|
|
*/ |
176
|
|
|
public function getPort() |
177
|
|
|
{ |
178
|
|
|
return $this->port; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Set game |
183
|
|
|
* |
184
|
|
|
* @param Game $game |
185
|
|
|
*/ |
186
|
|
|
public function setGame($game) |
187
|
|
|
{ |
188
|
|
|
$this->game = $game; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Get gameId |
193
|
|
|
* |
194
|
|
|
* @return integer |
195
|
|
|
*/ |
196
|
|
|
public function getGame() |
197
|
|
|
{ |
198
|
|
|
return $this->game; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Set maxplayers |
203
|
|
|
* |
204
|
|
|
* @param integer $maxplayers |
205
|
|
|
*/ |
206
|
|
|
public function setMaxplayers($maxplayers) |
207
|
|
|
{ |
208
|
|
|
$this->maxplayers = $maxplayers; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Get maxplayers |
213
|
|
|
* |
214
|
|
|
* @return integer |
215
|
|
|
*/ |
216
|
|
|
public function getMaxplayers() |
217
|
|
|
{ |
218
|
|
|
return $this->maxplayers; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Get absolute path of binaries directory |
223
|
|
|
* |
224
|
|
|
* @return string |
225
|
|
|
*/ |
226
|
|
|
public function getAbsoluteBinDir() |
227
|
|
|
{ |
228
|
|
|
return rtrim(rtrim($this->getAbsoluteDir(), '/') . '/' . $this->getGame()->getBinDir() . '/', '/') . '/'; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Get absolute path of game content directory |
233
|
|
|
* |
234
|
|
|
* @return string |
235
|
|
|
*/ |
236
|
|
|
public function getAbsoluteGameContentDir() |
237
|
|
|
{ |
238
|
|
|
return $this->getAbsoluteBinDir(); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
public function getScreenName() |
242
|
|
|
{ |
243
|
|
|
$screenName = $this->getMachine()->getUsername() . '-' . $this->getDir(); |
244
|
|
|
|
245
|
|
|
return $this->getScreenNameHash($screenName); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
public function getInstallScreenName() |
249
|
|
|
{ |
250
|
|
|
$screenName = $this->getMachine()->getUsername() . '-install-' . $this->getDir(); |
251
|
|
|
|
252
|
|
|
return $this->getScreenNameHash($screenName); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
public function getPluginInstallScreenName($scriptName = '') |
256
|
|
|
{ |
257
|
|
|
$screenName = $this->getMachine()->getUsername() . '-plugin-install-' . $scriptName . '-' . $this->getDir(); |
258
|
|
|
|
259
|
|
|
return $this->getScreenNameHash($screenName); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
public function getScreenNameHash($screenName, $hashLength = 20) |
263
|
|
|
{ |
264
|
|
|
$screenName = sha1($screenName); |
265
|
|
|
$screenName = substr($screenName, 0, $hashLength); |
266
|
|
|
|
267
|
|
|
return 'dp-' . $screenName; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
public function setQuery(QueryInterface $query) |
271
|
|
|
{ |
272
|
|
|
$this->query = $query; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
public function getQuery() |
276
|
|
|
{ |
277
|
|
|
return $this->query; |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Set rconPassword |
282
|
|
|
* |
283
|
|
|
* @param string $rconPassword |
284
|
|
|
*/ |
285
|
|
|
public function setRconPassword($rconPassword) |
286
|
|
|
{ |
287
|
|
|
$this->rconPassword = $rconPassword; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Get rconPassword |
292
|
|
|
* |
293
|
|
|
* @return string |
294
|
|
|
*/ |
295
|
|
|
public function getRconPassword() |
296
|
|
|
{ |
297
|
|
|
return $this->rconPassword; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
public function isEmptyRconPassword() |
301
|
|
|
{ |
302
|
|
|
return empty($this->rconPassword); |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
public function setRcon(RconInterface $rcon) |
306
|
|
|
{ |
307
|
|
|
$this->rcon = $rcon; |
308
|
|
|
|
309
|
|
|
return $this->rcon; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
public function getRcon() |
313
|
|
|
{ |
314
|
|
|
return $this->rcon; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Add plugin |
319
|
|
|
* |
320
|
|
|
* @param \DP\Core\GameBundle\Entity\Plugin $plugin |
321
|
|
|
*/ |
322
|
|
|
public function addPlugin(\DP\Core\GameBundle\Entity\Plugin $plugin) |
323
|
|
|
{ |
324
|
|
|
$this->plugins[] = $plugin; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* Remove a server plugin |
329
|
|
|
* @param \DP\Core\GameBundle\Entity\Plugin $plugin |
330
|
|
|
*/ |
331
|
|
|
public function removePlugin(\DP\Core\GameBundle\Entity\Plugin $plugin) |
332
|
|
|
{ |
333
|
|
|
$this->plugins->removeElement($plugin); |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Get plugins recorded as "installed on the server" |
338
|
|
|
* |
339
|
|
|
* @return \Doctrine\Common\Collections\ArrayCollection |
340
|
|
|
*/ |
341
|
|
|
public function getPlugins() |
342
|
|
|
{ |
343
|
|
|
if ($this->plugins instanceof \Doctrine\ORM\PersistentCollection) { |
344
|
|
|
return $this->plugins->getValues(); |
345
|
|
|
} |
346
|
|
|
else { |
347
|
|
|
return $this->plugins; |
348
|
|
|
} |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
public function getInstalledPlugins() |
352
|
|
|
{ |
353
|
|
|
return $this->getPlugins(); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
public function getNotInstalledPlugins() |
357
|
|
|
{ |
358
|
|
|
$intersectCallback = function ($plugin1, $plugin2) { |
359
|
|
|
return $plugin1->getId() - $plugin2->getId(); |
360
|
|
|
}; |
361
|
|
|
$plugins = $this->getGame()->getPlugins()->getValues(); |
362
|
|
|
|
363
|
|
|
// On compare l'array contenant l'ensemble des plugins dispo pour le jeu |
364
|
|
|
// A ceux installés sur le serveur |
365
|
|
|
return array_udiff($plugins, $this->getPlugins(), $intersectCallback); |
|
|
|
|
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
public function getServerLogs() |
369
|
|
|
{ |
370
|
|
|
try { |
371
|
|
|
return $this->getMachine()->getConnection()->getScreenContent($this->getScreenName()); |
372
|
|
|
} |
373
|
|
|
catch (ScreenNotExistException $e) { |
374
|
|
|
return null; |
375
|
|
|
} |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
public function getInstallLogs() |
379
|
|
|
{ |
380
|
|
|
try { |
381
|
|
|
return $this->getMachine()->getConnection()->getScreenContent($this->getInstallScreenName()); |
382
|
|
|
} |
383
|
|
|
catch (ScreenNotExistException $e) { |
384
|
|
|
return null; |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
public function finalizeInstallation(\Twig_Environment $twig) |
389
|
|
|
{ |
390
|
|
|
$this->uploadShellScripts($twig); |
391
|
|
|
$this->uploadDefaultServerConfigurationFile(); |
392
|
|
|
$this->removeInstallationFiles(); |
393
|
|
|
|
394
|
|
|
$this->setInstallationStatus(101); |
395
|
|
|
|
396
|
|
|
return true; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* @todo: refacto domain logic |
401
|
|
|
*/ |
402
|
|
|
public function installPlugin(\Twig_Environment $twig, Plugin $plugin) |
403
|
|
|
{ |
404
|
|
|
throw new NotImplementedException(); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
public function uninstallPlugin(\Twig_Environment $twig, Plugin $plugin) |
408
|
|
|
{ |
409
|
|
|
throw new NotImplementedException(); |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
abstract public function uploadShellScripts(\Twig_Environment $twig); |
413
|
|
|
|
414
|
|
|
abstract public function uploadDefaultServerConfigurationFile(); |
415
|
|
|
|
416
|
|
|
abstract public function removeInstallationFiles(); |
417
|
|
|
|
418
|
|
|
abstract public function regenerateScripts(\Twig_Environment $twig); |
419
|
|
|
|
420
|
|
|
public static function loadValidatorMetadata(ClassMetadata $metadata) |
421
|
|
|
{ |
422
|
|
|
$metadata->addPropertyConstraint('machine', new Assert\NotNull(array('message' => 'gameServer.assert.machine'))); |
423
|
|
|
$metadata->addPropertyConstraint('name', new Assert\NotBlank(array('message' => 'gameServer.assert.name'))); |
424
|
|
|
$metadata->addPropertyConstraint('port', new Assert\NotBlank(array('message' => 'gameServer.assert.port'))); |
425
|
|
|
$metadata->addPropertyConstraint('port', new Assert\Range(array( |
426
|
|
|
'min' => 1024, 'minMessage' => 'gameServer.assert.port', |
427
|
|
|
'max' => 65536, 'maxMessage' => 'gameServer.assert.port' |
428
|
|
|
))); |
429
|
|
|
$metadata->addPropertyConstraint('rconPassword', new Assert\NotBlank(array('message' => 'gameServer.assert.rconPassword'))); |
430
|
|
|
$metadata->addPropertyConstraint('dir', new Assert\NotBlank(array('message' => 'gameServer.assert.dir'))); |
431
|
|
|
$metadata->addPropertyConstraint('maxplayers', new Assert\NotBlank(array('message' => 'gameServer.assert.maxplayers'))); |
432
|
|
|
$metadata->addPropertyConstraint('maxplayers', new Assert\Range(array('min' => 2, 'minMessage' => 'gameServer.assert.maxplayers'))); |
433
|
|
|
} |
434
|
|
|
} |
435
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.