feat(proxy-dashboard): implement ProxyDashboardCacheService to manage Traefik dashboard cache; clear cache on configuration changes and proxy actions
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Actions\Proxy;
|
namespace App\Actions\Proxy;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class SaveConfiguration
|
class SaveConfiguration
|
||||||
@@ -20,6 +21,9 @@ class SaveConfiguration
|
|||||||
$server->proxy->last_saved_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
|
$server->proxy->last_saved_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache when configuration is saved
|
||||||
|
ProxyDashboardCacheService::clearCache($server);
|
||||||
|
|
||||||
return instant_remote_process([
|
return instant_remote_process([
|
||||||
"mkdir -p $proxy_path",
|
"mkdir -p $proxy_path",
|
||||||
"echo '$docker_compose_yml_base64' | base64 -d | tee $proxy_path/docker-compose.yml > /dev/null",
|
"echo '$docker_compose_yml_base64' | base64 -d | tee $proxy_path/docker-compose.yml > /dev/null",
|
||||||
|
@@ -5,6 +5,7 @@ namespace App\Actions\Proxy;
|
|||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use App\Events\ProxyStatusChanged;
|
use App\Events\ProxyStatusChanged;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
@@ -28,6 +29,10 @@ class StartProxy
|
|||||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||||
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
|
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache when proxy configuration changes
|
||||||
|
ProxyDashboardCacheService::clearCache($server);
|
||||||
|
|
||||||
if ($server->isSwarmManager()) {
|
if ($server->isSwarmManager()) {
|
||||||
$commands = $commands->merge([
|
$commands = $commands->merge([
|
||||||
"mkdir -p $proxy_path/dynamic",
|
"mkdir -p $proxy_path/dynamic",
|
||||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Proxy;
|
|||||||
|
|
||||||
use App\Events\ProxyStatusChanged;
|
use App\Events\ProxyStatusChanged;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class StopProxy
|
class StopProxy
|
||||||
@@ -23,6 +24,9 @@ class StopProxy
|
|||||||
$server->proxy->force_stop = $forceStop;
|
$server->proxy->force_stop = $forceStop;
|
||||||
$server->proxy->status = 'exited';
|
$server->proxy->status = 'exited';
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache when proxy stops
|
||||||
|
ProxyDashboardCacheService::clearCache($server);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@@ -6,6 +6,7 @@ use App\Actions\Proxy\CheckProxy;
|
|||||||
use App\Actions\Proxy\StartProxy;
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Actions\Proxy\StopProxy;
|
use App\Actions\Proxy\StopProxy;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@@ -39,6 +40,9 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
StartProxy::run($this->server, force: true);
|
StartProxy::run($this->server, force: true);
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache after proxy restart
|
||||||
|
ProxyDashboardCacheService::clearCache($this->server);
|
||||||
|
|
||||||
// CheckProxy::run($this->server, true);
|
// CheckProxy::run($this->server, true);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
|
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Server;
|
namespace App\Livewire\Server;
|
||||||
|
|
||||||
use App\Actions\Proxy\CheckConfiguration;
|
|
||||||
use App\Actions\Proxy\CheckProxy;
|
use App\Actions\Proxy\CheckProxy;
|
||||||
use App\Actions\Proxy\StartProxy;
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Actions\Proxy\StopProxy;
|
use App\Actions\Proxy\StopProxy;
|
||||||
use App\Jobs\RestartProxyJob;
|
use App\Jobs\RestartProxyJob;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Navbar extends Component
|
class Navbar extends Component
|
||||||
@@ -36,17 +36,13 @@ class Navbar extends Component
|
|||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
$this->currentRoute = request()->route()->getName();
|
$this->currentRoute = request()->route()->getName();
|
||||||
$this->serverIp = $this->server->id === 0 ? base_ip() : $this->server->ip;
|
$this->serverIp = $this->server->id === 0 ? base_ip() : $this->server->ip;
|
||||||
|
$this->loadProxyConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadProxyConfiguration()
|
public function loadProxyConfiguration()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$proxy_settings = CheckConfiguration::run($this->server);
|
$this->traefikDashboardAvailable = ProxyDashboardCacheService::isTraefikDashboardAvailable($this->server);
|
||||||
if (str($proxy_settings)->contains('--api.dashboard=true') && str($proxy_settings)->contains('--api.insecure=true')) {
|
|
||||||
$this->traefikDashboardAvailable = true;
|
|
||||||
} else {
|
|
||||||
$this->traefikDashboardAvailable = false;
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
@@ -55,6 +51,8 @@ class Navbar extends Component
|
|||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
// Clear cache before restarting proxy
|
||||||
|
ProxyDashboardCacheService::clearCache($this->server);
|
||||||
RestartProxyJob::dispatch($this->server);
|
RestartProxyJob::dispatch($this->server);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
@@ -123,7 +121,7 @@ class Navbar extends Component
|
|||||||
if ($forceStop) {
|
if ($forceStop) {
|
||||||
$this->dispatch('info', 'Proxy is stopped manually.');
|
$this->dispatch('info', 'Proxy is stopped manually.');
|
||||||
} else {
|
} else {
|
||||||
$this->dispatch('info', 'Proxy is stopped manually. Starting in a moment.');
|
$this->dispatch('info', 'Proxy is stopped manually.<br>Starting in a moment.');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@@ -5,6 +5,7 @@ namespace App\Livewire\Server;
|
|||||||
use App\Actions\Proxy\CheckConfiguration;
|
use App\Actions\Proxy\CheckConfiguration;
|
||||||
use App\Actions\Proxy\SaveConfiguration;
|
use App\Actions\Proxy\SaveConfiguration;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Services\ProxyDashboardCacheService;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Proxy extends Component
|
class Proxy extends Component
|
||||||
@@ -41,6 +42,10 @@ class Proxy extends Component
|
|||||||
{
|
{
|
||||||
$this->server->proxy = null;
|
$this->server->proxy = null;
|
||||||
$this->server->save();
|
$this->server->save();
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache when proxy type changes
|
||||||
|
ProxyDashboardCacheService::clearCache($this->server);
|
||||||
|
|
||||||
$this->dispatch('reloadWindow');
|
$this->dispatch('reloadWindow');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +54,10 @@ class Proxy extends Component
|
|||||||
try {
|
try {
|
||||||
$this->server->changeProxy($proxy_type, async: false);
|
$this->server->changeProxy($proxy_type, async: false);
|
||||||
$this->selectedProxy = $this->server->proxy->type;
|
$this->selectedProxy = $this->server->proxy->type;
|
||||||
|
|
||||||
|
// Clear Traefik dashboard cache when proxy type is selected
|
||||||
|
ProxyDashboardCacheService::clearCache($this->server);
|
||||||
|
|
||||||
$this->dispatch('reloadWindow');
|
$this->dispatch('reloadWindow');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
67
app/Services/ProxyDashboardCacheService.php
Normal file
67
app/Services/ProxyDashboardCacheService.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class ProxyDashboardCacheService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get Redis cache key for Traefik dashboard availability
|
||||||
|
*/
|
||||||
|
public static function getCacheKey(Server $server): string
|
||||||
|
{
|
||||||
|
return "server:{$server->id}:traefik:dashboard_available";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if Traefik dashboard is available (from cache or compute)
|
||||||
|
*/
|
||||||
|
public static function isTraefikDashboardAvailable(Server $server): bool
|
||||||
|
{
|
||||||
|
$cacheKey = static::getCacheKey($server);
|
||||||
|
|
||||||
|
// Try to get from cache first
|
||||||
|
$cachedValue = Cache::get($cacheKey);
|
||||||
|
|
||||||
|
if ($cachedValue !== null) {
|
||||||
|
return $cachedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not in cache, compute the value
|
||||||
|
try {
|
||||||
|
$proxy_settings = \App\Actions\Proxy\CheckConfiguration::run($server);
|
||||||
|
$dashboardAvailable = str($proxy_settings)->contains('--api.dashboard=true') &&
|
||||||
|
str($proxy_settings)->contains('--api.insecure=true');
|
||||||
|
|
||||||
|
// Cache the result (cache indefinitely until proxy restart)
|
||||||
|
Cache::forever($cacheKey, $dashboardAvailable);
|
||||||
|
|
||||||
|
return $dashboardAvailable;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// If there's an error checking configuration, default to false and don't cache
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear Traefik dashboard cache for a server
|
||||||
|
*/
|
||||||
|
public static function clearCache(Server $server): void
|
||||||
|
{
|
||||||
|
$cacheKey = static::getCacheKey($server);
|
||||||
|
Cache::forget($cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear Traefik dashboard cache for multiple servers
|
||||||
|
*/
|
||||||
|
public static function clearCacheForServers(array $serverIds): void
|
||||||
|
{
|
||||||
|
foreach ($serverIds as $serverId) {
|
||||||
|
$cacheKey = "server:{$serverId}:traefik:dashboard_available";
|
||||||
|
Cache::forget($cacheKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,7 +17,7 @@
|
|||||||
<livewire:server.navbar :server="$server" :parameters="$parameters" />
|
<livewire:server.navbar :server="$server" :parameters="$parameters" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<h2 class="pt-4">Terminal</h2>
|
<h2 class="pb-4">Terminal</h2>
|
||||||
@if (!$hasShell)
|
@if (!$hasShell)
|
||||||
<div class="flex items-center justify-center w-full py-4 mx-auto">
|
<div class="flex items-center justify-center w-full py-4 mx-auto">
|
||||||
<div class="p-4 w-full rounded-sm border dark:bg-coolgray-100 dark:border-coolgray-300">
|
<div class="p-4 w-full rounded-sm border dark:bg-coolgray-100 dark:border-coolgray-300">
|
||||||
|
Reference in New Issue
Block a user