Completed
Push — master ( 30a8ff...83681b )
by Taosikai
12:10
created

TunnelServer::getSocket()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Spike library
4
 * @author Tao <[email protected]>
5
 */
6
namespace Spike\Server\TunnelServer;
7
8
use React\EventLoop\LoopInterface;
9
use React\Socket\ConnectionInterface;
10
use React\Socket\Server as Socket;
11
use Slince\Event\Event;
12
use Spike\Exception\InvalidArgumentException;
13
use Spike\Protocol\Spike;
14
use Spike\Protocol\SpikeInterface;
15
use Spike\Server\EventStore;
16
use Spike\Server\Server;
17
use Spike\Server\TunnelServer\Timer\ReviewPublicConnection;
18
use Spike\Timer\UseTimerTrait;
19
use Spike\Tunnel\TunnelInterface;
20
use Slince\Event\Dispatcher;
21
use Spike\Timer\TimerInterface;
22
23
abstract class TunnelServer implements TunnelServerInterface
24
{
25
    use UseTimerTrait;
26
27
    /**
28
     * @var ConnectionInterface
29
     */
30
    protected $controlConnection;
31
32
    /**
33
     * @var PublicConnectionCollection
34
     */
35
    protected $publicConnections;
36
37
    /**
38
     * @var Socket
39
     */
40
    protected $socket;
41
42
    /**
43
     * @var TunnelInterface
44
     */
45
    protected $tunnel;
46
47
    /**
48
     * @var Server
49
     */
50
    protected $server;
51
52
    /**
53
     * @var LoopInterface
54
     */
55
    protected $loop;
56
57
    public function __construct(Server $server, ConnectionInterface $controlConnection, TunnelInterface $tunnel, LoopInterface $loop)
58
    {
59
        $this->server = $server;
60
        $this->controlConnection = $controlConnection;
61
        $this->tunnel = $tunnel;
62
        $this->loop = $loop;
63
        $this->publicConnections = new PublicConnectionCollection();
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function run()
70
    {
71
        $this->socket = new Socket($this->getListenAddress(), $this->loop);
72
        $this->socket->on('connection', function($connection){
73
            var_dump($connection);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($connection); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
74
            $publicConnection = new PublicConnection($connection);
75
            $this->publicConnections->add($publicConnection);
76
            $this->handlePublicConnection($publicConnection);
77
        });
78
        //Creates defaults timers
79
        foreach ($this->getDefaultTimers() as $timer) {
80
            $this->addTimer($timer);
81
        }
82
    }
83
84
    /**
85
     * Gets the event dispatcher
86
     * @return Dispatcher
87
     */
88
    public function getDispatcher()
89
    {
90
        return $this->server->getDispatcher();
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function close()
97
    {
98
        //Close all public connection
99
        foreach ($this->publicConnections as $publicConnection) {
100
            $this->closePublicConnection($publicConnection, 'The tunnel server has been closed');
101
        }
102
        //Cancel all timers
103
        foreach ($this->timers as $timer) {
104
            $timer->cancel();
105
        }
106
        $this->publicConnections = null;
107
        $this->timers = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array<integer,object<Spike\Timer\TimerInterface>> of property $timers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
108
        $this->socket->close();
109
    }
110
111
    /**
112
     * Handles the public connection
113
     * @param PublicConnection $publicConnection
114
     */
115
    public function handlePublicConnection(PublicConnection $publicConnection)
116
    {
117
        $requestProxyMessage = new Spike('request_proxy', $this->tunnel->toArray(), [
118
            'Proxy-Connection-ID' => $publicConnection->getId()
119
        ]);
120
        $this->controlConnection->write($requestProxyMessage);
121
        //Fires 'request_proxy' event
122
        $this->getDispatcher()->dispatch(new Event(EventStore::REQUEST_PROXY, $this, [
123
            'message' => $requestProxyMessage
124
        ]));
125
        $publicConnection->removeAllListeners();
126
        $publicConnection->pause();
127
    }
128
129
    /**
130
     * Registers proxy connection
131
     * @param ConnectionInterface $proxyConnection
132
     * @param SpikeInterface $message
133
     */
134
    public function registerProxyConnection(ConnectionInterface $proxyConnection, SpikeInterface $message)
135
    {
136
        $connectionId = $message->getHeader('Proxy-Connection-ID');
137
        $publicConnection = $this->publicConnections->findById($connectionId);
138
        if (is_null($publicConnection)) {
139
            throw new InvalidArgumentException(sprintf('Cannot find the public connection "%s"', $connectionId));
140
        }
141
        $startProxyMessage = new Spike('start_proxy');
142
        $proxyConnection->write($startProxyMessage);
143
        //Fires 'start_proxy' event
144
        $this->getDispatcher()->dispatch(new Event(EventStore::REQUEST_PROXY, $this, [
145
            'message' => $startProxyMessage
146
        ]));
147
        //Resumes the public connection
148
        $publicConnection->resume();
149
        $publicConnection->pipe($proxyConnection);
150
        $proxyConnection->pipe($publicConnection->getConnection());
151
        $proxyConnection->write($publicConnection->getInitBuffer());
152
153
        //Handles public connection close
154
        $handlePublicConnectionClose = function() use ($proxyConnection, $publicConnection, &$handleProxyConnectionClose){
155
            $proxyConnection->removeListener('close', $handleProxyConnectionClose);
156
            $proxyConnection->removeListener('error', $handleProxyConnectionClose);
157
            $proxyConnection->end();
158
            echo 'proxy end';
159
            $this->publicConnections->removeElement($publicConnection);
160
        };
161
        $publicConnection->on('close', $handlePublicConnectionClose);
162
        $publicConnection->on('error', $handlePublicConnectionClose);
163
164
        //Handles proxy connection close
165
        $handleProxyConnectionClose = function () use ($publicConnection, &$handlePublicConnectionClose) {
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $handleProxyConnectionClose, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
166
            $publicConnection->removeListener('close', $handlePublicConnectionClose);
167
            $publicConnection->removeListener('error', $handlePublicConnectionClose);
168
            $publicConnection->end();
169
            echo 'tunnel end';
170
        };
171
        $proxyConnection->on('close', $handleProxyConnectionClose);
172
        $proxyConnection->on('error', $handleProxyConnectionClose);
173
    }
174
175
    /**
176
     * Gets the server address to bind
177
     * @return string
178
     */
179
    protected function getListenAddress()
180
    {
181
        return "{$this->server->getHost()}:{$this->tunnel->getServerPort()}";
182
    }
183
184
    /**
185
     * Creates default timers
186
     * @return TimerInterface[]
187
     */
188
    protected function getDefaultTimers()
189
    {
190
        return [
191
            new ReviewPublicConnection($this)
192
        ];
193
    }
194
195
    /**
196
     * Gets the socket of the tunnel server
197
     * @return Socket
198
     */
199
    public function getSocket()
200
    {
201
        return $this->socket;
202
    }
203
    /**
204
     * {@inheritdoc}
205
     */
206
    public function getControlConnection()
207
    {
208
        return $this->controlConnection;
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function getLoop()
215
    {
216
        return $this->loop;
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222
    public function getPublicConnections()
223
    {
224
        return $this->publicConnections;
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230
    public function getTunnel()
231
    {
232
        return $this->tunnel;
233
    }
234
}