1
|
|
|
<?php |
2
|
|
|
namespace ZendFirebase\Stream; |
3
|
|
|
|
4
|
|
|
use GuzzleHttp; |
5
|
|
|
use RuntimeException; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* PHP7 FIREBASE LIBRARY (http://samuelventimiglia.it/) |
9
|
|
|
* |
10
|
|
|
* |
11
|
|
|
* @link https://github.com/Samuel18/zend_Firebase |
12
|
|
|
* @copyright Copyright (c) 2016-now Ventimiglia Samuel - Biasin Davide |
13
|
|
|
* @license BSD 3-Clause License |
14
|
|
|
* |
15
|
|
|
*/ |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* This class create an object of Client |
19
|
|
|
* |
20
|
|
|
* @author ghostbyte |
21
|
|
|
* @package ZendFirebase |
22
|
|
|
* @since 2016-10-28 |
23
|
|
|
* |
24
|
|
|
*/ |
25
|
|
|
class StreamClient |
26
|
|
|
{ |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Stream pattern END_OF_MESSAGE |
30
|
|
|
* |
31
|
|
|
* @var string |
32
|
|
|
*/ |
33
|
|
|
const END_OF_MESSAGE = "/\r\n\r\n|\n\n|\r\r/"; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Client for send request |
37
|
|
|
* |
38
|
|
|
* @var GuzzleHttp\Client $client |
39
|
|
|
*/ |
40
|
|
|
private $client; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Responce object from rest |
44
|
|
|
* |
45
|
|
|
* @var GuzzleHttp\Psr7\Response $response |
46
|
|
|
*/ |
47
|
|
|
private $response; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Request url to send request |
51
|
|
|
* |
52
|
|
|
* @var string $url |
53
|
|
|
*/ |
54
|
|
|
private $url; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Request options to add to url |
58
|
|
|
* |
59
|
|
|
* @var string |
60
|
|
|
*/ |
61
|
|
|
private $options = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Last received message id |
65
|
|
|
* |
66
|
|
|
* @var string $lastMessageId |
67
|
|
|
*/ |
68
|
|
|
private $lastMessageId; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Reconnection time in milliseconds |
72
|
|
|
* |
73
|
|
|
* @var integer $retry |
74
|
|
|
*/ |
75
|
|
|
private $retry = 3000; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Constructor |
79
|
|
|
* |
80
|
|
|
* @param string $url |
81
|
|
|
* @param integer $requestDelay |
82
|
|
|
* @throws InvaliArgumentException |
83
|
|
|
*/ |
84
|
|
|
public function __construct($url, $requestDelay, $options) |
85
|
|
|
{ |
86
|
|
|
$this->url = $url; |
87
|
|
|
$this->retry = $requestDelay; |
88
|
|
|
$this->options = $options; |
89
|
|
|
|
90
|
|
|
if (empty($this->url)) { |
91
|
|
|
throw new \InvalidArgumentException('Error: url empty...'); |
92
|
|
|
} |
93
|
|
|
$this->createClientObject(); |
94
|
|
|
$this->connect(); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Create client |
99
|
|
|
*/ |
100
|
|
|
private function createClientObject() |
101
|
|
|
{ |
102
|
|
|
$this->client = new GuzzleHttp\Client([ |
103
|
|
|
'headers' => [ |
104
|
|
|
'Accept' => 'text/event-stream', |
105
|
|
|
'Cache-Control' => 'no-cache', |
106
|
|
|
'allow_redirects' => true |
107
|
|
|
], |
108
|
|
|
|
109
|
|
|
'base_uri' => $this->url, |
110
|
|
|
]); |
111
|
|
|
|
112
|
|
|
$this->connect(); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* |
117
|
|
|
* @return string $lastMessageId |
118
|
|
|
*/ |
119
|
|
|
public function getLastMessageId(): string |
120
|
|
|
{ |
121
|
|
|
return $this->lastMessageId; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* |
126
|
|
|
* @param string $lastMessageId |
127
|
|
|
*/ |
128
|
|
|
public function setLastMessageId($lastMessageId) |
129
|
|
|
{ |
130
|
|
|
$this->lastMessageId = $lastMessageId; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Connect to firebase server |
135
|
|
|
* |
136
|
|
|
* @throws RuntimeException |
137
|
|
|
*/ |
138
|
|
|
private function connect() |
139
|
|
|
{ |
140
|
|
|
|
141
|
|
|
$this->sendRequest(); |
142
|
|
|
|
143
|
|
|
if ($this->response->getStatusCode() == 204) { |
144
|
|
|
throw new RuntimeException('Error: Server forbid connection retry by responding 204 status code.'); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Create url with or without query options |
150
|
|
|
* |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
|
|
private function createUrl(): string |
154
|
|
|
{ |
155
|
|
|
return $this->url . $this->options; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Send Request |
160
|
|
|
*/ |
161
|
|
|
private function sendRequest() |
162
|
|
|
{ |
163
|
|
|
try { |
164
|
|
|
$headers = []; |
165
|
|
|
if ($this->lastMessageId) { |
166
|
|
|
$headers['Last-Event-ID'] = $this->lastMessageId; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
$this->response = $this->client->request('GET', $this->createUrl(), [ |
170
|
|
|
'stream' => true, |
171
|
|
|
'headers' => $headers, |
172
|
|
|
]); |
173
|
|
|
|
174
|
|
|
} catch (\GuzzleException $e) { |
|
|
|
|
175
|
|
|
die((string)$e->getResponse()->getBody()); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Returns generator that yields new event when it's available on stream. |
183
|
|
|
*/ |
184
|
|
|
public function getEvents() |
185
|
|
|
{ |
186
|
|
|
/* initialize empty buffer */ |
187
|
|
|
$buffer = ''; |
188
|
|
|
|
189
|
|
|
/* bring body of response */ |
190
|
|
|
$body = $this->response->getBody(); |
191
|
|
|
|
192
|
|
|
/* infinte loop */ |
193
|
|
|
while (true) { |
194
|
|
|
/* if server close connection - try to reconnect */ |
195
|
|
|
if ($body->eof()) { |
196
|
|
|
/* wait retry period before reconnection */ |
197
|
|
|
sleep($this->retry / 1000); |
198
|
|
|
|
199
|
|
|
/* reconnect */ |
200
|
|
|
$this->connect(); |
201
|
|
|
|
202
|
|
|
/* clear buffer since there is no sense in partial message */ |
203
|
|
|
$buffer = ''; |
204
|
|
|
} |
205
|
|
|
/* start read into stream */ |
206
|
|
|
$buffer .= $body->read(1); |
207
|
|
|
|
208
|
|
|
if (preg_match(self::END_OF_MESSAGE, $buffer)) { |
209
|
|
|
$parts = preg_split(self::END_OF_MESSAGE, $buffer, 2); |
210
|
|
|
|
211
|
|
|
$rawMessage = $parts[0]; |
212
|
|
|
$remaining = $parts[1]; |
213
|
|
|
|
214
|
|
|
$buffer = $remaining; |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Save event into StreamEvent |
218
|
|
|
* |
219
|
|
|
* @var StreamEvent $event |
220
|
|
|
*/ |
221
|
|
|
$event = StreamEvent::parse($rawMessage); |
222
|
|
|
|
223
|
|
|
yield $event; |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.