Files
ladill-hosting/app/Services/Hosting/HostingNodePoolService.php
T
isaaccladandCursor e251a4cf60
Deploy Ladill Hosting / deploy (push) Failing after 17s
Initial Ladill Hosting app with Gitea deploy pipeline.
Shared web hosting extracted from the platform monolith, with CI deploy
to /var/www/ladill-hosting matching Bird/Domains/Email.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:24:20 +00:00

87 lines
2.5 KiB
PHP

<?php
namespace App\Services\Hosting;
use App\Models\HostingAccount;
use App\Models\HostingNode;
use Illuminate\Support\Collection;
class HostingNodePoolService
{
public function poolRoot(HostingNode $node): HostingNode
{
return $node->isExtension() && $node->primary
? $node->primary
: $node;
}
/**
* @return Collection<int, HostingNode>
*/
public function poolMembers(HostingNode $node): Collection
{
$root = $this->poolRoot($node);
return HostingNode::query()
->where(function ($query) use ($root) {
$query->where('id', $root->id)
->orWhere('primary_hosting_node_id', $root->id);
})
->where('type', HostingNode::TYPE_SHARED)
->whereNotIn('status', [HostingNode::STATUS_DECOMMISSIONED])
->orderBy('role')
->get();
}
public function poolDiskGb(HostingNode $node): int
{
return (int) $this->poolMembers($node)->sum('disk_gb');
}
public function poolLogicalCapacityGb(HostingNode $node): float
{
return round($this->poolMembers($node)->sum(fn (HostingNode $m) => $m->logicalCapacityGb()), 2);
}
public function poolAllocatedDiskGb(HostingNode $node): int
{
$memberIds = $this->poolMembers($node)->pluck('id');
return (int) HostingAccount::query()
->whereIn('hosting_node_id', $memberIds)
->where('type', HostingAccount::TYPE_SHARED)
->sum('allocated_disk_gb');
}
public function poolUsedDiskGb(HostingNode $node): int
{
$memberIds = $this->poolMembers($node)->pluck('id');
$bytes = (int) HostingAccount::query()
->whereIn('hosting_node_id', $memberIds)
->where('type', HostingAccount::TYPE_SHARED)
->sum('disk_used_bytes');
return (int) ceil($bytes / 1073741824);
}
/**
* Member node with the most room for a new shared account.
*/
public function findProvisioningMember(HostingNode $poolRoot, int $requestedDiskGb = 0, ?string $segment = null): ?HostingNode
{
$members = $this->poolMembers($poolRoot)
->filter(fn (HostingNode $n) => $n->canProvision($requestedDiskGb, $segment));
if ($members->isEmpty()) {
return null;
}
return $members->sortBy(fn (HostingNode $n) => sprintf(
'%012.2f-%012d',
(float) $n->current_load_percent,
$n->used_disk_gb,
))->first();
}
}