Completed
Push — master ( e26ab3...1dd3f4 )
by Maxime
9s
created

WebSocketClient   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 14
dl 0
loc 136
ccs 0
cts 70
cp 0
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A start() 0 16 3
A setConfig() 0 12 1
A getConnectorFactory() 0 18 4
A getLoop() 0 8 2
A getMessageProcessor() 0 19 2
1
<?php
2
3
/**
4
 * This file is a part of Woketo package.
5
 *
6
 * (c) Nekland <[email protected]>
7
 *
8
 * For the full license, take a look to the LICENSE file
9
 * on the root directory of this project
10
 */
11
12
namespace Nekland\Woketo\Client;
13
14
use Nekland\Woketo\Http\Url;
15
use Nekland\Woketo\Message\MessageHandlerInterface;
16
use Nekland\Woketo\Rfc6455\FrameFactory;
17
use Nekland\Woketo\Rfc6455\MessageFactory;
18
use Nekland\Woketo\Rfc6455\MessageHandler\CloseFrameHandler;
19
use Nekland\Woketo\Rfc6455\MessageHandler\PingFrameHandler;
20
use Nekland\Woketo\Rfc6455\MessageHandler\RsvCheckFrameHandler;
21
use Nekland\Woketo\Rfc6455\MessageHandler\WrongOpcodeHandler;
22
use Nekland\Woketo\Rfc6455\MessageProcessor;
23
use React\EventLoop\Factory as LoopFactory;
24
use React\EventLoop\LoopInterface;
25
26
class WebSocketClient
27
{
28
    /**
29
     * @var Url
30
     */
31
    private $url;
32
33
    /**
34
     * @var array
35
     */
36
    private $config;
37
38
    /**
39
     * @var Connection
40
     */
41
    private $connection;
42
43
    /**
44
     * @var ConnectorFactoryInterface
45
     */
46
    private $connectorFactory;
47
48
    /**
49
     * @var LoopInterface
50
     */
51
    private $loop;
52
53
    /**
54
     * @var MessageProcessor
55
     */
56
    private $messageProcessor;
57
58
    public function __construct(string $url, array $config = [], ConnectorFactoryInterface $connectorFactory = null)
59
    {
60
        $this->url = new Url($url);
61
        $this->connectorFactory = $connectorFactory;
62
        $this->setConfig($config);
63
    }
64
65
    /**
66
     * @param MessageHandlerInterface $handler
67
     * @throws \Exception
68
     */
69
    public function start(MessageHandlerInterface $handler)
70
    {
71
        if ($this->config['prod'] && \extension_loaded('xdebug')) {
72
            throw new \Exception('xdebug is enabled, it\'s a performance issue. Disable that extension or specify "prod" option to false.');
73
        }
74
75
        $this->connection = new Connection(
76
            $this->url,
77
            $this->getConnectorFactory()->createConnector()->connect($this->url->getHost() . ':' . $this->url->getPort()),
78
            $this->getMessageProcessor(),
79
            $handler,
80
            $this->loop
81
        );
82
83
        $this->loop->run();
84
    }
85
86
    /**
87
     * @param array $config
88
     * @return self
89
     */
90
    public function setConfig(array $config = [])
91
    {
92
        $this->config = array_merge([
93
            'frame' => [],
94
            'message' => [],
95
            'prod' => true,
96
            'ssl' => [],
97
            'dns' => null,
98
        ], $config);
99
100
        return $this;
101
    }
102
103
    /**
104
     * Creates a connector factory with the given configuration if none given in the constructor.
105
     *
106
     * @return ConnectorFactoryInterface
107
     */
108
    private function getConnectorFactory() : ConnectorFactoryInterface
109
    {
110
        if ($this->connectorFactory !== null) {
111
            return $this->connectorFactory;
112
        }
113
        $this->connectorFactory = new ConnectorFactory($this->getLoop());
114
        $this->connectorFactory->setSslOptions($this->config['ssl']);
115
116
        $this->connectorFactory->enableDns();
117
        if (null !== $this->config['dns']) {
118
            $this->connectorFactory->setDnsServer($this->config['dns']);
119
        }
120
        if ($this->url->isSecured()) {
121
            $this->connectorFactory->enableSsl();
122
        }
123
124
        return $this->connectorFactory;
125
    }
126
127
    /**
128
     * @return LoopInterface
129
     */
130
    private function getLoop() : LoopInterface
131
    {
132
        if (null !== $this->loop) {
133
            return $this->loop;
134
        }
135
136
        return $this->loop = LoopFactory::create();
137
    }
138
139
    /**
140
     * @return MessageProcessor
141
     */
142
    private function getMessageProcessor(): MessageProcessor
143
    {
144
        if (!empty($this->messageProcessor)) {
145
            return $this->messageProcessor;
146
        }
147
148
        $this->messageProcessor = new MessageProcessor(
149
            true,
150
            new FrameFactory($this->config['frame']),
151
            new MessageFactory($this->config['message'])
152
        );
153
154
        $this->messageProcessor->addHandler(new PingFrameHandler());
155
        $this->messageProcessor->addHandler(new CloseFrameHandler());
156
        $this->messageProcessor->addHandler(new WrongOpcodeHandler());
157
        $this->messageProcessor->addHandler(new RsvCheckFrameHandler());
158
159
        return $this->messageProcessor;
160
    }
161
}
162