Completed
Branch master (4189fe)
by Ventimiglia
02:27
created

StreamClient::infiniteLoop()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 40
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 40
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 5
nop 6
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
     * Last received message id
58
     *
59
     * @var string $lastMessageId
60
     */
61
    private $lastMessageId;
62
63
    /**
64
     * Reconnection time in milliseconds
65
     *
66
     * @var integer $retry
67
     */
68
    private $retry = 3000;
69
70
    /**
71
     * Constructor
72
     *
73
     * @param string $url
74
     * @param integer $requestDelay
75
     * @throws InvaliArgumentException
76
     */
77
    public function __construct($url, $requestDelay)
78
    {
79
        $this->url = $url;
80
        $this->retry = $requestDelay;
81
82
        if (empty($this->url)) {
83
            throw new \InvalidArgumentException('Error: url empty...');
84
        }
85
        $this->createClientObject();
86
        $this->connect();
87
    }
88
89
    /**
90
     * Create client
91
     */
92
    private function createClientObject()
93
    {
94
        $this->client = new GuzzleHttp\Client([
95
            'headers' => [
96
                'Accept' => 'text/event-stream',
97
                'Cache-Control' => 'no-cache',
98
                'allow_redirects' => true
99
            ]
100
        ]);
101
102
        $this->connect();
103
104
    }
105
106
    /**
107
     *
108
     * @return string $lastMessageId
109
     */
110
    public function getLastMessageId(): string
111
    {
112
        return $this->lastMessageId;
113
    }
114
115
    /**
116
     *
117
     * @param string $lastMessageId
118
     */
119
    public function setLastMessageId($lastMessageId)
120
    {
121
        $this->lastMessageId = $lastMessageId;
122
    }
123
124
    /**
125
     * Connect to firebase server
126
     *
127
     * @throws RuntimeException
128
     */
129
    private function connect()
130
    {
131
        $headers = [];
132
        if ($this->lastMessageId) {
133
            $headers['Last-Event-ID'] = $this->lastMessageId;
134
        }
135
136
        $this->response = $this->client->request('GET', $this->url, [
137
            'stream' => true,
138
            'headers' => $headers
139
        ]);
140
141
        if ($this->response->getStatusCode() == 204) {
142
            throw new RuntimeException('Error: Server forbid connection retry by responding 204 status code.');
143
        }
144
    }
145
146
    /**
147
     * Returns generator that yields new event when it's available on stream.
148
     *
149
     * @return \Generator
150
     */
151
    public function getEvents()
152
    {
153
        /* initialize empty buffer */
154
        $buffer = '';
155
156
        /* bring body of response */
157
        $body = $this->response->getBody();
158
159
160
        $buffer = $this->infiniteLoop($buffer, $body, $parts, $rawMessage, $remaining, $event);
0 ignored issues
show
Bug introduced by
The variable $parts does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $rawMessage does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $remaining does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $event does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Documentation introduced by
$buffer is of type string, but the function expects a object<GuzzleHttp\Psr7\Stream>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
$buffer is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
161
    }
162
163
    /**
164
     * Create infinite loop
165
     *
166
     * @param GuzzleHttp\Psr7\Stream $buffer
167
     * @param mixed $body
168
     * @param mixed $parts
169
     * @param mixed $rawMessage
170
     * @param mixed $remaining
171
     * @param mixed $event
172
     * @return \Generator
173
     */
174
    private function infiniteLoop($buffer, $body, $parts, $rawMessage, $remaining, $event): GuzzleHttp\Psr7\Stream
0 ignored issues
show
Unused Code introduced by
The parameter $parts is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $rawMessage is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $remaining is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
175
    {
176
177
        /* infinte loop */
178
        while (true) {
179
            /* if server close connection - try to reconnect */
180
            if ($body->eof()) {
181
                /* wait retry period before reconnection */
182
                sleep($this->retry / 1000);
183
184
                /* reconnect */
185
                $this->connect();
186
187
                /* clear buffer since there is no sense in partial message */
188
                $buffer = '';
189
            }
190
            /* start read into stream */
191
            $buffer .= $body->read(1);
192
193
            if (preg_match(self::END_OF_MESSAGE, $buffer)) {
194
                $parts = preg_split(self::END_OF_MESSAGE, $buffer, 2);
195
196
                $rawMessage = $parts[0];
197
                $remaining = $parts[1];
198
199
                $buffer = $remaining;
200
201
                /**
202
                 * Save event into StreamEvent
203
                 *
204
                 * @var StreamEvent
205
                 * @return StreamEvent $event
206
                 */
207
                $event = StreamEvent::parse($rawMessage);
208
209
                yield $event;
210
            }
211
        }
212
        return $buffer;
213
    }
214
}
215