Completed
Pull Request — master (#168)
by De Cramer
03:26
created

AbstractApplication::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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