Completed
Push — master ( e22f7e...4537c6 )
by Evgenij
06:03
created

SocketBag::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
crap 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 resetTransferRateCounters(SocketInterface $socket)
155
    {
156 2
        $descriptor = $this->requireDescriptor($socket);
157 1
        $descriptor->resetCounter(RequestDescriptor::COUNTER_RECV_MIN_RATE);
158 1
        $descriptor->resetCounter(RequestDescriptor::COUNTER_SEND_MIN_RATE);
159 1
    }
160
161
    /** {@inheritdoc} */
162 102
    public function getSocketMetaData(SocketInterface $socket)
163
    {
164 102
        return $this->requireDescriptor($socket)->getMetadata();
165
    }
166
167
    /** {@inheritdoc} */
168 17
    public function setSocketMetaData(SocketInterface $socket, $key, $value = null)
169
    {
170
        $writableKeys = [
171 17
            RequestExecutorInterface::META_ADDRESS                    => 1,
172 17
            RequestExecutorInterface::META_USER_CONTEXT               => 1,
173 17
            RequestExecutorInterface::META_CONNECTION_TIMEOUT         => 1,
174 17
            RequestExecutorInterface::META_IO_TIMEOUT                 => 1,
175 17
            RequestExecutorInterface::META_SOCKET_STREAM_CONTEXT      => 1,
176 17
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED          => 1,
177 17
            RequestExecutorInterface::META_MIN_RECEIVE_SPEED_DURATION => 1,
178 17
            RequestExecutorInterface::META_MIN_SEND_SPEED             => 1,
179 17
            RequestExecutorInterface::META_MIN_SEND_SPEED_DURATION    => 1,
180 17
        ];
181
182 17
        if (!is_array($key)) {
183 17
            $key = [ $key => $value ];
184 17
        }
185
186 17
        $key = array_intersect_key($key, $writableKeys);
187 17
        $this->requireDescriptor($socket)->setMetadata($key);
188 17
    }
189
190
    /**
191
     * Return socket key in internal storage
192
     *
193
     * @param SocketInterface $socket Socket object
194
     *
195
     * @return string
196
     */
197 163
    private function getOperationStorageKey(SocketInterface $socket)
198
    {
199 163
        return spl_object_hash($socket);
200
    }
201
202
    /**
203
     * Require operation descriptor for given socket
204
     *
205
     * @param SocketInterface $socket Socket object
206
     *
207
     * @return RequestDescriptor
208
     * @throws \OutOfBoundsException
209
     */
210 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...
211
    {
212 105
        $hash = $this->getOperationStorageKey($socket);
213 105
        if (!isset($this->items[$hash])) {
214 2
            throw new \OutOfBoundsException('Trying to perform operation on not added socket.');
215
        }
216
217 103
        return $this->items[$hash];
218
    }
219
220
    /**
221
     * Return metadata items
222
     *
223
     * @return RequestDescriptor[]
224
     */
225 136
    public function getItems()
226
    {
227 136
        return $this->items;
228
    }
229
}
230