Subversion Repositories qbpwcf-lib(archive)

Rev

Rev 915 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 liveuser 1
<?php
2
namespace Ratchet\Server;
3
use Ratchet\MessageComponentInterface;
4
use React\EventLoop\LoopInterface;
5
use React\Socket\ServerInterface;
6
use React\EventLoop\Factory as LoopFactory;
7
use React\Socket\Server as Reactor;
8
use React\Socket\SecureServer as SecureReactor;
9
 
10
/**
11
 * Creates an open-ended socket to listen on a port for incoming connections.
12
 * Events are delegated through this to attached applications
13
 */
14
class IoServer {
15
    /**
16
     * @var \React\EventLoop\LoopInterface
17
     */
18
    public $loop;
19
 
20
    /**
21
     * @var \Ratchet\MessageComponentInterface
22
     */
23
    public $app;
24
 
25
    /**
26
     * The socket server the Ratchet Application is run off of
27
     * @var \React\Socket\ServerInterface
28
     */
29
    public $socket;
30
 
31
    /**
32
     * @param \Ratchet\MessageComponentInterface  $app      The Ratchet application stack to host
33
     * @param \React\Socket\ServerInterface       $socket   The React socket server to run the Ratchet application off of
34
     * @param \React\EventLoop\LoopInterface|null $loop     The React looper to run the Ratchet application off of
35
     */
36
    public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop = null) {
37
        if (false === strpos(PHP_VERSION, "hiphop")) {
38
            gc_enable();
39
        }
40
 
41
        set_time_limit(0);
42
        ob_implicit_flush();
43
 
44
        $this->loop = $loop;
45
        $this->app  = $app;
46
        $this->socket = $socket;
47
 
48
        $socket->on('connection', array($this, 'handleConnect'));
49
    }
50
 
51
    /**
52
     * @param  \Ratchet\MessageComponentInterface $component  The application that I/O will call when events are received
53
     * @param  int                                $port       The port to server sockets on
54
     * @param  string                             $address    The address to receive sockets on (0.0.0.0 means receive connections from any)
55
     * @return IoServer
56
     */
57
    public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') {
58
        $loop   = LoopFactory::create();
59
        $socket = new Reactor($address . ':' . $port, $loop);
60
 
61
        return new static($component, $socket, $loop);
62
    }
63
 
64
    /**
65
     * Run the application by entering the event loop
66
     * @throws \RuntimeException If a loop was not previously specified
67
     */
68
    public function run() {
69
        if (null === $this->loop) {
70
            throw new \RuntimeException("A React Loop was not provided during instantiation");
71
        }
72
 
73
        // @codeCoverageIgnoreStart
74
        $this->loop->run();
75
        // @codeCoverageIgnoreEnd
76
    }
77
 
78
    /**
79
     * Triggered when a new connection is received from React
80
     * @param \React\Socket\ConnectionInterface $conn
81
     */
82
    public function handleConnect($conn) {
83
        $conn->decor = new IoConnection($conn);
84
        $conn->decor->resourceId = (int)$conn->stream;
85
 
86
        $uri = $conn->getRemoteAddress();
87
        $conn->decor->remoteAddress = trim(
88
            parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri, PHP_URL_HOST),
89
            '[]'
90
        );
91
 
92
        $this->app->onOpen($conn->decor);
93
 
94
        $conn->on('data', function ($data) use ($conn) {
95
            $this->handleData($data, $conn);
96
        });
97
        $conn->on('close', function () use ($conn) {
98
            $this->handleEnd($conn);
99
        });
100
        $conn->on('error', function (\Exception $e) use ($conn) {
101
            $this->handleError($e, $conn);
102
        });
103
    }
104
 
105
    /**
106
     * Data has been received from React
107
     * @param string                            $data
108
     * @param \React\Socket\ConnectionInterface $conn
109
     */
110
    public function handleData($data, $conn) {
111
        try {
112
            $this->app->onMessage($conn->decor, $data);
113
        } catch (\Exception $e) {
114
            $this->handleError($e, $conn);
115
        }
116
    }
117
 
118
    /**
119
     * A connection has been closed by React
120
     * @param \React\Socket\ConnectionInterface $conn
121
     */
122
    public function handleEnd($conn) {
123
        try {
124
            $this->app->onClose($conn->decor);
125
        } catch (\Exception $e) {
126
            $this->handleError($e, $conn);
127
        }
128
 
129
        unset($conn->decor);
130
    }
131
 
132
    /**
133
     * An error has occurred, let the listening application know
134
     * @param \Exception                        $e
135
     * @param \React\Socket\ConnectionInterface $conn
136
     */
137
    public function handleError(\Exception $e, $conn) {
138
        $this->app->onError($conn->decor, $e);
139
    }
140
}