big update all menus
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Nas;
|
||||
|
||||
use App\Models\NasMikrotik;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use RouterOS\Client;
|
||||
use RouterOS\Query;
|
||||
use Throwable;
|
||||
|
||||
class RouterOsApiService
|
||||
{
|
||||
public function testConnection(NasMikrotik $mikrotik): array
|
||||
{
|
||||
$startedAt = hrtime(true);
|
||||
$client = $this->connect($mikrotik);
|
||||
$identity = $client->query('/system/identity/print')->read()[0] ?? [];
|
||||
$resource = $client->query('/system/resource/print')->read()[0] ?? [];
|
||||
|
||||
return [
|
||||
'connected' => true,
|
||||
'latency_ms' => (int) round((hrtime(true) - $startedAt) / 1_000_000),
|
||||
'identity' => $identity['name'] ?? null,
|
||||
'version' => $resource['version'] ?? null,
|
||||
'uptime' => $resource['uptime'] ?? null,
|
||||
'platform' => $resource['platform'] ?? null,
|
||||
'board_name' => $resource['board-name'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
public function createAccount(NasMikrotik $mikrotik, string $serviceType, array $attributes): array
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$this->assertUsernameAvailable($client, $serviceType, $attributes['username']);
|
||||
$query = new Query($this->path($serviceType, 'add'));
|
||||
foreach ($this->accountAttributes($attributes) as $key => $value) {
|
||||
$query->equal($key, $value);
|
||||
}
|
||||
$client->query($query)->read();
|
||||
|
||||
return $this->findAccount($client, $serviceType, $attributes['username']);
|
||||
}
|
||||
|
||||
public function updateAccount(NasMikrotik $mikrotik, string $serviceType, string $username, array $attributes): array
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$account = $this->findAccount($client, $serviceType, $username);
|
||||
$query = (new Query($this->path($serviceType, 'set')))->equal('.id', $account['.id']);
|
||||
foreach ($this->accountAttributes($attributes) as $key => $value) {
|
||||
$query->equal($key, $value);
|
||||
}
|
||||
$client->query($query)->read();
|
||||
|
||||
return $this->findAccount($client, $serviceType, $attributes['username'] ?? $username);
|
||||
}
|
||||
|
||||
public function setEnabled(NasMikrotik $mikrotik, string $serviceType, string $username, bool $enabled): array
|
||||
{
|
||||
return $this->updateAccount($mikrotik, $serviceType, $username, [
|
||||
'disabled' => $enabled ? 'no' : 'yes',
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAccount(NasMikrotik $mikrotik, string $serviceType, string $username): void
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$account = $this->findAccount($client, $serviceType, $username);
|
||||
$client->query(
|
||||
(new Query($this->path($serviceType, 'remove')))->equal('.id', $account['.id'])
|
||||
)->read();
|
||||
}
|
||||
|
||||
public function syncProfile(NasMikrotik $mikrotik, string $serviceType, string $name, array $attributes, string $mode = 'update'): array
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$base = $serviceType === 'hotspot' ? '/ip/hotspot/user/profile' : '/ppp/profile';
|
||||
$rows = $client->query((new Query("{$base}/print"))->where('name', $name))->read();
|
||||
$existing = $rows[0] ?? null;
|
||||
if ($mode === 'adopt') {
|
||||
if (! $existing) throw ValidationException::withMessages(['profile' => "Profile {$name} tidak ditemukan untuk di-adopt."]);
|
||||
return $existing;
|
||||
}
|
||||
if (! $existing) {
|
||||
$query = (new Query("{$base}/add"))->equal('name', $name);
|
||||
} else {
|
||||
$query = (new Query("{$base}/set"))->equal('.id', $existing['.id']);
|
||||
}
|
||||
foreach (array_filter($attributes, fn ($value) => $value !== null) as $key => $value) $query->equal($key, $value);
|
||||
$client->query($query)->read();
|
||||
$rows = $client->query((new Query("{$base}/print"))->where('name', $name))->read();
|
||||
return $rows[0] ?? [];
|
||||
}
|
||||
|
||||
public function inspectAccount(NasMikrotik $mikrotik, string $serviceType, string $username): array
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$account = $this->findAccount($client, $serviceType, $username);
|
||||
$activeBase = in_array($serviceType, ['ppp','pppoe'], true) ? '/ppp/active' : '/ip/hotspot/active';
|
||||
$active = $client->query((new Query("{$activeBase}/print"))->where('name', $username))->read()[0] ?? null;
|
||||
return ['account' => $account, 'active' => $active];
|
||||
}
|
||||
|
||||
public function disconnectAccount(NasMikrotik $mikrotik, string $serviceType, string $username): void
|
||||
{
|
||||
$client = $this->connect($mikrotik);
|
||||
$activeBase = in_array($serviceType, ['ppp','pppoe'], true) ? '/ppp/active' : '/ip/hotspot/active';
|
||||
$rows = $client->query((new Query("{$activeBase}/print"))->where('name', $username))->read();
|
||||
foreach ($rows as $row) if (! empty($row['.id'])) $client->query((new Query("{$activeBase}/remove"))->equal('.id', $row['.id']))->read();
|
||||
}
|
||||
|
||||
private function connect(NasMikrotik $mikrotik): Client
|
||||
{
|
||||
if ($mikrotik->connection_type !== 'api') {
|
||||
throw ValidationException::withMessages(['mikrotik' => 'Perangkat tidak menggunakan koneksi RouterOS API.']);
|
||||
}
|
||||
if ($mikrotik->status !== 'active') {
|
||||
throw ValidationException::withMessages(['mikrotik' => 'Perangkat Mikrotik sedang nonaktif.']);
|
||||
}
|
||||
if (! $mikrotik->host || ! $mikrotik->api_username || ! $mikrotik->api_password) {
|
||||
throw ValidationException::withMessages(['mikrotik' => 'Host, username API, dan password API wajib lengkap.']);
|
||||
}
|
||||
|
||||
try {
|
||||
return new Client([
|
||||
'host' => $mikrotik->host,
|
||||
'user' => $mikrotik->api_username,
|
||||
'pass' => $mikrotik->api_password,
|
||||
'port' => (int) ($mikrotik->api_port ?: 8728),
|
||||
'timeout' => (int) ($mikrotik->timeout ?: 10),
|
||||
'socket_timeout' => (int) ($mikrotik->timeout ?: 10),
|
||||
'attempts' => 1,
|
||||
'delay' => 0,
|
||||
'ssl' => (int) ($mikrotik->api_port ?: 8728) === 8729,
|
||||
]);
|
||||
} catch (Throwable $exception) {
|
||||
throw ValidationException::withMessages([
|
||||
'mikrotik' => 'Koneksi RouterOS API gagal: '.$exception->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function findAccount(Client $client, string $serviceType, string $username): array
|
||||
{
|
||||
$rows = $client->query(
|
||||
(new Query($this->path($serviceType, 'print')))->where('name', $username)
|
||||
)->read();
|
||||
if (empty($rows[0]['.id'])) {
|
||||
throw ValidationException::withMessages(['username' => "Akun {$username} tidak ditemukan di Mikrotik."]);
|
||||
}
|
||||
|
||||
return $rows[0];
|
||||
}
|
||||
|
||||
private function assertUsernameAvailable(Client $client, string $serviceType, string $username): void
|
||||
{
|
||||
$rows = $client->query(
|
||||
(new Query($this->path($serviceType, 'print')))->where('name', $username)
|
||||
)->read();
|
||||
if ($rows) {
|
||||
throw ValidationException::withMessages(['username' => "Username {$username} sudah ada di Mikrotik."]);
|
||||
}
|
||||
}
|
||||
|
||||
private function accountAttributes(array $attributes): array
|
||||
{
|
||||
return array_filter([
|
||||
'name' => $attributes['username'] ?? null,
|
||||
'password' => $attributes['password'] ?? null,
|
||||
'profile' => $attributes['profile'] ?? null,
|
||||
'comment' => $attributes['comment'] ?? null,
|
||||
'disabled' => $attributes['disabled'] ?? null,
|
||||
], fn ($value) => $value !== null);
|
||||
}
|
||||
|
||||
private function path(string $serviceType, string $action): string
|
||||
{
|
||||
$base = match ($serviceType) {
|
||||
'ppp', 'pppoe' => '/ppp/secret',
|
||||
'hotspot' => '/ip/hotspot/user',
|
||||
default => throw ValidationException::withMessages(['service_type' => 'Tipe layanan harus PPPoE atau Hotspot.']),
|
||||
};
|
||||
|
||||
return "{$base}/{$action}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user