Issues (61)

app/Services/ServerService.php (2 issues)

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
The expression return $result could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
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 ignore-unused  annotation

245
    private function checkServer(/** @scrutinizer ignore-unused */ Server $server): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
246
    {
247
        // There is no checkers for server status
248
    }
249
}
250