StreamSocket   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 60
c 3
b 0
f 0
dl 0
loc 154
ccs 55
cts 55
cp 1
rs 10
wmc 17

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getConnectTimeout() 0 3 1
A setConnectTimeout() 0 11 3
A isPersistent() 0 3 1
A getTransport() 0 3 1
A setTransport() 0 10 2
A __construct() 0 13 1
A createSocket() 0 22 3
A getSocket() 0 3 1
A getStreamFlags() 0 3 2
A getStreamContext() 0 3 1
A getStreamAddress() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\Japha\Bridge\Socket;
6
7
use Soluble\Japha\Bridge\Exception\ConnectionException;
8
use Soluble\Japha\Bridge\Exception\InvalidArgumentException;
9
10
class StreamSocket implements StreamSocketInterface
11
{
12
    public const TRANSPORT_SSL = 'ssl';
13
    public const TRANSPORT_TCP = 'tcp';
14
15
    public const REGISTERED_TRANSPORTS = [
16
        self::TRANSPORT_SSL,
17
        self::TRANSPORT_TCP
18
    ];
19
20
    public const DEFAULT_CONTEXT = [
21
        'http' => [
22
            'protocol_version' => '1.1',
23
        ]
24
    ];
25
26
    public const DEFAULT_CONNECT_TIMEOUTS = [
27
        'HOST_127.0.0.1' => 5.0,
28
        'HOST_localhost' => 5.0,
29
        'DEFAULT' => 20.0
30
    ];
31
32
    /**
33
     * @var resource
34
     */
35
    protected $socket;
36
37
    protected $persistent = false;
38
    protected $address;
39
    protected $connectTimeout;
40
    protected $streamContext;
41
    protected $transport;
42
43
    /**
44
     * @param string  $transport      tcp, ssl... see self::TRANSPORT
45
     * @param string  $address        ip:port
46
     * @param float   $connectTimeout connection timeout in seconds (double: i.e: 5.0)
47
     * @param mixed[] $streamContext  see stream_context_create()
48
     * @param bool    $persistent     whether to use persistent connections
49
     */
50 38
    public function __construct(
51
        string $transport,
52
        string $address,
53
        float $connectTimeout = null,
54
        array $streamContext = self::DEFAULT_CONTEXT,
55
        bool $persistent = false
56
    ) {
57 38
        $this->setTransport($transport);
58 37
        $this->address = $address;
59 37
        $this->setConnectTimeout($connectTimeout);
60 37
        $this->streamContext = $streamContext;
61 37
        $this->persistent = $persistent;
62 37
        $this->createSocket();
63 34
    }
64
65 37
    protected function setConnectTimeout(float $timeout = null): void
66
    {
67 37
        if ($timeout === null) {
68 33
            list($host) = explode(':', $this->address);
69 33
            if (array_key_exists("HOST_$host", self::DEFAULT_CONNECT_TIMEOUTS)) {
70 33
                $timeout = self::DEFAULT_CONNECT_TIMEOUTS["HOST_$host"];
71
            } else {
72 1
                $timeout = self::DEFAULT_CONNECT_TIMEOUTS['DEFAULT'];
73
            }
74
        }
75 37
        $this->connectTimeout = $timeout;
76 37
    }
77
78
    /**
79
     * @throws InvalidArgumentException when getting an unsupported transport
80
     */
81 38
    protected function setTransport(string $transport): void
82
    {
83 38
        if (!in_array($transport, self::REGISTERED_TRANSPORTS, true)) {
84 1
            throw new InvalidArgumentException(sprintf(
85 1
                'Unsupported transport "%s" given (supported: %s)',
86 1
                $transport,
87 1
                implode(',', array_keys(self::REGISTERED_TRANSPORTS))
88
            ));
89
        }
90 37
        $this->transport = $transport;
91 37
    }
92
93 35
    public function getTransport(): string
94
    {
95 35
        return $this->transport;
96
    }
97
98 1
    public function getConnectTimeout(): float
99
    {
100 1
        return $this->connectTimeout;
101
    }
102
103
    /**
104
     * @return resource php socket
105
     */
106 30
    public function getSocket()
107
    {
108 30
        return $this->socket;
109
    }
110
111 35
    public function getStreamAddress(): string
112
    {
113 35
        return sprintf('%s://%s', $this->getTransport(), $this->address);
114
    }
115
116
    /**
117
     * Whether the connection is persistent or not.
118
     *
119
     * @return bool
120
     */
121 1
    public function isPersistent(): bool
122
    {
123 1
        return $this->persistent;
124
    }
125
126
    /**
127
     * @throws ConnectionException
128
     */
129 35
    protected function createSocket(): void
130
    {
131 35
        $socket = @stream_socket_client(
132 35
            $this->getStreamAddress(),
133 35
            $errno,
134 35
            $errstr,
135 35
            $this->connectTimeout,
136 35
            $this->getStreamFlags(),
137 35
            $this->getStreamContext()
138
        );
139
140 35
        if ($socket === false || !is_resource($socket)) {
141 3
            $msg = sprintf(
142 3
                "Could not connect to the php-java-bridge server '%s'. Please start it. (err: %s, %s)",
143 3
                $this->address,
144 3
                $errno ?? 0,
145 3
                $errstr ?? 'Empty errstr returned'
146
            );
147 3
            throw new ConnectionException($msg);
148
        }
149
150 32
        $this->socket = $socket;
151 32
    }
152
153 35
    protected function getStreamFlags(): int
154
    {
155 35
        return $this->persistent ? STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT;
156
    }
157
158
    /**
159
     * @return resource
160
     */
161 35
    protected function getStreamContext()
162
    {
163 35
        return stream_context_create($this->streamContext);
164
    }
165
}
166