Completed
Push — master ( cb357b...f21b76 )
by Biao
03:49
created

LaravelS::convertRequest()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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