1 | <?php |
||||
2 | |||||
3 | namespace Gameap\Services; |
||||
4 | |||||
5 | use Gameap\Exceptions\Services\EmptyCommandException; |
||||
6 | use Gameap\Exceptions\Services\InvalidCommandException; |
||||
7 | use Gameap\Exceptions\Services\ServerInactiveException; |
||||
8 | use Gameap\Models\Server; |
||||
9 | use GameQ\Exception\Protocol as GameqProtocolException; |
||||
10 | use GameQ\Exception\Query as GameqQueryException; |
||||
11 | use GameQ\Exception\Server as GameqServerException; |
||||
12 | use GameQ\GameQ; |
||||
13 | use Knik\Gameap\GdaemonCommands; |
||||
14 | use Storage; |
||||
15 | |||||
16 | class ServerService |
||||
17 | { |
||||
18 | public const CONSOLE_MAX_SYMBOLS = 10000; |
||||
19 | |||||
20 | /** |
||||
21 | * @var GameQ |
||||
22 | */ |
||||
23 | protected $gameq; |
||||
24 | |||||
25 | /** |
||||
26 | * @var GdaemonCommands |
||||
27 | */ |
||||
28 | protected $gdaemonCommands; |
||||
29 | |||||
30 | /** |
||||
31 | * @var string |
||||
32 | */ |
||||
33 | protected $storageDisk = 'local'; |
||||
34 | |||||
35 | /** |
||||
36 | * ServerService constructor. |
||||
37 | * |
||||
38 | * @param GameQ $gameq |
||||
39 | * @param GdaemonCommands $gdaemonCommands |
||||
40 | */ |
||||
41 | public function __construct(GameQ $gameq, GdaemonCommands $gdaemonCommands) |
||||
42 | 3 | { |
|||
43 | $this->gameq = $gameq; |
||||
44 | 3 | $this->gdaemonCommands = $gdaemonCommands; |
|||
45 | 3 | } |
|||
46 | 3 | ||||
47 | /** |
||||
48 | * Add default server disk |
||||
49 | * |
||||
50 | * @param Server $server |
||||
51 | */ |
||||
52 | public function registerDisk(Server $server): void |
||||
53 | { |
||||
54 | foreach ($server->file_manager_disks as $diskName => $diskConfig) { |
||||
55 | if (empty(config("filesystems.disks.{$diskName}"))) { |
||||
56 | config(["filesystems.disks.{$diskName}" => $diskConfig]); |
||||
57 | } |
||||
58 | } |
||||
59 | } |
||||
60 | |||||
61 | /** |
||||
62 | * @param Server $server |
||||
63 | * @return array|string[] |
||||
64 | * @throws \Exception |
||||
65 | */ |
||||
66 | public function query(Server $server): array |
||||
67 | 6 | { |
|||
68 | $host = "{$server->server_ip}:{$server->query_port}"; |
||||
69 | 6 | ||||
70 | try { |
||||
71 | $query = $this->gameq->setOption('timeout', 5) |
||||
72 | 6 | ->addServer([ |
|||
73 | 6 | 'type' => $server->game->engine, |
|||
74 | 6 | 'host' => $host, |
|||
75 | 6 | ]) |
|||
76 | ->process(); |
||||
77 | 6 | } catch (GameqServerException | GameqQueryException | GameqProtocolException $exception) { |
|||
78 | return [ |
||||
79 | 'status' => 'query not supported for this game', |
||||
80 | ]; |
||||
81 | } |
||||
82 | |||||
83 | |||||
84 | $serverResult = $query[$host] ?? null; |
||||
85 | 6 | ||||
86 | if (!empty($serverResult['gq_online'])) { |
||||
87 | 6 | $result = [ |
|||
88 | 'status' => ($serverResult['gq_online'] ?? null) ? 'online' : 'offline', |
||||
89 | 3 | 'hostname' => $serverResult['gq_hostname'] ?? null, |
|||
90 | 3 | 'map' => $serverResult['gq_mapname'] ?? null, |
|||
91 | 3 | 'players' => ($serverResult['gq_numplayers'] ?? 0) . '/' . ($serverResult['gq_maxplayers'] ?? 0), |
|||
92 | 3 | 'version' => $serverResult['version'] ?? null, |
|||
93 | 3 | 'password' => ($serverResult['gq_password'] ?? null) ? 'yes' : 'no', |
|||
94 | 3 | 'joinlink' => $serverResult['gq_joinlink'] ?? null, |
|||
95 | 3 | ]; |
|||
96 | } else { |
||||
97 | $result = [ |
||||
98 | 'status' => 'offline', |
||||
99 | 6 | ]; |
|||
100 | } |
||||
101 | |||||
102 | return $result; |
||||
103 | 6 | } |
|||
104 | |||||
105 | /** |
||||
106 | * @param Server $server |
||||
107 | * @param string $command |
||||
108 | * @param array $extraData |
||||
109 | * @return string |
||||
110 | */ |
||||
111 | public function replaceShortCodes(Server $server, string $command, array $extraData = []): string |
||||
112 | 15 | { |
|||
113 | foreach ($extraData as $key => $value) { |
||||
114 | 15 | $command = str_replace('{' . $key . '}', $value, $command); |
|||
115 | 9 | } |
|||
116 | |||||
117 | $replaceArray = [ |
||||
118 | 'node_work_path' => $server->dedicatedServer->work_path, |
||||
119 | 15 | 'node_tools_path' => $server->dedicatedServer->work_path . "/tools", |
|||
120 | 15 | 'host' => $server->server_ip, |
|||
121 | 15 | 'port' => $server->server_port, |
|||
122 | 15 | 'query_port' => $server->query_port, |
|||
123 | 15 | 'rcon_port' => $server->rcon_port, |
|||
124 | 15 | 'dir' => $server->full_path, |
|||
125 | 15 | 'id' => $server->id, |
|||
126 | 15 | 'uuid' => $server->uuid, |
|||
127 | 15 | 'uuid_short' => $server->uuid_short, |
|||
128 | 'game' => $server->game_id, |
||||
129 | 'user' => $server->su_user, |
||||
130 | 15 | ]; |
|||
131 | 15 | ||||
132 | foreach ($replaceArray as $key => $value) { |
||||
133 | $command = str_replace('{' . $key . '}', $value, $command); |
||||
134 | 15 | } |
|||
135 | |||||
136 | return $command; |
||||
137 | } |
||||
138 | |||||
139 | /** |
||||
140 | * @param Server $server |
||||
141 | * @param string $command |
||||
142 | * @param array $extraData |
||||
143 | * @return string |
||||
144 | * |
||||
145 | * @throws InvalidCommandException |
||||
146 | 15 | * @throws EmptyCommandException |
|||
147 | */ |
||||
148 | 15 | public function getCommand(Server $server, string $command, array $extraData = []): string |
|||
149 | 15 | { |
|||
150 | $property = 'script_' . $command; |
||||
151 | 15 | $attributes = $server->dedicatedServer->getAttributes(); |
|||
152 | 12 | ||||
153 | if (array_key_exists($property, $attributes)) { |
||||
154 | 12 | $script = $server->dedicatedServer->getAttribute($property); |
|||
155 | |||||
156 | if (empty($script)) { |
||||
157 | throw new EmptyCommandException(); |
||||
158 | 12 | } |
|||
159 | |||||
160 | return $this->replaceShortCodes($server, $script, $extraData); |
||||
161 | 3 | } |
|||
162 | |||||
163 | throw new InvalidCommandException(); |
||||
164 | } |
||||
165 | |||||
166 | /** |
||||
167 | * @param Server $server |
||||
168 | 6 | * @return string |
|||
169 | * @throws ServerInactiveException|InvalidCommandException |
||||
170 | 6 | */ |
|||
171 | 3 | public function getConsoleLog(Server $server): string |
|||
172 | { |
||||
173 | $this->checkServer($server); |
||||
174 | 3 | $this->configureGdaemon($server); |
|||
175 | 3 | ||||
176 | try { |
||||
177 | $command = $this->getCommand($server, 'get_console'); |
||||
178 | $result = $this->gdaemonCommands->exec($command, $exitCode); |
||||
179 | } catch (EmptyCommandException $e) { |
||||
180 | $this->registerDisk($server); |
||||
181 | 3 | $result = Storage::disk('server')->get('output.txt'); |
|||
182 | } |
||||
183 | |||||
184 | if (mb_strlen($result) > self::CONSOLE_MAX_SYMBOLS) { |
||||
185 | $result = mb_substr($result, mb_strlen($result) - self::CONSOLE_MAX_SYMBOLS, self::CONSOLE_MAX_SYMBOLS); |
||||
186 | } |
||||
187 | 3 | ||||
188 | // Fix |
||||
189 | 3 | // Malformed UTF-8 characters, possibly incorrectly encoded |
|||
190 | $result = mb_convert_encoding($result, 'UTF-8', 'UTF-8'); |
||||
191 | |||||
192 | return $result; |
||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||
193 | } |
||||
194 | |||||
195 | /** |
||||
196 | * @param Server $server |
||||
197 | 9 | * @param string $command |
|||
198 | * @return bool |
||||
199 | 9 | * |
|||
200 | 6 | * @throws InvalidCommandException |
|||
201 | * @throws ServerInactiveException |
||||
202 | */ |
||||
203 | 6 | public function sendConsoleCommand(Server $server, string $command): bool |
|||
204 | 6 | { |
|||
205 | if ($server->processActive() === false) { |
||||
206 | throw new ServerInactiveException('Server is down'); |
||||
207 | } |
||||
208 | |||||
209 | $this->configureGdaemon($server); |
||||
210 | |||||
211 | try { |
||||
212 | $command = $this->getCommand($server, 'send_command', ['command' => $command]); |
||||
213 | $this->gdaemonCommands->exec($command, $exitCode); |
||||
214 | } catch (EmptyCommandException $e) { |
||||
215 | $this->registerDisk($server); |
||||
216 | |||||
217 | 6 | if (Storage::disk('server')->put('input.txt', $command)) { |
|||
218 | // Success |
||||
219 | $exitCode = 0; |
||||
220 | } else { |
||||
221 | // Failure |
||||
222 | $exitCode = 1; |
||||
223 | } |
||||
224 | } |
||||
225 | 9 | ||||
226 | return $exitCode === 0; |
||||
227 | 9 | } |
|||
228 | 9 | ||||
229 | /** |
||||
230 | 9 | * Setting up gdaemon commands configuration |
|||
231 | * |
||||
232 | * @param Server $server |
||||
233 | */ |
||||
234 | private function configureGdaemon(Server $server): void |
||||
235 | { |
||||
236 | 15 | $this->gdaemonCommands->setConfig( |
|||
237 | $server->dedicatedServer->gdaemonSettings($this->storageDisk) |
||||
238 | 15 | ); |
|||
239 | 6 | } |
|||
240 | |||||
241 | 9 | /** |
|||
242 | * @param Server $server |
||||
243 | * @throws ServerInactiveException |
||||
244 | */ |
||||
245 | private function checkServer(Server $server): void |
||||
0 ignored issues
–
show
The parameter
$server is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
246 | { |
||||
247 | // There is no checkers for server status |
||||
248 | } |
||||
249 | } |
||||
250 |