Passed
Push — master ( 9ac57c...18281d )
by Biao
03:34
created

LaravelS::setOutputStyle()   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 1
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\Coroutine\Context;
7
use Hhxsv5\LaravelS\Swoole\DynamicResponse;
8
use Hhxsv5\LaravelS\Swoole\Request;
9
use Hhxsv5\LaravelS\Swoole\Server;
10
use Hhxsv5\LaravelS\Swoole\StaticResponse;
11
use Hhxsv5\LaravelS\Swoole\Traits\CustomProcessTrait;
12
use Hhxsv5\LaravelS\Swoole\Traits\InotifyTrait;
13
use Hhxsv5\LaravelS\Swoole\Traits\LaravelTrait;
14
use Hhxsv5\LaravelS\Swoole\Traits\LogTrait;
15
use Hhxsv5\LaravelS\Swoole\Traits\ProcessTitleTrait;
16
use Hhxsv5\LaravelS\Swoole\Traits\TimerTrait;
17
use Illuminate\Http\Request as IlluminateRequest;
18
use Symfony\Component\Console\Style\OutputStyle;
19
use Symfony\Component\HttpFoundation\BinaryFileResponse;
20
21
22
/**
23
 * Swoole Request => Laravel Request
24
 * Laravel Request => Laravel handle => Laravel Response
25
 * Laravel Response => Swoole Response
26
 */
27
class LaravelS extends Server
28
{
29
    /**
30
     * Fix conflicts of traits
31
     */
32
    use InotifyTrait, LaravelTrait, LogTrait, ProcessTitleTrait, TimerTrait, CustomProcessTrait {
33
        LogTrait::log insteadof InotifyTrait, TimerTrait, CustomProcessTrait;
34
        LogTrait::logException insteadof InotifyTrait, TimerTrait, CustomProcessTrait;
35
        LogTrait::callWithCatchException insteadof InotifyTrait, TimerTrait, CustomProcessTrait;
36
        ProcessTitleTrait::setProcessTitle insteadof InotifyTrait, TimerTrait, CustomProcessTrait;
37
        LaravelTrait::initLaravel insteadof TimerTrait, CustomProcessTrait;
38
    }
39
40
    protected $laravelConf;
41
42
    /**
43
     * @var Laravel $laravel
44
     */
45
    protected $laravel;
46
47
    /**
48
     * @var OutputStyle $outputStyle
49
     */
50
    protected $outputStyle;
51
52
    public function __construct(array $svrConf, array $laravelConf)
53
    {
54
        parent::__construct($svrConf);
55
        $this->laravelConf = $laravelConf;
56
57
        $timerCfg = isset($this->conf['timer']) ? $this->conf['timer'] : [];
58
        $timerCfg['process_prefix'] = $svrConf['process_prefix'];
59
        $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...
60
61
        $inotifyCfg = isset($this->conf['inotify_reload']) ? $this->conf['inotify_reload'] : [];
62
        if (!isset($inotifyCfg['watch_path'])) {
63
            $inotifyCfg['watch_path'] = $this->laravelConf['root_path'];
64
        }
65
        $inotifyCfg['process_prefix'] = $svrConf['process_prefix'];
66
        $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_websocket_server.
Loading history...
Bug introduced by
The property inotifyProcess does not seem to exist on swoole_http_server.
Loading history...
67
68
        $processes = isset($this->conf['processes']) ? $this->conf['processes'] : [];
69
        $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...
70
    }
71
72
    public function setOutputStyle(OutputStyle $outputStyle)
73
    {
74
        $this->outputStyle = $outputStyle;
75
    }
76
77
    protected function bindWebSocketEvent()
78
    {
79
        parent::bindWebSocketEvent();
80
81
        if ($this->enableWebSocket) {
82
            $eventHandler = function ($method, array $params) {
83
                $this->callWithCatchException(function () use ($method, $params) {
84
                    call_user_func_array([$this->getWebSocketHandler(), $method], $params);
85
                });
86
            };
87
88
            $this->swoole->on('Open', function (\swoole_websocket_server $server, \swoole_http_request $request) use ($eventHandler) {
89
                // Start Laravel's lifetime, then support session ...middleware.
90
                $this->laravel->resetSession();
91
                $laravelRequest = $this->convertRequest($this->laravel, $request);
92
                $this->laravel->bindRequest($laravelRequest);
93
                $this->laravel->handleDynamic($laravelRequest);
94
                $eventHandler('onOpen', func_get_args());
95
                $this->laravel->saveSession();
96
            });
97
        }
98
    }
99
100
    public function onWorkerStart(\swoole_http_server $server, $workerId)
101
    {
102
        parent::onWorkerStart($server, $workerId);
103
104
        // To implement gracefully reload
105
        // Delay to create Laravel
106
        // Delay to include Laravel's autoload.php
107
        $this->laravel = $this->initLaravel($this->laravelConf, $this->swoole);
108
    }
109
110
    protected function convertRequest(Laravel $laravel, \swoole_http_request $request)
111
    {
112
        $rawGlobals = $laravel->getRawGlobals();
113
        $server = isset($rawGlobals['_SERVER']) ? $rawGlobals['_SERVER'] : [];
114
        $env = isset($rawGlobals['_ENV']) ? $rawGlobals['_ENV'] : [];
115
        return (new Request($request))->toIlluminateRequest($server, $env);
116
    }
117
118
    public function onRequest(\swoole_http_request $request, \swoole_http_response $response)
119
    {
120
        parent::onRequest($request, $response);
121
        try {
122
            $laravelRequest = $this->convertRequest($this->laravel, $request);
123
            $this->laravel->bindRequest($laravelRequest);
124
            $this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);
125
            $success = $this->handleStaticResource($this->laravel, $laravelRequest, $response);
126
            if ($success === false) {
127
                $this->handleDynamicResource($this->laravel, $laravelRequest, $response);
128
            }
129
        } catch (\Exception $e) {
130
            $this->handleException($e, $response);
131
        } catch (\Throwable $e) {
132
            $this->handleException($e, $response);
133
        }
134
    }
135
136
    /**
137
     * @param \Exception|\Throwable $e
138
     * @param \swoole_http_response $response
139
     */
140
    protected function handleException($e, \swoole_http_response $response)
141
    {
142
        $error = sprintf('onRequest: Uncaught exception "%s"([%d]%s) at %s:%s, %s%s', get_class($e), $e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine(), PHP_EOL, $e->getTraceAsString());
143
        $this->log($error, 'ERROR');
144
        try {
145
            $response->status(500);
146
            $response->end('Oops! An unexpected error occurred: ' . $e->getMessage());
147
        } catch (\Exception $e) {
148
            // Catch: zm_deactivate_swoole: Fatal error: Uncaught exception 'ErrorException' with message 'swoole_http_response::status(): http client#2 is not exist.
149
        }
150
    }
151
152
    protected function handleStaticResource(Laravel $laravel, IlluminateRequest $laravelRequest, \swoole_http_response $swooleResponse)
153
    {
154
        // For Swoole < 1.9.17
155
        if (!empty($this->conf['handle_static'])) {
156
            $laravelResponse = $laravel->handleStatic($laravelRequest);
157
            if ($laravelResponse !== false) {
158
                $laravelResponse->headers->set('Server', $this->conf['server'], true);
159
                $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
160
                (new StaticResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
161
                return true;
162
            }
163
        }
164
        return false;
165
    }
166
167
    protected function handleDynamicResource(Laravel $laravel, IlluminateRequest $laravelRequest, \swoole_http_response $swooleResponse)
168
    {
169
        $laravelResponse = $laravel->handleDynamic($laravelRequest);
170
        $laravelResponse->headers->set('Server', $this->conf['server'], true);
171
        $laravel->fireEvent('laravels.generated_response', [$laravelRequest, $laravelResponse]);
172
        $laravel->cleanRequest($laravelRequest);
173
        if ($laravelResponse instanceof BinaryFileResponse) {
174
            (new StaticResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
175
        } else {
176
            (new DynamicResponse($swooleResponse, $laravelResponse))->send($this->conf['enable_gzip']);
177
        }
178
        return true;
179
    }
180
}
181