|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
|
|
4
|
|
|
namespace eXpansion\Framework\Core\Services\Application; |
|
5
|
|
|
|
|
6
|
|
|
use eXpansion\Framework\Core\Services\Console; |
|
7
|
|
|
use eXpansion\Framework\Core\Services\DedicatedConnection\Factory; |
|
8
|
|
|
use Maniaplanet\DedicatedServer\Connection; |
|
9
|
|
|
use Propel\Runtime\Connection\Exception\ConnectionException; |
|
10
|
|
|
use Propel\Runtime\Propel; |
|
11
|
|
|
use Psr\Log\LoggerInterface; |
|
12
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
|
13
|
|
|
|
|
14
|
|
|
abstract class AbstractApplication implements RunInterface |
|
15
|
|
|
{ |
|
16
|
|
|
/** Base eXpansion callbacks. */ |
|
17
|
|
|
const EVENT_BEFORE_INIT = "expansion.before_init"; |
|
18
|
|
|
const EVENT_AFTER_INIT = "expansion.after_init"; |
|
19
|
|
|
const EVENT_READY = "expansion.ready"; |
|
20
|
|
|
const EVENT_STOP = "expansion.stop"; |
|
21
|
|
|
|
|
22
|
|
|
const EXPANSION_VERSION = "dev"; |
|
23
|
|
|
|
|
24
|
|
|
/** @var Factory */ |
|
25
|
|
|
protected $factory; |
|
26
|
|
|
|
|
27
|
|
|
/** @var DispatcherInterface */ |
|
28
|
|
|
protected $dispatcher; |
|
29
|
|
|
|
|
30
|
|
|
/** @var Console */ |
|
31
|
|
|
protected $console; |
|
32
|
|
|
|
|
33
|
|
|
/** @var bool */ |
|
34
|
|
|
protected $isRunning = true; |
|
35
|
|
|
/** |
|
36
|
|
|
* @var LoggerInterface |
|
37
|
|
|
*/ |
|
38
|
|
|
private $logger; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* AbstractApplication constructor. |
|
42
|
|
|
* |
|
43
|
|
|
* @param DispatcherInterface $dispatcher |
|
44
|
|
|
* @param Factory $factory |
|
45
|
|
|
* @param Console $output |
|
46
|
|
|
* @param LoggerInterface $logger |
|
47
|
|
|
*/ |
|
48
|
150 |
|
public function __construct( |
|
49
|
|
|
DispatcherInterface $dispatcher, |
|
50
|
|
|
Factory $factory, |
|
51
|
|
|
Console $output, |
|
52
|
|
|
LoggerInterface $logger |
|
53
|
|
|
) { |
|
54
|
150 |
|
$this->factory = $factory; |
|
55
|
150 |
|
$this->dispatcher = $dispatcher; |
|
56
|
150 |
|
$this->console = $output; |
|
57
|
150 |
|
$this->logger = $logger; |
|
58
|
150 |
|
} |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* Initialize eXpansion. |
|
62
|
|
|
* |
|
63
|
|
|
* @param OutputInterface $console |
|
64
|
|
|
* |
|
65
|
|
|
* @return $this|mixed |
|
66
|
|
|
* @throws \Maniaplanet\DedicatedServer\Xmlrpc\TransportException |
|
67
|
|
|
*/ |
|
68
|
1 |
|
public function init(OutputInterface $console) |
|
69
|
|
|
{ |
|
70
|
1 |
|
$this->console->init($console, $this->dispatcher); |
|
71
|
1 |
|
$this->dispatcher->dispatch(self::EVENT_BEFORE_INIT, []); |
|
72
|
|
|
|
|
73
|
1 |
|
$this->factory->createConnection(); |
|
74
|
1 |
|
$this->dispatcher->init($this->factory->getConnection()); |
|
75
|
|
|
|
|
76
|
1 |
|
$this->dispatcher->dispatch(self::EVENT_AFTER_INIT, []); |
|
77
|
1 |
|
return $this; |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Run eXpansion |
|
82
|
|
|
* |
|
83
|
|
|
* @inheritdoc |
|
84
|
|
|
*/ |
|
85
|
2 |
|
public function run() |
|
86
|
|
|
{ |
|
87
|
|
|
// Time each cycle needs to take in microseconds. Wrunning 60 cycles per seconds to have optimal response time. |
|
88
|
2 |
|
$cycleTime = (1 / 60) * 1000000; |
|
89
|
|
|
|
|
90
|
|
|
// Running GC collect every 5 minutes should be sufficient.; |
|
91
|
2 |
|
$gcCycleTime = 60 * 5; |
|
92
|
|
|
|
|
93
|
|
|
// Time when we will force gc cycles. |
|
94
|
2 |
|
$maxGcCycleTime = 60 * 20; |
|
95
|
|
|
|
|
96
|
|
|
// Last time garbage collector ran. Assume that at start it ran. |
|
97
|
2 |
|
$lastGcTime = time(); |
|
98
|
|
|
|
|
99
|
2 |
|
$this->console->writeln("Running preflight checks..."); |
|
100
|
2 |
|
$this->factory->getConnection()->enableCallbacks(true); |
|
101
|
|
|
|
|
102
|
|
|
// need to send this for scripts to start callback handling |
|
103
|
|
|
try { |
|
104
|
2 |
|
$this->factory->getConnection()->triggerModeScriptEvent("XmlRpc.EnableCallbacks", ["True"]); |
|
105
|
|
|
} catch (\Exception $exception) { |
|
106
|
|
|
$this->factory->getConnection()->saveMatchSettings('MatchSettings/eXpansion-mode-fail-'.date(DATE_ISO8601).'.txt'); |
|
107
|
|
|
throw $exception; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
2 |
|
$this->console->writeln("preflight checks OK."); |
|
111
|
|
|
|
|
112
|
2 |
|
$this->dispatcher->dispatch(self::EVENT_READY, []); |
|
113
|
|
|
|
|
114
|
2 |
|
$this->console->writeln("And takeoff"); |
|
115
|
|
|
|
|
116
|
|
|
do { |
|
117
|
2 |
|
$startTime = microtime(true); |
|
118
|
|
|
|
|
119
|
|
|
// Run the actuall application |
|
120
|
2 |
|
$this->executeRun(); |
|
121
|
|
|
|
|
122
|
2 |
|
$endTime = microtime(true); |
|
123
|
2 |
|
$delay = $cycleTime - (($endTime - $startTime) * 1000000); |
|
124
|
|
|
|
|
125
|
|
|
// If we got lot's of time and it's been a while since last GC collect let's run a garbage collector |
|
126
|
|
|
// cycle this iteration. |
|
127
|
2 |
|
if ($delay > $cycleTime / 2 && $lastGcTime < (time() - $gcCycleTime)) { |
|
128
|
|
|
// PHP does this automatically as well but in some mysterious ways it can sometimes keep in memory |
|
129
|
|
|
// hundred of mb's before running it. |
|
130
|
|
|
gc_collect_cycles(); |
|
131
|
|
|
$lastGcTime = time(); |
|
132
|
|
|
|
|
133
|
|
|
// Renew delay so that this iteration isn't much slower then the others |
|
134
|
|
|
$endTime = microtime(true); |
|
135
|
|
|
$delay = $cycleTime - (($endTime - $startTime) * 1000000); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
2 |
|
if ($lastGcTime < (time() - $maxGcCycleTime)) { |
|
139
|
|
|
//It's been a while since last Garbage collection forcing it to go even through the application is |
|
140
|
|
|
// running slow. |
|
141
|
|
|
gc_collect_cycles(); |
|
142
|
|
|
$lastGcTime = time(); |
|
143
|
|
|
|
|
144
|
2 |
|
} elseif ($delay > 0) { |
|
145
|
2 |
|
usleep($delay); |
|
146
|
|
|
} |
|
147
|
2 |
|
} while ($this->isRunning); |
|
148
|
|
|
|
|
149
|
2 |
|
$this->factory->getConnection()->sendHideManialinkPage(null); |
|
150
|
2 |
|
$this->factory->getConnection()->triggerModeScriptEvent("Shootmania.UI.ResetProperties", []); |
|
151
|
2 |
|
$this->factory->getConnection()->triggerModeScriptEvent("Trackmania.UI.ResetProperties", []); |
|
152
|
2 |
|
} |
|
153
|
|
|
|
|
154
|
|
|
/** |
|
155
|
|
|
* Stop eXpansion. |
|
156
|
|
|
*/ |
|
157
|
2 |
|
public function stopApplication() |
|
158
|
|
|
{ |
|
159
|
2 |
|
$this->dispatcher->dispatch(self::EVENT_STOP, []); |
|
160
|
2 |
|
$this->isRunning = false; |
|
161
|
2 |
|
} |
|
162
|
|
|
|
|
163
|
|
|
abstract protected function executeRun(); |
|
164
|
|
|
} |
|
165
|
|
|
|