Completed
Push — master ( f30e4c...e7851f )
by
unknown
16s
created

AbstractApplication   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 91.43%

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 3
dl 0
loc 135
ccs 32
cts 35
cp 0.9143
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A init() 0 9 1
executeRun() 0 1 ?
B run() 0 63 7
A stopApplication() 0 5 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
    public function run()
71 2
    {
72
        // Time each cycle needs to take in microseconds. Wrunning 60 cycles per seconds to have optimal response time.
73
        $cycleTime = (1 / 60) * 1000000;
74 2
75 2
        // Running GC collect every 5 minutes should be sufficient.;
76 2
        $gcCycleTime = 60 * 5;
77
78 2
        // 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
        $lastGcTime = time();
83 2
84 2
        $this->console->writeln("Running preflight checks...");
85
        $this->connection->enableCallbacks(true);
86
87
        // need to send this for scripts to start callback handling
88
        try {
89
            $this->connection->triggerModeScriptEvent("XmlRpc.EnableCallbacks", ["True"]);
90 2
            $this->connection->triggerModeScriptEvent("XmlRpc.SetApiVersion", [self::SCRIPT_API_VERSION]);
91
        } catch (\Exception $exception) {
92 2
            $this->connection->saveMatchSettings('MatchSettings/eXpansion-mode-fail-'.date(DATE_ISO8601).'.txt');
93
            throw $exception;
94
        }
95 2
96
        $this->console->writeln("preflight checks OK.");
97 2
        $this->dispatcher->dispatch(self::EVENT_READY, []);
98
        $this->console->writeln("And takeoff");
99 2
100 2
        do {
101
            $startTime = microtime(true);
102 2
103
            // Run the actuall application
104 2
            $this->executeRun();
105 2
106
            $endTime = microtime(true);
107
            $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 2
            // cycle this iteration.
111
            if ($delay > $cycleTime/2 && $lastGcTime < (time() - $gcCycleTime)) {
112 2
                // PHP does this automatically as well but in some mysterious ways it can sometimes keep in memory
113 2
                // hundred of mb's before running it.
114 2
                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
            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
            } elseif ($delay > 0) {
129
                usleep($delay);
130
            }
131
        } while ($this->isRunning);
132
    }
133
134
    /**
135
     * Stop eXpansion.
136
     */
137
    public function stopApplication()
138
    {
139
        $this->dispatcher->dispatch(self::EVENT_STOP, []);
140
        $this->isRunning = false;
141
    }
142
143
    abstract protected function executeRun();
144
}
145