ctrlpanel/app/Classes/Pterodactyl.php

442 lines
13 KiB
PHP
Raw Permalink Normal View History

2021-06-05 09:26:32 +00:00
<?php
namespace App\Classes;
use App\Models\Egg;
use App\Models\Nest;
use App\Models\Node;
2022-08-03 12:34:00 +00:00
use App\Models\Product;
use App\Models\Server;
use App\Models\User;
2021-06-05 09:26:32 +00:00
use Exception;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
class Pterodactyl
2021-06-05 09:26:32 +00:00
{
//TODO: Extend error handling (maybe logger for more errors when debugging)
2021-06-05 09:26:32 +00:00
/**
* @return PendingRequest
2021-06-05 09:26:32 +00:00
*/
public static function client()
2021-06-05 09:26:32 +00:00
{
return Http::withHeaders([
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:TOKEN'),
'Content-type' => 'application/json',
'Accept' => 'Application/vnd.pterodactyl.v1+json',
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
2021-06-05 09:26:32 +00:00
}
public static function clientAdmin()
2022-08-11 13:50:33 +00:00
{
return Http::withHeaders([
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN'),
'Content-type' => 'application/json',
'Accept' => 'Application/vnd.pterodactyl.v1+json',
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
2022-08-11 13:50:33 +00:00
}
2021-06-05 09:26:32 +00:00
/**
* @return Exception
2021-06-05 09:26:32 +00:00
*/
private static function getException(string $message = '', int $status = 0): Exception
2021-06-05 09:26:32 +00:00
{
if ($status == 404) {
2023-01-19 10:18:51 +00:00
return new Exception('Ressource does not exist on pterodactyl - ' . $message, 404);
}
if ($status == 403) {
2023-01-19 10:18:51 +00:00
return new Exception('No permission on pterodactyl, check pterodactyl token and permissions - ' . $message, 403);
}
if ($status == 401) {
2023-01-19 10:18:51 +00:00
return new Exception('No pterodactyl token set - ' . $message, 401);
}
if ($status == 500) {
2023-01-19 10:18:51 +00:00
return new Exception('Pterodactyl server error - ' . $message, 500);
}
2023-01-19 10:18:51 +00:00
return new Exception('Request Failed, is pterodactyl set-up correctly? - ' . $message);
2021-06-05 09:26:32 +00:00
}
/**
* @param Nest $nest
2021-06-05 09:26:32 +00:00
* @return mixed
*
2021-06-05 09:26:32 +00:00
* @throws Exception
*/
public static function getEggs(Nest $nest)
2021-06-05 09:26:32 +00:00
{
try {
$response = self::client()->get("/application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get eggs from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response->json()['data'];
}
/**
* @return mixed
*
2021-06-05 09:26:32 +00:00
* @throws Exception
*/
public static function getNodes()
2021-06-05 09:26:32 +00:00
{
try {
$response = self::client()->get('/application/nodes?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get nodes from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response->json()['data'];
}
2022-08-11 14:19:12 +00:00
2022-08-11 06:06:40 +00:00
/**
* @return mixed
*
2022-08-11 06:06:40 +00:00
* @throws Exception
* @description Returns the infos of a single node
*/
public static function getNode($id)
{
2022-08-11 06:06:40 +00:00
try {
$response = self::client()->get('/application/nodes/' . $id);
} catch (Exception $e) {
2022-08-11 06:06:40 +00:00
throw self::getException($e->getMessage());
}
if ($response->failed()) {
2023-01-19 10:18:51 +00:00
throw self::getException('Failed to get node id ' . $id . ' - ' . $response->status());
}
2022-08-11 06:06:40 +00:00
return $response->json()['attributes'];
}
2022-08-11 14:19:12 +00:00
public static function getServers()
{
2022-08-11 06:06:40 +00:00
try {
$response = self::client()->get('/application/servers?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
2022-08-11 06:06:40 +00:00
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get list of servers - ', $response->status());
}
2022-08-11 06:06:40 +00:00
return $response->json()['data'];
}
2021-06-05 09:26:32 +00:00
2021-11-07 11:10:46 +00:00
/**
* @return null
*
2021-11-07 11:10:46 +00:00
* @throws Exception
*/
public static function getNests()
2021-11-07 11:10:46 +00:00
{
try {
$response = self::client()->get('/application/nests?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get nests from pterodactyl', $response->status());
}
2021-11-07 11:10:46 +00:00
return $response->json()['data'];
}
2021-06-05 09:26:32 +00:00
/**
* @return mixed
*
2021-06-05 09:26:32 +00:00
* @throws Exception
*/
public static function getLocations()
2021-06-05 09:26:32 +00:00
{
try {
$response = self::client()->get('/application/locations?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get locations from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response->json()['data'];
}
/**
* @param Node $node
2021-06-05 09:26:32 +00:00
* @return mixed
*
2021-11-07 11:10:46 +00:00
* @throws Exception
2021-06-05 09:26:32 +00:00
*/
public static function getFreeAllocationId(Node $node)
2021-06-05 09:26:32 +00:00
{
return self::getFreeAllocations($node)[0]['attributes']['id'] ?? null;
2021-06-05 09:26:32 +00:00
}
/**
* @param Node $node
* @return array|mixed|null
*
* @throws Exception
*/
public static function getFreeAllocations(Node $node)
{
$response = self::getAllocations($node);
$freeAllocations = [];
if (isset($response['data'])) {
2023-01-19 10:18:51 +00:00
if (!empty($response['data'])) {
foreach ($response['data'] as $allocation) {
2023-01-19 10:18:51 +00:00
if (!$allocation['attributes']['assigned']) {
array_push($freeAllocations, $allocation);
}
}
}
}
return $freeAllocations;
}
2021-06-05 09:26:32 +00:00
/**
* @param Node $node
2021-11-07 11:10:46 +00:00
* @return array|mixed
*
2021-06-05 09:26:32 +00:00
* @throws Exception
*/
public static function getAllocations(Node $node)
2021-06-05 09:26:32 +00:00
{
$per_page = config('SETTINGS::SERVER:ALLOCATION_LIMIT', 200);
try {
$response = self::client()->get("/application/nodes/{$node->id}/allocations?per_page={$per_page}");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get allocations from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response->json();
}
/**
* @param string $route
* @return string
*/
public static function url(string $route): string
{
return config('SETTINGS::SYSTEM:PTERODACTYL:URL') . $route;
}
2021-06-05 09:26:32 +00:00
/**
* @param Server $server
* @param Egg $egg
* @param int $allocationId
2021-06-05 09:26:32 +00:00
* @return Response
*/
public static function createServer(Server $server, Egg $egg, int $allocationId)
2021-06-05 09:26:32 +00:00
{
return self::client()->post('/application/servers', [
'name' => $server->name,
'external_id' => $server->id,
'user' => $server->user->pterodactyl_id,
'egg' => $egg->id,
'docker_image' => $egg->docker_image,
'startup' => $egg->startup,
'environment' => $egg->getEnvironmentVariables(),
'limits' => [
'memory' => $server->product->memory,
'swap' => $server->product->swap,
'disk' => $server->product->disk,
'io' => $server->product->io,
'cpu' => $server->product->cpu,
2021-06-05 09:26:32 +00:00
],
'feature_limits' => [
'databases' => $server->product->databases,
'backups' => $server->product->backups,
'allocations' => $server->product->allocations,
],
'allocation' => [
'default' => $allocationId,
2021-06-05 09:26:32 +00:00
],
]);
}
public static function suspendServer(Server $server)
{
try {
$response = self::client()->post("/application/servers/$server->pterodactyl_id/suspend");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to suspend server from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response;
}
public static function unSuspendServer(Server $server)
{
try {
$response = self::client()->post("/application/servers/$server->pterodactyl_id/unsuspend");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to unsuspend server from pterodactyl - ', $response->status());
}
2021-06-05 09:26:32 +00:00
return $response;
}
/**
* Get user by pterodactyl id
*
* @param int $pterodactylId
* @return mixed
2021-06-05 09:26:32 +00:00
*/
public function getUser(int $pterodactylId)
2021-06-05 09:26:32 +00:00
{
try {
$response = self::client()->get("/application/users/{$pterodactylId}");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
if ($response->failed()) {
throw self::getException('Failed to get user from pterodactyl - ', $response->status());
}
return $response->json()['attributes'];
}
/**
* Get serverAttributes by pterodactyl id
*
* @param int $pterodactylId
* @return mixed
*/
public static function getServerAttributes(int $pterodactylId, bool $deleteOn404 = false)
{
try {
$response = self::client()->get("/application/servers/{$pterodactylId}?include=egg,node,nest,location");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
//print response body
if ($response->failed()) {
if ($deleteOn404) { //Delete the server if it does not exist (server deleted on pterodactyl)
Server::where('pterodactyl_id', $pterodactylId)->first()->delete();
return;
} else {
throw self::getException('Failed to get server attributes from pterodactyl - ', $response->status());
}
}
return $response->json()['attributes'];
2021-06-05 09:26:32 +00:00
}
2022-08-03 12:34:00 +00:00
2022-08-11 14:55:24 +00:00
/**
* Update Server Resources
*
* @param Server $server
* @param Product $product
* @return Response
2022-08-11 14:55:24 +00:00
*/
public static function updateServer(Server $server, Product $product)
2022-08-03 12:34:00 +00:00
{
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/build", [
'allocation' => $server->allocation,
'memory' => $product->memory,
'swap' => $product->swap,
'disk' => $product->disk,
'io' => $product->io,
'cpu' => $product->cpu,
'threads' => null,
'feature_limits' => [
'databases' => $product->databases,
'backups' => $product->backups,
'allocations' => $product->allocations,
],
2022-08-03 12:34:00 +00:00
]);
}
2023-01-19 10:18:51 +00:00
/**
* Update the owner of a server
*
* @param int $userId
* @param Server $server
* @return mixed
*/
public static function updateServerOwner(Server $server, int $userId)
2023-01-19 10:18:51 +00:00
{
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/details", [
2023-01-19 10:18:51 +00:00
'name' => $server->name,
'user' => $userId,
]);
}
2022-08-11 14:55:24 +00:00
/**
* Power Action Specific Server
*
* @param Server $server
* @param string $action
* @return Response
2022-08-11 14:55:24 +00:00
*/
public static function powerAction(Server $server, $action)
2022-08-11 13:50:33 +00:00
{
return self::clientAdmin()->post("/client/servers/{$server->identifier}/power", [
'signal' => $action,
2022-08-11 13:50:33 +00:00
]);
}
2022-08-11 14:55:24 +00:00
2022-08-12 11:30:15 +00:00
/**
* Get info about user
*/
public static function getClientUser()
2022-08-12 11:30:15 +00:00
{
return self::clientAdmin()->get('/client/account');
2022-08-12 11:30:15 +00:00
}
2022-08-11 14:55:24 +00:00
/**
* Check if node has enough free resources to allocate the given resources
*
* @param Node $node
* @param int $requireMemory
* @param int $requireDisk
* @return bool
2022-08-11 14:55:24 +00:00
*/
public static function checkNodeResources(Node $node, int $requireMemory, int $requireDisk)
2022-08-11 14:55:24 +00:00
{
try {
$response = self::client()->get("/application/nodes/{$node->id}");
2022-08-11 14:55:24 +00:00
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
$node = $response['attributes'];
$freeMemory = ($node['memory'] * ($node['memory_overallocate'] + 100) / 100) - $node['allocated_resources']['memory'];
$freeDisk = ($node['disk'] * ($node['disk_overallocate'] + 100) / 100) - $node['allocated_resources']['disk'];
2022-08-11 14:55:24 +00:00
if ($freeMemory < $requireMemory) {
return false;
}
if ($freeDisk < $requireDisk) {
2022-08-11 14:55:24 +00:00
return false;
}
return true;
2022-08-11 14:55:24 +00:00
}
2021-06-05 09:26:32 +00:00
}