Completed
Push — master ( e64ecf...0cc421 )
by Biao
09:35
created

LaravelS::onShutdown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 8
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\ServerStopInterface;
8
use Hhxsv5\LaravelS\Swoole\Events\MasterStartInterface;
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
68
    protected function bindWebSocketEvent()
69
    {
70
        parent::bindWebSocketEvent();
71
72
        if ($this->enableWebSocket) {
73
            $eventHandler = function ($method, array $params) {
74
                $this->callWithCatchException(function () use ($method, $params) {
75
                    call_user_func_array([$this->getWebSocketHandler(), $method], $params);
76
                });
77
            };
78
79
            $this->swoole->on('Open', function (WebSocketServer $server, SwooleRequest $request) use ($eventHandler) {
80
                // Start Laravel's lifetime, then support session ...middleware.
81
                $laravelRequest = $this->convertRequest($this->laravel, $request);
82
                $this->laravel->bindRequest($laravelRequest);
83
                $this->laravel->cleanProviders();
84
                $this->laravel->handleDynamic($laravelRequest);
85
                $eventHandler('onOpen', func_get_args());
86
                $this->laravel->saveSession();
87
                $this->laravel->clean();
88
            });
89
        }
90
    }
91
92
    public function onStart(HttpServer $server)
93
    {
94
        // Fire MasterStart event
95
        if (isset($this->conf['event_handlers']['MasterStart'])) {
96
            Laravel::autoload($this->laravelConf['root_path']);
97
            $this->fireEvent('MasterStart', MasterStartInterface::class, [$server]);
98
        }
99
100
        parent::onStart($server);
101
    }
102
103
    public function onShutdown(HttpServer $server)
104
    {
105
        parent::onShutdown($server);
106
107
        // Fire ServerStop event
108
        if (isset($this->conf['event_handlers']['ServerStop'])) {
109
            Laravel::autoload($this->laravelConf['root_path']);
110
            $this->fireEvent('ServerStop', ServerStopInterface::class, [$server]);
111
        }
112
    }
113
114
    public function onWorkerStart(HttpServer $server, $workerId)
115
    {
116
        parent::onWorkerStart($server, $workerId);
117
118
        // To implement gracefully reload
119
        // Delay to create Laravel
120
        // Delay to include Laravel's autoload.php
121
        $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
122
123
        // Fire WorkerStart event
124
        $this->fireEvent('WorkerStart', WorkerStartInterface::class, func_get_args());
125
    }
126
127
    public function onWorkerStop(HttpServer $server, $workerId)
128
    {
129
        parent::onWorkerStop($server, $workerId);
130
131
        // Fire WorkerStop event
132
        $this->fireEvent('WorkerStop', WorkerStopInterface::class, func_get_args());
133
    }
134
135
    public function onWorkerError(HttpServer $server, $workerId, $workerPId, $exitCode, $signal)
136
    {
137
        parent::onWorkerError($server, $workerId, $workerPId, $exitCode, $signal);
138
139
        Laravel::autoload($this->laravelConf['root_path']);
140
141
        // Fire WorkerError event
142
        $this->fireEvent('WorkerError', WorkerErrorInterface::class, func_get_args());
143
    }
144
145
    protected function convertRequest(Laravel $laravel, SwooleRequest $request)
146
    {
147
        $rawGlobals = $laravel->getRawGlobals();
148
        $server = isset($rawGlobals['_SERVER']) ? $rawGlobals['_SERVER'] : [];
149
        $env = isset($rawGlobals['_ENV']) ? $rawGlobals['_ENV'] : [];
150
        return (new Request($request))->toIlluminateRequest($server, $env);
151
    }
152
153
    public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)
154
    {
155
        try {
156
            parent::onRequest($swooleRequest, $swooleResponse);
157
            $laravelRequest = $this->convertRequest($this->laravel, $swooleRequest);
158
            $this->laravel->bindRequest($laravelRequest);
159
            $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
160
            $success = $this->handleStaticResource($this->laravel, $laravelRequest, $swooleResponse);
161
            if ($success === false) {
162
                $this->handleDynamicResource($this->laravel, $laravelRequest, $swooleResponse);
163
            }
164
        } catch (\Exception $e) {
165
            $this->handleException($e, $swooleResponse);
166
        } catch (\Throwable $e) {
167
            $this->handleException($e, $swooleResponse);
168
        }
169
    }
170
171
    /**
172
     * @param \Exception|\Throwable $e
173
     * @param SwooleResponse $response
174
     */
175
    protected function handleException($e, SwooleResponse $response)
176
    {
177
        $error = sprintf(
178
            'onRequest: Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
179
            get_class($e),
180
            $e->getCode(),
181
            $e->getMessage(),
182
            $e->getFile(),
183
            $e->getLine(),
184
            PHP_EOL,
185
            $e->getTraceAsString()
186
        );
187
        $this->error($error);
188
        try {
189
            $response->status(500);
190
            $response->end('Oops! An unexpected error occurred: ' . $e->getMessage());
191
        } catch (\Exception $e) {
192
            $this->logException($e);
193
        }
194
    }
195
196
    protected function handleStaticResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
197
    {
198
        // For Swoole < 1.9.17
199
        if (!empty($this->conf['handle_static'])) {
200
            $laravelResponse = $laravel->handleStatic($laravelRequest);
201
            if ($laravelResponse !== false) {
202
                $laravelResponse->headers->set('Server', $this->conf['server'], true);
203
                $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
204
                (new StaticResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
205
                return true;
206
            }
207
        }
208
        return false;
209
    }
210
211
    protected function handleDynamicResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
212
    {
213
        $laravel->cleanProviders();
214
        $laravelResponse = $laravel->handleDynamic($laravelRequest);
215
        $laravelResponse->headers->set('Server', $this->conf['server'], true);
216
        $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
217
        if ($laravelResponse instanceof BinaryFileResponse) {
218
            $response = new StaticResponse($swooleResponse, $laravelResponse);
219
        } else {
220
            $response = new DynamicResponse($swooleResponse, $laravelResponse);
221
        }
222
        $response->send($this->conf['enable_gzip']);
223
        $laravel->clean();
224
        return true;
225
    }
226
227
    /**@var OutputStyle */
228
    protected static $outputStyle;
229
230
    public static function setOutputStyle(OutputStyle $outputStyle)
231
    {
232
        static::$outputStyle = $outputStyle;
233
    }
234
235
    public static function getOutputStyle()
236
    {
237
        return static::$outputStyle;
238
    }
239
}
240