Completed
Push — master ( 50b448...b57b98 )
by Biao
03:45
created

LaravelS::getOutputStyle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
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...
introduced by
The trait Hhxsv5\LaravelS\Swoole\Traits\TimerTrait 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
        $this->swoole->customProcessPids = [];
0 ignored issues
show
Bug introduced by
The property customProcessPids does not seem to exist on Swoole\WebSocket\Server.
Loading history...
Bug introduced by
The property customProcessPids does not seem to exist on Swoole\Http\Server.
Loading history...
74
    }
75
76
    protected function bindWebSocketEvent()
77
    {
78
        parent::bindWebSocketEvent();
79
80
        if ($this->enableWebSocket) {
81
            $eventHandler = function ($method, array $params) {
82
                $this->callWithCatchException(function () use ($method, $params) {
83
                    call_user_func_array([$this->getWebSocketHandler(), $method], $params);
84
                });
85
            };
86
87
            $this->swoole->on('Open', function (WebSocketServer $server, SwooleRequest $request) use ($eventHandler) {
88
                // Start Laravel's lifetime, then support session ...middleware.
89
                $laravelRequest = $this->convertRequest($this->laravel, $request);
90
                $this->laravel->bindRequest($laravelRequest);
91
                $this->laravel->handleDynamic($laravelRequest);
92
                $eventHandler('onOpen', func_get_args());
93
                $this->laravel->saveSession();
94
                $this->laravel->clean();
95
            });
96
        }
97
    }
98
99
    public function onWorkerStart(HttpServer $server, $workerId)
100
    {
101
        parent::onWorkerStart($server, $workerId);
102
103
        // To implement gracefully reload
104
        // Delay to create Laravel
105
        // Delay to include Laravel's autoload.php
106
        $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
107
108
        // Fire WorkerStart event
109
        $this->fireEvent('WorkerStart', WorkerStartInterface::class, func_get_args());
110
    }
111
112
    public function onWorkerStop(HttpServer $server, $workerId)
113
    {
114
        parent::onWorkerStop($server, $workerId);
115
116
        // Fire WorkerStop event
117
        $this->fireEvent('WorkerStop', WorkerStopInterface::class, func_get_args());
118
    }
119
120
    public function onWorkerError(HttpServer $server, $workerId, $workerPId, $exitCode, $signal)
121
    {
122
        parent::onWorkerError($server, $workerId, $workerPId, $exitCode, $signal);
123
124
        // Fire WorkerError event
125
        $this->fireEvent('WorkerError', WorkerErrorInterface::class, func_get_args());
126
    }
127
128
    public function onPipeMessage(HttpServer $server, $srcWorkerId, $message)
129
    {
130
        // Save the PID file of the custom processes
131
        if (isset($message['custom_process_pid'])) {
132
            $server->customProcessPids[] = $message['custom_process_pid'];
0 ignored issues
show
Bug introduced by
The property customProcessPids does not seem to exist on Swoole\Http\Server.
Loading history...
133
            $processCount = count($server->customProcesses);
0 ignored issues
show
Bug introduced by
The property customProcesses does not seem to exist on Swoole\Http\Server.
Loading history...
134
            $pidCount = count($server->customProcessPids);
135
            if ($pidCount !== $processCount) {
136
                return;
137
            }
138
            $pidfile = dirname($server->setting['pid_file']) . '/laravels-custom-processes.pid';
139
            file_put_contents($pidfile, implode(',', $server->customProcessPids));
140
            return;
141
        }
142
143
        parent::onPipeMessage($server, $srcWorkerId, $message);
144
    }
145
146
    protected function convertRequest(Laravel $laravel, SwooleRequest $request)
147
    {
148
        $rawGlobals = $laravel->getRawGlobals();
149
        $server = isset($rawGlobals['_SERVER']) ? $rawGlobals['_SERVER'] : [];
150
        $env = isset($rawGlobals['_ENV']) ? $rawGlobals['_ENV'] : [];
151
        return (new Request($request))->toIlluminateRequest($server, $env);
152
    }
153
154
    public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)
155
    {
156
        try {
157
            parent::onRequest($swooleRequest, $swooleResponse);
158
            $laravelRequest = $this->convertRequest($this->laravel, $swooleRequest);
159
            $this->laravel->bindRequest($laravelRequest);
160
            $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
161
            $success = $this->handleStaticResource($this->laravel, $laravelRequest, $swooleResponse);
162
            if ($success === false) {
163
                $this->handleDynamicResource($this->laravel, $laravelRequest, $swooleResponse);
164
            }
165
        } catch (\Exception $e) {
166
            $this->handleException($e, $swooleResponse);
167
        } catch (\Throwable $e) {
168
            $this->handleException($e, $swooleResponse);
169
        }
170
    }
171
172
    /**
173
     * @param \Exception|\Throwable $e
174
     * @param SwooleResponse $response
175
     */
176
    protected function handleException($e, SwooleResponse $response)
177
    {
178
        $error = sprintf(
179
            'onRequest: Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
180
            get_class($e),
181
            $e->getCode(),
182
            $e->getMessage(),
183
            $e->getFile(),
184
            $e->getLine(),
185
            PHP_EOL,
186
            $e->getTraceAsString()
187
        );
188
        $this->error($error);
189
        try {
190
            $response->status(500);
191
            $response->end('Oops! An unexpected error occurred: ' . $e->getMessage());
192
        } catch (\Exception $e) {
193
            $this->logException($e);
194
        }
195
    }
196
197
    protected function handleStaticResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
198
    {
199
        // For Swoole < 1.9.17
200
        if (!empty($this->conf['handle_static'])) {
201
            $laravelResponse = $laravel->handleStatic($laravelRequest);
202
            if ($laravelResponse !== false) {
203
                $laravelResponse->headers->set('Server', $this->conf['server'], true);
204
                $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
205
                (new StaticResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
206
                return true;
207
            }
208
        }
209
        return false;
210
    }
211
212
    protected function handleDynamicResource(Laravel $laravel, IlluminateRequest $laravelRequest, SwooleResponse $swooleResponse)
213
    {
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