get(HttpDispatcher::class), $container->get(ExceptionHandlerDispatcher::class), $container->get(ResponseEmitter::class) ); $this->packer = $packer ?? new JsonPacker(); $this->initCoreMiddleware($server); $this->initBaseUri($server); } public function get(string $uri, array $data = [], array $headers = []) { $response = $this->request('GET', $uri, [ 'headers' => $headers, 'query' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function post(string $uri, array $data = [], array $headers = []) { $response = $this->request('POST', $uri, [ 'headers' => $headers, 'form_params' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function put(string $uri, array $data = [], array $headers = []) { $response = $this->request('PUT', $uri, [ 'headers' => $headers, 'form_params' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function patch(string $uri, array $data = [], array $headers = []) { $response = $this->request('PATCH', $uri, [ 'headers' => $headers, 'form_params' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function delete(string $uri, array $data = [], array $headers = []) { $response = $this->request('DELETE', $uri, [ 'headers' => $headers, 'query' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function json(string $uri, array $data = [], array $headers = []) { $headers['Content-Type'] = 'application/json'; $response = $this->request('POST', $uri, [ 'headers' => $headers, 'json' => $data, ]); return $this->packer->unpack((string) $response->getBody()); } public function file(string $uri, array $data = [], array $headers = []) { $multipart = []; if (Arr::isAssoc($data)) { $data = [$data]; } foreach ($data as $item) { $name = $item['name']; $file = $item['file']; $multipart[] = [ 'name' => $name, 'contents' => fopen($file, 'r'), 'filename' => basename($file), ]; } $response = $this->request('POST', $uri, [ 'headers' => $headers, 'multipart' => $multipart, ]); return $this->packer->unpack((string) $response->getBody()); } public function request(string $method, string $path, array $options = [], ?callable $callable = null) { return wait(function () use ($method, $path, $options, $callable) { $callable && $callable(); return $this->execute($this->initRequest($method, $path, $options)); }, $this->waitTimeout); } public function sendRequest(ServerRequestInterface $psr7Request, ?callable $callable = null): ResponseInterface { return wait(function () use ($psr7Request, $callable) { $callable && $callable(); return $this->execute($psr7Request); }, $this->waitTimeout); } public function initRequest(string $method, string $path, array $options = []): ServerRequestInterface { $query = $options['query'] ?? []; $params = $options['form_params'] ?? []; $json = $options['json'] ?? []; $headers = $options['headers'] ?? []; $multipart = $options['multipart'] ?? []; $parsePath = parse_url($path); $path = $parsePath['path']; $uriPathQuery = $parsePath['query'] ?? []; if (! empty($uriPathQuery)) { parse_str($uriPathQuery, $pathQuery); $query = array_merge($pathQuery, $query); } $data = $params; // Initialize PSR-7 Request and Response objects. $uri = (new Uri($this->baseUri . ltrim($path, '/')))->withQuery(http_build_query($query)); $content = http_build_query($params); if ($method == 'POST' && data_get($headers, 'Content-Type') == 'application/json') { $content = json_encode($json, JSON_UNESCAPED_UNICODE); $data = $json; } $body = new SwooleStream($content); $request = new Psr7Request($method, $uri, $headers, $body); return $request->withQueryParams($query) ->withParsedBody($data) ->withUploadedFiles($this->normalizeFiles($multipart)); } protected function execute(ServerRequestInterface $psr7Request): ResponseInterface { $this->persistToContext($psr7Request, new Psr7Response()); $psr7Request = $this->coreMiddleware->dispatch($psr7Request); /** @var Dispatched $dispatched */ $dispatched = $psr7Request->getAttribute(Dispatched::class); $middlewares = $this->middlewares; if ($dispatched->isFound()) { $registeredMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod()); $middlewares = array_merge($middlewares, $registeredMiddlewares); } $middlewares = MiddlewareManager::sortMiddlewares($middlewares); try { $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware); } catch (Throwable $throwable) { // Delegate the exception to exception handler. $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers); } return $psr7Response; } protected function persistToContext(ServerRequestInterface $request, ResponseInterface $response) { Context::set(ServerRequestInterface::class, $request); Context::set(ResponseInterface::class, $response); } protected function initBaseUri(string $server): void { if ($this->container->has(ConfigInterface::class)) { $config = $this->container->get(ConfigInterface::class); $servers = $config->get('server.servers', []); foreach ($servers as $item) { if ($item['name'] == $server) { $this->baseUri = sprintf('http://127.0.0.1:%d/', (int) $item['port']); break; } } } } protected function normalizeFiles(array $multipart): array { $files = []; $fileSystem = $this->container->get(Filesystem::class); foreach ($multipart as $item) { if (isset($item['name'], $item['contents'], $item['filename'])) { $name = $item['name']; $contents = $item['contents']; $filename = $item['filename']; $dir = BASE_PATH . '/runtime/uploads'; $tmpName = $dir . '/' . $filename; if (! is_dir($dir)) { $fileSystem->makeDirectory($dir); } $fileSystem->put($tmpName, $contents); $stats = fstat($contents); $files[$name] = new UploadedFile( $tmpName, $stats['size'], 0, $name ); } } return $files; } protected function getStream(string $resource) { $stream = fopen('php://temp', 'r+'); if ($resource !== '') { fwrite($stream, $resource); fseek($stream, 0); } return $stream; } }