lthn.io/app/Core/Cdn/Console/PushAssetsToCdn.php
Claude 41a90cbff8
feat: lthn.io API serving live chain data
Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.

Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 17:17:42 +01:00

198 lines
5.8 KiB
PHP

<?php
/*
* Core PHP Framework
*
* Licensed under the European Union Public Licence (EUPL) v1.2.
* See LICENSE file for details.
*/
declare(strict_types=1);
namespace Core\Cdn\Console;
use Core\Cdn\Services\FluxCdnService;
use Core\Cdn\Services\StorageUrlResolver;
use Core\Plug\Storage\Bunny\VBucket;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class PushAssetsToCdn extends Command
{
protected $signature = 'cdn:push-assets
{--domain=host.uk.com : Workspace domain for vBucket scoping}
{--flux : Push Flux UI assets only}
{--fontawesome : Push Font Awesome assets only}
{--js : Push JavaScript assets only}
{--all : Push all static assets (default)}
{--dry-run : Show what would be uploaded without uploading}';
protected $description = 'Push static assets to CDN storage zone for edge delivery';
protected StorageUrlResolver $cdn;
/**
* VBucket instance (Core\Plug\Storage\Bunny\VBucket when available).
*/
protected ?object $vbucket = null;
protected bool $dryRun = false;
protected int $uploadCount = 0;
protected int $failCount = 0;
public function handle(FluxCdnService $flux, StorageUrlResolver $cdn): int
{
if (! class_exists(VBucket::class)) {
$this->error('Push assets to CDN requires Core\Plug\Storage\Bunny\VBucket class. Plug module not installed.');
return self::FAILURE;
}
$this->cdn = $cdn;
$this->dryRun = $this->option('dry-run');
// Create vBucket for workspace isolation
$domain = $this->option('domain');
$this->vbucket = VBucket::public($domain);
$pushFlux = $this->option('flux');
$pushFontawesome = $this->option('fontawesome');
$pushJs = $this->option('js');
$pushAll = $this->option('all') || (! $pushFlux && ! $pushFontawesome && ! $pushJs);
$this->info("Pushing assets to CDN storage zone for {$domain}...");
$this->line("vBucket: {$this->vbucket->id()}");
$this->newLine();
if ($pushAll || $pushFlux) {
$this->pushFluxAssets($flux);
}
if ($pushAll || $pushFontawesome) {
$this->pushFontAwesomeAssets();
}
if ($pushAll || $pushJs) {
$this->pushJsAssets();
}
$this->newLine();
if ($this->dryRun) {
$this->info("Dry run complete. Would upload {$this->uploadCount} files.");
} else {
$this->info("Upload complete. {$this->uploadCount} files uploaded, {$this->failCount} failed.");
$this->line('CDN URL: '.config('cdn.urls.cdn'));
}
return $this->failCount > 0 ? self::FAILURE : self::SUCCESS;
}
protected function pushFluxAssets(FluxCdnService $flux): void
{
$this->components->info('Flux UI assets');
$assets = $flux->getCdnAssetPaths();
foreach ($assets as $sourcePath => $cdnPath) {
$this->uploadFile($sourcePath, $cdnPath);
}
}
protected function pushFontAwesomeAssets(): void
{
$this->components->info('Font Awesome assets');
$basePath = public_path('vendor/fontawesome');
if (! File::isDirectory($basePath)) {
$this->warn(' Font Awesome directory not found at public/vendor/fontawesome');
return;
}
// Push CSS files
$cssPath = "{$basePath}/css";
if (File::isDirectory($cssPath)) {
foreach (File::files($cssPath) as $file) {
$cdnPath = 'vendor/fontawesome/css/'.$file->getFilename();
$this->uploadFile($file->getPathname(), $cdnPath);
}
}
// Push webfonts
$webfontsPath = "{$basePath}/webfonts";
if (File::isDirectory($webfontsPath)) {
foreach (File::files($webfontsPath) as $file) {
$cdnPath = 'vendor/fontawesome/webfonts/'.$file->getFilename();
$this->uploadFile($file->getPathname(), $cdnPath);
}
}
}
protected function pushJsAssets(): void
{
$this->components->info('JavaScript assets');
$jsPath = public_path('js');
if (! File::isDirectory($jsPath)) {
$this->warn(' JavaScript directory not found at public/js');
return;
}
foreach (File::files($jsPath) as $file) {
if ($file->getExtension() === 'js') {
$cdnPath = 'js/'.$file->getFilename();
$this->uploadFile($file->getPathname(), $cdnPath);
}
}
}
protected function uploadFile(string $sourcePath, string $cdnPath): void
{
if (! file_exists($sourcePath)) {
$this->warn(" ✗ Source not found: {$sourcePath}");
$this->failCount++;
return;
}
$size = $this->formatBytes(filesize($sourcePath));
if ($this->dryRun) {
$this->line(" [DRY-RUN] {$cdnPath} ({$size})");
$this->uploadCount++;
return;
}
// Push directly to CDN storage zone via vBucket (workspace-isolated)
$contents = file_get_contents($sourcePath);
$result = $this->vbucket->putContents($cdnPath, $contents);
if ($result->isOk()) {
$this->line("{$cdnPath} ({$size})");
$this->uploadCount++;
} else {
$this->error(" ✗ Failed: {$cdnPath}");
$this->failCount++;
}
}
protected function formatBytes(int $bytes): string
{
if ($bytes >= 1048576) {
return round($bytes / 1048576, 2).' MB';
}
if ($bytes >= 1024) {
return round($bytes / 1024, 2).' KB';
}
return $bytes.' bytes';
}
}