1 | <?php |
||||||
2 | /** |
||||||
3 | * HTTP by stream-sock server |
||||||
4 | * User: moyo |
||||||
5 | * Date: 08/01/2018 |
||||||
6 | * Time: 2:26 PM |
||||||
7 | */ |
||||||
8 | |||||||
9 | namespace Carno\HTTP\Powered\Native; |
||||||
10 | |||||||
11 | use Carno\HTTP\Exception\NVServerCreatingException; |
||||||
12 | use Carno\HTTP\Powered\Native\Parser\Requesting; |
||||||
13 | use Carno\HTTP\Powered\Native\Parser\Responding; |
||||||
14 | use Carno\HTTP\Powered\Native\Parser\Protocol; |
||||||
15 | use Carno\HTTP\Server\Connection as HTTPConn; |
||||||
16 | use Carno\Net\Address; |
||||||
17 | use Carno\Net\Connection as NETConn; |
||||||
18 | use Carno\Net\Contracts\HTTP; |
||||||
19 | use Carno\Net\Events; |
||||||
20 | use Psr\Http\Message\ResponseInterface as Response; |
||||||
21 | use Throwable; |
||||||
22 | |||||||
23 | class Server implements HTTP |
||||||
24 | { |
||||||
25 | /** |
||||||
26 | * @var string |
||||||
27 | */ |
||||||
28 | private $serviced = null; |
||||||
29 | |||||||
30 | /** |
||||||
31 | * @var resource |
||||||
32 | */ |
||||||
33 | private $listener = null; |
||||||
34 | |||||||
35 | /** |
||||||
36 | * @var Events |
||||||
37 | */ |
||||||
38 | private $events = null; |
||||||
39 | |||||||
40 | /** |
||||||
41 | * @var int |
||||||
42 | */ |
||||||
43 | private $idx = 0; |
||||||
44 | |||||||
45 | /** |
||||||
46 | * @var resource[] |
||||||
47 | */ |
||||||
48 | private $fds = []; |
||||||
49 | |||||||
50 | /** |
||||||
51 | * Server constructor. |
||||||
52 | * @param string $serviced |
||||||
53 | * @param Address $listen |
||||||
54 | * @param Events $events |
||||||
55 | */ |
||||||
56 | public function __construct(string $serviced, Address $listen, Events $events) |
||||||
57 | { |
||||||
58 | $this->serviced = $serviced; |
||||||
59 | $this->events = $events; |
||||||
60 | |||||||
61 | $err = $msg = null; |
||||||
62 | |||||||
63 | if (false === |
||||||
64 | $this->listener = stream_socket_server( |
||||||
65 | sprintf('tcp://%s:%d', $listen->host(), $listen->port()), |
||||||
66 | $err, |
||||||
67 | $msg |
||||||
68 | ) |
||||||
69 | ) { |
||||||
70 | throw new NVServerCreatingException($msg, $err); |
||||||
71 | } |
||||||
72 | |||||||
73 | $this->events->notify( |
||||||
74 | Events\Server::STARTUP, |
||||||
75 | (new NETConn) |
||||||
76 | ->setServiced($this->serviced) |
||||||
77 | ->setLocal($listen->host(), $listen->port()) |
||||||
78 | ); |
||||||
79 | } |
||||||
80 | |||||||
81 | /** |
||||||
82 | * startup http server |
||||||
83 | */ |
||||||
84 | public function serve() : void |
||||||
85 | { |
||||||
86 | swoole_event_add($this->listener, function ($server) { |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
87 | $this->incoming($server); |
||||||
88 | }); |
||||||
89 | } |
||||||
90 | |||||||
91 | /** |
||||||
92 | * shutdown http server |
||||||
93 | */ |
||||||
94 | public function shutdown() : void |
||||||
95 | { |
||||||
96 | swoole_event_del($this->listener); |
||||||
0 ignored issues
–
show
The function
swoole_event_del was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
97 | stream_socket_shutdown($this->listener, STREAM_SHUT_RDWR); |
||||||
98 | } |
||||||
99 | |||||||
100 | /** |
||||||
101 | * @param int $conn |
||||||
102 | * @param Response $response |
||||||
103 | * @return bool |
||||||
104 | */ |
||||||
105 | public function reply(int $conn, Response $response) : bool |
||||||
106 | { |
||||||
107 | (new Responding(new Protocol($this->fds[$conn] ?? null)))->makeResponse($response); |
||||||
108 | |||||||
109 | if ($response->getHeaderLine('Connection') === 'close') { |
||||||
110 | $this->close($conn); |
||||||
111 | } |
||||||
112 | |||||||
113 | return true; |
||||||
114 | } |
||||||
115 | |||||||
116 | /** |
||||||
117 | * @param int $conn |
||||||
118 | * @return bool |
||||||
119 | */ |
||||||
120 | public function close(int $conn) : bool |
||||||
121 | { |
||||||
122 | if ($fd = $this->fds[$conn] ?? null) { |
||||||
123 | unset($this->fds[$conn]); |
||||||
124 | swoole_event_del($fd); |
||||||
0 ignored issues
–
show
The function
swoole_event_del was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
125 | return fclose($fd); |
||||||
126 | } else { |
||||||
127 | return false; |
||||||
128 | } |
||||||
129 | } |
||||||
130 | |||||||
131 | /** |
||||||
132 | * @param $server |
||||||
133 | */ |
||||||
134 | private function incoming($server) : void |
||||||
135 | { |
||||||
136 | $idx = $this->idx += 1; |
||||||
137 | swoole_event_add($this->fds[$idx] = stream_socket_accept($server), function () use ($idx) { |
||||||
0 ignored issues
–
show
The function
swoole_event_add was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
138 | $this->receiving($idx); |
||||||
139 | }); |
||||||
140 | } |
||||||
141 | |||||||
142 | /** |
||||||
143 | * @param int $idx |
||||||
144 | */ |
||||||
145 | private function receiving(int $idx) : void |
||||||
146 | { |
||||||
147 | try { |
||||||
148 | $srq = (new Requesting(new Protocol($this->fds[$idx] ?? null)))->getServerRequest(); |
||||||
149 | $this->events->notify( |
||||||
150 | Events\HTTP::REQUESTING, |
||||||
151 | (new HTTPConn) |
||||||
152 | ->setID($idx) |
||||||
153 | ->setRequest($srq) |
||||||
154 | ->setServiced($this->serviced) |
||||||
155 | ->from($this) |
||||||
156 | ); |
||||||
157 | } catch (Throwable $e) { |
||||||
158 | $this->close($idx); |
||||||
159 | } |
||||||
160 | } |
||||||
161 | } |
||||||
162 |