fix: service navbar using new realtime events

This commit is contained in:
Andras Bacsai 2023-12-08 12:12:44 +01:00
parent 86c2415210
commit b55bd298f2
16 changed files with 107 additions and 33 deletions

View File

@ -39,7 +39,7 @@ public function __construct(CoolifyTaskArgs $remoteProcessArgs)
public function __invoke(): Activity public function __invoke(): Activity
{ {
$job = new CoolifyTask($this->activity, ignore_errors: $this->remoteProcessArgs->ignore_errors); $job = new CoolifyTask($this->activity, ignore_errors: $this->remoteProcessArgs->ignore_errors, call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish);
dispatch($job); dispatch($job);
$this->activity->refresh(); $this->activity->refresh();
return $this->activity; return $this->activity;

View File

@ -21,6 +21,8 @@ class RunRemoteProcess
public bool $ignore_errors; public bool $ignore_errors;
public $call_event_on_finish = null;
protected $time_start; protected $time_start;
protected $current_time; protected $current_time;
@ -34,7 +36,7 @@ class RunRemoteProcess
/** /**
* Create a new job instance. * Create a new job instance.
*/ */
public function __construct(Activity $activity, bool $hide_from_output = false, bool $is_finished = false, bool $ignore_errors = false) public function __construct(Activity $activity, bool $hide_from_output = false, bool $is_finished = false, bool $ignore_errors = false, $call_event_on_finish = null)
{ {
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value) { if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value) {
@ -45,6 +47,7 @@ public function __construct(Activity $activity, bool $hide_from_output = false,
$this->hide_from_output = $hide_from_output; $this->hide_from_output = $hide_from_output;
$this->is_finished = $is_finished; $this->is_finished = $is_finished;
$this->ignore_errors = $ignore_errors; $this->ignore_errors = $ignore_errors;
$this->call_event_on_finish = $call_event_on_finish;
} }
public static function decodeOutput(?Activity $activity = null): string public static function decodeOutput(?Activity $activity = null): string
@ -79,12 +82,18 @@ public function __invoke(): ProcessResult
if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) { if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
$status = ProcessStatus::ERROR; $status = ProcessStatus::ERROR;
} else { } else {
if (($processResult->exitCode() == 0 && $this->is_finished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) { if ($processResult->exitCode() == 0 && $this->is_finished) {
$status = ProcessStatus::FINISHED; $status = ProcessStatus::FINISHED;
} }
if ($processResult->exitCode() != 0 && !$this->ignore_errors) { if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
$status = ProcessStatus::ERROR; $status = ProcessStatus::ERROR;
} }
// if (($processResult->exitCode() == 0 && $this->is_finished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) {
// $status = ProcessStatus::FINISHED;
// }
// if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
// $status = ProcessStatus::ERROR;
// }
} }
$this->activity->properties = $this->activity->properties->merge([ $this->activity->properties = $this->activity->properties->merge([
@ -97,7 +106,16 @@ public function __invoke(): ProcessResult
if ($processResult->exitCode() != 0 && !$this->ignore_errors) { if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode()); throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode());
} }
if ($this->call_event_on_finish) {
try {
event(resolve("App\\Events\\$this->call_event_on_finish", [
'userId' => $this->activity->causer_id,
'typeUuid' => $this->activity->getExtraProperty('type_uuid'),
]));
} catch (\Throwable $e) {
ray($e);
}
}
return $processResult; return $processResult;
} }

View File

@ -23,12 +23,12 @@ public function handle(Service $service)
$commands[] = "echo 'Starting containers.'"; $commands[] = "echo 'Starting containers.'";
$commands[] = "docker compose up -d --remove-orphans --force-recreate --build"; $commands[] = "docker compose up -d --remove-orphans --force-recreate --build";
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true"; $commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
$compose = data_get($service,'docker_compose',[]); $compose = data_get($service, 'docker_compose', []);
$serviceNames = data_get(Yaml::parse($compose),'services',[]); $serviceNames = data_get(Yaml::parse($compose), 'services', []);
foreach($serviceNames as $serviceName => $serviceConfig){ foreach ($serviceNames as $serviceName => $serviceConfig) {
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} || true"; $commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} || true";
} }
$activity = remote_process($commands, $service->server); $activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
return $activity; return $activity;
} }
} }

View File

@ -19,6 +19,7 @@ public function __construct(
public ?Model $model = null, public ?Model $model = null,
public ?string $status = null , public ?string $status = null ,
public bool $ignore_errors = false, public bool $ignore_errors = false,
public $call_event_on_finish = null,
) { ) {
if(is_null($status)){ if(is_null($status)){
$this->status = ProcessStatus::QUEUED->value; $this->status = ProcessStatus::QUEUED->value;

View File

@ -0,0 +1,28 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ServiceStatusChanged implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $userId;
public function __construct($userId = null)
{
$this->userId = $userId;
}
public function broadcastOn(): array
{
return [
new PrivateChannel("custom.{$this->userId}"),
];
}
}

View File

@ -21,6 +21,7 @@ class CoolifyTask implements ShouldQueue, ShouldBeEncrypted
public function __construct( public function __construct(
public Activity $activity, public Activity $activity,
public bool $ignore_errors = false, public bool $ignore_errors = false,
public $call_event_on_finish = null
) { ) {
} }
@ -32,6 +33,7 @@ public function handle(): void
$remote_process = resolve(RunRemoteProcess::class, [ $remote_process = resolve(RunRemoteProcess::class, [
'activity' => $this->activity, 'activity' => $this->activity,
'ignore_errors' => $this->ignore_errors, 'ignore_errors' => $this->ignore_errors,
'call_event_on_finish' => $this->call_event_on_finish
]); ]);
$remote_process(); $remote_process();

View File

@ -3,7 +3,6 @@
namespace App\Livewire\Modal; namespace App\Livewire\Modal;
use App\Models\Service; use App\Models\Service;
use Livewire\Component;
use LivewireUI\Modal\ModalComponent; use LivewireUI\Modal\ModalComponent;
class EditCompose extends ModalComponent class EditCompose extends ModalComponent

View File

@ -133,13 +133,13 @@ public function setServer(Server $server)
public function setDestination(string $destination_uuid) public function setDestination(string $destination_uuid)
{ {
$this->destination_uuid = $destination_uuid; $this->destination_uuid = $destination_uuid;
return $this->redirectRoute('project.resources.new', [ return redirect()->route('project.resources.new', [
'project_uuid' => $this->parameters['project_uuid'], 'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name'], 'environment_name' => $this->parameters['environment_name'],
'type' => $this->type, 'type' => $this->type,
'destination' => $this->destination_uuid, 'destination' => $this->destination_uuid,
'server_id' => $this->server_id, 'server_id' => $this->server_id,
], navigate: true); ]);
} }
public function loadServers() public function loadServers()

View File

@ -13,7 +13,15 @@ class Index extends Component
public $databases; public $databases;
public array $parameters; public array $parameters;
public array $query; public array $query;
protected $listeners = ["refreshStacks", "checkStatus"]; public function getListeners()
{
$userId = auth()->user()->id;
return [
"echo-private:custom.{$userId},ServiceStatusChanged" => 'checkStatus',
"refreshStacks",
"checkStatus",
];
}
public function render() public function render()
{ {
return view('livewire.project.service.index'); return view('livewire.project.service.index');
@ -28,7 +36,7 @@ public function mount()
} }
public function checkStatus() public function checkStatus()
{ {
dispatch(new ContainerStatusJob($this->service->server)); dispatch_sync(new ContainerStatusJob($this->service->server));
$this->refreshStacks(); $this->refreshStacks();
} }
public function refreshStacks() public function refreshStacks()

View File

@ -6,9 +6,6 @@
class Modal extends Component class Modal extends Component
{ {
public function checkStatus() {
$this->dispatch('checkStatus');
}
public function render() public function render()
{ {
return view('livewire.project.service.modal'); return view('livewire.project.service.modal');

View File

@ -4,25 +4,53 @@
use App\Actions\Service\StartService; use App\Actions\Service\StartService;
use App\Actions\Service\StopService; use App\Actions\Service\StopService;
use App\Jobs\ContainerStatusJob;
use App\Models\Service; use App\Models\Service;
use Livewire\Component; use Livewire\Component;
use Spatie\Activitylog\Models\Activity;
class Navbar extends Component class Navbar extends Component
{ {
public Service $service; public Service $service;
public array $parameters; public array $parameters;
public array $query; public array $query;
protected $listeners = ["checkStatus"]; public $isDeploymentProgress = false;
public function checkDeployments() {
$activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
$status = data_get($activity, 'properties.status');
if ($status === 'queued' || $status === 'in_progress') {
$this->isDeploymentProgress = true;
} else {
$this->isDeploymentProgress = false;
}
}
public function getListeners()
{
$userId = auth()->user()->id;
return [
"echo-private:custom.{$userId},ServiceStatusChanged" => 'serviceStatusChanged',
];
}
public function serviceStatusChanged()
{
$this->service->refresh();
}
public function render() public function render()
{ {
return view('livewire.project.service.navbar'); return view('livewire.project.service.navbar');
} }
public function checkStatus() { public function checkStatus()
{
$this->service->refresh(); $this->service->refresh();
} }
public function deploy() public function deploy()
{ {
$this->checkDeployments();
if ($this->isDeploymentProgress) {
$this->dispatch('error', 'There is a deployment in progress.');
return;
}
$this->service->parse(); $this->service->parse();
$activity = StartService::run($this->service); $activity = StartService::run($this->service);
$this->dispatch('newMonitorActivity', $activity->id); $this->dispatch('newMonitorActivity', $activity->id);

View File

@ -8,12 +8,12 @@ class Sponsorship extends Component
{ {
public function getListeners() public function getListeners()
{ {
$teamId = auth()->user()->currentTeam()->id; $userId = auth()->user()->id;
return [ return [
"echo-private:custom.{$teamId},TestEvent" => 'testEvent', "echo-private:custom.{$userId},TestEvent" => 'testEvent',
]; ];
} }
public function testEvent() public function testEvent($asd)
{ {
$this->dispatch('success', 'Realtime events configured!'); $this->dispatch('success', 'Realtime events configured!');
} }

View File

@ -5,7 +5,6 @@
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Symfony\Component\Yaml\Yaml;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class Service extends BaseModel class Service extends BaseModel
@ -207,7 +206,6 @@ public function extraFields()
break; break;
} }
} }
ray($fields);
$databases = $this->databases()->get(); $databases = $this->databases()->get();
foreach ($databases as $database) { foreach ($databases as $database) {

View File

@ -24,6 +24,7 @@ function remote_process(
?string $type_uuid = null, ?string $type_uuid = null,
?Model $model = null, ?Model $model = null,
bool $ignore_errors = false, bool $ignore_errors = false,
$callEventOnFinish = null
): Activity { ): Activity {
if (is_null($type)) { if (is_null($type)) {
$type = ActivityTypes::INLINE->value; $type = ActivityTypes::INLINE->value;
@ -47,18 +48,12 @@ function remote_process(
type: $type, type: $type,
type_uuid: $type_uuid, type_uuid: $type_uuid,
model: $model, model: $model,
ignore_errors: $ignore_errors ignore_errors: $ignore_errors,
call_event_on_finish: $callEventOnFinish,
), ),
])(); ])();
} }
// function removePrivateKeyFromSshAgent(Server $server)
// {
// if (data_get($server, 'privateKey.private_key') === null) {
// throw new \Exception("Server {$server->name} does not have a private key");
// }
// // processWithEnv()->run("echo '{$server->privateKey->private_key}' | ssh-add -d -");
// }
function savePrivateKeyToFs(Server $server) function savePrivateKeyToFs(Server $server)
{ {
if (data_get($server, 'privateKey.private_key') === null) { if (data_get($server, 'privateKey.private_key') === null) {

View File

@ -1,5 +1,5 @@
<div> <div>
<x-modal submitWireAction="checkStatus" modalId="startService"> <x-modal noSubmit modalId="startService">
<x-slot:modalBody> <x-slot:modalBody>
<livewire:activity-monitor header="Service Startup Logs" /> <livewire:activity-monitor header="Service Startup Logs" />
</x-slot:modalBody> </x-slot:modalBody>

View File

@ -48,7 +48,7 @@
if (auth()->user()?->currentTeam()->id !== 0) { if (auth()->user()?->currentTeam()->id !== 0) {
return redirect('/'); return redirect('/');
} }
event(new \App\Events\TestEvent()); event(new \App\Events\TestEvent('asd'));
return 'Look at your other tab.'; return 'Look at your other tab.';
})->middleware('auth'); })->middleware('auth');