Completed
Push — master ( b57b98...bd0757 )
by Biao
04:00
created

LaravelS   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 96
dl 0
loc 186
rs 10
c 0
b 0
f 0
wmc 26

12 Methods

Rating   Name   Duplication   Size   Complexity  
A onWorkerStart() 0 11 1
A __construct() 0 18 5
A bindWebSocketEvent() 0 19 2
A handleStaticResource() 0 13 3
A handleException() 0 18 2
A onRequest() 0 15 4
A onWorkerStop() 0 6 1
A onWorkerError() 0 6 1
A convertRequest() 0 6 3
A handleDynamicResource() 0 13 2
A getOutputStyle() 0 3 1
A setOutputStyle() 0 3 1
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
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...
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
        if ($laravelResponse instanceof BinaryFileResponse) {
199
            $response = new StaticResponse($swooleResponse, $laravelResponse);
200
        } else {
201
            $response = new DynamicResponse($swooleResponse, $laravelResponse);
202
        }
203
        $response->send($this->conf['enable_gzip']);
204
        $laravel->clean();
205
        return true;
206
    }
207
208
    /**@var OutputStyle */
209
    protected static $outputStyle;
210
211
    public static function setOutputStyle(OutputStyle $outputStyle)
212
    {
213
        static::$outputStyle = $outputStyle;
214
    }
215
216
    public static function getOutputStyle()
217
    {
218
        return static::$outputStyle;
219
    }
220
}
221