Issues (1019)

src/LaravelS.php (1 issue)

1
<?php
2
3
namespace Hhxsv5\LaravelS;
4
5
use Hhxsv5\LaravelS\Illuminate\Laravel;
6
use Hhxsv5\LaravelS\Illuminate\LaravelTrait;
7
use Hhxsv5\LaravelS\Illuminate\LogTrait;
8
use Hhxsv5\LaravelS\Swoole\DynamicResponse;
9
use Hhxsv5\LaravelS\Swoole\Events\ServerStartInterface;
10
use Hhxsv5\LaravelS\Swoole\Events\ServerStopInterface;
11
use Hhxsv5\LaravelS\Swoole\Events\WorkerErrorInterface;
12
use Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface;
13
use Hhxsv5\LaravelS\Swoole\Events\WorkerStopInterface;
14
use Hhxsv5\LaravelS\Swoole\InotifyTrait;
15
use Hhxsv5\LaravelS\Swoole\Process\CustomProcessTrait;
16
use Hhxsv5\LaravelS\Swoole\Process\ProcessTitleTrait;
17
use Hhxsv5\LaravelS\Swoole\Request;
18
use Hhxsv5\LaravelS\Swoole\Server;
19
use Hhxsv5\LaravelS\Swoole\StaticResponse;
20
use Hhxsv5\LaravelS\Swoole\Timer\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\Server\Port;
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;
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
        $timerConf = isset($this->conf['timer']) ? $this->conf['timer'] : [];
54
        $timerConf['process_prefix'] = $svrConf['process_prefix'];
55
        $this->swoole->timerProcess = $this->addTimerProcess($this->swoole, $timerConf, $this->laravelConf);
56
57
        $inotifyConf = isset($this->conf['inotify_reload']) ? $this->conf['inotify_reload'] : [];
58
        if (!isset($inotifyConf['watch_path'])) {
59
            $inotifyConf['watch_path'] = $this->laravelConf['root_path'];
60
        }
61
        $inotifyConf['process_prefix'] = $svrConf['process_prefix'];
62
        $this->swoole->inotifyProcess = $this->addInotifyProcess($this->swoole, $inotifyConf, $this->laravelConf);
63
64
        $processes = isset($this->conf['processes']) ? $this->conf['processes'] : [];
65
        $this->swoole->customProcesses = $this->addCustomProcesses($this->swoole, $svrConf['process_prefix'], $processes, $this->laravelConf);
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 beforeWebSocketHandShake(SwooleRequest $request)
75
    {
76
        // Start Laravel's lifetime, then support session ...middleware.
77
        $laravelRequest = $this->convertRequest($this->laravel, $request);
78
        $this->laravel->bindRequest($laravelRequest);
79
        $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
80
        $this->laravel->cleanProviders();
81
        $laravelResponse = $this->laravel->handleDynamic($laravelRequest);
82
        $this->laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
83
    }
84
85
    protected function afterWebSocketOpen(SwooleRequest $request)
0 ignored issues
show
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

85
    protected function afterWebSocketOpen(/** @scrutinizer ignore-unused */ SwooleRequest $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
86
    {
87
        // End Laravel's lifetime.
88
        $this->laravel->saveSession();
89
        $this->laravel->clean();
90
    }
91
92
    protected function triggerWebSocketEvent($event, array $params)
93
    {
94
        if ($event === 'onHandShake') {
95
            $this->beforeWebSocketHandShake($params[0]);
96
            if (!empty($this->conf['server'])) {
97
                $params[1]->header('Server', $this->conf['server']);
98
            }
99
        }
100
101
        parent::triggerWebSocketEvent($event, $params);
102
103
        switch ($event) {
104
            case 'onHandShake':
105
                if (isset($params[1]->header['Sec-Websocket-Accept'])) {
106
                    // Successful handshake
107
                    parent::triggerWebSocketEvent('onOpen', [$this->swoole, $params[0]]);
108
                }
109
                $this->afterWebSocketOpen($params[0]);
110
                break;
111
            case 'onOpen':
112
                $this->afterWebSocketOpen($params[1]);
113
                break;
114
        }
115
    }
116
117
    protected function triggerPortEvent(Port $port, $handlerClass, $event, array $params)
118
    {
119
        switch ($event) {
120
            case 'onHandShake':
121
                $this->beforeWebSocketHandShake($params[0]);
122
            case 'onRequest':
123
                if (!empty($this->conf['server'])) {
124
                    $params[1]->header('Server', $this->conf['server']);
125
                }
126
                break;
127
        }
128
129
        parent::triggerPortEvent($port, $handlerClass, $event, $params);
130
131
        switch ($event) {
132
            case 'onHandShake':
133
                if (isset($params[1]->header['Sec-Websocket-Accept'])) {
134
                    // Successful handshake
135
                    parent::triggerPortEvent($port, $handlerClass, 'onOpen', [$this->swoole, $params[0]]);
136
                }
137
                $this->afterWebSocketOpen($params[0]);
138
                break;
139
            case 'onOpen':
140
                $this->afterWebSocketOpen($params[1]);
141
                break;
142
        }
143
    }
144
145
    public function onShutdown(HttpServer $server)
146
    {
147
        parent::onShutdown($server);
148
149
        // Fire ServerStop event
150
        if (isset($this->conf['event_handlers']['ServerStop'])) {
151
            $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
152
            $this->fireEvent('ServerStop', ServerStopInterface::class, [$server]);
153
        }
154
    }
155
156
    public function onWorkerStart(HttpServer $server, $workerId)
157
    {
158
        parent::onWorkerStart($server, $workerId);
159
160
        // To implement gracefully reload
161
        // Delay to create Laravel
162
        // Delay to include Laravel's autoload.php
163
        $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
164
165
        // Fire WorkerStart event
166
        $this->fireEvent('WorkerStart', WorkerStartInterface::class, func_get_args());
167
    }
168
169
    public function onWorkerStop(HttpServer $server, $workerId)
170
    {
171
        parent::onWorkerStop($server, $workerId);
172
173
        // Fire WorkerStop event
174
        $this->fireEvent('WorkerStop', WorkerStopInterface::class, func_get_args());
175
    }
176
177
    public function onWorkerError(HttpServer $server, $workerId, $workerPId, $exitCode, $signal)
178
    {
179
        parent::onWorkerError($server, $workerId, $workerPId, $exitCode, $signal);
180
181
        Laravel::autoload($this->laravelConf['root_path']);
182
183
        // Fire WorkerError event
184
        $this->fireEvent('WorkerError', WorkerErrorInterface::class, func_get_args());
185
    }
186
187
    protected function convertRequest(Laravel $laravel, SwooleRequest $request)
188
    {
189
        $rawGlobals = $laravel->getRawGlobals();
190
        return (new Request($request))->toIlluminateRequest($rawGlobals['_SERVER'], $rawGlobals['_ENV']);
191
    }
192
193
    public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)
194
    {
195
        try {
196
            $laravelRequest = $this->convertRequest($this->laravel, $swooleRequest);
197
            $this->laravel->bindRequest($laravelRequest);
198
            $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
199
            $handleStaticSuccess = false;
200
            if ($this->conf['handle_static']) {
201
                // For Swoole < 1.9.17
202
                $handleStaticSuccess = $this->handleStaticResource($this->laravel, $laravelRequest, $swooleResponse);
203
            }
204
            if (!$handleStaticSuccess) {
205
                $this->handleDynamicResource($this->laravel, $laravelRequest, $swooleResponse);
206
            }
207
        } catch (\Exception $e) {
208
            $this->handleException($e, $swooleResponse);
209
        }
210
    }
211
212
    /**
213
     * @param \Exception $e
214
     * @param SwooleResponse $response
215
     */
216
    protected function handleException($e, SwooleResponse $response)
217
    {
218
        $error = sprintf(
219
            'onRequest: Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
220
            get_class($e),
221
            $e->getCode(),
222
            $e->getMessage(),
223
            $e->getFile(),
224
            $e->getLine(),
225
            PHP_EOL,
226
            $e->getTraceAsString()
227
        );
228
        $this->error($error);
229
        try {
230
            $response->status(500);
231
            $response->end('Oops! An unexpected error occurred');
232
        } catch (\Exception $e) {
233
            $this->logException($e);
234
        }
235
    }
236
237
    protected function handleStaticResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
238
    {
239
        $laravelResponse = $laravel->handleStatic($laravelRequest);
240
        if ($laravelResponse === false) {
241
            return false;
242
        }
243
        if (!empty($this->conf['server'])) {
244
            $laravelResponse->headers->set('Server', $this->conf['server'], true);
245
        }
246
        $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
247
        $response = new StaticResponse($swooleResponse, $laravelResponse);
248
        $response->setChunkLimit($this->conf['swoole']['buffer_output_size']);
249
        $response->send($this->conf['enable_gzip']);
250
        return true;
251
    }
252
253
    protected function handleDynamicResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
254
    {
255
        $laravel->cleanProviders();
256
        $laravelResponse = $laravel->handleDynamic($laravelRequest);
257
        if (!empty($this->conf['server'])) {
258
            $laravelResponse->headers->set('Server', $this->conf['server'], true);
259
        }
260
        $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
261
        if ($laravelResponse instanceof BinaryFileResponse) {
262
            $response = new StaticResponse($swooleResponse, $laravelResponse);
263
        } else {
264
            $response = new DynamicResponse($swooleResponse, $laravelResponse);
265
        }
266
        $response->setChunkLimit($this->conf['swoole']['buffer_output_size']);
267
        $response->send($this->conf['enable_gzip']);
268
        $laravel->clean();
269
        return true;
270
    }
271
272
    /**@var OutputStyle */
273
    protected static $outputStyle;
274
275
    public static function setOutputStyle(OutputStyle $outputStyle)
276
    {
277
        static::$outputStyle = $outputStyle;
278
    }
279
280
    public static function getOutputStyle()
281
    {
282
        return static::$outputStyle;
283
    }
284
}
285