Passed
Push — master ( f0b67b...ec9c11 )
by y
01:29
created

WebSocketServer::broadcast()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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