Client   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 9
Bugs 2 Features 0
Metric Value
wmc 25
c 9
b 2
f 0
lcom 1
cbo 2
dl 0
loc 211
ccs 0
cts 118
cp 0
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A execute() 0 14 2
A executeRequest() 0 17 1
A verifyStatusCode() 0 11 2
A reset() 0 4 1
A openSocket() 0 16 4
A openUnixSocket() 0 15 3
A openTcpSocket() 0 17 3
A setSocketTimeout() 0 7 2
A closeSocket() 0 7 2
A readSocket() 0 21 4
1
<?php
2
namespace Kwkm\MkLiveStatusClient;
3
4
use \RuntimeException;
5
6
/**
7
 * Class Client
8
 *
9
 * @package Kwkm\MkLiveStatusClient
10
 * @author Takehiro Kawakami <[email protected]>
11
 * @license MIT
12
 */
13
class Client
14
{
15
    /**
16
     * 設定
17
     * @var Configuration
18
     * @link http://php.net/manual/en/function.socket-set-option.php
19
     */
20
    protected $config;
21
22
    /**
23
     * ソケットのリソース
24
     * @var resource
25
     */
26
    protected $socket = null;
27
28
    /**
29
     * コンストラクタ
30
     *
31
     * @param Configuration $conf
32
     * @throw \BadFunctionCallException
33
     * @throw \InvalidArgumentException
34
     */
35
    public function __construct(Configuration $conf)
36
    {
37
        $this->config = $conf;
38
39
        $this->reset();
40
    }
41
42
    /**
43
     * Lqlの実行
44
     *
45
     * @param \Kwkm\MkLiveStatusClient\LqlAbstract $lql
46
     * @return array
47
     * @throw \RuntimeException
48
     */
49
    public function execute(LqlAbstract $lql)
50
    {
51
        $result = $this->executeRequest($lql->build());
52
53
        $this->verifyStatusCode($result);
54
55
        $response = utf8_encode($result['response']);
56
57
        if (is_null($response)) {
58
            throw new RuntimeException("The response was invalid.");
59
        }
60
61
        return $response;
62
    }
63
64
    /**
65
     * リクエストの発行
66
     * @param $query
67
     * @return array
68
     */
69
    private function executeRequest($query)
70
    {
71
        $this->openSocket();
72
        socket_write($this->socket, $query);
73
        // Read 16 bytes to get the status code and body size
74
        $header = $this->readSocket(16);
75
        $status = substr($header, 0, 3);
76
        $length = intval(trim(substr($header, 4, 11)));
77
        $response = $this->readSocket($length);
78
        $this->closeSocket();
79
80
        return array(
81
            'status' => $status,
82
            'length' => $length,
83
            'response' => $response,
84
        );
85
    }
86
87
    /**
88
     * ステータスコードの確認
89
     * @param $response
90
     */
91
    private function verifyStatusCode($response)
92
    {
93
        // Check for errors. A 200 response means request was OK.
94
        // Any other response is a failure.
95
        if ($response['status'] != "200") {
96
            throw new RuntimeException(
97
                "Error response from Nagios MK Livestatus: " . $response['status'],
98
                (int) $response['status']
99
            );
100
        }
101
    }
102
103
    /**
104
     * リセット処理
105
     */
106
    public function reset()
107
    {
108
        $this->closeSocket();
109
    }
110
111
    /**
112
     * 接続の開始
113
     *
114
     * @throw \RuntimeException
115
     */
116
    protected function openSocket()
117
    {
118
        if (!is_null($this->socket)) {
119
            // Assume socket still good and continue
120
            return;
121
        }
122
123
        switch ($this->config->socketType) {
124
            case 'unix':
125
                $this->openUnixSocket();
126
                break;
127
            case 'tcp':
128
                $this->openTcpSocket();
129
                break;
130
        }
131
    }
132
133
    /**
134
     * Unixソケットの接続を開始
135
     */
136
    private function openUnixSocket()
137
    {
138
        $this->socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
139
        if (!$this->socket) {
140
            $this->socket = null;
141
            throw new RuntimeException("Could not create socket.");
142
        }
143
144
        if (false === socket_connect($this->socket, $this->config->socketPath)) {
145
            $this->closeSocket();
146
            throw new RuntimeException("Unable to connect to socket.");
147
        }
148
149
        $this->setSocketTimeout();
150
    }
151
152
    /**
153
     * Tcpソケットの接続を開始
154
     */
155
    private function openTcpSocket()
156
    {
157
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
158
        if (!$this->socket) {
159
            $this->socket = null;
160
            throw new RuntimeException("Could not create socket.");
161
        }
162
163
        if (false === socket_connect($this->socket, $this->config->socketAddress, $this->config->socketPort)) {
164
            $this->closeSocket();
165
            throw new RuntimeException("Unable to connect to socket.");
166
        }
167
168
        socket_set_option($this->socket, SOL_TCP, TCP_NODELAY, 1);
169
170
        $this->setSocketTimeout();
171
    }
172
173
    /**
174
     * ソケットタイムアウトの設定
175
     */
176
    private function setSocketTimeout()
177
    {
178
        if (count($this->config->socketTimeout) !== 0) {
179
            socket_set_option($this->socket, SOCK_STREAM, SO_RCVTIMEO, $this->config->socketTimeout);
180
            socket_set_option($this->socket, SOCK_STREAM, SO_SNDTIMEO, $this->config->socketTimeout);
181
        }
182
    }
183
184
    /**
185
     * 接続の切断
186
     */
187
    protected function closeSocket()
188
    {
189
        if (is_resource($this->socket)) {
190
            socket_close($this->socket);
191
        }
192
        $this->socket = null;
193
    }
194
195
    /**
196
     * ソケットの読み出し
197
     *
198
     * @param integer $length
199
     * @return string
200
     * @throw \RuntimeException
201
     */
202
    protected function readSocket($length)
203
    {
204
        $offset = 0;
205
        $socketData = "";
206
        while ($offset < $length) {
207
            if (false === ($data = socket_read($this->socket, $length - $offset))) {
208
                throw new RuntimeException(
209
                    "Problem reading from socket: "
210
                    . socket_strerror(socket_last_error($this->socket))
211
                );
212
            }
213
            $dataLen = strlen($data);
214
            $offset += $dataLen;
215
            $socketData .= $data;
216
            if ($dataLen == 0) {
217
                break;
218
            }
219
        }
220
221
        return $socketData;
222
    }
223
}
224