Passed
Push — master ( a91d54...875978 )
by y
02:08
created

WebSocketServer   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 137
rs 10
c 0
b 0
f 0
wmc 17

13 Methods

Rating   Name   Duplication   Size   Complexity  
A accept() 0 6 1
A count() 0 2 1
A broadcastBinary() 0 2 1
A broadcastFrame() 0 4 3
A newClient() 0 2 1
A __construct() 0 4 1
A onOutOfBand() 0 1 1
A onReadable() 0 2 1
A getClients() 0 2 1
A close() 0 11 3
A broadcastPing() 0 2 1
A remove() 0 3 1
A broadcastText() 0 2 1
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
    public function broadcastBinary (string $payload) {
50
        $this->broadcastFrame($payload, Frame::OP_BINARY);
51
    }
52
53
    /**
54
     * Sends a frame to all clients in the OK state.
55
     *
56
     * @param string $payload
57
     * @param int $opCode
58
     * @param bool $final
59
     */
60
    public function broadcastFrame (string $payload, int $opCode = Frame::OP_TEXT, bool $final = true) {
61
        foreach ($this->clients as $client) {
62
            if ($client->isOk()) {
63
                $client->getFrameHandler()->write(...func_get_args());
0 ignored issues
show
Bug introduced by
func_get_args() is expanded, but the parameter $payload of Helix\Socket\WebSocket\FrameHandler::write() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
                $client->getFrameHandler()->write(/** @scrutinizer ignore-type */ ...func_get_args());
Loading history...
64
            }
65
        }
66
    }
67
68
    /**
69
     * Sends a ping to all clients in the OK state.
70
     *
71
     * @param string $payload
72
     */
73
    public function broadcastPing (string $payload = '') {
74
        $this->broadcastFrame($payload, Frame::OP_PING);
75
    }
76
77
    /**
78
     * Sends a message to all clients in the OK state.
79
     *
80
     * @param string $text
81
     */
82
    public function broadcastText (string $text) {
83
        $this->broadcastFrame($text, Frame::OP_TEXT);
84
    }
85
86
    /**
87
     * Closes and removes all clients.
88
     *
89
     * @param int $code
90
     * @param string $reason
91
     * @return StreamServer
92
     */
93
    public function close (int $code = Frame::CLOSE_INTERRUPT, $reason = '') {
94
        foreach ($this->clients as $client) {
95
            try {
96
                $client->close($code, $reason);
97
            }
98
            catch (Exception $e) {
99
                continue;
100
            }
101
        }
102
        $this->reactor->remove($this);
103
        return parent::close();
104
    }
105
106
    /**
107
     * The number of clients attached.
108
     *
109
     * @return int
110
     */
111
    public function count (): int {
112
        return count($this->clients);
113
    }
114
115
    /**
116
     * @return WebSocketClient[]
117
     */
118
    public function getClients () {
119
        return $this->clients;
120
    }
121
122
    /**
123
     * @param resource $resource
124
     * @return WebSocketClient
125
     */
126
    protected function newClient ($resource) {
127
        return new WebSocketClient($resource, $this);
128
    }
129
130
    /**
131
     * Servers never get OOB data.
132
     *
133
     * @inheritDoc
134
     */
135
    final public function onOutOfBand (): void {
136
    }
137
138
    /**
139
     * @inheritDoc
140
     */
141
    public function onReadable (): void {
142
        $this->accept();
143
    }
144
145
    /**
146
     * Removes the client from the server and reactor.
147
     *
148
     * @param WebSocketClient $client
149
     */
150
    public function remove (WebSocketClient $client) {
151
        unset($this->clients[$client->getId()]);
152
        $this->reactor->remove($client);
153
    }
154
}