Completed
Push — master ( fcbcd2...296f3b )
by Biao
03:38
created

LaravelS::onStart()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
namespace Hhxsv5\LaravelS;
4
5
use Hhxsv5\LaravelS\Illuminate\Laravel;
6
use Hhxsv5\LaravelS\Swoole\DynamicResponse;
7
use Hhxsv5\LaravelS\Swoole\Events\ServerStartInterface;
8
use Hhxsv5\LaravelS\Swoole\Events\ServerStopInterface;
9
use Hhxsv5\LaravelS\Swoole\Events\WorkerErrorInterface;
10
use Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface;
11
use Hhxsv5\LaravelS\Swoole\Events\WorkerStopInterface;
12
use Hhxsv5\LaravelS\Swoole\Request;
13
use Hhxsv5\LaravelS\Swoole\Server;
14
use Hhxsv5\LaravelS\Swoole\StaticResponse;
15
use Hhxsv5\LaravelS\Swoole\Traits\CustomProcessTrait;
16
use Hhxsv5\LaravelS\Swoole\Traits\InotifyTrait;
17
use Hhxsv5\LaravelS\Swoole\Traits\LaravelTrait;
18
use Hhxsv5\LaravelS\Swoole\Traits\LogTrait;
19
use Hhxsv5\LaravelS\Swoole\Traits\ProcessTitleTrait;
20
use Hhxsv5\LaravelS\Swoole\Traits\TimerTrait;
21
use Illuminate\Http\Request as IlluminateRequest;
22
use Swoole\Http\Request as SwooleRequest;
23
use Swoole\Http\Response as SwooleResponse;
24
use Swoole\Http\Server as HttpServer;
25
use Swoole\WebSocket\Server as WebSocketServer;
26
use Symfony\Component\Console\Style\OutputStyle;
27
use Symfony\Component\HttpFoundation\BinaryFileResponse;
28
29
30
/**
31
 * Swoole Request => Laravel Request
32
 * Laravel Request => Laravel handle => Laravel Response
33
 * Laravel Response => Swoole Response
34
 */
35
class LaravelS extends Server
36
{
37
    /**
38
     * Fix conflicts of traits
39
     */
40
    use InotifyTrait, LaravelTrait, LogTrait, ProcessTitleTrait, TimerTrait, CustomProcessTrait;
0 ignored issues
show
introduced by
The trait Hhxsv5\LaravelS\Swoole\Traits\TimerTrait requires some properties which are not provided by Hhxsv5\LaravelS\LaravelS: $setting, $pid
Loading history...
introduced by
The trait Hhxsv5\LaravelS\Swoole\Traits\CustomProcessTrait requires some properties which are not provided by Hhxsv5\LaravelS\LaravelS: $setting, $pid
Loading history...
41
42
    /**@var array */
43
    protected $laravelConf;
44
45
    /**@var Laravel */
46
    protected $laravel;
47
48
    public function __construct(array $svrConf, array $laravelConf)
49
    {
50
        parent::__construct($svrConf);
51
        $this->laravelConf = $laravelConf;
52
53
        $timerCfg = isset($this->conf['timer']) ? $this->conf['timer'] : [];
54
        $timerCfg['process_prefix'] = $svrConf['process_prefix'];
55
        $this->swoole->timerProcess = $this->addTimerProcess($this->swoole, $timerCfg, $this->laravelConf);
0 ignored issues
show
Bug introduced by
The property timerProcess does not seem to exist on Swoole\Http\Server.
Loading history...
Bug introduced by
The property timerProcess does not seem to exist on Swoole\WebSocket\Server.
Loading history...
56
57
        $inotifyCfg = isset($this->conf['inotify_reload']) ? $this->conf['inotify_reload'] : [];
58
        if (!isset($inotifyCfg['watch_path'])) {
59
            $inotifyCfg['watch_path'] = $this->laravelConf['root_path'];
60
        }
61
        $inotifyCfg['process_prefix'] = $svrConf['process_prefix'];
62
        $this->swoole->inotifyProcess = $this->addInotifyProcess($this->swoole, $inotifyCfg, $this->laravelConf);
0 ignored issues
show
Bug introduced by
The property inotifyProcess does not seem to exist on Swoole\Http\Server.
Loading history...
Bug introduced by
The property inotifyProcess does not seem to exist on Swoole\WebSocket\Server.
Loading history...
63
64
        $processes = isset($this->conf['processes']) ? $this->conf['processes'] : [];
65
        $this->swoole->customProcesses = $this->addCustomProcesses($this->swoole, $svrConf['process_prefix'], $processes, $this->laravelConf);
0 ignored issues
show
Bug introduced by
The property customProcesses does not seem to exist on Swoole\Http\Server.
Loading history...
Bug introduced by
The property customProcesses does not seem to exist on Swoole\WebSocket\Server.
Loading history...
66
67
        // Fire ServerStart event
68
        if (isset($this->conf['event_handlers']['ServerStart'])) {
69
            Laravel::autoload($this->laravelConf['root_path']);
70
            $this->fireEvent('ServerStart', ServerStartInterface::class, [$this->swoole]);
71
        }
72
    }
73
74
    protected function bindWebSocketEvent()
75
    {
76
        parent::bindWebSocketEvent();
77
78
        if ($this->enableWebSocket) {
79
            $eventHandler = function ($method, array $params) {
80
                $this->callWithCatchException(function () use ($method, $params) {
81
                    call_user_func_array([$this->getWebSocketHandler(), $method], $params);
82
                });
83
            };
84
85
            $this->swoole->on('Open', function (WebSocketServer $server, SwooleRequest $request) use ($eventHandler) {
86
                // Start Laravel's lifetime, then support session ...middleware.
87
                $laravelRequest = $this->convertRequest($this->laravel, $request);
88
                $this->laravel->bindRequest($laravelRequest);
89
                $this->laravel->cleanProviders();
90
                $this->laravel->handleDynamic($laravelRequest);
91
                $eventHandler('onOpen', func_get_args());
92
                $this->laravel->saveSession();
93
                $this->laravel->clean();
94
            });
95
        }
96
    }
97
98
    public function onShutdown(HttpServer $server)
99
    {
100
        parent::onShutdown($server);
101
102
        // Fire ServerStop event
103
        if (isset($this->conf['event_handlers']['ServerStop'])) {
104
            Laravel::autoload($this->laravelConf['root_path']);
105
            $this->fireEvent('ServerStop', ServerStopInterface::class, [$server]);
106
        }
107
    }
108
109
    public function onWorkerStart(HttpServer $server, $workerId)
110
    {
111
        parent::onWorkerStart($server, $workerId);
112
113
        // To implement gracefully reload
114
        // Delay to create Laravel
115
        // Delay to include Laravel's autoload.php
116
        $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
117
118
        // Fire WorkerStart event
119
        $this->fireEvent('WorkerStart', WorkerStartInterface::class, func_get_args());
120
    }
121
122
    public function onWorkerStop(HttpServer $server, $workerId)
123
    {
124
        parent::onWorkerStop($server, $workerId);
125
126
        // Fire WorkerStop event
127
        $this->fireEvent('WorkerStop', WorkerStopInterface::class, func_get_args());
128
    }
129
130
    public function onWorkerError(HttpServer $server, $workerId, $workerPId, $exitCode, $signal)
131
    {
132
        parent::onWorkerError($server, $workerId, $workerPId, $exitCode, $signal);
133
134
        Laravel::autoload($this->laravelConf['root_path']);
135
136
        // Fire WorkerError event
137
        $this->fireEvent('WorkerError', WorkerErrorInterface::class, func_get_args());
138
    }
139
140
    protected function convertRequest(Laravel $laravel, SwooleRequest $request)
141
    {
142
        $rawGlobals = $laravel->getRawGlobals();
143
        $server = isset($rawGlobals['_SERVER']) ? $rawGlobals['_SERVER'] : [];
144
        $env = isset($rawGlobals['_ENV']) ? $rawGlobals['_ENV'] : [];
145
        return (new Request($request))->toIlluminateRequest($server, $env);
146
    }
147
148
    public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)
149
    {
150
        try {
151
            parent::onRequest($swooleRequest, $swooleResponse);
152
            $laravelRequest = $this->convertRequest($this->laravel, $swooleRequest);
153
            $this->laravel->bindRequest($laravelRequest);
154
            $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
155
            $success = $this->handleStaticResource($this->laravel, $laravelRequest, $swooleResponse);
156
            if ($success === false) {
157
                $this->handleDynamicResource($this->laravel, $laravelRequest, $swooleResponse);
158
            }
159
        } catch (\Exception $e) {
160
            $this->handleException($e, $swooleResponse);
161
        } catch (\Throwable $e) {
162
            $this->handleException($e, $swooleResponse);
163
        }
164
    }
165
166
    /**
167
     * @param \Exception|\Throwable $e
168
     * @param SwooleResponse $response
169
     */
170
    protected function handleException($e, SwooleResponse $response)
171
    {
172
        $error = sprintf(
173
            'onRequest: Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
174
            get_class($e),
175
            $e->getCode(),
176
            $e->getMessage(),
177
            $e->getFile(),
178
            $e->getLine(),
179
            PHP_EOL,
180
            $e->getTraceAsString()
181
        );
182
        $this->error($error);
183
        try {
184
            $response->status(500);
185
            $response->end('Oops! An unexpected error occurred: ' . $e->getMessage());
186
        } catch (\Exception $e) {
187
            $this->logException($e);
188
        }
189
    }
190
191
    protected function handleStaticResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
192
    {
193
        // For Swoole < 1.9.17
194
        if (!empty($this->conf['handle_static'])) {
195
            $laravelResponse = $laravel->handleStatic($laravelRequest);
196
            if ($laravelResponse !== false) {
197
                $laravelResponse->headers->set('Server', $this->conf['server'], true);
198
                $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
199
                (new StaticResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
200
                return true;
201
            }
202
        }
203
        return false;
204
    }
205
206
    protected function handleDynamicResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
207
    {
208
        $laravel->cleanProviders();
209
        $laravelResponse = $laravel->handleDynamic($laravelRequest);
210
        $laravelResponse->headers->set('Server', $this->conf['server'], true);
211
        $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
212
        if ($laravelResponse instanceof BinaryFileResponse) {
213
            $response = new StaticResponse($swooleResponse, $laravelResponse);
214
        } else {
215
            $response = new DynamicResponse($swooleResponse, $laravelResponse);
216
        }
217
        $response->send($this->conf['enable_gzip']);
218
        $laravel->clean();
219
        return true;
220
    }
221
222
    /**@var OutputStyle */
223
    protected static $outputStyle;
224
225
    public static function setOutputStyle(OutputStyle $outputStyle)
226
    {
227
        static::$outputStyle = $outputStyle;
228
    }
229
230
    public static function getOutputStyle()
231
    {
232
        return static::$outputStyle;
233
    }
234
}
235