]> jfr.im git - irc/unrealircd/unrealircd-rpc-php.git/blame - lib/Connection.php
Add $rpc->stats()->get();
[irc/unrealircd/unrealircd-rpc-php.git] / lib / Connection.php
CommitLineData
562c96c0
BM
1<?php
2
50d6d455 3namespace UnrealIRCd;
562c96c0 4
8d5a112f 5use Exception;
562c96c0
BM
6use WebSocket;
7
8class Connection
9{
50d6d455
D
10 protected WebSocket\Client $connection;
11
1a3fda20
BM
12 public $errno = 0;
13 public $error = NULL;
14
a18591f9 15 public function __construct(string $uri, string $api_login, array $options = null)
50d6d455
D
16 {
17 $context = $options["context"] ?? stream_context_create();
18
8d5a112f 19 if (isset($options["tls_verify"]) && !$options["tls_verify"]) {
50d6d455
D
20 stream_context_set_option($context, 'ssl', 'verify_peer', false);
21 stream_context_set_option($context, 'ssl', 'verify_peer_name', false);
22 }
23
24 $this->connection = new WebSocket\Client($uri, [
25 'context' => $context,
26 'headers' => [
27 'Authorization' => sprintf('Basic %s', base64_encode($api_login)),
28 ],
29 'timeout' => 10,
30 ]);
31
57c1d592
BM
32 /* Start the connection now */
33 $this->connection->ping();
50d6d455
D
34 }
35
8d5a112f
D
36 /**
37 * Encode and send a query to the RPC server.
38 *
39 * @note I'm not sure on the response type except that it may be either an object or array.
40 *
41 * @param string $method
a18591f9
D
42 * @param array|null $params
43 *
8d5a112f
D
44 * @return object|array|bool
45 * @throws Exception
46 */
a18591f9 47 public function query(string $method, array|null $params = null): object|array|bool
50d6d455 48 {
8d5a112f
D
49 $id = random_int(1, 99999);
50
50d6d455
D
51 $rpc = [
52 "jsonrpc" => "2.0",
53 "method" => $method,
54 "params" => $params,
8d5a112f 55 "id" => $id
50d6d455
D
56 ];
57
58 $json_rpc = json_encode($rpc);
50d6d455 59 $this->connection->text($json_rpc);
a3518a0a
BM
60
61 do {
62 $reply = $this->connection->receive();
63
64 $reply = json_decode($reply);
65
66 if (property_exists($reply, 'result')) {
67 /* Possibly we are streaming log events, then ignore this event
68 * NOTE: This does mean that this event is "lost"
69 */
70 if ($id !== $reply->id)
71 continue;
72 $this->errno = 0;
73 $this->error = NULL;
74 return $reply->result;
75 }
76
77 if (property_exists($reply, 'error')) {
78 $this->errno = $reply->error->code;
79 $this->error = $reply->error->message;
80 return false;
81 }
82 } while(0);
83
84 /* This should never happen */
85 throw new Exception('Invalid JSON-RPC response from UnrealIRCd: not an error and not a result.');
86 }
87
88 /**
89 * Grab and/or wait for next event. Used for log streaming.
90 * @note This function will return NULL after a 10 second timeout,
91 * this so the function is not entirely blocking. You can safely
92 * retry the operation if the return value === NULL.
93 *
94 * @return object|array|bool|null
95 * @throws Exception
96 */
97 public function eventloop(): object|array|bool|null
98 {
49faf2cf 99 $starttime = microtime(true);
a3518a0a
BM
100 try {
101 $reply = $this->connection->receive();
49faf2cf
BM
102 } catch (WebSocket\TimeoutException $e) {
103 if (microtime(true) - $starttime < 1)
104 {
105 /* There's some bug in the library: if we
106 * caught the timeout exception once (so
107 * harmless) and then later the server gets
108 * killed or closes the connection otherwise,
109 * then it will again throw WebSocket\TimeoutException
110 * even though it has nothing to do with timeouts.
111 * We detect this by checking if the timeout
112 * took less than 1 second, then we know for sure
113 * that it wasn't really a timeout (since the
114 * timeout is normally 10 seconds).
115 */
116 throw $e;
117 }
a3518a0a
BM
118 return NULL;
119 }
50d6d455
D
120
121 $reply = json_decode($reply);
122
65cc0295 123 if (property_exists($reply, 'result')) {
1a3fda20
BM
124 $this->errno = 0;
125 $this->error = NULL;
657dad63 126 return $reply->result;
50d6d455 127 }
bea99f3a 128
a3518a0a 129 /* This would be weird */
1a3fda20
BM
130 if (property_exists($reply, 'error')) {
131 $this->errno = $reply->error->code;
132 $this->error = $reply->error->message;
133 return false;
bea99f3a
D
134 }
135
1a3fda20 136 /* This should never happen */
a3518a0a 137 throw new Exception('Invalid JSON-RPC data from UnrealIRCd: not an error and not a result.');
50d6d455 138 }
7c7017a2 139
c6e7dd34
BM
140 public function rpc(): Rpc
141 {
142 return new Rpc($this);
143 }
144
1ef2e09f
BM
145 public function stats(): Stats
146 {
147 return new Stats($this);
148 }
149
7c7017a2
BM
150 public function user(): User
151 {
152 return new User($this);
153 }
154
155 public function channel(): Channel
156 {
157 return new Channel($this);
158 }
159
e4de690d 160 public function serverban(): ServerBan
7c7017a2 161 {
e4de690d 162 return new ServerBan($this);
7c7017a2
BM
163 }
164
165 public function spamfilter(): Spamfilter
166 {
167 return new Spamfilter($this);
168 }
1ef2e09f 169
8fd8402e
VP
170 public function nameban(): NameBan
171 {
172 return new NameBan($this);
173 }
1ef2e09f 174
1d1d6c90
VP
175 public function server(): Server
176 {
177 return new Server($this);
178 }
1ef2e09f 179
65b6ddcb 180 public function serverbanexception(): ServerBanException
9d9157c2 181 {
9ff6e559 182 return new ServerBanException($this);
9d9157c2 183 }
1ef2e09f 184
a3518a0a
BM
185 public function log(): Log
186 {
187 return new Log($this);
188 }
562c96c0 189}