5
5
use Amp \ForbidSerialization ;
6
6
use Amp \Http \Client \Request ;
7
7
use Amp \Http \HttpMessage ;
8
+ use Amp \Http \HttpRequest ;
8
9
use League \Uri ;
9
10
use Psr \Http \Message \UriInterface as PsrUri ;
10
11
11
- final class WebsocketHandshake extends HttpMessage
12
+ /**
13
+ * @psalm-import-type HeaderParamArrayType from HttpMessage
14
+ * @psalm-import-type HeaderParamValueType from HttpMessage
15
+ * @psalm-import-type QueryArrayType from HttpRequest
16
+ * @psalm-import-type QueryValueType from HttpRequest
17
+ */
18
+ final class WebsocketHandshake extends HttpRequest
12
19
{
13
20
use ForbidSerialization;
14
21
15
- private PsrUri $ uri ;
16
-
17
22
private float $ tcpConnectTimeout = 10 ;
18
23
19
24
private float $ tlsHandshakeTimeout = 10 ;
20
25
21
26
private int $ headerSizeLimit = Request::DEFAULT_HEADER_SIZE_LIMIT ;
22
27
23
28
/**
24
- * @param string| PsrUri $uri target address of websocket (e.g. ws://foo.bar/bar or
29
+ * @param PsrUri|string $uri Target address of websocket (e.g. ws://foo.bar/bar or
25
30
* wss://crypto.example/?secureConnection) or a PsrUri instance.
26
- * @param string[]|string[][] $headers
31
+ * @param HeaderParamArrayType $headers
27
32
*/
28
33
public function __construct (PsrUri |string $ uri , array $ headers = [])
29
34
{
30
- $ this ->uri = $ this ->makeUri ($ uri );
31
- $ this ->setHeaders ($ headers );
32
- }
35
+ parent ::__construct ('GET ' , self ::makeUri ($ uri ));
33
36
34
- /**
35
- * @return PsrUri Websocket URI (scheme will be either ws or wss).
36
- */
37
- public function getUri (): PsrUri
38
- {
39
- return $ this ->uri ;
37
+ $ this ->setHeaders ($ headers );
40
38
}
41
39
42
40
/**
@@ -45,7 +43,7 @@ public function getUri(): PsrUri
45
43
public function withUri (PsrUri |string $ uri ): self
46
44
{
47
45
$ clone = clone $ this ;
48
- $ clone ->uri = $ clone -> makeUri ($ uri );
46
+ $ clone ->setUri ( self :: makeUri ($ uri) );
49
47
50
48
return $ clone ;
51
49
}
@@ -98,18 +96,13 @@ public function withHeaderSizeLimit(int $headerSizeLimit): self
98
96
/**
99
97
* Replaces all headers in the returned instance.
100
98
*
101
- * @param array<non-empty-string, string|array<string>> $headers
99
+ * @param HeaderParamArrayType $headers
102
100
*
103
101
* @return self Cloned object.
104
102
*/
105
103
public function withHeaders (array $ headers ): self
106
104
{
107
105
$ clone = clone $ this ;
108
-
109
- foreach ($ clone ->getRawHeaders () as [$ field ]) {
110
- $ clone ->removeHeader ($ field );
111
- }
112
-
113
106
$ clone ->setHeaders ($ headers );
114
107
115
108
return $ clone ;
@@ -119,7 +112,7 @@ public function withHeaders(array $headers): self
119
112
* Replaces the given header in the returned instance.
120
113
*
121
114
* @param non-empty-string $name
122
- * @param string|array<string> $value
115
+ * @param HeaderParamValueType $value
123
116
*
124
117
* @return self Cloned object.
125
118
*/
@@ -135,7 +128,7 @@ public function withHeader(string $name, string|array $value): self
135
128
* Adds the given header in the returned instance.
136
129
*
137
130
* @param non-empty-string $name
138
- * @param string|array<string> $value
131
+ * @param HeaderParamValueType $value
139
132
*
140
133
* @return self Cloned object.
141
134
*/
@@ -160,7 +153,7 @@ public function withoutHeader(string $name): self
160
153
return $ clone ;
161
154
}
162
155
163
- protected function setHeader (string $ name , $ value ): void
156
+ protected function setHeader (string $ name , array | string $ value ): void
164
157
{
165
158
if (($ name [0 ] ?? ': ' ) === ': ' ) {
166
159
throw new \Error ("Header name cannot be empty or start with a colon (:) " );
@@ -169,7 +162,7 @@ protected function setHeader(string $name, $value): void
169
162
parent ::setHeader ($ name , $ value );
170
163
}
171
164
172
- protected function addHeader (string $ name , $ value ): void
165
+ protected function addHeader (string $ name , array | string $ value ): void
173
166
{
174
167
if (($ name [0 ] ?? ': ' ) === ': ' ) {
175
168
throw new \Error ("Header name cannot be empty or start with a colon (:) " );
@@ -178,25 +171,80 @@ protected function addHeader(string $name, $value): void
178
171
parent ::addHeader ($ name , $ value );
179
172
}
180
173
181
- private function makeUri (PsrUri |string $ uri ): PsrUri
174
+ /**
175
+ * @param QueryArrayType $parameters
176
+ *
177
+ * @return self Cloned object.
178
+ */
179
+ public function withQueryParameters (array $ parameters ): self
180
+ {
181
+ $ clone = clone $ this ;
182
+ $ clone ->setQueryParameters ($ parameters );
183
+
184
+ return $ clone ;
185
+ }
186
+
187
+ /**
188
+ * @param QueryValueType $value
189
+ *
190
+ * @return self Cloned object.
191
+ */
192
+ public function withQueryParameter (string $ key , array |string |null $ value ): self
193
+ {
194
+ $ clone = clone $ this ;
195
+ $ clone ->setQueryParameter ($ key , $ value );
196
+
197
+ return $ clone ;
198
+ }
199
+
200
+ /**
201
+ * @param QueryValueType $value
202
+ *
203
+ * @return self Cloned object.
204
+ */
205
+ public function withAddedQueryParameter (string $ key , array |string |null $ value ): self
206
+ {
207
+ $ clone = clone $ this ;
208
+ $ clone ->addQueryParameter ($ key , $ value );
209
+
210
+ return $ clone ;
211
+ }
212
+
213
+ /**
214
+ * @return self Cloned object.
215
+ */
216
+ public function withoutQueryParameter (string $ key ): self
217
+ {
218
+ $ clone = clone $ this ;
219
+ $ clone ->removeQueryParameter ($ key );
220
+
221
+ return $ clone ;
222
+ }
223
+
224
+ /**
225
+ * @return self Cloned object.
226
+ */
227
+ public function withoutQuery (): self
228
+ {
229
+ $ clone = clone $ this ;
230
+ $ clone ->removeQuery ();
231
+
232
+ return $ clone ;
233
+ }
234
+
235
+ private static function makeUri (PsrUri |string $ uri ): PsrUri
182
236
{
183
237
if (\is_string ($ uri )) {
184
238
try {
185
239
$ uri = Uri \Http::createFromString ($ uri );
186
240
} catch (\Exception $ exception ) {
187
- throw new \Error ('Invalid Websocket URI provided ' , 0 , $ exception );
241
+ throw new \ValueError ('Invalid Websocket URI provided ' , 0 , $ exception );
188
242
}
189
243
}
190
244
191
- switch ($ uri ->getScheme ()) {
192
- case 'ws ' :
193
- case 'wss ' :
194
- break ;
195
-
196
- default :
197
- throw new \Error ('The URI scheme must be ws or wss: \'' . $ uri ->getScheme () . '\'' );
198
- }
199
-
200
- return $ uri ;
245
+ return match ($ uri ->getScheme ()) {
246
+ 'ws ' , 'wss ' => $ uri ,
247
+ default => throw new \ValueError ('The URI scheme must be ws or wss, got " ' . $ uri ->getScheme () . '" ' ),
248
+ };
201
249
}
202
250
}
0 commit comments