ts3phpframework
Loading...
Searching...
No Matches
ServerQuery.php
Go to the documentation of this file.
1<?php
2
3namespace PlanetTeamSpeak\TeamSpeak3Framework\Adapter;
4
5use PlanetTeamSpeak\TeamSpeak3Framework\Adapter\ServerQuery\Event;
6use PlanetTeamSpeak\TeamSpeak3Framework\Adapter\ServerQuery\Reply;
7use PlanetTeamSpeak\TeamSpeak3Framework\Exception\AdapterException;
8use PlanetTeamSpeak\TeamSpeak3Framework\Exception\ServerQueryException;
9use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Profiler;
10use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Signal;
11use PlanetTeamSpeak\TeamSpeak3Framework\Helper\StringHelper;
12use PlanetTeamSpeak\TeamSpeak3Framework\Node\Host;
13use PlanetTeamSpeak\TeamSpeak3Framework\Node\Node;
14use PlanetTeamSpeak\TeamSpeak3Framework\TeamSpeak3;
15use PlanetTeamSpeak\TeamSpeak3Framework\Transport\Transport;
16
21class ServerQuery extends Adapter
22{
28 protected ?Host $host = null;
29
35 protected ?int $timer = null;
36
42 protected int $count = 0;
43
49 protected array $block = ["help"];
50
58 protected function syn(): void
59 {
60 $this->initTransport($this->options);
61 $this->transport->setAdapter($this);
62
63 Profiler::init(spl_object_hash($this));
64
65 $rdy = $this->getTransport()->readLine();
66
67 if (!$rdy->startsWith(TeamSpeak3::TS3_PROTO_IDENT) && !$rdy->startsWith(TeamSpeak3::TEA_PROTO_IDENT) && !(defined("CUSTOM_PROTO_IDENT") && $rdy->startsWith(CUSTOM_PROTO_IDENT))) {
68 throw new AdapterException("invalid reply from the server (" . $rdy . ")");
69 }
70
71 Signal::getInstance()->emit("serverqueryConnected", $this);
72 }
73
79 public function __destruct()
80 {
81 // do not disconnect, when acting as bot in non-blocking mode
82 if (! $this->getTransport()->getConfig("blocking")) {
83 return;
84 }
85
86 if ($this->getTransport() instanceof Transport && $this->transport->isConnected()) {
87 try {
88 $this->request("quit");
89 } catch (AdapterException) {
90 return;
91 }
92 }
93 }
94
103 public function request(string $cmd, bool $throw = true): Reply
104 {
105 $query = StringHelper::factory($cmd)->section(TeamSpeak3::SEPARATOR_CELL);
106
107 if (strstr($cmd, "\r") || strstr($cmd, "\n")) {
108 throw new AdapterException("illegal characters in command '" . $query . "'");
109 } elseif (in_array($query, $this->block)) {
110 throw new ServerQueryException("command not found", 0x100);
111 }
112
113 Signal::getInstance()->emit("serverqueryCommandStarted", $cmd);
114
115 $this->getProfiler()->start();
116 $this->getTransport()->sendLine($cmd);
117 $this->timer = time();
118 $this->count++;
119
120 $rpl = [];
121
122 do {
123 if (! $this->getTransport()->isConnected()) {
124 break;
125 }
126 $str = $this->getTransport()->readLine();
127 $rpl[] = $str;
128 } while ($str->section(TeamSpeak3::SEPARATOR_CELL) != TeamSpeak3::ERROR);
129
130 $this->getProfiler()->stop();
131
132 $reply = new Reply($rpl, $cmd, $this->getHost(), $throw);
133
134 Signal::getInstance()->emit("serverqueryCommandFinished", $cmd, $reply);
135
136 return $reply;
137 }
138
145 public function wait(): Event
146 {
147 if ($this->getTransport()->getConfig("blocking")) {
148 throw new AdapterException("only available in non-blocking mode");
149 }
150
151 do {
152 if (! $this->getTransport()->isConnected()) {
153 break;
154 }
155 $evt = $this->getTransport()->readLine();
156 } while (!$evt->section(TeamSpeak3::SEPARATOR_CELL)->startsWith(TeamSpeak3::EVENT));
157
158 return new Event($evt, $this->getHost());
159 }
160
168 public function prepare(string $cmd, array $params = []): string
169 {
170 $args = [];
171 $cells = [];
172
173 foreach ($params as $ident => $value) {
174 $ident = is_numeric($ident) ? "" : strtolower($ident) . TeamSpeak3::SEPARATOR_PAIR;
175
176 if (is_array($value)) {
177 $value = array_values($value);
178
179 for ($i = 0; $i < count($value); $i++) {
180 if ($value[$i] === null) {
181 continue;
182 } elseif ($value[$i] === false) {
183 $value[$i] = 0x00;
184 } elseif ($value[$i] === true) {
185 $value[$i] = 0x01;
186 } elseif ($value[$i] instanceof Node) {
187 $value[$i] = $value[$i]->getId();
188 }
189
190 $cells[$i][] = $ident . StringHelper::factory($value[$i])->escape()->toUtf8();
191 }
192 } else {
193 if ($value === null) {
194 continue;
195 } elseif ($value === false) {
196 $value = 0x00;
197 } elseif ($value === true) {
198 $value = 0x01;
199 } elseif ($value instanceof Node) {
200 $value = $value->getId();
201 }
202
203 $args[] = $ident . StringHelper::factory($value)->escape()->toUtf8();
204 }
205 }
206
207 foreach (array_keys($cells) as $ident) {
208 $cells[$ident] = implode(TeamSpeak3::SEPARATOR_CELL, $cells[$ident]);
209 }
210
211 if (count($args)) {
212 $cmd .= " " . implode(TeamSpeak3::SEPARATOR_CELL, $args);
213 }
214 if (count($cells)) {
215 $cmd .= " " . implode(TeamSpeak3::SEPARATOR_LIST, $cells);
216 }
217
218 return trim($cmd);
219 }
220
226 public function getQueryLastTimestamp(): ?int
227 {
228 return $this->timer;
229 }
230
236 public function getQueryCount(): int
237 {
238 return $this->count;
239 }
240
246 public function getQueryRuntime(): float
247 {
248 return $this->getProfiler()->getRuntime();
249 }
250
256 public function getHost(): ?Host
257 {
258 if ($this->host === null) {
259 $this->host = new Host($this);
260 }
261
262 return $this->host;
263 }
264}
initTransport(array $options, string $transport=TCP::class)
Definition Adapter.php:111
Provides methods to analyze and format a ServerQuery event.
Definition Event.php:21
Provides methods to analyze and format a ServerQuery reply.
Definition Reply.php:19
Enhanced exception class for PlanetTeamSpeak\TeamSpeak3Framework\Adapter\Adapter objects.
Enhanced exception class for PlanetTeamSpeak\TeamSpeak3Framework\Adapter\ServerQuery objects.
Class describing a TeamSpeak 3 server instance and all it's parameters.
Definition Host.php:23
const SEPARATOR_CELL
protocol cell separator
const SEPARATOR_PAIR
protocol pair separator
const SEPARATOR_LIST
protocol list separator
Abstract class for connecting to a TeamSpeak 3 Server through different ways of transport.
Definition Transport.php:17