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\VoipServer\TeamspeakServerBundle\Entity; |
13
|
|
|
|
14
|
|
|
use Dedipanel\PHPSeclibWrapperBundle\Connection\Connection; |
15
|
|
|
use Doctrine\ORM\Mapping as ORM; |
16
|
|
|
use DP\VoipServer\TeamspeakServerBundle\Service\ServerQueryFactory; |
17
|
|
|
use DP\VoipServer\VoipServerBundle\Entity\VoipServer; |
18
|
|
|
use Symfony\Component\HttpFoundation\File\UploadedFile; |
19
|
|
|
use Symfony\Component\Validator\Constraints as Assert; |
20
|
|
|
use Symfony\Component\Validator\Mapping\ClassMetadata; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* TeamspeakServer |
24
|
|
|
* |
25
|
|
|
* @ORM\Table(name="teamspeak_server") |
26
|
|
|
* @ORM\Entity(repositoryClass="DP\Core\CoreBundle\Entity\MachineRelatedRepository") |
27
|
|
|
*/ |
28
|
|
|
class TeamspeakServer extends VoipServer |
29
|
|
|
{ |
30
|
|
|
/** |
31
|
|
|
* @var integer $queryPort |
32
|
|
|
* |
33
|
|
|
* @ORM\Column(name="query_port", type="integer", nullable=true) |
34
|
|
|
*/ |
35
|
|
|
private $queryPort; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var string $queryLogin |
39
|
|
|
* |
40
|
|
|
* @ORM\Column(name="query_login", type="string", length=32, nullable=true) |
41
|
|
|
*/ |
42
|
|
|
private $queryLogin; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var string $queryPassword |
46
|
|
|
* |
47
|
|
|
* @ORM\Column(name="query_passwd", type="string", length=32, nullable=true) |
48
|
|
|
*/ |
49
|
|
|
private $queryPassword; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var integer $filetransferPort |
53
|
|
|
* |
54
|
|
|
* @ORM\Column(name="filetransfer_port", type="integer", nullable=true) |
55
|
|
|
*/ |
56
|
|
|
private $filetransferPort; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var integer $voicePort |
60
|
|
|
* |
61
|
|
|
* @ORM\Column(name="voice_port", type="integer", nullable=true) |
62
|
|
|
*/ |
63
|
|
|
private $voicePort; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var UploadedFile $licenceFile |
67
|
|
|
*/ |
68
|
|
|
private $licenceFile; |
69
|
|
|
|
70
|
|
|
/** @var bool $firstStart */ |
71
|
|
|
private $firstStart; |
72
|
|
|
|
73
|
|
|
|
74
|
|
|
public function __construct() |
75
|
|
|
{ |
76
|
|
|
parent::__construct(); |
77
|
|
|
|
78
|
|
|
$this->voicePort = 9987; |
79
|
|
|
$this->queryPort = 10011; |
80
|
|
|
$this->queryLogin = 'serveradmin'; |
81
|
|
|
$this->filetransferPort = 30033; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Set the port needed by the query |
86
|
|
|
* |
87
|
|
|
* @param integer $port |
88
|
|
|
* @return integer |
89
|
|
|
*/ |
90
|
|
|
public function setQueryPort($port) |
91
|
|
|
{ |
92
|
|
|
$this->queryPort = $port; |
93
|
|
|
|
94
|
|
|
return $this; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Get the port needed by the query |
99
|
|
|
* |
100
|
|
|
* @return integer |
101
|
|
|
*/ |
102
|
|
|
public function getQueryPort() |
103
|
|
|
{ |
104
|
|
|
return $this->queryPort; |
|
|
|
|
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Get the login needed by the query |
109
|
|
|
* |
110
|
|
|
* @return string |
111
|
|
|
*/ |
112
|
|
|
public function getQueryLogin() |
113
|
|
|
{ |
114
|
|
|
return $this->queryLogin; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Set the password needed by the query |
119
|
|
|
* |
120
|
|
|
* @param string $password |
121
|
|
|
* @return TeamspeakServer |
122
|
|
|
*/ |
123
|
|
|
public function setQueryPassword($password) |
124
|
|
|
{ |
125
|
|
|
// Prevent unsetting the password from forms |
126
|
|
|
if (!empty($password)) { |
127
|
|
|
$this->queryPassword = $password; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
return $this; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Get the password needed by the query |
135
|
|
|
* |
136
|
|
|
* @return string |
137
|
|
|
*/ |
138
|
|
|
public function getQueryPassword() |
139
|
|
|
{ |
140
|
|
|
return $this->queryPassword; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Set the filetransfer port used by teamspeak |
145
|
|
|
* |
146
|
|
|
* @param integer $filetransferPort |
147
|
|
|
* @return TeamspeakServer |
148
|
|
|
*/ |
149
|
|
|
public function setFiletransferPort($filetransferPort) |
150
|
|
|
{ |
151
|
|
|
$this->filetransferPort = $filetransferPort; |
152
|
|
|
|
153
|
|
|
return $this; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Get the filetransfer port used by teamspeak |
158
|
|
|
* |
159
|
|
|
* @return integer |
160
|
|
|
*/ |
161
|
|
|
public function getFiletransferPort() |
162
|
|
|
{ |
163
|
|
|
return $this->filetransferPort; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Get the default voice port |
168
|
|
|
* (will be used by the first instance) |
169
|
|
|
* |
170
|
|
|
* @param integer $voicePort |
171
|
|
|
* @return TeamspeakServer |
172
|
|
|
*/ |
173
|
|
|
public function setVoicePort($voicePort) |
174
|
|
|
{ |
175
|
|
|
$this->voicePort = $voicePort; |
176
|
|
|
|
177
|
|
|
return $this; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Get the default voice port |
182
|
|
|
* (will be used by the first instance) |
183
|
|
|
* |
184
|
|
|
* @return integer |
185
|
|
|
*/ |
186
|
|
|
public function getVoicePort() |
187
|
|
|
{ |
188
|
|
|
return $this->voicePort; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Set the uploaded licence file |
193
|
|
|
* |
194
|
|
|
* @param UploadedFile $licenceFile |
195
|
|
|
* @return TeamspeakServer |
196
|
|
|
*/ |
197
|
|
|
public function setLicenceFile(UploadedFile $licenceFile = null) |
198
|
|
|
{ |
199
|
|
|
$this->licenceFile = $licenceFile; |
200
|
|
|
|
201
|
|
|
return $this; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Has the licence file been uploaded ? |
206
|
|
|
* |
207
|
|
|
* @return boolean |
208
|
|
|
*/ |
209
|
|
|
public function hasLicenceFile() |
210
|
|
|
{ |
211
|
|
|
return $this->licenceFile !== null; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** {@inheritdoc} */ |
215
|
|
|
public function getInstallationProgress() |
216
|
|
|
{ |
217
|
|
|
$conn = $this->getMachine()->getConnection(); |
218
|
|
|
$installDir = $this->getAbsoluteDir(); |
219
|
|
|
$logPath = $installDir . 'install.log'; |
220
|
|
|
|
221
|
|
|
if ($conn->fileExists($installDir . '/ts3server_startscript.sh')) { |
222
|
|
|
return 100; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// On récupère les 20 dernières lignes du fichier afin de déterminer le pourcentage |
226
|
|
|
$installLog = $conn->exec('tail -n 20 ' . $logPath); |
227
|
|
|
$percent = $this->getPercentFromInstallLog($installLog); |
228
|
|
|
|
229
|
|
|
return $percent; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** {@inheritdoc} */ |
233
|
|
|
public function installServer(\Twig_Environment $twig) |
234
|
|
|
{ |
235
|
|
|
$conn = $this->getMachine()->getConnection(); |
236
|
|
|
$installDir = $this->getAbsoluteDir(); |
237
|
|
|
$logPath = $installDir . '/install.log'; |
238
|
|
|
$tempPath = $installDir . '/server.tgz'; |
239
|
|
|
|
240
|
|
|
$conn->mkdir($installDir); |
241
|
|
|
|
242
|
|
|
$dlUrl = 'http://dl.4players.de/ts/releases/3.0.10.3/teamspeak3-server_linux-x86-3.0.10.3.tar.gz'; |
243
|
|
|
$untarDir = $installDir . '/teamspeak3-server_linux-x86'; |
244
|
|
|
if ($this->getMachine()->is64Bit()) { |
245
|
|
|
$dlUrl = 'http://dl.4players.de/ts/releases/3.0.10.3/teamspeak3-server_linux-amd64-3.0.10.3.tar.gz'; |
246
|
|
|
$untarDir = $installDir . '/teamspeak3-server_linux-amd64'; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
$cmd = 'wget -o ' . $logPath . ' -O ' . $tempPath . ' ' . $dlUrl . ' '; |
250
|
|
|
$cmd .= '&& tar zxf ' . $tempPath . ' -C ' . $installDir . ' '; |
251
|
|
|
$cmd .= '&& mv ' . $untarDir . '/* ' . $installDir . ' '; |
252
|
|
|
$cmd .= '&& wget -O ' . $installDir . '/sql/defaults.sql http://media.teamspeak.com/literature/defaults.sql '; |
253
|
|
|
$cmd .= '&& rm -Rf ' . $untarDir . ' ' . $tempPath . ' ' . $logPath; |
254
|
|
|
|
255
|
|
|
$conn->exec($cmd); |
256
|
|
|
|
257
|
|
|
$this->installationStatus = 0; |
258
|
|
|
|
259
|
|
|
return true; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** {@inheritdoc} */ |
263
|
|
|
public function finalizeInstallation(\Twig_Environment $twig) |
264
|
|
|
{ |
265
|
|
|
$conn = $this->getMachine()->getConnection(); |
266
|
|
|
$installDir = $this->getAbsoluteDir(); |
267
|
|
|
|
268
|
|
|
if (!$conn->dirExists($installDir)) { |
269
|
|
|
return false; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
$this->uploadConfigFile(); |
273
|
|
|
|
274
|
|
|
if ($this->hasLicenceFile()) { |
275
|
|
|
$this->uploadLicenceFile(); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
$conn->exec("echo \$SSH_CLIENT | awk '{print \$1}' >> ${installDir}/query_ip_whitelist.txt"); |
279
|
|
|
|
280
|
|
|
$this->firstStart = true; |
281
|
|
|
$this->changeState('start'); |
282
|
|
|
sleep(2); |
283
|
|
|
$this->changeState('stop'); |
284
|
|
|
|
285
|
|
|
$this->firstStart = false; |
286
|
|
|
$this->changeState('start'); |
287
|
|
|
|
288
|
|
|
$this->installationStatus = 101; |
289
|
|
|
|
290
|
|
|
return true; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
public function uploadConfigFile() |
294
|
|
|
{ |
295
|
|
|
$config = ''; |
296
|
|
|
$config .= $this->getGeneralConfig() . "\n"; |
297
|
|
|
$config .= $this->getDatabaseConfig(); |
298
|
|
|
|
299
|
|
|
$filepath = $this->getAbsoluteDir() . '/ts3server.ini'; |
300
|
|
|
|
301
|
|
|
return $this |
302
|
|
|
->getMachine() |
303
|
|
|
->getConnection() |
304
|
|
|
->upload($filepath, $config, 0750) |
305
|
|
|
; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
public function uploadLicenceFile() |
309
|
|
|
{ |
310
|
|
|
if (!$this->hasLicenceFile()) { |
311
|
|
|
return false; |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
$licencePath = $this->getAbsoluteDir() . '/serverkey.dat'; |
315
|
|
|
$filepath = $this->licenceFile->getPathname(); |
316
|
|
|
$content = file_get_contents($filepath); |
317
|
|
|
|
318
|
|
|
@unlink($filepath); |
|
|
|
|
319
|
|
|
unset($this->licenceFile); |
320
|
|
|
|
321
|
|
|
return $this |
322
|
|
|
->getMachine() |
323
|
|
|
->getConnection() |
324
|
|
|
->upload($licencePath, $content, 0750) |
325
|
|
|
; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
public function getGeneralConfig() |
329
|
|
|
{ |
330
|
|
|
$publicIp = $this->getMachine()->getPublicIp(); |
331
|
|
|
$privateIp = $this->getMachine()->getPrivateIp(); |
332
|
|
|
|
333
|
|
|
return <<<EOF |
334
|
|
|
machine_id= |
335
|
|
|
default_voice_port={$this->voicePort} |
336
|
|
|
voice_ip=${publicIp} |
337
|
|
|
licensepath= |
338
|
|
|
filetransfer_port={$this->filetransferPort} |
339
|
|
|
filetransfer_ip={$publicIp} |
340
|
|
|
query_port={$this->queryPort} |
341
|
|
|
query_ip={$privateIp} |
342
|
|
|
logpath=logs/ |
343
|
|
|
logquerycommands=0 |
344
|
|
|
EOF; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
public function getDatabaseConfig() |
348
|
|
|
{ |
349
|
|
|
return <<<EOF |
350
|
|
|
dbplugin=ts3db_sqlite3 |
351
|
|
|
dbpluginparameter= |
352
|
|
|
dbsqlpath=sql/ |
353
|
|
|
dbsqlcreatepath=create_sqlite/ |
354
|
|
|
EOF; |
355
|
|
|
|
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** {@inheritdoc} */ |
359
|
|
|
public function changeState($state) |
360
|
|
|
{ |
361
|
|
|
$cmd = $this->getAbsoluteDir() . '/ts3server_startscript.sh ' . $state; |
362
|
|
|
|
363
|
|
|
if ($state == 'start') { |
364
|
|
|
$cmd .= ' ' . $this->getStartParams(); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
$core = $this->getCore(); |
368
|
|
|
if (!empty($core)) { |
369
|
|
|
$cmd = 'taskset -c ' . implode(',', $core) . ' ' . $cmd; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
return $this |
373
|
|
|
->getMachine() |
374
|
|
|
->getConnection() |
375
|
|
|
->exec($cmd) |
376
|
|
|
; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
public function getStartParams() |
380
|
|
|
{ |
381
|
|
|
$params = array(); |
382
|
|
|
$params[] = 'create_default_virtualserver=0'; |
383
|
|
|
|
384
|
|
|
if ($this->firstStart) { |
385
|
|
|
$password = \TeamSpeak3_Helper_String::factory($this->queryPassword)->escape(); |
|
|
|
|
386
|
|
|
|
387
|
|
|
$params[] = 'serveradmin_password=' . $this->queryPassword; |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
return '"' . implode(' ', $params) . '"' . (($this->firstStart) ? ' &' : ''); |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** {@inheritdoc} */ |
394
|
|
|
public function getAbsoluteDir() |
395
|
|
|
{ |
396
|
|
|
return rtrim($this->getMachine()->getHome(), '/') . '/' . trim($this->dir, '/'); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** {@inheritdoc} */ |
400
|
|
|
public function getName() |
401
|
|
|
{ |
402
|
|
|
return strval($this); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
public function getFullName() |
406
|
|
|
{ |
407
|
|
|
return $this->getName(); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
/** {@inheritdoc} */ |
411
|
|
|
public function getType() |
412
|
|
|
{ |
413
|
|
|
return 'teamspeak'; |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
public function __toString() |
417
|
|
|
{ |
418
|
|
|
return strval($this->getMachine()); |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
public static function loadValidatorMetadata(ClassMetadata $metadata) |
422
|
|
|
{ |
423
|
|
|
$metadata->addPropertyConstraint('voicePort', new Assert\NotBlank(array('message' => 'teamspeak_server.assert.voice_port.empty'))); |
424
|
|
|
$metadata->addPropertyConstraint('voicePort', new Assert\Range(array( |
425
|
|
|
'min' => 1024, |
426
|
|
|
'minMessage' => 'teamspeak_server.assert.voice_port.min', |
427
|
|
|
'max' => 65536, |
428
|
|
|
'maxMessage' => 'teamspeak_server.assert.voice_port.max', |
429
|
|
|
))); |
430
|
|
|
$metadata->addPropertyConstraint('queryPort', new Assert\NotBlank(array('message' => 'teamspeak_server.assert.query_port.empty'))); |
431
|
|
|
$metadata->addPropertyConstraint('queryPort', new Assert\Range(array( |
432
|
|
|
'min' => 1024, |
433
|
|
|
'minMessage' => 'teamspeak_server.assert.query_port.min', |
434
|
|
|
'max' => 65536, |
435
|
|
|
'maxMessage' => 'teamspeak_server.assert.query_port.max', |
436
|
|
|
))); |
437
|
|
|
$metadata->addPropertyConstraint('queryPassword', new Assert\NotBlank(array('message' => 'teamspeak_server.assert.query_password.empty'))); |
438
|
|
|
$metadata->addPropertyConstraint('filetransferPort', new Assert\NotBlank(array('message' => 'teamspeak_server.assert.filetransfer_port.empty'))); |
439
|
|
|
$metadata->addPropertyConstraint('filetransferPort', new Assert\Range(array( |
440
|
|
|
'min' => 1024, |
441
|
|
|
'minMessage' => 'teamspeak_server.assert.filetransfer_port.min', |
442
|
|
|
'max' => 65536, |
443
|
|
|
'maxMessage' => 'teamspeak_server.assert.filetransfer_port.max', |
444
|
|
|
))); |
445
|
|
|
$metadata->addPropertyConstraint('licenceFile', new Assert\File(array( |
446
|
|
|
'maxSize' => 200, |
447
|
|
|
'maxSizeMessage' => 'teamspeak_server.assert.licence_file.max_size', |
448
|
|
|
))); |
449
|
|
|
} |
450
|
|
|
} |
451
|
|
|
|
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.