44
55use Gos \Component \WebSocketClient \Exception \BadResponseException ;
66use Gos \Component \WebSocketClient \Exception \WebsocketException ;
7+ use Psr \Log \LoggerInterface ;
78
89/**
9- * WS Client
10+ * WS Client.
1011 *
1112 * @author Martin Bažík <[email protected] > 1213 * @author Johann Saunier <[email protected] > @@ -31,31 +32,76 @@ class Client
3132 /** @var string */
3233 protected $ sessionId ;
3334
35+ /** @var string */
36+ protected $ origin ;
37+
38+ /** @var LoggerInterface */
39+ protected $ logger ;
40+
41+ /** @var bool */
42+ protected $ closing ;
43+
44+ /** @var bool */
45+ protected $ secured ;
46+
3447 /**
35- * @param string $endpoint
48+ * @param string $host
49+ * @param int|string $port
50+ * @param bool $secured
51+ * @param string $origin
3652 */
37- public function __construct ($ endpoint )
53+ public function __construct ($ host , $ port , $ secured = false , $ origin = null )
3854 {
39- $ this ->endpoint = $ endpoint ;
40- $ this ->parseUrl ();
55+ $ this ->serverHost = $ host ;
4156 $ this ->connected = false ;
42- $ this ->serverPort = 80 ;
57+ $ this ->closing = false ;
58+ $ this ->secured = $ secured ;
59+ $ this ->serverPort = $ port ;
60+
61+ if (null === $ origin ) {
62+ $ origin = $ host ;
63+ }
64+
65+ $ this ->origin = $ origin ;
66+
67+ $ protocol = (true === $ this ->secured ? 'ssl ' : 'tcp ' );
68+
69+ $ this ->endpoint = sprintf (
70+ '%s://%s:%s ' ,
71+ $ protocol ,
72+ $ host ,
73+ $ port
74+ );
75+ }
76+
77+ /**
78+ * @param LoggerInterface $logger
79+ */
80+ public function setLogger (LoggerInterface $ logger = null )
81+ {
82+ $ this ->logger = $ logger ;
83+ }
84+
85+ public function setAuthenticationToken ()
86+ {
87+ /* @todo **/
4388 }
4489
4590 /**
4691 * @param string $target
4792 *
4893 * @return string
94+ *
4995 * @throws BadResponseException
5096 * @throws WebsocketException
5197 */
52- public function connect ($ target = '/websocket/ ' )
98+ public function connect ($ target = '/ ' )
5399 {
54100 if ($ this ->connected ) {
55101 return $ this ->sessionId ;
56102 }
57103
58- $ this ->socket = stream_socket_client ($ this ->serverHost . ' : ' . $ this -> serverPort , $ errno , $ errstr );
104+ $ this ->socket = stream_socket_client ($ this ->endpoint , $ errno , $ errstr );
59105
60106 if (!$ this ->socket ) {
61107 throw new BadResponseException ('Could not open socket. Reason: ' . $ errstr );
@@ -73,6 +119,8 @@ public function connect($target = '/websocket/')
73119
74120 $ this ->sessionId = $ payload [1 ];
75121
122+ $ this ->connected = true ;
123+
76124 return $ this ->sessionId ;
77125 }
78126
@@ -91,13 +139,22 @@ protected function upgradeProtocol($target)
91139 throw new WebsocketException ('Wamp Server Target is wrong. ' );
92140 }
93141
94- $ out = "GET " . $ target . " HTTP/1.1 \r\n" ;
95- $ out .= "Host: {$ this ->serverHost } \r\n" ;
142+ $ protocol = true === $ this ->secured ? 'wss ' : 'ws ' ;
143+
144+ $ out = "GET {$ protocol }:// {$ this ->serverHost }: {$ this ->serverPort }{$ target } HTTP/1.1 \r\n" ;
145+ $ out .= "Host: {$ this ->serverHost }: {$ this ->serverPort }\r\n" ;
146+ $ out .= "Pragma: no-cache \r\n" ;
147+ $ out .= "Cache-Control: no-cache \r\n" ;
96148 $ out .= "Upgrade: WebSocket \r\n" ;
97149 $ out .= "Connection: Upgrade \r\n" ;
98- $ out .= "Sec-WebSocket-Key: $ key \r\n" ;
150+ $ out .= "Sec-WebSocket-Key: $ key \r\n" ;
151+ $ out .= "Sec-WebSocket-Protocol: wamp \r\n" ;
152+
153+ //@todo support auth
154+ // $out .= "Cookie: PHPSESSID=2okar2mng0mklk62iutc0bert0\r\n";
155+
99156 $ out .= "Sec-WebSocket-Version: 13 \r\n" ;
100- $ out .= "Origin: * \r\n\r\n" ;
157+ $ out .= "Origin: { $ this -> origin } \r\n\r\n" ;
101158
102159 fwrite ($ this ->socket , $ out );
103160
@@ -123,9 +180,10 @@ protected function verifyResponse($response)
123180 }
124181
125182 /**
126- * Read the buffer and return the oldest event in stack
183+ * Read the buffer and return the oldest event in stack.
127184 *
128185 * @see https://tools.ietf.org/html/rfc6455#section-5.2
186+ *
129187 * @return string
130188 */
131189 protected function read ()
@@ -150,14 +208,36 @@ protected function read()
150208 }
151209
152210 /**
153- * Disconnect
211+ * Disconnect.
154212 *
155213 * @return boolean
156214 */
157215 public function disconnect ()
158216 {
217+ if (false === $ this ->connected ) {
218+ return true ;
219+ }
220+
159221 if ($ this ->socket ) {
222+ $ this ->send (WebsocketPayload::generateClosePayload (), WebsocketPayload::OPCODE_CLOSE );
223+ $ this ->closing = true ;
224+
225+ $ payloadLength = ord (fread ($ this ->socket , 1 ));
226+ $ payload = fread ($ this ->socket , $ payloadLength );
227+
228+ if ($ payloadLength >= 2 ) {
229+ $ bin = $ payload [0 ] . $ payload [1 ];
230+ $ status = bindec (sprintf ("%08b%08b " , ord ($ payload [0 ]), ord ($ payload [1 ])));
231+ }
232+
233+ if ($ this ->closing ) {
234+ $ this ->closing = false ;
235+ } else {
236+ $ this ->send ($ bin . 'Close acknowledged: ' . $ status , WebsocketPayload::OPCODE_CLOSE );
237+ }
238+
160239 fclose ($ this ->socket );
240+ $ this ->connected = false ;
161241
162242 return true ;
163243 }
@@ -166,19 +246,21 @@ public function disconnect()
166246 }
167247
168248 /**
169- * Send message to the websocket
249+ * Send message to the websocket.
170250 *
171251 * @access private
172- * @param array $data
252+ *
253+ * @param array $data
254+ *
173255 * @return $this|Client
174256 */
175- protected function send ($ data )
257+ protected function send ($ data, $ opcode = WebsocketPayload:: OPCODE_TEXT , $ masked = true )
176258 {
177259 $ rawMessage = json_encode ($ data );
178260 $ payload = new WebsocketPayload ();
179261 $ payload
180- ->setOpcode (WebsocketPayload:: OPCODE_TEXT )
181- ->setMask (true )
262+ ->setOpcode ($ opcode )
263+ ->setMask ($ masked )
182264 ->setPayload ($ rawMessage );
183265
184266 $ encoded = $ payload ->encodePayload ();
@@ -188,8 +270,10 @@ protected function send($data)
188270 }
189271
190272 /**
191- * Establish a prefix on server
273+ * Establish a prefix on server.
274+ *
192275 * @see http://wamp.ws/spec#prefix_message
276+ *
193277 * @param string $prefix
194278 * @param string $uri
195279 */
@@ -201,8 +285,10 @@ public function prefix($prefix, $uri)
201285 }
202286
203287 /**
204- * Call a procedure on server
288+ * Call a procedure on server.
289+ *
205290 * @see http://wamp.ws/spec#call_message
291+ *
206292 * @param string $procURI
207293 * @param mixed $arguments
208294 */
@@ -218,22 +304,31 @@ public function call($procUri, $arguments = [])
218304 }
219305
220306 /**
221- * The client will send an event to all clients connected to the server who have subscribed to the topicURI
307+ * The client will send an event to all clients connected to the server who have subscribed to the topicURI.
308+ *
222309 * @see http://wamp.ws/spec#publish_message
310+ *
223311 * @param string $topicUri
224312 * @param string $payload
225313 * @param string $exclude
226314 * @param string $eligible
227315 */
228316 public function publish ($ topicUri , $ payload , $ exclude = [], $ eligible = [])
229317 {
230- $ type = Protocol::MSG_PUBLISH ;
231- $ data = array ($ type , $ topicUri , $ payload , $ exclude , $ eligible );
318+ if (null !== $ this ->logger ) {
319+ $ this ->logger ->info (sprintf (
320+ 'Publish in %s ' ,
321+ $ topicUri
322+ ));
323+ }
324+
325+ $ data = array (Protocol::MSG_PUBLISH , $ topicUri , $ payload , $ exclude , $ eligible );
232326 $ this ->send ($ data );
233327 }
234328
235329 /**
236330 * Subscribers receive PubSub events published by subscribers via the EVENT message. The EVENT message contains the topicURI, the topic under which the event was published, and event, the PubSub event payload.
331+ *
237332 * @param string $topicUri
238333 * @param string $payload
239334 */
@@ -260,27 +355,4 @@ protected function generateKey($length = 16)
260355
261356 return base64_encode (substr ($ tmp , 0 , $ length ));
262357 }
263-
264- /**
265- * Parse the url and set server parameters
266- *
267- * @access private
268- * @return bool
269- */
270- protected function parseUrl ()
271- {
272- $ url = parse_url ($ this ->endpoint );
273-
274- $ this ->serverHost = $ url ['host ' ];
275- $ this ->serverPort = isset ($ url ['port ' ]) ? $ url ['port ' ] : null ;
276-
277- if (array_key_exists ('scheme ' , $ url ) && $ url ['scheme ' ] == 'https ' ) {
278- $ this ->serverHost = 'ssl:// ' . $ this ->serverHost ;
279- if (!$ this ->serverPort ) {
280- $ this ->serverPort = 443 ;
281- }
282- }
283-
284- return true ;
285- }
286358}
0 commit comments