- UpdateDnsRecords Action: controller method now one-liner, all DNS logic in Action with activity logging and edit lock. - Prometheus metrics at /v1/metrics: chain_height, alias_count, claims_pending, dns_tickets, gateways_live. Grafana-ready. - ValidateJsonRequest middleware: enforces application/json on POST, 64KB body size limit. Applied to all /v1/* API routes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
2.5 KiB
PHP
91 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Mod\Names\Actions;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Mod\Chain\Services\DaemonRpc;
|
|
use Mod\Chain\Services\WalletRpc;
|
|
use Mod\Names\Models\DnsTicket;
|
|
use Mod\Names\Models\NameActivity;
|
|
|
|
/**
|
|
* Update DNS records for a .lthn name on the sidechain.
|
|
*
|
|
* $ticket = UpdateDnsRecords::run('mybrand', [
|
|
* ['type' => 'A', 'host' => '@', 'value' => '1.2.3.4'],
|
|
* ]);
|
|
*/
|
|
class UpdateDnsRecords
|
|
{
|
|
public function __construct(
|
|
private readonly DaemonRpc $rpc,
|
|
private readonly WalletRpc $wallet,
|
|
) {}
|
|
|
|
public function handle(string $name, array $records): DnsTicket
|
|
{
|
|
$name = strtolower(trim($name));
|
|
|
|
// Edit lock
|
|
$editLock = "dns_edit_lock:{$name}";
|
|
if (Cache::has($editLock)) {
|
|
throw ValidationException::withMessages([
|
|
'name' => 'A DNS update for this name is already pending.',
|
|
]);
|
|
}
|
|
|
|
$alias = $this->rpc->getAliasByName($name);
|
|
if (! $alias) {
|
|
throw ValidationException::withMessages([
|
|
'name' => 'Name not registered.',
|
|
]);
|
|
}
|
|
|
|
$address = $alias['address'] ?? '';
|
|
$comment = $this->buildComment($records);
|
|
|
|
$result = $this->wallet->updateAlias($name, $address, $comment);
|
|
|
|
if (isset($result['tx_id'])) {
|
|
Cache::put($editLock, true, 300);
|
|
$ticket = DnsTicket::open($name, $records, $result['tx_id'], $address, $comment);
|
|
} else {
|
|
$ticket = DnsTicket::open($name, $records, null, $address, $comment);
|
|
}
|
|
|
|
NameActivity::log($name, 'dns_updated', [
|
|
'ticket_id' => $ticket->ticket_id,
|
|
'records' => $records,
|
|
], request()?->ip());
|
|
|
|
return $ticket;
|
|
}
|
|
|
|
private function buildComment(array $records): string
|
|
{
|
|
$dnsEntries = [];
|
|
foreach ($records as $record) {
|
|
$type = $record['type'] ?? 'A';
|
|
$host = $record['host'] ?? '@';
|
|
$value = $record['value'] ?? '';
|
|
if ($value) {
|
|
$dnsEntries[] = "{$type}:{$host}:{$value}";
|
|
}
|
|
}
|
|
|
|
$comment = 'v=lthn1;type=user';
|
|
if ($dnsEntries) {
|
|
$comment .= ';dns=' . implode('|', $dnsEntries);
|
|
}
|
|
|
|
return $comment;
|
|
}
|
|
|
|
public static function run(string $name, array $records): DnsTicket
|
|
{
|
|
return app(static::class)->handle($name, $records);
|
|
}
|
|
}
|