VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
118 lines
4.0 KiB
PHP
118 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hosting;
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\URL;
|
|
use Phar;
|
|
use PharData;
|
|
use RuntimeException;
|
|
|
|
class ServerAgentReleaseService
|
|
{
|
|
public function currentVersion(): string
|
|
{
|
|
return (string) config('hosting.server_agent.release_version', '0.2.0');
|
|
}
|
|
|
|
/**
|
|
* @return array{version: string, archive_path: string, checksum_sha256: string, filename: string}
|
|
*/
|
|
public function ensureRelease(?string $version = null): array
|
|
{
|
|
$version ??= $this->currentVersion();
|
|
$releaseDirectory = storage_path('app/server-agent/releases/'.$version);
|
|
$packageDirectory = $releaseDirectory.'/package';
|
|
$archiveFilename = "ladill-server-agent-{$version}.tar.gz";
|
|
$archivePath = $releaseDirectory.'/'.$archiveFilename;
|
|
$tarPath = $releaseDirectory."/ladill-server-agent-{$version}.tar";
|
|
|
|
File::ensureDirectoryExists($packageDirectory);
|
|
File::ensureDirectoryExists($releaseDirectory);
|
|
|
|
$renderedFiles = [
|
|
'install.sh' => $this->renderInstallScript(),
|
|
'ladill-server-agent' => $this->renderAgentScript($version),
|
|
'ladill-server-agent.service' => $this->renderTemplate(resource_path('server-agent/ladill-server-agent.service.tpl')),
|
|
'manifest.json' => json_encode([
|
|
'name' => 'ladill-server-agent',
|
|
'version' => $version,
|
|
'built_at' => now()->toIso8601String(),
|
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n",
|
|
];
|
|
|
|
foreach ($renderedFiles as $filename => $contents) {
|
|
File::put($packageDirectory.'/'.$filename, $contents);
|
|
}
|
|
|
|
if (! File::exists($archivePath)) {
|
|
if (File::exists($tarPath)) {
|
|
File::delete($tarPath);
|
|
}
|
|
|
|
try {
|
|
$phar = new PharData($tarPath);
|
|
foreach (array_keys($renderedFiles) as $filename) {
|
|
$phar->addFile($packageDirectory.'/'.$filename, $filename);
|
|
}
|
|
$phar->compress(Phar::GZ);
|
|
unset($phar);
|
|
} catch (\Throwable $e) {
|
|
throw new RuntimeException('Unable to build the server agent release archive.', previous: $e);
|
|
} finally {
|
|
if (File::exists($tarPath)) {
|
|
File::delete($tarPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! File::exists($archivePath)) {
|
|
throw new RuntimeException('The server agent release archive was not created.');
|
|
}
|
|
|
|
return [
|
|
'version' => $version,
|
|
'archive_path' => $archivePath,
|
|
'checksum_sha256' => hash_file('sha256', $archivePath),
|
|
'filename' => $archiveFilename,
|
|
];
|
|
}
|
|
|
|
public function temporaryDownloadUrl(?string $version = null, ?\DateTimeInterface $expiresAt = null): string
|
|
{
|
|
$version ??= $this->currentVersion();
|
|
$expiresAt ??= now()->addMinutes((int) config('hosting.server_agent.signed_release_ttl_minutes', 10080));
|
|
|
|
return URL::temporarySignedRoute('server-agent.releases.download', $expiresAt, [
|
|
'version' => $version,
|
|
]);
|
|
}
|
|
|
|
private function renderAgentScript(string $version): string
|
|
{
|
|
return str_replace(
|
|
['{{AGENT_VERSION}}', '{{HEARTBEAT_INTERVAL_SECONDS}}'],
|
|
[
|
|
$version,
|
|
(string) config('hosting.server_agent.heartbeat_interval_seconds', 15),
|
|
],
|
|
$this->renderTemplate(resource_path('server-agent/ladill-server-agent.sh.tpl'))
|
|
);
|
|
}
|
|
|
|
private function renderInstallScript(): string
|
|
{
|
|
return $this->renderTemplate(resource_path('server-agent/install.sh.tpl'));
|
|
}
|
|
|
|
private function renderTemplate(string $path): string
|
|
{
|
|
$contents = @file_get_contents($path);
|
|
if ($contents === false) {
|
|
throw new RuntimeException("Unable to load server agent release template: {$path}");
|
|
}
|
|
|
|
return $contents;
|
|
}
|
|
}
|