Completed
Push — master ( bbe9d4...e82ffc )
by De Cramer
10s
created

AbstractApplication::stopApplication()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 1
eloc 3
nc 1
nop 0
crap 1
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 151
    public function __construct(
49
        DispatcherInterface $dispatcher,
50
        Factory $factory,
51
        Console $output,
52
        LoggerInterface $logger
53
    ) {
54 151
        $this->factory = $factory;
55 151
        $this->dispatcher = $dispatcher;
56 151
        $this->console = $output;
57 151
        $this->logger = $logger;
58 151
    }
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->checkPhpExtensions($console);
71
72 1
        $this->console->init($console, $this->dispatcher);
73 1
        $this->dispatcher->dispatch(self::EVENT_BEFORE_INIT, []);
74
75 1
        $this->factory->createConnection();
76 1
        $this->dispatcher->init($this->factory->getConnection());
77
78 1
        $this->dispatcher->dispatch(self::EVENT_AFTER_INIT, []);
79 1
        return $this;
80
    }
81
82 1
    protected function checkPhpExtensions(OutputInterface $console)
83
    {
84
        $extensions = array(
85 1
            'openssl' => 'extension=php_openssl.dll',
86
            'curl' => 'extension=curl.dll',
87
        );
88 1
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
89
            $extensions['com_dotnet'] = 'extension=php_com_dotnet.dll';
90
        }
91
92 1
        $status = true;
93 1
        $showIni = false;
94 1 View Code Duplication
        foreach ($extensions as $extension => $description) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95 1
            if (!extension_loaded($extension)) {
96
                $console->writeln(
97
                    "<error>eXpansion needs PHP extension $extension to run. Enable it to run eXpansion => " . $description . "</error>"
98
                );
99
                $status = false;
100 1
                $showIni = true;
101
            }
102
        }
103
104
        $recommend = array(
105 1
            'xmlrpc' => "It will have better performances !",
106
        );
107 1 View Code Duplication
        foreach ($recommend as $extension => $reason) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108 1
            if (!extension_loaded($extension)) {
109
                $console->writeln(
110
                    "<error>eXpansion works better with PHP extension</error> <info>$extension</info>: " . $reason . ""
111
                );
112 1
                $showIni = true;
113
            }
114
        }
115
116 1
        if ($showIni) {
117
            $console->writeln('<info>[PHP] PHP is using fallowing ini file :</info> "'. php_ini_loaded_file() .'"');
118
            sleep(5);
119
        }
120 1
        return $status;
121
    }
122
123
    /**
124
     * Run eXpansion
125
     *
126
     * @inheritdoc
127
     */
128 2
    public function run()
129
    {
130
        // Time each cycle needs to take in microseconds. Wrunning 60 cycles per seconds to have optimal response time.
131 2
        $cycleTime = (1 / 60) * 1000000;
132
133
        // Running GC collect every 5 minutes should be sufficient.;
134 2
        $gcCycleTime = 60 * 5;
135
136
        // Time when we will force gc cycles.
137 2
        $maxGcCycleTime = 60 * 20;
138
139
        // Last time garbage collector ran. Assume that at start it ran.
140 2
        $lastGcTime = time();
141
142 2
        $this->console->writeln("Running preflight checks...");
143 2
        $this->factory->getConnection()->enableCallbacks(true);
144
145
        // need to send this for scripts to start callback handling
146
        try {
147 2
            $this->factory->getConnection()->triggerModeScriptEvent("XmlRpc.EnableCallbacks", ["True"]);
148
        } catch (\Exception $exception) {
149
            $this->factory->getConnection()->saveMatchSettings('MatchSettings/eXpansion-mode-fail-'.date(DATE_ISO8601).'.txt');
150
            throw $exception;
151
        }
152
153 2
        $this->console->writeln("preflight checks OK.");
154
155 2
        $this->dispatcher->dispatch(self::EVENT_READY, []);
156
157 2
        $this->console->writeln("And takeoff");
158
159
        do {
160 2
            $startTime = microtime(true);
161
162
            // Run the actuall application
163 2
            $this->executeRun();
164
165 2
            $endTime = microtime(true);
166 2
            $delay = $cycleTime - (($endTime - $startTime) * 1000000);
167
168
            // If we got lot's of time and it's been a while since last GC collect let's run a garbage collector
169
            // cycle this iteration.
170 2
            if ($delay > $cycleTime / 2 && $lastGcTime < (time() - $gcCycleTime)) {
171
                // PHP does this automatically as well but in some mysterious ways it can sometimes keep in memory
172
                // hundred of mb's before running it.
173
                gc_collect_cycles();
174
                $lastGcTime = time();
175
176
                // Renew delay so that this iteration isn't much slower then the others
177
                $endTime = microtime(true);
178
                $delay = $cycleTime - (($endTime - $startTime) * 1000000);
179
            }
180
181 2
            if ($lastGcTime < (time() - $maxGcCycleTime)) {
182
                //It's been a while since last Garbage collection forcing it to go even through the application is
183
                // running slow.
184
                gc_collect_cycles();
185
                $lastGcTime = time();
186
187 2
            } elseif ($delay > 0) {
188 2
                usleep($delay);
189
            }
190 2
        } while ($this->isRunning);
191
192 2
        $this->factory->getConnection()->sendHideManialinkPage(null);
193 2
        $this->factory->getConnection()->triggerModeScriptEvent("Shootmania.UI.ResetProperties", []);
194 2
        $this->factory->getConnection()->triggerModeScriptEvent("Trackmania.UI.ResetProperties", []);
195 2
    }
196
197
    /**
198
     * Stop eXpansion.
199
     */
200 2
    public function stopApplication()
201
    {
202 2
        $this->dispatcher->dispatch(self::EVENT_STOP, []);
203 2
        $this->isRunning = false;
204 2
    }
205
206
    abstract protected function executeRun();
207
}
208