Skip to content

Commit dd8cd34

Browse files
committed
Update classes and interfaces
1 parent d46dcc4 commit dd8cd34

File tree

8 files changed

+94
-149
lines changed

8 files changed

+94
-149
lines changed

.gitignore

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
# Dependency directories (remove the comment below to include it)
2-
# vendor/
3-
.idea
4-
vendor
5-
.phpunit.result.cache
1+
# Composer lock file
62
composer.lock
3+
4+
# IDEs
5+
/.idea
6+
/.vscode
7+
8+
# Vendors
9+
/vendor
10+
**/vendor
11+
12+
# Temp dirs & trash
13+
/tests/server*
14+
clover*
15+
cover*
16+
.DS_Store
17+
*.cache

src/HttpWorker.php

Lines changed: 30 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use Spiral\RoadRunner\Message\Command\StreamStop;
1616
use Spiral\RoadRunner\Payload;
1717
use Spiral\RoadRunner\WorkerInterface;
18-
use Stringable;
1918

2019
/**
2120
* @psalm-import-type HeadersList from Request
@@ -40,29 +39,17 @@
4039
*/
4140
class HttpWorker implements HttpWorkerInterface
4241
{
43-
/**
44-
* @var WorkerInterface
45-
*/
46-
private WorkerInterface $worker;
47-
48-
/**
49-
* @param WorkerInterface $worker
50-
*/
51-
public function __construct(WorkerInterface $worker)
52-
{
53-
$this->worker = $worker;
42+
public function __construct(
43+
private readonly WorkerInterface $worker,
44+
) {
5445
}
5546

56-
/**
57-
* @return WorkerInterface
58-
*/
5947
public function getWorker(): WorkerInterface
6048
{
6149
return $this->worker;
6250
}
6351

6452
/**
65-
* {@inheritDoc}
6653
* @throws \JsonException
6754
*/
6855
public function waitRequest(): ?Request
@@ -81,11 +68,15 @@ public function waitRequest(): ?Request
8168
}
8269

8370
/**
84-
* {@inheritDoc}
8571
* @throws \JsonException
8672
*/
87-
public function respond(int $status, string $body, array $headers = []): void
73+
public function respond(int $status, string|Generator $body, array $headers = []): void
8874
{
75+
if ($body instanceof Generator) {
76+
$this->respondStream($status, $body, $headers);
77+
return;
78+
}
79+
8980
$head = (string)\json_encode([
9081
'status' => $status,
9182
'headers' => $headers ?: (object)[],
@@ -94,14 +85,7 @@ public function respond(int $status, string $body, array $headers = []): void
9485
$this->worker->respond(new Payload($body, $head));
9586
}
9687

97-
/**
98-
* Respond data using Streamed Output
99-
*
100-
* @param Generator<mixed, scalar|Stringable, mixed, Stringable|scalar|null> $body Body generator.
101-
* Each yielded value will be sent as a separated stream chunk.
102-
* Returned value will be sent as a last stream package.
103-
*/
104-
public function respondStream(int $status, Generator $body, array $headers = []): void
88+
private function respondStream(int $status, Generator $body, array $headers = []): void
10589
{
10690
$head = (string)\json_encode([
10791
'status' => $status,
@@ -126,50 +110,33 @@ public function respondStream(int $status, Generator $body, array $headers = [])
126110
}
127111

128112
/**
129-
* @param string $body
130113
* @param RequestContext $context
131-
* @return Request
132-
*
133-
* @psalm-suppress InaccessibleProperty
134114
*/
135115
private function createRequest(string $body, array $context): Request
136116
{
137-
$request = new Request();
138-
$request->body = $body;
139-
140-
$this->hydrateRequest($request, $context);
141-
142-
return $request;
143-
}
144-
145-
/**
146-
* @param Request $request
147-
* @param RequestContext $context
148-
*
149-
* @psalm-suppress InaccessibleProperty
150-
* @psalm-suppress MixedPropertyTypeCoercion
151-
*/
152-
private function hydrateRequest(Request $request, array $context): void
153-
{
154-
$request->remoteAddr = $context['remoteAddr'];
155-
$request->protocol = $context['protocol'];
156-
$request->method = $context['method'];
157-
$request->uri = $context['uri'];
158-
\parse_str($context['rawQuery'], $request->query);
159-
160-
$request->attributes = (array)($context['attributes'] ?? []);
161-
$request->headers = $this->filterHeaders((array)($context['headers'] ?? []));
162-
$request->cookies = (array)($context['cookies'] ?? []);
163-
$request->uploads = (array)($context['uploads'] ?? []);
164-
$request->parsed = (bool)$context['parsed'];
165-
166-
$request->attributes[Request::PARSED_BODY_ATTRIBUTE_NAME] = $request->parsed;
117+
\parse_str($context['rawQuery'], $query);
118+
return new Request(
119+
remoteAddr: $context['remoteAddr'],
120+
protocol: $context['protocol'],
121+
method: $context['method'],
122+
uri: $context['uri'],
123+
headers: $this->filterHeaders((array)($context['headers'] ?? [])),
124+
cookies: (array)($context['cookies'] ?? []),
125+
uploads: (array)($context['uploads'] ?? []),
126+
attributes: [
127+
Request::PARSED_BODY_ATTRIBUTE_NAME => (bool)$context['parsed'],
128+
] + (array)($context['attributes'] ?? []),
129+
query: $query,
130+
body: $body,
131+
parsed: (bool)$context['parsed'],
132+
);
167133
}
168134

169135
/**
170136
* Remove all non-string and empty-string keys
171137
*
172-
* @return array<string, mixed>
138+
* @param array<array-key, array<array-key, string>> $headers
139+
* @return HeadersList
173140
*/
174141
private function filterHeaders(array $headers): array
175142
{
@@ -180,7 +147,8 @@ private function filterHeaders(array $headers): array
180147
unset($headers[$key]);
181148
}
182149
}
183-
/** @var array<string, mixed> $headers */
150+
151+
/** @var HeadersList $headers */
184152
return $headers;
185153
}
186154
}

src/HttpWorkerInterface.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace Spiral\RoadRunner\Http;
1313

14+
use Generator;
1415
use Spiral\RoadRunner\WorkerAwareInterface;
16+
use Stringable;
1517

1618
/**
1719
* @psalm-import-type HeadersList from Request
@@ -28,10 +30,14 @@ public function waitRequest(): ?Request;
2830
/**
2931
* Send response to the application server.
3032
*
31-
* @param int $status Http status code
32-
* @param string $body Body of response
33+
* @param int $status Http status code
34+
* @param Generator<mixed, scalar|Stringable, mixed, Stringable|scalar|null>|string $body Body of response.
35+
* If the body is a generator, then each yielded value will be sent as a separated stream chunk.
36+
* Returned value will be sent as a last stream package.
37+
* Note: Stream response is experimental feature and isn't supported by RoadRunner yet.
38+
* But you can try to use RoadRunner 2.9-alpha to test it.
3339
* @param HeadersList|array $headers An associative array of the message's headers. Each key MUST be a header name,
3440
* and each value MUST be an array of strings for that header.
3541
*/
36-
public function respond(int $status, string $body, array $headers = []): void;
42+
public function respond(int $status, string|Generator $body, array $headers = []): void;
3743
}

src/PSR7Worker.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class PSR7Worker implements PSR7WorkerInterface
3333
/**
3434
* @var int Preferred chunk size for streaming output.
3535
* if not greater than 0, then streaming response is turned off
36+
* @internal
3637
*/
3738
public int $chunkSize = 0;
3839

@@ -117,18 +118,13 @@ public function waitRequest(): ?ServerRequestInterface
117118
*/
118119
public function respond(ResponseInterface $response): void
119120
{
120-
if ($this->chunkSize > 0) {
121-
$this->httpWorker->respondStream(
122-
$response->getStatusCode(),
123-
$this->streamToGenerator($response->getBody()),
124-
$response->getHeaders()
125-
);
126-
} else {
127-
$this->httpWorker->respond(
128-
$response->getStatusCode(),
129-
(string)$response->getBody(),
130-
$response->getHeaders());
131-
}
121+
$this->httpWorker->respond(
122+
$response->getStatusCode(),
123+
$this->chunkSize > 0
124+
? $this->streamToGenerator($response->getBody())
125+
: (string)$response->getBody(),
126+
$response->getHeaders()
127+
);
132128
}
133129

134130
/**

src/PSR7WorkerInterface.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,10 @@
1717

1818
interface PSR7WorkerInterface extends WorkerAwareInterface
1919
{
20-
/**
21-
* @return ServerRequestInterface|null
22-
*/
2320
public function waitRequest(): ?ServerRequestInterface;
2421

2522
/**
2623
* Send response to the application server.
27-
*
28-
* @param ResponseInterface $response
2924
*/
3025
public function respond(ResponseInterface $response): void;
3126
}

src/Request.php

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -18,77 +18,46 @@
1818
*
1919
* @psalm-type UploadedFile = array {
2020
* name: string,
21-
* error: positive-int|0,
21+
* error: int<0, max>,
2222
* tmpName: string,
23-
* size: positive-int|0,
23+
* size: int<0, max>,
2424
* mime: string
2525
* }
2626
*
27-
* @psalm-type HeadersList = array<string, array<array-key, string>>
27+
* @psalm-type HeadersList = array<non-empty-string, array<array-key, string>>
2828
* @psalm-type AttributesList = array<string, mixed>
29-
* @psalm-type QueryArgumentsList = array<string, string>
29+
* @psalm-type QueryArgumentsList = array
3030
* @psalm-type CookiesList = array<string, string>
3131
* @psalm-type UploadedFilesList = array<array-key, UploadedFile>
32+
*
33+
* @psalm-immutable
3234
*/
3335
#[Immutable]
3436
final class Request
3537
{
3638
public const PARSED_BODY_ATTRIBUTE_NAME = 'rr_parsed_body';
3739

3840
/**
39-
* @var string
40-
*/
41-
public string $remoteAddr = '127.0.0.1';
42-
43-
/**
44-
* @var string
45-
*/
46-
public string $protocol = 'HTTP/1.0';
47-
48-
/**
49-
* @var string
50-
*/
51-
public string $method = 'GET';
52-
53-
/**
54-
* @var string
55-
*/
56-
public string $uri = 'http://localhost';
57-
58-
/**
59-
* @var HeadersList
60-
*/
61-
public array $headers = [];
62-
63-
/**
64-
* @var CookiesList
41+
* @param HeadersList $headers
42+
* @param CookiesList $cookies
43+
* @param UploadedFilesList $uploads
44+
* @param AttributesList $attributes
45+
* @param QueryArgumentsList $query
6546
*/
66-
public array $cookies = [];
67-
68-
/**
69-
* @var UploadedFilesList
70-
*/
71-
public array $uploads = [];
72-
73-
/**
74-
* @var AttributesList
75-
*/
76-
public array $attributes = [];
77-
78-
/**
79-
* @var QueryArgumentsList
80-
*/
81-
public array $query = [];
82-
83-
/**
84-
* @var string
85-
*/
86-
public string $body = '';
87-
88-
/**
89-
* @var bool
90-
*/
91-
public bool $parsed = false;
47+
public function __construct(
48+
public readonly string $remoteAddr = '127.0.0.1',
49+
public readonly string $protocol = 'HTTP/1.0',
50+
public readonly string $method = 'GET',
51+
public readonly string $uri = 'http://localhost',
52+
public readonly array $headers = [],
53+
public readonly array $cookies = [],
54+
public readonly array $uploads = [],
55+
public readonly array $attributes = [],
56+
public readonly array $query = [],
57+
public readonly string $body = '',
58+
public readonly bool $parsed = false,
59+
) {
60+
}
9261

9362
/**
9463
* @return string

tests/Feature/StreamResponseTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function testStreamResponseWithMultipleFrames(): void
5555

5656
$chunks = ['Hel', 'lo,', ' Wo', 'rld', '!'];
5757
ServerRunner::getBuffer();
58-
$httpWorker->respondStream(
58+
$httpWorker->respond(
5959
200,
6060
(function () use ($chunks) {
6161
yield from $chunks;
@@ -73,7 +73,7 @@ public function testStopStreamResponse(): void
7373
// Flush buffer
7474
ServerRunner::getBuffer();
7575

76-
$httpWorker->respondStream(
76+
$httpWorker->respond(
7777
200,
7878
(function () {
7979
yield 'Hel';
@@ -114,4 +114,4 @@ private function sendCommand(BaseCommand $command)
114114
$this->getRelay()->send($command->getRequestFrame());
115115
\usleep(500_000);
116116
}
117-
}
117+
}

0 commit comments

Comments
 (0)