Completed
Branch feature/streamRestApi (3bb468)
by Ventimiglia
02:23
created

StreamClient::createClientObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 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
     * 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
103
    /**
104
     *
105
     * @return string $lastMessageId
106
     */
107
    public function getLastMessageId(): string
108
    {
109
        return $this->lastMessageId;
110
    }
111
112
    /**
113
     *
114
     * @param string $lastMessageId
115
     */
116
    public function setLastMessageId($lastMessageId)
117
    {
118
        $this->lastMessageId = $lastMessageId;
119
    }
120
121
    /**
122
     * Connect to firebase server
123
     *
124
     * @throws RuntimeException
125
     */
126
    private function connect()
127
    {
128
        $headers = [];
129
        if ($this->lastMessageId) {
130
            $headers['Last-Event-ID'] = $this->lastMessageId;
131
        }
132
133
        $this->response = $this->client->request('GET', $this->url, [
134
            'stream' => true,
135
            'headers' => $headers
136
        ]);
137
138
        if ($this->response->getStatusCode() == 204) {
139
            throw new RuntimeException('Error: Server forbid connection retry by responding 204 status code.');
140
        }
141
    }
142
143
    /**
144
     * Returns generator that yields new event when it's available on stream.
145
     *
146
     * @return \Generator
147
     */
148
    public function getEvents()
149
    {
150
        /* initialize empty buffer */
151
        $buffer = '';
152
153
        /* bring body of response */
154
        $body = $this->response->getBody();
155
156
        $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<ZendFirebase\Stream\unknown>.

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...
157
    }
158
159
    /**
160
     * Create infinite loop
161
     *
162
     * @param unknown $buffer
163
     * @param unknown $body
164
     * @param unknown $parts
165
     * @param unknown $rawMessage
166
     * @param unknown $remaining
167
     * @param unknown $event
168
     * @return unknown|Generator
169
     */
170
    private function infiniteLoop($buffer, $body, $parts, $rawMessage, $remaining, $event): string
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...
171
    {
172
        /* infinte loop */
173
        while (true) {
174
            /* if server close connection - try to reconnect */
175
            if ($body->eof()) {
176
                /* wait retry period before reconnection */
177
                sleep($this->retry / 1000);
178
179
                /* reconnect */
180
                $this->connect();
181
182
                /* clear buffer since there is no sense in partial message */
183
                $buffer = '';
184
            }
185
            /* start read into stream */
186
            $buffer .= $body->read(1);
187
188
            if (preg_match(self::END_OF_MESSAGE, $buffer)) {
189
                $parts = preg_split(self::END_OF_MESSAGE, $buffer, 2);
190
191
                $rawMessage = $parts[0];
192
                $remaining = $parts[1];
193
194
                $buffer = $remaining;
195
196
                /**
197
                 * Save event into StreamEvent
198
                 *
199
                 * @var StreamEvent
200
                 * @return StreamEvent $event
201
                 */
202
                $event = StreamEvent::parse($rawMessage);
203
204
                yield $event;
205
            }
206
        }
207
        return $buffer;
208
    }
209
}
210