Completed
Branch 0.4-dev (d45f7e)
by Evgenij
02:39
created

SocketBag   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 206
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 97.78%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 2
dl 0
loc 206
ccs 88
cts 90
cp 0.9778
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A count() 0 4 1
B addSocket() 0 40 3
A getSocketOperation() 0 4 1
A setSocketOperation() 0 4 1
A hasSocket() 0 5 1
A removeSocket() 0 14 4
A postponeSocket() 0 9 2
A resetSpeedRateCounters() 0 4 1
A getSocketMetaData() 0 4 1
A setSocketMetaData() 0 21 2
A getOperationStorageKey() 0 4 1
A requireDescriptor() 0 9 2
A getItems() 0 4 1
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\SocketInterface;
18
19
/**
20
 * Class SocketBag
21
 */
22
class SocketBag implements SocketBagInterface
23
{
24
    /**
25
     * RequestExecutorInterface
26
     *
27
     * @var RequestExecutorInterface
28
     */
29
    private $executor;
30
31
    /**
32
     * Target metadata items
33
     *
34
     * @var RequestDescriptor[]
35
     */
36
    private $items;
37
38
    /**
39
     * Configuration
40
     *
41
     * @var Configuration
42
     */
43
    private $configuration;
44
45
    /**
46
     * SocketBag constructor.
47
     *
48
     * @param RequestExecutorInterface $executor Owner RequestExecutor
49
     * @param Configuration            $configuration Configuration with default values
50
     */
51 172
    public function __construct(RequestExecutorInterface $executor, Configuration $configuration)
52
    {
53 172
        $this->executor      = $executor;
54 172
        $this->items         = [];
55 172
        $this->configuration = $configuration;
56 172
    }
57
58
    /** {@inheritdoc} */
59 1
    public function count()
60
    {
61 1
        return count($this->items);
62
    }
63
64
65
    /** {@inheritdoc} */
66 160
    public function addSocket(
67
        SocketInterface $socket,
68
        OperationInterface $operation,
69
        array $metadata = null,
70
        EventHandlerInterface $eventHandlers = null
71
    ) {
72 160
        $hash = $this->getOperationStorageKey($socket);
73 160
        if (isset($this->items[$hash])) {
74 1
            throw new \LogicException('Can not add socket twice.');
75
        }
76
77 160
        $meta = array_merge(
78
            [
79 160
                RequestExecutorInterface::META_ADDRESS                    => null,
80 160
                RequestExecutorInterface::META_USER_CONTEXT               => null,
81 160
                RequestExecutorInterface::META_SOCKET_STREAM_CONTEXT      => $this->configuration->getStreamContext(),
82 160
                RequestExecutorInterface::META_MIN_RECEIVE_SPEED          => $this->configuration->getMinReceiveSpeed(),
83 160
                RequestExecutorInterface::META_MIN_RECEIVE_SPEED_DURATION =>
84 160
                                                                    $this->configuration->getMinReceiveSpeedDuration(),
85 160
                RequestExecutorInterface::META_MIN_SEND_SPEED             => $this->configuration->getMinSendSpeed(),
86 160
                RequestExecutorInterface::META_MIN_SEND_SPEED_DURATION    =>
87 160
                                                                    $this->configuration->getMinSendSpeedDuration(),
88 160
                RequestExecutorInterface::META_CONNECTION_TIMEOUT         => $this->configuration->getConnectTimeout(),
89 160
                RequestExecutorInterface::META_IO_TIMEOUT                 => $this->configuration->getIoTimeout(),
90 160
            ],
91 160
            $metadata ?: [],
92
            [
93 160
                RequestExecutorInterface::META_CONNECTION_START_TIME  => null,
94 160
                RequestExecutorInterface::META_CONNECTION_FINISH_TIME => null,
95 160
                RequestExecutorInterface::META_LAST_IO_START_TIME     => null,
96 160
                RequestExecutorInterface::META_BYTES_SENT             => 0,
97 160
                RequestExecutorInterface::META_BYTES_RECEIVED         => 0,
98 160
                RequestExecutorInterface::META_REQUEST_COMPLETE       => false,
99 160
                RequestExecutorInterface::META_RECEIVE_SPEED          => 0,
100 160
                RequestExecutorInterface::META_SEND_SPEED             => 0,
101
            ]
102 160
        );
103
104 160
        $this->items[$hash] = new RequestDescriptor($socket, $operation, $meta, $eventHandlers);
105 160
    }
106
107
    /** {@inheritdoc} */
108 1
    public function getSocketOperation(SocketInterface $socket)
109
    {
110 1
        return $this->requireDescriptor($socket)->getOperation();
111
    }
112
113
    /** {@inheritdoc} */
114 1
    public function setSocketOperation(SocketInterface $socket, OperationInterface $operation)
115
    {
116 1
        $this->requireDescriptor($socket)->setOperation($operation);
117 1
    }
118
119
    /** {@inheritdoc} */
120 3
    public function hasSocket(SocketInterface $socket)
121
    {
122 3
        $hash = $this->getOperationStorageKey($socket);
123 3
        return isset($this->items[$hash]);
124
    }
125
126
    /** {@inheritdoc} */
127 3
    public function removeSocket(SocketInterface $socket)
128
    {
129 3
        $key = $this->getOperationStorageKey($socket);
130 3
        if (!isset($this->items[$key])) {
131 1
            return;
132
        }
133
134 2
        $meta = $this->items[$key]->getMetadata();
135 2
        if (!$meta[RequestExecutorInterface::META_REQUEST_COMPLETE] && $this->executor->isExecuting()) {
136 1
            throw new \LogicException('Can not remove unprocessed socket during request processing.');
137
        }
138
139 1
        unset($this->items[$key]);
140 1
    }
141
142
    /** {@inheritdoc} */
143 1
    public function postponeSocket(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...
144
    {
145 1
        $key = $this->getOperationStorageKey($socket);
146 1
        if (!isset($this->items[$key])) {
147 1
            return;
148
        }
149
150
        $this->items[$key]->postpone();
151
    }
152
153
    /** {@inheritdoc} */
154 2
    public function resetSpeedRateCounters(SocketInterface $socket)
155
    {
156 2
        $this->requireDescriptor($socket)->resetCounter(RequestDescriptor::COUNTER_RECV_MIN_RATE);
157 1
    }
158
159
    /** {@inheritdoc} */
160 102
    public function getSocketMetaData(SocketInterface $socket)
161
    {
162 102
        return $this->requireDescriptor($socket)->getMetadata();
163
    }
164
165
    /** {@inheritdoc} */
166 17
    public function setSocketMetaData(SocketInterface $socket, $key, $value = null)
167
    {
168
        $writableKeys = [
169 17
            RequestExecutorInterface::META_ADDRESS                    => 1,
170 17
            RequestExecutorInterface::META_USER_CONTEXT               => 1,
171 17
            RequestExecutorInterface::META_CONNECTION_TIMEOUT         => 1,
172 17
            RequestExecutorInterface::META_IO_TIMEOUT                 => 1,
173 17
            RequestExecutorInterface::META_SOCKET_STREAM_CONTEXT      => 1,
174 17
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED          => 1,
175 17
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED_DURATION => 1,
176 17
            RequestExecutorInterface::META_MIN_SEND_SPEED             => 1,
177 17
            RequestExecutorInterface::META_MIN_SEND_SPEED_DURATION    => 1,
178 17
        ];
179
180 17
        if (!is_array($key)) {
181 17
            $key = [ $key => $value ];
182 17
        }
183
184 17
        $key = array_intersect_key($key, $writableKeys);
185 17
        $this->requireDescriptor($socket)->setMetadata($key);
186 17
    }
187
188
    /**
189
     * Return socket key in internal storage
190
     *
191
     * @param SocketInterface $socket Socket object
192
     *
193
     * @return string
194
     */
195 163
    private function getOperationStorageKey(SocketInterface $socket)
196
    {
197 163
        return spl_object_hash($socket);
198
    }
199
200
    /**
201
     * Require operation descriptor for given socket
202
     *
203
     * @param SocketInterface $socket Socket object
204
     *
205
     * @return RequestDescriptor
206
     * @throws \OutOfBoundsException
207
     */
208 105
    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...
209
    {
210 105
        $hash = $this->getOperationStorageKey($socket);
211 105
        if (!isset($this->items[$hash])) {
212 2
            throw new \OutOfBoundsException('Trying to perform operation on not added socket.');
213
        }
214
215 103
        return $this->items[$hash];
216
    }
217
218
    /**
219
     * Return metadata items
220
     *
221
     * @return RequestDescriptor[]
222
     */
223 136
    public function getItems()
224
    {
225 136
        return $this->items;
226
    }
227
}
228