10 protected WebSocket\Client
$connection;
15 public function __construct(string $uri, string $api_login, array $options = null)
17 $context = $options["context"] ?? stream_context_create();
19 if (isset($options["tls_verify"]) && !$options["tls_verify"]) {
20 stream_context_set_option($context, 'ssl', 'verify_peer', false);
21 stream_context_set_option($context, 'ssl', 'verify_peer_name', false);
24 $this->connection
= new WebSocket\
Client($uri, [
25 'context' => $context,
27 'Authorization' => sprintf('Basic %s', base64_encode($api_login)),
32 /* Start the connection now */
33 if (isset($options["issuer"]))
35 /* Set issuer and don't wait for the reply (async) */
36 $this->query('rpc.set_issuer', ['name' => $options["issuer"]], true);
39 $this->connection
->ping();
44 * Encode and send a query to the RPC server.
46 * @note I'm not sure on the response type except that it may be either an object or array.
48 * @param string $method
49 * @param array|null $params
50 * @param bool $no_wait
52 * @return object|array|bool
55 public function query(string $method, array|null $params = null, $no_wait = false): object|array|bool
57 $id = random_int(1, 99999);
66 $json_rpc = json_encode($rpc);
67 $this->connection
->text($json_rpc);
74 $reply = $this->connection
->receive();
76 $reply = json_decode($reply);
78 if (property_exists($reply, 'id') && ($id !== $reply->id
))
80 /* This is not our request. Perhaps we are streaming log events
81 * or this is an asynchronous response to like set_issuer.
82 * We don't care about that, continue.
83 * NOTE: This does mean that this event info is "lost"
88 if (property_exists($reply, 'result')) {
91 return $reply->result
;
94 if (property_exists($reply, 'error')) {
95 $this->errno
= $reply->error
->code
;
96 $this->error
= $reply->error
->message
;
99 if (time() - $starttime > 10)
100 throw new Exception('RPC request timed out');
101 } while(1); // wait for the reply to OUR request
103 /* This should never happen */
104 throw new Exception('Invalid JSON-RPC response from UnrealIRCd: not an error and not a result.');
108 * Grab and/or wait for next event. Used for log streaming.
109 * @note This function will return NULL after a 10 second timeout,
110 * this so the function is not entirely blocking. You can safely
111 * retry the operation if the return value === NULL.
113 * @return object|array|bool|null
116 public function eventloop(): object|array|bool|null
118 $this->connection
->setTimeout(2); /* lower timeout for socket loop */
119 $starttime = microtime(true);
121 $reply = $this->connection
->receive();
122 } catch (WebSocket\TimeoutException
$e) {
123 if (microtime(true) - $starttime < 1)
125 /* There's some bug in the library: if we
126 * caught the timeout exception once (so
127 * harmless) and then later the server gets
128 * killed or closes the connection otherwise,
129 * then it will again throw WebSocket\TimeoutException
130 * even though it has nothing to do with timeouts.
131 * We detect this by checking if the timeout
132 * took less than 1 second, then we know for sure
133 * that it wasn't really a timeout (since the
134 * timeout is normally 10 seconds).
141 $this->connection
->setTimeout(10); /* set timeout back again */
143 $reply = json_decode($reply);
145 if (property_exists($reply, 'result')) {
148 return $reply->result
;
151 /* This would be weird */
152 if (property_exists($reply, 'error')) {
153 $this->errno
= $reply->error
->code
;
154 $this->error
= $reply->error
->message
;
158 /* This should never happen */
159 throw new Exception('Invalid JSON-RPC data from UnrealIRCd: not an error and not a result.');
162 public function rpc(): Rpc
164 return new Rpc($this);
167 public function stats(): Stats
169 return new Stats($this);
172 public function user(): User
174 return new User($this);
177 public function channel(): Channel
179 return new Channel($this);
182 public function serverban(): ServerBan
184 return new ServerBan($this);
187 public function spamfilter(): Spamfilter
189 return new Spamfilter($this);
192 public function nameban(): NameBan
194 return new NameBan($this);
197 public function server(): Server
199 return new Server($this);
202 public function serverbanexception(): ServerBanException
204 return new ServerBanException($this);
207 public function log(): Log
209 return new Log($this);