Completed
Push — master ( 924d4f...dce329 )
by Charlotte
7s
created

Message::setConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * This file is a part of Woketo package.
4
 *
5
 * (c) Nekland <[email protected]>
6
 *
7
 * For the full license, take a look to the LICENSE file
8
 * on the root directory of this project
9
 */
10
11
namespace Nekland\Woketo\Rfc6455;
12
13
use Nekland\Tools\StringTools;
14
use Nekland\Woketo\Exception\Frame\WrongEncodingException;
15
use Nekland\Woketo\Exception\LimitationException;
16
use Nekland\Woketo\Exception\MissingDataException;
17
18
class Message
19
{
20
    /**
21
     * It allows ~50MiB buffering as the default of Frame content is 0.5MB
22
     */
23
    const MAX_MESSAGES_BUFFERING = 100;
24
    
25
    /**
26
     * @var array|Frame[]
27
     */
28
    private $frames;
29
30
    /**
31
     * @var bool
32
     */
33
    private $isComplete;
34
35
    /**
36
     * @var string
37
     */
38
    private $buffer;
39
40
    /**
41
     * @see Message::setConfig() for full default configuration.
42
     * 
43
     * @var array
44
     */
45
    private $config;
46
47 51
    public function __construct(array $config = [])
48
    {
49 51
        $this->frames = [];
50 51
        $this->isComplete = false;
51 51
        $this->buffer = '';
52 51
        $this->setConfig($config);
53 51
    }
54
55
    /**
56
     * Add some data to the buffer.
57
     *
58
     * @param $data
59
     */
60 15
    public function addBuffer($data)
61
    {
62 15
        $this->buffer .= $data;
63 15
    }
64
65
    /**
66
     * Clear the buffer.
67
     */
68 1
    public function clearBuffer()
69
    {
70 1
        $this->buffer = '';
71 1
    }
72
73
    /**
74
     * Get data inside the buffer.
75
     *
76
     * @return string
77
     */
78 15
    public function getBuffer()
79
    {
80 15
        return $this->buffer;
81
    }
82
83
    /**
84
     * Remove data from the start of the buffer.
85
     *
86
     * @param Frame $frame
87
     * @return string
88
     */
89 10
    public function removeFromBuffer(Frame $frame) : string
90
    {
91 10
        $this->buffer = StringTools::removeStart($this->getBuffer(), $frame->getRawData(), '8bit');
92
93 10
        return $this->buffer;
94
    }
95
96
    /**
97
     * @param Frame $frame
98
     * @return Message
99
     * @throws \InvalidArgumentException
100
     * @throws LimitationException
101
     * @throws WrongEncodingException
102
     */
103 45
    public function addFrame(Frame $frame) : Message
104
    {
105 45
        if ($this->isComplete) {
106
            throw new \InvalidArgumentException('The message is already complete.');
107
        }
108
109 45
        if (count($this->frames) > $this->config['maxMessagesBuffering']) {
110 1
            throw new LimitationException(
111 1
                sprintf('We don\'t accept more than %s frames by message. This is a security limitation.', $this->config['maxMessagesBuffering'])
112
            );
113
        }
114
115 45
        $this->isComplete = $frame->isFinal();
116 45
        $this->frames[] = $frame;
117
118 45
        if ($this->isComplete()) {
119 41
            if (in_array($this->getFirstFrame()->getOpcode(), [Frame::OP_CLOSE, Frame::OP_TEXT]) && !mb_check_encoding($this->getContent(), 'UTF-8')) {
120 2
                throw new WrongEncodingException('The text is not encoded in UTF-8.');
121
            }
122
        }
123
124 43
        return $this;
125
    }
126
127
    /**
128
     * @return Frame
129
     * @throws MissingDataException
130
     */
131 41
    public function getFirstFrame() : Frame
132
    {
133 41
        if (empty($this->frames[0])) {
134
            throw new MissingDataException('There is no first frame for now.');
135
        }
136
137 41
        return $this->frames[0];
138
    }
139
140
    /**
141
     * This could in the future be deprecated in favor of a stream object.
142
     *
143
     * @return string
144
     * @throws MissingDataException
145
     */
146 26
    public function getContent() : string
147
    {
148 26
        if (!$this->isComplete) {
149 1
            throw new MissingDataException('The message is not complete. Frames are missing.');
150
        }
151
152 25
        $res = '';
153
154 25
        foreach ($this->frames as $frame) {
155 25
            $res .= $frame->getContent();
156
        }
157
158 25
        return $res;
159
    }
160
161
    /**
162
     * @return int
163
     */
164 19
    public function getOpcode()
165
    {
166 19
        return $this->getFirstFrame()->getOpcode();
167
    }
168
169
    /**
170
     * @return bool
171
     */
172 45
    public function isComplete()
173
    {
174 45
        return $this->isComplete;
175
    }
176
177
    /**
178
     * @return bool
179
     */
180
    public function isOperation()
181
    {
182
        return in_array($this->getFirstFrame()->getOpcode(), [Frame::OP_TEXT, Frame::OP_BINARY]);
183
    }
184
185
    /**
186
     * @return Frame[]
187
     */
188 4
    public function getFrames()
189
    {
190 4
        return $this->frames;
191
    }
192
193
    /**
194
     * @return bool
195
     */
196 11
    public function hasFrames()
197
    {
198 11
        return !empty($this->frames);
199
    }
200
201
    /**
202
     * @return int
203
     */
204
    public function countFrames() : int
205
    {
206
        return count($this->frames);
207
    }
208
209
    /**
210
     * @param array $config
211
     * @return Message
212
     */
213 51
    public function setConfig(array $config = [])
214
    {
215 51
        $this->config = array_merge([
216
            'maxMessagesBuffering' => Message::MAX_MESSAGES_BUFFERING
217 51
        ], $config);
218
        
219 51
        return $this;
220
    }
221
}
222