Completed
Push — master ( 41a3d7...798a98 )
by John
04:27
created

TelnetClient::factory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
ccs 0
cts 7
cp 0
rs 9.4285
cc 1
eloc 5
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * This file is part of graze/telnet-client.
5
 *
6
 * Copyright (c) 2016 Nature Delivered Ltd. <https://www.graze.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @license https://github.com/graze/telnet-client/blob/master/LICENSE
12
 * @link https://github.com/graze/telnet-client
13
 */
14
15
namespace Graze\TelnetClient;
16
17
use \Graze\TelnetClient\TelnetClientInterface;
18
use \Graze\TelnetClient\PromptMatcher;
19
use \Graze\TelnetClient\InterpretAsCommand;
20
use \Socket\Raw\Socket;
21
use \Socket\Raw\Factory as SocketFactory;
22
use \Graze\TelnetClient\TelnetClientBuilder;
23
24
class TelnetClient implements TelnetClientInterface
25
{
26
    /**
27
     * @var SocketFactory
28
     */
29
    protected $socketFactory;
30
31
    /**
32
     * @var PromptMatcher
33
     */
34
    protected $promptMatcher;
35
36
    /**
37
     * @var InterpretAsCommand
38
     */
39
    protected $interpretAsCommand;
40
41
    /**
42
     * @var string
43
     */
44
    protected $prompt = '\$';
45
46
    /**
47
     * @var string
48
     */
49
    protected $promptError = 'ERROR';
50
51
    /**
52
     * @var string
53
     */
54
    protected $lineEnding = "\n";
55
56
    /**
57
     * @var Socket
58
     */
59
    protected $socket;
60
61
    /**
62
     * @var string
63
     */
64
    protected $buffer;
65
66
    /**
67
     * @var string
68
     */
69
    protected $NULL;
70
71
    /**
72
     * @var string
73
     */
74
    protected $DC1;
75
76
    /**
77
     * @var string
78
     */
79
    protected $IAC;
80
81
    /**
82
     * @param SocketFactory $socketFactory
83
     * @param PromptMatcher $promptMatcher
84
     * @param InterpretAsCommand $interpretAsCommand
85
     */
86 9
    public function __construct(
87
        SocketFactory $socketFactory,
88
        PromptMatcher $promptMatcher,
89
        InterpretAsCommand $interpretAsCommand
90
    ) {
91 9
        $this->socketFactory = $socketFactory;
92 9
        $this->promptMatcher = $promptMatcher;
93 9
        $this->interpretAsCommand = $interpretAsCommand;
94
95 9
        $this->NULL = chr(0);
96 9
        $this->DC1 = chr(17);
97 9
    }
98
99
    /**
100
     * @param string $dsn
101
     * @param string $prompt
102
     * @param string $promptError
103
     * @param string $lineEnding
104
     */
105 9
    public function connect($dsn, $prompt = null, $promptError = null, $lineEnding = null)
106
    {
107 9
        if ($prompt !== null) {
108 2
            $this->setPrompt($prompt);
109 2
        }
110
111 9
        if ($promptError !== null) {
112 2
            $this->setPromptError($promptError);
113 2
        }
114
115 9
        if ($lineEnding !== null) {
116 8
            $this->setLineEnding($lineEnding);
117 8
        }
118
119 9
        $this->setSocket($this->socketFactory->createClient($dsn));
120 9
    }
121
122
    /**
123
     * @param string $prompt
124
     */
125 1
    public function setPrompt($prompt)
126
    {
127 1
        $this->prompt = $prompt;
128 1
    }
129
130
    /**
131
     * @param string $promptError
132
     */
133 1
    public function setPromptError($promptError)
134
    {
135 1
        $this->promptError = $promptError;
136 1
    }
137
138
    /**
139
     * @param string $lineEnding
140
     */
141 7
    public function setLineEnding($lineEnding)
142
    {
143 7
        $this->lineEnding = $lineEnding;
144 7
    }
145
146
    /**
147
     * @param Socket $socket
148
     */
149 7
    public function setSocket(Socket $socket)
150
    {
151 7
        $this->socket = $socket;
152 7
    }
153
154
    /**
155
     * @param string $command
156
     * @param string $prompt
157
     *
158
     * @return \Graze\TelnetClient\TelnetResponseInterface
159
     */
160 7
    public function execute($command, $prompt = null)
161
    {
162 7
        $this->write($command);
163 7
        return $this->getResponse($prompt);
164
    }
165
166
    /**
167
     * @param string $command
168
     *
169
     * @return void
170
     */
171 7
    protected function write($command)
172
    {
173 7
        $this->socket->write($command . $this->lineEnding);
174 7
    }
175
176
    /**
177
     * @param string $prompt
178
     *
179
     * @return \Graze\TelnetClient\TelnetResponseInterface
180
     */
181 7
    protected function getResponse($prompt = null)
182
    {
183 7
        $isError = false;
184 7
        $buffer = '';
185
        do {
186
            // process one character at a time (RFC 854 states 8-bit ASCII characters)
187 7
            $character = $this->socket->read(1);
188
189 7
            if (in_array($character, [$this->NULL, $this->DC1])) {
190
                break;
191
            }
192
193 7
            if ($this->interpretAsCommand->interpret($character, $this->socket)) {
194
                continue;
195
            }
196
197 7
            $buffer .= $character;
198
199
            // check for prompt
200 7
            if ($this->promptMatcher->isMatch($prompt ?: $this->prompt, $buffer, $this->lineEnding)) {
201 4
                break;
202
            }
203
204
            // check for error prompt
205 7
            if ($this->promptMatcher->isMatch($this->promptError, $buffer, $this->lineEnding)) {
206 3
                $isError = true;
207 3
                break;
208
            }
209
210 7
        } while (true);
211
212 7
        return new TelnetResponse(
213 7
            $isError,
214 7
            $this->promptMatcher->getResponseText(),
215 7
            $this->promptMatcher->getMatches()
216 7
        );
217
    }
218
219
220
    /**
221
     * @return TelnetClientInterface
222
     */
223
    public static function factory()
224
    {
225
        new static(
226
            new SocketFactory(),
227
            new PromptMatcher(),
228
            new InterpretAsCommand()
229
        );
230
    }
231
232 7
    public function __destruct()
233
    {
234 7
        if (!$this->socket) {
235
            return;
236
        }
237
238 7
        $this->socket->close();
239 7
    }
240
}
241