Completed
Push — master ( c97103...9edfc5 )
by Evgenij
03:08
created

SocketBag::requireDescriptor()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Async sockets
4
 *
5
 * @copyright Copyright (c) 2015-2017, Efimov Evgenij <[email protected]>
6
 *
7
 * This source file is subject to the MIT license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
namespace AsyncSockets\RequestExecutor\Metadata;
11
12
use AsyncSockets\Configuration\Configuration;
13
use AsyncSockets\Operation\OperationInterface;
14
use AsyncSockets\RequestExecutor\EventHandlerInterface;
15
use AsyncSockets\RequestExecutor\RequestExecutorInterface;
16
use AsyncSockets\RequestExecutor\SocketBagInterface;
17
use AsyncSockets\Socket\PersistentClientSocket;
18
use AsyncSockets\Socket\SocketInterface;
19
20
/**
21
 * Class SocketBag
22
 */
23
class SocketBag implements SocketBagInterface
24
{
25
    /**
26
     * RequestExecutorInterface
27
     *
28
     * @var RequestExecutorInterface
29
     */
30
    private $executor;
31
32
    /**
33
     * Target metadata items
34
     *
35
     * @var RequestDescriptor[]
36
     */
37
    private $items;
38
39
    /**
40
     * Configuration
41
     *
42
     * @var Configuration
43
     */
44
    private $configuration;
45
46
    /**
47
     * SocketBag constructor.
48
     *
49
     * @param RequestExecutorInterface $executor Owner RequestExecutor
50
     * @param Configuration            $configuration Configuration with default values
51
     */
52 175
    public function __construct(RequestExecutorInterface $executor, Configuration $configuration)
53
    {
54 175
        $this->executor      = $executor;
55 175
        $this->items         = [];
56 175
        $this->configuration = $configuration;
57 175
    }
58
59
    /** {@inheritdoc} */
60 1
    public function count()
61
    {
62 1
        return count($this->items);
63
    }
64
65
66
    /** {@inheritdoc} */
67 163
    public function addSocket(
68
        SocketInterface $socket,
69
        OperationInterface $operation,
70
        array $metadata = null,
71
        EventHandlerInterface $eventHandlers = null
72
    ) {
73 163
        $hash = $this->getOperationStorageKey($socket);
74 163
        if (isset($this->items[$hash])) {
75 1
            throw new \LogicException('Can not add socket twice.');
76
        }
77
78 163
        $meta = array_merge(
79
            [
80 163
                RequestExecutorInterface::META_ADDRESS                    => null,
81 163
                RequestExecutorInterface::META_USER_CONTEXT               => null,
82 163
                RequestExecutorInterface::META_SOCKET_STREAM_CONTEXT      => $this->configuration->getStreamContext(),
83 163
                RequestExecutorInterface::META_MIN_RECEIVE_SPEED          => $this->configuration->getMinReceiveSpeed(),
84 163
                RequestExecutorInterface::META_MIN_RECEIVE_SPEED_DURATION =>
85 163
                                                                    $this->configuration->getMinReceiveSpeedDuration(),
86 163
                RequestExecutorInterface::META_MIN_SEND_SPEED             => $this->configuration->getMinSendSpeed(),
87 163
                RequestExecutorInterface::META_MIN_SEND_SPEED_DURATION    =>
88 163
                                                                    $this->configuration->getMinSendSpeedDuration(),
89 163
                RequestExecutorInterface::META_CONNECTION_TIMEOUT         => $this->configuration->getConnectTimeout(),
90 163
                RequestExecutorInterface::META_IO_TIMEOUT                 => $this->configuration->getIoTimeout(),
91 163
                RequestExecutorInterface::META_KEEP_ALIVE                 => $socket instanceof PersistentClientSocket,
92 163
            ],
93 163
            $metadata ?: [],
94
            [
95 163
                RequestExecutorInterface::META_CONNECTION_START_TIME  => null,
96 163
                RequestExecutorInterface::META_CONNECTION_FINISH_TIME => null,
97 163
                RequestExecutorInterface::META_LAST_IO_START_TIME     => null,
98 163
                RequestExecutorInterface::META_BYTES_SENT             => 0,
99 163
                RequestExecutorInterface::META_BYTES_RECEIVED         => 0,
100 163
                RequestExecutorInterface::META_REQUEST_COMPLETE       => false,
101 163
                RequestExecutorInterface::META_RECEIVE_SPEED          => 0,
102 163
                RequestExecutorInterface::META_SEND_SPEED             => 0,
103
            ]
104 163
        );
105
106 163
        $this->items[$hash] = new RequestDescriptor($socket, $operation, $meta, $eventHandlers);
107 163
    }
108
109
    /** {@inheritdoc} */
110 1
    public function getSocketOperation(SocketInterface $socket)
111
    {
112 1
        return $this->requireDescriptor($socket)->getOperation();
113
    }
114
115
    /** {@inheritdoc} */
116 1
    public function setSocketOperation(SocketInterface $socket, OperationInterface $operation)
117
    {
118 1
        $this->requireDescriptor($socket)->setOperation($operation);
119 1
    }
120
121
    /** {@inheritdoc} */
122 3
    public function hasSocket(SocketInterface $socket)
123
    {
124 3
        $hash = $this->getOperationStorageKey($socket);
125 3
        return isset($this->items[$hash]);
126
    }
127
128
    /** {@inheritdoc} */
129 3
    public function removeSocket(SocketInterface $socket)
130
    {
131 3
        $key = $this->getOperationStorageKey($socket);
132 3
        if (!isset($this->items[$key])) {
133 1
            return;
134
        }
135
136 2
        $meta = $this->items[$key]->getMetadata();
137 2
        if (!$meta[RequestExecutorInterface::META_REQUEST_COMPLETE] && $this->executor->isExecuting()) {
138 1
            throw new \LogicException('Can not remove unprocessed socket during request processing.');
139
        }
140
141 1
        unset($this->items[$key]);
142 1
    }
143
144
    /** {@inheritdoc} */
145 1
    public function forgetSocket(SocketInterface $socket)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
    {
147 1
        $key = $this->getOperationStorageKey($socket);
148 1
        if (!isset($this->items[$key])) {
149 1
            return;
150
        }
151
152
        $this->items[$key]->forget();
153
    }
154
155
    /** {@inheritdoc} */
156 2
    public function resetTransferRateCounters(SocketInterface $socket)
157
    {
158 2
        $descriptor = $this->requireDescriptor($socket);
159 1
        $descriptor->resetCounter(RequestDescriptor::COUNTER_RECV_MIN_RATE);
160 1
        $descriptor->resetCounter(RequestDescriptor::COUNTER_SEND_MIN_RATE);
161 1
    }
162
163
    /** {@inheritdoc} */
164 105
    public function getSocketMetaData(SocketInterface $socket)
165
    {
166 105
        return $this->requireDescriptor($socket)->getMetadata();
167
    }
168
169
    /** {@inheritdoc} */
170 18
    public function setSocketMetaData(SocketInterface $socket, $key, $value = null)
171
    {
172
        $writableKeys = [
173 18
            RequestExecutorInterface::META_ADDRESS                    => 1,
174 18
            RequestExecutorInterface::META_USER_CONTEXT               => 1,
175 18
            RequestExecutorInterface::META_CONNECTION_TIMEOUT         => 1,
176 18
            RequestExecutorInterface::META_IO_TIMEOUT                 => 1,
177 18
            RequestExecutorInterface::META_SOCKET_STREAM_CONTEXT      => 1,
178 18
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED          => 1,
179 18
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED_DURATION => 1,
180 18
            RequestExecutorInterface::META_MIN_SEND_SPEED             => 1,
181 18
            RequestExecutorInterface::META_MIN_SEND_SPEED_DURATION    => 1,
182 18
            RequestExecutorInterface::META_KEEP_ALIVE                 => 1,
183 18
        ];
184
185 18
        if (!is_array($key)) {
186 18
            $key = [ $key => $value ];
187 18
        }
188
189 18
        $key = array_intersect_key($key, $writableKeys);
190 18
        $this->requireDescriptor($socket)->setMetadata($key);
191 18
    }
192
193
    /**
194
     * Return socket key in internal storage
195
     *
196
     * @param SocketInterface $socket Socket object
197
     *
198
     * @return string
199
     */
200 166
    private function getOperationStorageKey(SocketInterface $socket)
201
    {
202 166
        return spl_object_hash($socket);
203
    }
204
205
    /**
206
     * Require operation descriptor for given socket
207
     *
208
     * @param SocketInterface $socket Socket object
209
     *
210
     * @return RequestDescriptor
211
     * @throws \OutOfBoundsException
212
     */
213 108
    private function requireDescriptor(SocketInterface $socket)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214
    {
215 108
        $hash = $this->getOperationStorageKey($socket);
216 108
        if (!isset($this->items[$hash])) {
217 2
            throw new \OutOfBoundsException('Trying to perform operation on not added socket.');
218
        }
219
220 106
        return $this->items[$hash];
221
    }
222
223
    /**
224
     * Return metadata items
225
     *
226
     * @return RequestDescriptor[]
227
     */
228 136
    public function getItems()
229
    {
230 136
        return $this->items;
231
    }
232
}
233