WebSocketServer::close()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
namespace Helix\Socket\WebSocket;
4
5
use Countable;
6
use Exception;
7
use Helix\Socket\ReactiveInterface;
8
use Helix\Socket\Reactor;
9
use Helix\Socket\StreamServer;
10
11
/**
12
 * A WebSocket server.
13
 *
14
 * @see https://tools.ietf.org/html/rfc6455
15
 */
16
class WebSocketServer extends StreamServer implements Countable, ReactiveInterface {
17
18
    /**
19
     * Holds all connected clients.
20
     *
21
     * @var WebSocketClient[]
22
     */
23
    protected $clients = [];
24
25
    /**
26
     * @var Reactor
27
     */
28
    protected $reactor;
29
30
    /**
31
     * @param $resource
32
     * @param Reactor $reactor
33
     */
34
    public function __construct ($resource, Reactor $reactor) {
35
        parent::__construct($resource);
36
        $reactor->add($this);
37
        $this->reactor = $reactor;
38
    }
39
40
    /**
41
     * @return WebSocketClient
42
     */
43
    public function accept (): WebSocketClient {
44
        /**
45
         * @see newClient()
46
         * @var WebSocketClient $client
47
         */
48
        $client = parent::accept();
49
        $this->clients[$client->getId()] = $client;
50
        $this->reactor->add($client);
51
        return $client;
52
    }
53
54
    /**
55
     * Sends a payload to all clients in the OK state.
56
     *
57
     * @param int $opCode
58
     * @param string $payload
59
     */
60
    public function broadcast (int $opCode, string $payload) {
61
        foreach ($this->clients as $client) {
62
            if ($client->isOk()) {
63
                $client->getFrameHandler()->write($opCode, $payload);
64
            }
65
        }
66
    }
67
68
    /**
69
     * @param string $payload
70
     */
71
    public function broadcastBinary (string $payload) {
72
        $this->broadcast(Frame::OP_BINARY, $payload);
73
    }
74
75
    /**
76
     * Sends a ping to all clients in the OK state.
77
     *
78
     * @param string $payload
79
     */
80
    public function broadcastPing (string $payload = '') {
81
        $this->broadcast(Frame::OP_PING, $payload);
82
    }
83
84
    /**
85
     * Sends a message to all clients in the OK state.
86
     *
87
     * @param string $text
88
     */
89
    public function broadcastText (string $text) {
90
        $this->broadcast(Frame::OP_TEXT, $text);
91
    }
92
93
    /**
94
     * Closes and removes all clients.
95
     *
96
     * @param int $code
97
     * @param string $reason
98
     * @return $this
99
     */
100
    public function close (int $code = Frame::CLOSE_INTERRUPT, $reason = '') {
101
        foreach ($this->clients as $client) {
102
            try {
103
                $client->close($code, $reason); // clients remove themselves
104
            }
105
            catch (Exception $e) {
106
                continue;
107
            }
108
        }
109
        $this->reactor->remove($this);
110
        return parent::close();
111
    }
112
113
    /**
114
     * The number of clients attached.
115
     *
116
     * @return int
117
     */
118
    public function count (): int {
119
        return count($this->clients);
120
    }
121
122
    /**
123
     * @return WebSocketClient[]
124
     */
125
    public function getClients () {
126
        return $this->clients;
127
    }
128
129
    /**
130
     * @param resource $resource
131
     * @return WebSocketClient
132
     */
133
    protected function newClient ($resource): WebSocketClient {
134
        return new WebSocketClient($resource, $this);
135
    }
136
137
    /**
138
     * WebSocket servers never get OOB data.
139
     */
140
    final public function onOutOfBand (): void {
141
        // do nothing
142
    }
143
144
    /**
145
     * Auto-accept.
146
     */
147
    public function onReadable (): void {
148
        $this->accept();
149
    }
150
151
    /**
152
     * Removes the client from the server and reactor.
153
     *
154
     * @param WebSocketClient $client
155
     */
156
    public function remove ($client): void {
157
        unset($this->clients[$client->getId()]);
158
        $this->reactor->remove($client);
159
    }
160
}