Completed
Branch master (1d1574)
by Evgenij
18:38
created

WriteIoHandler::writeDataToSocket()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 30
ccs 20
cts 20
cp 1
rs 8.439
cc 5
eloc 19
nc 6
nop 3
crap 5
1
<?php
2
/**
3
 * Async sockets
4
 *
5
 * @copyright Copyright (c) 2015-2016, 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\Pipeline;
11
12
use AsyncSockets\Event\WriteEvent;
13
use AsyncSockets\RequestExecutor\EventHandlerInterface;
14
use AsyncSockets\Operation\InProgressWriteOperation;
15
use AsyncSockets\RequestExecutor\IoHandlerInterface;
16
use AsyncSockets\Operation\OperationInterface;
17
use AsyncSockets\RequestExecutor\RequestExecutorInterface;
18
use AsyncSockets\Operation\WriteOperation;
19
use AsyncSockets\Socket\SocketInterface;
20
21
/**
22
 * Class WriteIoHandler
23
 */
24
class WriteIoHandler implements IoHandlerInterface
25
{
26
    /** {@inheritdoc} */
27 38
    public function supports(OperationInterface $operation)
28
    {
29 38
        return ($operation instanceof WriteOperation) || ($operation instanceof InProgressWriteOperation);
30
    }
31
32
    /** {@inheritdoc} */
33 42
    public function handle(
34
        OperationInterface $operation,
35
        SocketInterface $socket,
36
        RequestExecutorInterface $executor,
37
        EventHandlerInterface $eventHandler
38
    ) {
39
        /** @var WriteOperation $operation */
40 42
        $fireEvent = !($operation instanceof InProgressWriteOperation);
41
42 42
        if ($fireEvent) {
43 41
            $meta  = $executor->socketBag()->getSocketMetaData($socket);
44 41
            $event = new WriteEvent(
45 41
                $operation,
46 41
                $executor,
47 41
                $socket,
48 41
                $meta[ RequestExecutorInterface::META_USER_CONTEXT ]
49 41
            );
50 41
            $eventHandler->invokeEvent($event);
51 30
            $nextOperation = $event->getNextOperation();
52 30
        } else {
53 1
            $nextOperation = $operation;
54
        }
55
56 31
        return $this->writeDataToSocket($operation, $socket, $nextOperation);
57
    }
58
59
    /**
60
     * Perform data writing to socket and return suitable next socket operation
61
     *
62
     * @param WriteOperation     $operation Current write operation instance
63
     * @param SocketInterface    $socket Socket object
64
     * @param OperationInterface $nextOperation Desirable next operation
65
     *
66
     * @return OperationInterface Actual next operation
67
     */
68 31
    private function writeDataToSocket(
69
        WriteOperation $operation,
70
        SocketInterface $socket,
71
        OperationInterface $nextOperation = null
72
    ) {
73 31
        $result               = $nextOperation;
74 31
        $extractNextOperation = true;
75 31
        if ($operation->hasData()) {
76 9
            $data    = $operation->getData();
77 9
            $length  = strlen($data);
78 9
            $written = $socket->write($data);
79 6
            if ($length !== $written) {
80 2
                $extractNextOperation = false;
81
82 2
                $operation = $this->makeInProgressWriteOperation($operation, $nextOperation);
83 2
                $operation->setData(
84 2
                    substr($operation->getData(), $written)
85 2
                );
86
87 2
                $result = $operation;
88 2
            }
89 6
        }
90
91 28
        if ($extractNextOperation && ($operation instanceof InProgressWriteOperation)) {
92
            /** @var InProgressWriteOperation $operation */
93 1
            $result = $operation->getNextOperation();
94 1
        }
95
96 28
        return $result;
97
    }
98
99
    /**
100
     * Marks write operation as in progress
101
     *
102
     * @param WriteOperation     $operation Current operation object
103
     * @param OperationInterface $nextOperation Next planned operation
104
     *
105
     * @return InProgressWriteOperation Next operation object
106
     */
107 2
    private function makeInProgressWriteOperation(WriteOperation $operation, OperationInterface $nextOperation = null)
108
    {
109 2
        $result = $operation;
110 2
        if (!($result instanceof InProgressWriteOperation)) {
111 2
            $result = new InProgressWriteOperation($nextOperation, $operation->getData());
112 2
        }
113
114 2
        return $result;
115
    }
116
}
117