DockerRawStream::onStdout()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Docker\Stream;
4
5
use Psr\Http\Message\StreamInterface;
6
7
class DockerRawStream
8
{
9
    const HEADER = 'application/vnd.docker.raw-stream';
10
11
    /** @var StreamInterface Stream for the response */
12
    protected $stream;
13
14
    /** @var callable[] A list of callable to call when there is a stdin output */
15
    protected $onStdinCallables = [];
16
17
    /** @var callable[] A list of callable to call when there is a stdout output */
18
    protected $onStdoutCallables = [];
19
20
    /** @var callable[] A list of callable to call when there is a stderr output */
21
    protected $onStderrCallables = [];
22
23 2
    public function __construct(StreamInterface $stream)
24
    {
25 2
        $this->stream = $stream;
26 2
    }
27
28
    /**
29
     * Add a callable to read stdin
30
     *
31
     * @param callable $callback
32
     */
33
    public function onStdin(callable $callback)
34
    {
35
        $this->onStdinCallables[] = $callback;
36
    }
37
38
    /**
39
     * Add a callable to read stdout
40
     *
41
     * @param callable $callback
42
     */
43 2
    public function onStdout(callable $callback)
44
    {
45 2
        $this->onStdoutCallables[] = $callback;
46 2
    }
47
48
    /**
49
     * Add a callable to read stderr
50
     *
51
     * @param callable $callback
52
     */
53
    public function onStderr(callable $callback)
54
    {
55
        $this->onStderrCallables[] = $callback;
56
    }
57
58
    /**
59
     * Read a frame in the stream
60
     */
61 2
    protected function readFrame()
62
    {
63 2
        $header  = $this->forceRead(8);
64
65 2
        if (strlen($header) < 8) {
66
            return;
67
        }
68
69 2
        $decoded = unpack('C1type/C3/N1size', $header);
70 2
        $output  = $this->forceRead($decoded['size']);
71 2
        $callbackList = [];
72
73 2
        if ($decoded['type'] == 0) {
74
            $callbackList = $this->onStdinCallables;
75
        }
76
77 2
        if ($decoded['type'] == 1) {
78 2
            $callbackList = $this->onStdoutCallables;
79 2
        }
80
81 2
        if ($decoded['type'] == 2) {
82
            $callbackList = $this->onStderrCallables;
83
        }
84
85 2
        foreach ($callbackList as $callback) {
86 2
            $callback($output);
87 2
        }
88 2
    }
89
90
    /**
91
     * Force to have something of the expected size (block)
92
     *
93
     * @param $length
94
     *
95
     * @return string
96
     */
97 2
    private function forceRead($length)
98
    {
99 2
        $read = "";
100
101
        do {
102 2
            $read .= $this->stream->read($length - strlen($read));
103 2
        } while (strlen($read) < $length && !$this->stream->eof());
104
105 2
        return $read;
106
    }
107
108
    /**
109
     * Wait for stream to finish and call callables if defined
110
     */
111 2
    public function wait()
112
    {
113 2
        while (!$this->stream->eof()) {
114 2
            $this->readFrame();
115 2
        }
116 2
    }
117
}
118