Merge branch 'pelican-dev:main' into feature/node-sftp-alias

This commit is contained in:
Boy132 2024-06-07 23:49:38 +02:00 committed by GitHub
commit 0156456919
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 345 additions and 144 deletions

View File

@ -59,7 +59,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
@ -119,7 +119,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none

View File

@ -98,7 +98,7 @@ class DatabaseSettingsCommand extends Command
} elseif ($this->variables['DB_CONNECTION'] === 'sqlite') {
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
'Database Path',
config('database.connections.sqlite.database', 'database.sqlite')
env('DB_DATABASE', 'database.sqlite')
);
}

View File

@ -24,7 +24,7 @@ class ProcessRunnableCommand extends Command
->whereRelation('server', fn (Builder $builder) => $builder->whereNull('status'))
->where('is_active', true)
->where('is_processing', false)
->whereDate('next_run_at', '<=', Carbon::now()->toDateString())
->whereDate('next_run_at', '<=', Carbon::now()->toDateTimeString())
->get();
if ($schedules->count() < 1) {

View File

@ -6,9 +6,9 @@ use App\Exceptions\DisplayException;
class TwoFactorAuthenticationTokenInvalid extends DisplayException
{
/**
* TwoFactorAuthenticationTokenInvalid constructor.
*/
public string $title = 'Invalid 2FA Code';
public string $icon = 'tabler-2fa';
public function __construct()
{
parent::__construct('The provided two-factor authentication token was not valid.');

View File

@ -8,6 +8,7 @@ use App\Services\Eggs\Sharing\EggImporterService;
use Exception;
use Filament\Actions;
use Filament\Forms;
use Filament\Forms\Components\Tabs;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Table;
@ -62,21 +63,58 @@ class ListEggs extends ListRecords
Actions\Action::make('import')
->label('Import')
->form([
Forms\Components\FileUpload::make('egg')
->acceptedFileTypes(['application/json'])
->storeFiles(false)
->multiple(),
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('From File')
->icon('tabler-file-upload')
->schema([
Forms\Components\FileUpload::make('egg')
->label('Egg')
->hint('This should be the json file ( egg-minecraft.json )')
->acceptedFileTypes(['application/json'])
->storeFiles(false)
->multiple(),
]),
Tabs\Tab::make('From URL')
->icon('tabler-world-upload')
->schema([
Forms\Components\TextInput::make('url')
->label('URL')
->hint('This URL should point to a single json file')
->url(),
]),
])
->contained(false),
])
->action(function (array $data): void {
/** @var TemporaryUploadedFile $eggFile */
$eggFile = $data['egg'];
/** @var EggImporterService $eggImportService */
$eggImportService = resolve(EggImporterService::class);
foreach ($eggFile as $file) {
if (!empty($data['egg'])) {
/** @var TemporaryUploadedFile[] $eggFile */
$eggFile = $data['egg'];
foreach ($eggFile as $file) {
try {
$eggImportService->fromFile($file);
} catch (Exception $exception) {
Notification::make()
->title('Import Failed')
->danger()
->send();
report($exception);
return;
}
}
}
if (!empty($data['url'])) {
try {
$eggImportService->handle($file);
$eggImportService->fromUrl($data['url']);
} catch (Exception $exception) {
Notification::make()
->title('Import Failed')

View File

@ -371,19 +371,20 @@ class CreateServer extends CreateRecord
$text = Forms\Components\TextInput::make('variable_value')
->hidden($this->shouldHideComponent(...))
->maxLength(191)
->rules([
->required(fn (Forms\Get $get) => in_array('required', explode('|', $get('rules'))))
->rules(
fn (Forms\Get $get): Closure => function (string $attribute, $value, Closure $fail) use ($get) {
$validator = Validator::make(['validatorkey' => $value], [
'validatorkey' => $get('rules'),
]);
if ($validator->fails()) {
$message = str($validator->errors()->first())->replace('validatorkey', $get('name'));
$message = str($validator->errors()->first())->replace('validatorkey', $get('name'))->toString();
$fail($message);
}
},
]);
);
$select = Forms\Components\Select::make('variable_value')
->hidden($this->shouldHideComponent(...))

View File

@ -576,6 +576,7 @@ class EditServer extends EditRecord
->options(fn (Server $server) => $server->node->mounts->mapWithKeys(fn ($mount) => [$mount->id => $mount->name]))
->descriptions(fn (Server $server) => $server->node->mounts->mapWithKeys(fn ($mount) => [$mount->id => "$mount->source -> $mount->target"]))
->label('Mounts')
->helperText(fn (Server $server) => $server->node->mounts->isNotEmpty() ? '' : 'No Mounts exist for this Node')
->columnSpanFull(),
]),
Tabs\Tab::make('Databases')

View File

@ -3,6 +3,7 @@
namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource;
use App\Services\Exceptions\FilamentExceptionHandler;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use App\Models\User;
@ -77,4 +78,9 @@ class EditUser extends EditRecord
{
return [];
}
public function exception($exception, $stopPropagation): void
{
(new FilamentExceptionHandler())->handle($exception, $stopPropagation);
}
}

View File

@ -46,7 +46,7 @@ class EggShareController extends Controller
*/
public function import(EggImportFormRequest $request): RedirectResponse
{
$egg = $this->importerService->handle($request->file('import_file'));
$egg = $this->importerService->fromFile($request->file('import_file'));
$this->alert->success(trans('admin/eggs.notices.imported'))->flash();
return redirect()->route('admin.eggs.view', ['egg' => $egg->id]);
@ -61,7 +61,7 @@ class EggShareController extends Controller
*/
public function update(EggImportFormRequest $request, Egg $egg): RedirectResponse
{
$this->updateImporterService->handle($egg, $request->file('import_file'));
$this->updateImporterService->fromFile($egg, $request->file('import_file'));
$this->alert->success(trans('admin/eggs.notices.updated_via_import'))->flash();
return redirect()->route('admin.eggs.view', ['egg' => $egg]);

View File

@ -3,7 +3,6 @@
namespace App\Http\Controllers\Admin\Nodes;
use Illuminate\View\View;
use Illuminate\Http\Request;
use App\Models\Node;
use Spatie\QueryBuilder\QueryBuilder;
use App\Http\Controllers\Controller;
@ -13,7 +12,7 @@ class NodeController extends Controller
/**
* Returns a listing of nodes on the system.
*/
public function index(Request $request): View
public function index(): View
{
$nodes = QueryBuilder::for(
Node::query()->withCount('servers')

View File

@ -3,7 +3,6 @@
namespace App\Http\Controllers\Admin\Nodes;
use Illuminate\View\View;
use Illuminate\Http\Request;
use App\Models\Node;
use Illuminate\Support\Collection;
use App\Models\Allocation;
@ -29,16 +28,10 @@ class NodeViewController extends Controller
/**
* Returns index view for a specific node on the system.
*/
public function index(Request $request, Node $node): View
public function index(Node $node): View
{
$node->loadCount('servers');
$stats = Node::query()
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
->join('servers', 'servers.node_id', '=', 'nodes.id')
->where('node_id', '=', $node->id)
->first();
return view('admin.nodes.view.index', [
'node' => $node,
'version' => $this->versionService,
@ -48,7 +41,7 @@ class NodeViewController extends Controller
/**
* Returns the settings page for a specific node.
*/
public function settings(Request $request, Node $node): View
public function settings(Node $node): View
{
return view('admin.nodes.view.settings', [
'node' => $node,
@ -58,7 +51,7 @@ class NodeViewController extends Controller
/**
* Return the node configuration page for a specific node.
*/
public function configuration(Request $request, Node $node): View
public function configuration(Node $node): View
{
return view('admin.nodes.view.configuration', compact('node'));
}
@ -66,7 +59,7 @@ class NodeViewController extends Controller
/**
* Return the node allocation management page.
*/
public function allocations(Request $request, Node $node): View
public function allocations(Node $node): View
{
$node->setRelation(
'allocations',
@ -92,7 +85,7 @@ class NodeViewController extends Controller
/**
* Return a listing of servers that exist for this specific node.
*/
public function servers(Request $request, Node $node): View
public function servers(Node $node): View
{
$this->plainInject([
'node' => Collection::wrap($node->makeVisible(['daemon_token_id', 'daemon_token']))

View File

@ -3,7 +3,6 @@
namespace App\Http\Controllers\Admin\Servers;
use Illuminate\View\View;
use Illuminate\Http\Request;
use App\Models\Server;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
@ -16,7 +15,7 @@ class ServerController extends Controller
* Returns all the servers that exist on the system using a paginated result set. If
* a query is passed along in the request it is also passed to the repository function.
*/
public function index(Request $request): View
public function index(): View
{
$servers = QueryBuilder::for(Server::query()->with('node', 'user', 'allocation'))
->allowedFilters([

View File

@ -37,7 +37,7 @@ class UserController extends Controller
/**
* Display user index page.
*/
public function index(Request $request): View
public function index(): View
{
$users = QueryBuilder::for(
User::query()->select('users.*')

View File

@ -124,38 +124,6 @@ class EggConfigurationService
return $response;
}
/**
* Replaces the legacy modifies from eggs with their new counterpart. The legacy Daemon would
* set SERVER_MEMORY, SERVER_IP, and SERVER_PORT with their respective values on the Daemon
* side. Ensure that anything referencing those properly replaces them with the matching config
* value.
*/
protected function replaceLegacyModifiers(string $key, string $value): string
{
switch ($key) {
case 'config.docker.interface':
$replace = 'config.docker.network.interface';
break;
case 'server.build.env.SERVER_MEMORY':
case 'env.SERVER_MEMORY':
$replace = 'server.build.memory';
break;
case 'server.build.env.SERVER_IP':
case 'env.SERVER_IP':
$replace = 'server.build.default.ip';
break;
case 'server.build.env.SERVER_PORT':
case 'env.SERVER_PORT':
$replace = 'server.build.default.port';
break;
default:
// By default, we don't need to change anything, only if we ended up matching a specific legacy item.
$replace = $key;
}
return str_replace("{{{$key}}}", "{{{$replace}}}", $value);
}
protected function matchAndReplaceKeys(mixed $value, array $structure): mixed
{
preg_match_all('/{{(?<key>[\w.-]*)}}/', $value, $matches);
@ -175,8 +143,6 @@ class EggConfigurationService
continue;
}
$value = $this->replaceLegacyModifiers($key, $value);
// We don't want to do anything with config keys since the Daemon will need to handle
// that. For example, the Spigot egg uses "config.docker.interface" to identify the Docker
// interface to proxy through, but the Panel would be unaware of that.
@ -198,7 +164,7 @@ class EggConfigurationService
// variable from the server configuration.
$plucked = Arr::get(
$structure,
preg_replace('/^env\./', 'build.env.', $key),
preg_replace('/^env\./', 'build.environment.', $key),
''
);

View File

@ -10,6 +10,16 @@ use App\Exceptions\Service\InvalidFileUploadException;
class EggParserService
{
public const UPGRADE_VARIABLES = [
'server.build.env.SERVER_IP' => 'server.allocations.default.ip',
'server.build.default.ip' => 'server.allocations.default.ip',
'server.build.env.SERVER_PORT' => 'server.allocations.default.port',
'server.build.default.port' => 'server.allocations.default.port',
'server.build.env.SERVER_MEMORY' => 'server.build.memory_limit',
'server.build.memory' => 'server.build.memory_limit',
'server.build.env' => 'server.build.environment',
];
/**
* Takes an uploaded file and parses out the egg configuration from within.
*
@ -26,11 +36,20 @@ class EggParserService
$version = $parsed['meta']['version'] ?? '';
return match ($version) {
$parsed = match ($version) {
'PTDL_v1' => $this->convertToV2($parsed),
'PTDL_v2' => $parsed,
default => throw new InvalidFileUploadException('The JSON file provided is not in a format that can be recognized.')
};
// Make sure we only use recent variable format from now on
$parsed['config']['files'] = str_replace(
array_keys(self::UPGRADE_VARIABLES),
array_values(self::UPGRADE_VARIABLES),
$parsed['config']['files'] ?? '',
);
return $parsed;
}
/**

View File

@ -9,6 +9,7 @@ use Illuminate\Http\UploadedFile;
use App\Models\EggVariable;
use Illuminate\Database\ConnectionInterface;
use App\Services\Eggs\EggParserService;
use Spatie\TemporaryDirectory\TemporaryDirectory;
class EggImporterService
{
@ -21,7 +22,7 @@ class EggImporterService
*
* @throws \App\Exceptions\Service\InvalidFileUploadException|\Throwable
*/
public function handle(UploadedFile $file): Egg
public function fromFile(UploadedFile $file): Egg
{
$parsed = $this->parser->handle($file);
@ -45,4 +46,20 @@ class EggImporterService
return $egg;
});
}
/**
* Take an url and parse it into a new egg.
*
* @throws \App\Exceptions\Service\InvalidFileUploadException|\Throwable
*/
public function fromUrl(string $url): Egg
{
$info = pathinfo($url);
$tmpDir = TemporaryDirectory::make()->deleteWhenDestroyed();
$tmpPath = $tmpDir->path($info['basename']);
file_put_contents($tmpPath, file_get_contents($url));
return $this->fromFile(new UploadedFile($tmpPath, $info['basename'], 'application/json'));
}
}

View File

@ -8,6 +8,7 @@ use Illuminate\Support\Collection;
use App\Models\EggVariable;
use Illuminate\Database\ConnectionInterface;
use App\Services\Eggs\EggParserService;
use Spatie\TemporaryDirectory\TemporaryDirectory;
class EggUpdateImporterService
{
@ -23,7 +24,7 @@ class EggUpdateImporterService
*
* @throws \App\Exceptions\Service\InvalidFileUploadException|\Throwable
*/
public function handle(Egg $egg, UploadedFile $file): Egg
public function fromFile(Egg $egg, UploadedFile $file): Egg
{
$parsed = $this->parser->handle($file);
@ -47,4 +48,20 @@ class EggUpdateImporterService
return $egg->refresh();
});
}
/**
* Update an existing Egg using an url.
*
* @throws \App\Exceptions\Service\InvalidFileUploadException|\Throwable
*/
public function fromUrl(Egg $egg, string $url): Egg
{
$info = pathinfo($url);
$tmpDir = TemporaryDirectory::make()->deleteWhenDestroyed();
$tmpPath = $tmpDir->path($info['basename']);
file_put_contents($tmpPath, file_get_contents($url));
return $this->fromFile($egg, new UploadedFile($tmpPath, $info['basename'], 'application/json'));
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Services\Exceptions;
use Exception;
use Filament\Notifications\Notification;
class FilamentExceptionHandler
{
public function handle(Exception $exception, callable $stopPropagation): void
{
Notification::make()
->title($exception->title ?? null)
->body($exception->body ?? $exception->getMessage())
->color($exception->color ?? 'danger')
->icon($exception->icon ?? 'tabler-x')
->danger()
->send();
if ($this->stopPropagation ?? true) {
$stopPropagation();
}
}
}

View File

@ -27,6 +27,8 @@ class NodeUpdateService
*/
public function handle(Node $node, array $data, bool $resetToken = false): Node
{
$data['id'] = $node->id;
if ($resetToken) {
$data['daemon_token'] = Str::random(Node::DAEMON_TOKEN_LENGTH);
$data['daemon_token_id'] = Str::random(Node::DAEMON_TOKEN_ID_LENGTH);
@ -35,15 +37,9 @@ class NodeUpdateService
[$updated, $exception] = $this->connection->transaction(function () use ($data, $node) {
/** @var \App\Models\Node $updated */
$updated = $node->replicate();
$updated->exists = true;
$updated->forceFill($data)->save();
try {
// If we're changing the FQDN for the node, use the newly provided FQDN for the connection
// address. This should alleviate issues where the node gets pointed to a "valid" FQDN that
// isn't actually running the daemon software, and therefore you can't actually change it
// back.
//
// This makes more sense anyways, because only the Panel uses the FQDN for connecting, the
// node doesn't actually care about this.
$node->fqdn = $updated->fqdn;
$this->configurationRepository->setNode($node)->update($updated);

View File

@ -9,10 +9,7 @@ return Application::configure(basePath: dirname(__DIR__))
\Prologue\Alerts\AlertsServiceProvider::class,
])
->withRouting(
web: __DIR__.'/../routes/web.php',
// api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
// channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {

View File

@ -33,6 +33,7 @@
"s1lentium/iptools": "~1.2.0",
"spatie/laravel-fractal": "^6.2",
"spatie/laravel-query-builder": "^5.8.1",
"spatie/temporary-directory": "^2.2",
"symfony/http-client": "^7.1",
"symfony/mailgun-mailer": "^7.1",
"symfony/postmark-mailer": "^7.0.7",

65
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8feeafbeb16044bd6716510a73393fc0",
"content-hash": "bf44faee3aae2b1d4c1b57893c1aba98",
"packages": [
{
"name": "abdelhamiderrahmouni/filament-monaco-editor",
@ -6990,6 +6990,67 @@
],
"time": "2024-05-10T08:19:35+00:00"
},
{
"name": "spatie/temporary-directory",
"version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/temporary-directory.git",
"reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
"reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\TemporaryDirectory\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alex Vanderbist",
"email": "alex@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Easily create, use and destroy temporary directories",
"homepage": "https://github.com/spatie/temporary-directory",
"keywords": [
"php",
"spatie",
"temporary-directory"
],
"support": {
"issues": "https://github.com/spatie/temporary-directory/issues",
"source": "https://github.com/spatie/temporary-directory/tree/2.2.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2023-12-25T11:46:58+00:00"
},
{
"name": "symfony/clock",
"version": "v7.0.7",
@ -13096,5 +13157,5 @@
"ext-zip": "*"
},
"platform-dev": [],
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.3.0"
}

View File

@ -75,10 +75,10 @@ class EggSeeder extends Seeder
->first();
if ($egg instanceof Egg) {
$this->updateImporterService->handle($egg, $file);
$this->updateImporterService->fromFile($egg, $file);
$this->command->info('Updated ' . $decoded['name']);
} else {
$this->importerService->handle($file);
$this->importerService->fromFile($file);
$this->command->comment('Created ' . $decoded['name']);
}
}

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:01+00:00",
"exported_at": "2024-06-04T22:51:49+00:00",
"name": "Bungeecord",
"author": "panel@example.com",
"uuid": "9e6b409e-4028-4947-aea8-50a2c404c271",
@ -24,7 +24,7 @@
"file_denylist": [],
"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"config.yml\": {\r\n \"parser\": \"yaml\",\r\n \"find\": {\r\n \"listeners[0].query_port\": \"{{server.build.default.port}}\",\r\n \"listeners[0].host\": \"0.0.0.0:{{server.build.default.port}}\",\r\n \"servers.*.address\": {\r\n \"regex:^(127\\\\.0\\\\.0\\\\.1|localhost)(:\\\\d{1,5})?$\": \"{{config.docker.interface}}$2\"\r\n }\r\n }\r\n }\r\n}",
"files": "{\r\n \"config.yml\": {\r\n \"parser\": \"yaml\",\r\n \"find\": {\r\n \"listeners[0].query_port\": \"{{server.allocations.default.port}}\",\r\n \"listeners[0].host\": \"0.0.0.0:{{server.allocations.default.port}}\",\r\n \"servers.*.address\": {\r\n \"regex:^(127\\\\.0\\\\.0\\\\.1|localhost)(:\\\\d{1,5})?$\": \"{{config.docker.interface}}$2\"\r\n }\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \"Listening on \"\r\n}",
"logs": "{}",
"stop": "end"

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:02+00:00",
"exported_at": "2024-06-04T22:51:58+00:00",
"name": "Forge Minecraft",
"author": "panel@example.com",
"uuid": "ed072427-f209-4603-875c-f540c6dd5a65",
@ -24,7 +24,7 @@
"file_denylist": [],
"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -Dterminal.jline=false -Dterminal.ansi=true $( [[ ! -f unix_args.txt ]] && printf %s \"-jar {{SERVER_JARFILE}}\" || printf %s \"@unix_args.txt\" )",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.allocations.default.port}}\",\r\n \"query.port\": \"{{server.allocations.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \"\r\n}",
"logs": "{}",
"stop": "stop"

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:02+00:00",
"exported_at": "2024-06-04T22:51:57+00:00",
"name": "Paper",
"author": "parker@example.com",
"uuid": "5da37ef6-58da-4169-90a6-e683e1721247",
@ -24,7 +24,7 @@
"file_denylist": [],
"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.allocations.default.port}}\",\r\n \"query.port\": \"{{server.allocations.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \"\r\n}",
"logs": "{}",
"stop": "stop"

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:03+00:00",
"exported_at": "2024-06-04T22:50:55+00:00",
"name": "Sponge (SpongeVanilla)",
"author": "panel@example.com",
"uuid": "f0d2f88f-1ff3-42a0-b03f-ac44c5571e6d",
@ -24,7 +24,7 @@
"file_denylist": [],
"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.allocations.default.port}}\",\r\n \"query.port\": \"{{server.allocations.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \"\r\n}",
"logs": "{}",
"stop": "stop"
@ -60,4 +60,4 @@
"field_type": "text"
}
]
}
}

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:03+00:00",
"exported_at": "2024-06-04T22:51:16+00:00",
"name": "Vanilla Minecraft",
"author": "panel@example.com",
"uuid": "9ac39f3d-0c34-4d93-8174-c52ab9e6c57b",
@ -24,7 +24,7 @@
"file_denylist": [],
"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}",
"config": {
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"server-port\": \"{{server.allocations.default.port}}\",\r\n \"query.port\": \"{{server.allocations.default.port}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \")! For help, type \"\r\n}",
"logs": "{}",
"stop": "stop"

View File

@ -4,7 +4,7 @@
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2024-06-02T20:42:08+00:00",
"exported_at": "2024-06-04T22:53:03+00:00",
"name": "Mumble Server",
"author": "panel@example.com",
"uuid": "727ee758-7fb2-4979-972b-d3eba4e1e9f0",
@ -16,7 +16,7 @@
"file_denylist": [],
"startup": "mumble-server -fg -ini murmur.ini",
"config": {
"files": "{\r\n \"murmur.ini\": {\r\n \"parser\": \"ini\",\r\n \"find\": {\r\n \"database\": \"\/home\/container\/murmur.sqlite\",\r\n \"logfile\": \"\/home\/container\/murmur.log\",\r\n \"port\": \"{{server.build.default.port}}\",\r\n \"host\": \"\",\r\n \"users\": \"{{server.build.env.MAX_USERS}}\"\r\n }\r\n }\r\n}",
"files": "{\r\n \"murmur.ini\": {\r\n \"parser\": \"ini\",\r\n \"find\": {\r\n \"database\": \"\/home\/container\/murmur.sqlite\",\r\n \"logfile\": \"\/home\/container\/murmur.log\",\r\n \"port\": \"{{server.allocations.default.port}}\",\r\n \"host\": \"\",\r\n \"users\": \"{{server.environment.MAX_USERS}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \"Server listening on\"\r\n}",
"logs": "{}",
"stop": "^C"

View File

@ -0,0 +1,92 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
$eggs = DB::table('eggs')->get();
foreach ($eggs as $egg) {
$updatedPort = str_replace(
'server.build.default.port',
'server.allocations.default.port',
$egg->config_files
);
if ($updatedPort !== $egg->config_files) {
$egg->config_files = $updatedPort;
echo "Processed Port update with ID: {$egg->name}\n";
}
$updatedIp = str_replace(
'server.build.default.ip',
'server.allocations.default.ip',
$egg->config_files
);
if ($updatedIp !== $egg->config_files) {
$egg->config_files = $updatedIp;
echo "Processed IP update with ID: {$egg->name}\n";
}
$updatedEnv = str_replace(
'server.build.env.',
'server.environment.',
$egg->config_files
);
if ($updatedEnv !== $egg->config_files) {
$egg->config_files = $updatedEnv;
echo "Processed ENV update with ID: {$egg->name}\n";
}
DB::table('eggs')
->where('id', $egg->id)
->update(['config_files' => $egg->config_files]);
}
}
public function down(): void
{
$eggs = DB::table('eggs')->get();
foreach ($eggs as $egg) {
$revertedEnv = str_replace(
'server.environment.',
'server.build.env.',
$egg->config_files
);
if ($revertedEnv !== $egg->config_files) {
$egg->config_files = $revertedEnv;
}
$revertedIp = str_replace(
'server.allocations.default.ip',
'server.build.default.ip',
$egg->config_files
);
if ($revertedIp !== $egg->config_files) {
$egg->config_files = $revertedIp;
}
$revertedPort = str_replace(
'server.allocations.default.port',
'server.build.default.port',
$egg->config_files
);
if ($revertedPort !== $egg->config_files) {
$egg->config_files = $revertedPort;
}
DB::table('eggs')
->where('id', $egg->id)
->update(['config_files' => $egg->config_files]);
}
}
};

View File

@ -26,46 +26,20 @@ This gives you the power to run game servers without bloating machines with a ho
Some of our popular eggs include but are not limited to:
* [Minecraft](https://github.com/pelican-eggs/minecraft)
* Paper
* Sponge
* Bungeecord
* Waterfall
* [SteamCMD](https://github.com/pelican-eggs/steamcmd)
* 7 Days to Die
* ARK: Survival
* ARMA
* Counter Strike
* DayZ
* Enshrouded
* Left 4 Dead
* Palworld
* Project Zomboid
* Sons of the Forest
* [Other Games](https://github.com/pelican-eggs/games)
* Among Us
* Factorio
* GTA
* Rimworld
* Terraria
* [Discord Bots](https://github.com/pelican-eggs/chatbots)
* Redbot
* JMusicBot
* SinusBot
* Dynamica
* [Software](https://github.com/pelican-eggs/software)
* [Programming Languages](https://github.com/pelican-eggs/generic)
* C#
* Java
* Lua
* Node.js
* Python
* [Database](https://github.com/pelican-eggs/database)
* Redis
* MariaDB
* PostgreSQL
* [Voice Servers](https://github.com/pelican-eggs/voice)
* [Storage](https://github.com/pelican-eggs/storage)
* [Monitoring](https://github.com/pelican-eggs/monitoring)
| Category | Eggs | | | |
|----------------------------------------------------------------------|-----------------|---------------|--------------------|----------------|
| [Minecraft](https://github.com/pelican-eggs/minecraft) | Paper | Sponge | Bungeecord | Waterfall |
| [SteamCMD](https://github.com/pelican-eggs/steamcmd) | 7 Days to Die | ARK: Survival | Arma 3 | Counter Strike |
| | DayZ | Enshrouded | Left 4 Dead | Palworld |
| | Project Zomboid | Satisfactory | Sons of the Forest | Starbound |
| [Standalone Games](https://github.com/pelican-eggs/games-standalone) | Among Us | Factorio | FTL | GTA |
| | Kerbal Space | Mindustry | Rimworld | Terraria |
| [Discord Bots](https://github.com/pelican-eggs/chatbots) | Redbot | JMusicBot | JMusicBot | Dynamica |
| [Voice Servers](https://github.com/pelican-eggs/voice) | Mumble | Teamspeak | Lavalink | |
| [Software](https://github.com/pelican-eggs/software) | Elasticsearch | Gitea | Grafana | RabbitMQ |
| [Programming](https://github.com/pelican-eggs/generic) | Node.js | Python | Java | C# |
| [Databases](https://github.com/pelican-eggs/database) | Redis | MariaDB | PostgreSQL | MongoDB |
| [Storage](https://github.com/pelican-eggs/storage) | S3 | SFTP Share | | |
| [Monitoring](https://github.com/pelican-eggs/monitoring) | Prometheus | Loki | | |
Copyright Pelican® 2024
*Copyright Pelican® 2024*