Completed
Push — master ( a7c0e3...a4c847 )
by
unknown
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 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 = "dev";
19
20
    /** @var Connection */
21
    protected $connection;
22
23
    /** @var DispatcherInterface */
24
    protected $dispatcher;
25
26
    /** @var Console */
27
    protected $console;
28
29
    /** @var bool */
30
    protected $isRunning = true;
31
32
    /**
33
     * Application constructor.
34
     *
35
     * @param DispatcherInterface $dispatcher
36
     * @param Connection $connection
37
     * @param Console $output
38
     */
39 138
    public function __construct(
40
        DispatcherInterface $dispatcher,
41
        Connection $connection,
42
        Console $output
43
    ) {
44 138
        $this->connection = $connection;
45 138
        $this->dispatcher = $dispatcher;
46 138
        $this->console = $output;
47 138
    }
48
49
    /**
50
     * Initialize eXpansion.
51
     *
52
     * @param OutputInterface $console
53
     *
54
     * @return $this
55
     */
56 1
    public function init(OutputInterface $console)
57
    {
58 1
        $this->console->init($console, $this->dispatcher);
59 1
        $this->dispatcher->dispatch(self::EVENT_BEFORE_INIT, []);
60 1
        $this->dispatcher->init($this->connection);
61 1
        $this->dispatcher->dispatch(self::EVENT_AFTER_INIT, []);
62
63 1
        return $this;
64
    }
65
66
    /**
67
     * Run eXpansion
68
     *
69
     * @inheritdoc
70
     */
71 2
    public function run()
72
    {
73
        // Time each cycle needs to take in microseconds. Wrunning 60 cycles per seconds to have optimal response time.
74 2
        $cycleTime = (1 / 60) * 1000000;
75
76
        // Running GC collect every 5 minutes should be sufficient.;
77 2
        $gcCycleTime = 60 * 5;
78
79
        // Time when we will force gc cycles.
80 2
        $maxGcCycleTime = 60 * 20;
81
82
        // Last time garbage collector ran. Assume that at start it ran.
83 2
        $lastGcTime = time();
84
85 2
        $this->console->writeln("Running preflight checks...");
86 2
        $this->connection->enableCallbacks(true);
87
88
        // need to send this for scripts to start callback handling
89
        try {
90 2
            $this->connection->triggerModeScriptEvent("XmlRpc.EnableCallbacks", ["True"]);
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