Completed
Branch feature/filterStream (0e183d)
by Ventimiglia
02:14
created

StreamClient::createUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
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) {
0 ignored issues
show
Bug introduced by
The class GuzzleException does not exist. Did you forget a USE statement, or did you not list all dependencies?

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.

Loading history...
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