header['sec-websocket-key']; $patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#'; if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) { throw new Exception('protocol error.', 500); } $key = base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', TRUE)); $headers = [ 'Upgrade' => 'websocket', 'Connection' => 'Upgrade', 'Sec-websocket-Accept' => $key, 'Sec-websocket-Version' => '13', ]; if (isset($request->header['sec-websocket-protocol'])) { $headers['Sec-websocket-Protocol'] = $request->header['sec-websocket-protocol']; } foreach ($headers as $key => $val) { $response->header($key, $val); } } /** * @param SResponse $response * @param int $code * @return false */ private function disconnect(SResponse $response, $code = 500): bool { $server = Snowflake::getWebSocket(); if (!$server->exist($response->fd)) { return false; } $response->status($code); $response->end(); return false; } /** * @param $response * @param int $code * @return false */ private function connect($response, $code = 101): bool { $response->status($code); $response->end(); return false; } /** * @param SRequest $request * @param SResponse $response * @return void * @throws Exception */ public function onHandler(SRequest $request, SResponse $response): void { try { defer(fn() => fire(Event::SYSTEM_RESOURCE_RELEASES)); $this->execute($request, $response); } catch (\Throwable $exception) { $this->addError($exception, 'throwable'); $response->status(500); $response->end($exception->getMessage()); } } /** * @param SRequest $request * @param SResponse $response * @return mixed * @throws Exception */ private function execute(SRequest $request, SResponse $response): mixed { $this->resolveParse($request, $response); $router = Snowflake::app()->getRouter(); [$sRequest, $sResponse] = $this->sRequest($request, $response); if (($node = $router->find_path($sRequest)) !== null) { return $node->dispatch($sRequest, $sResponse); } return $this->disconnect($response, 404); } /** * @param $request * @param SResponse $response * @return array * @throws NotFindClassException * @throws ReflectionException */ private function sRequest($request, SResponse $response): array { /** @var Request $sRequest */ $sRequest = Request::create($request); $sRequest->uri = '/' . Socket::HANDSHAKE . '::event'; $sRequest->headers = new HttpHeaders(ArrayAccess::merge($request->server, $request->header)); $sRequest->headers->replace('request_method', 'sw::socket'); $sRequest->headers->replace('request_uri', $sRequest->uri); $sRequest->params = new HttpParams([], $request->get, []); $sRequest->parseUri(); return [$sRequest, Response::create($response)]; } }