NodeObserver.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. namespace App\Observers;
  3. use App\Events\NodeActions;
  4. use App\Jobs\VNet\ReloadNode;
  5. use App\Models\Node;
  6. use App\Utils\DDNS;
  7. use Arr;
  8. use Exception;
  9. use Str;
  10. class NodeObserver
  11. {
  12. // 辅助方法:发送广播消息
  13. private function broadcastMessage(string $type, array $data, ?int $nodeId = null): void
  14. {
  15. broadcast(new NodeActions($type, $data, $nodeId));
  16. }
  17. // 辅助方法:处理DDNS操作并发送广播
  18. private function handleDdnsOperation(string $type, DDNS $dns, string $operation, string $ip = '', string $recordType = '', ?int $nodeId = null): void
  19. {
  20. try {
  21. if ($operation === 'store') {
  22. $dns->store($ip, $recordType);
  23. } elseif ($operation === 'destroy') {
  24. $dns->destroy($recordType, $ip);
  25. }
  26. $this->broadcastMessage($type, ['operation' => 'handle_ddns', 'sub_operation' => $operation, 'data' => $ip, 'status' => 1], $nodeId);
  27. } catch (Exception $e) {
  28. $this->broadcastMessage($type, ['operation' => 'handle_ddns', 'sub_operation' => $operation, 'data' => $ip, 'status' => 0, 'message' => $e->getMessage()], $nodeId);
  29. }
  30. }
  31. // 处理IP变化的辅助方法
  32. private function updateIpChanges(DDNS $dns, string $originalIps, array $currentIps, int $nodeId, string $recordType = 'A'): void
  33. {
  34. $originalIpsArray = array_filter(array_map('trim', explode(',', $originalIps)));
  35. // 计算需要删除的IP (在原列表但不在新列表中)
  36. $ipsToDelete = array_diff($originalIpsArray, $currentIps);
  37. // 计算需要添加的IP (在新列表但不在原列表中)
  38. $ipsToAdd = array_diff($currentIps, $originalIpsArray);
  39. $this->broadcastMessage('update', ['operation' => 'handle_ddns', 'sub_operation' => 'list', 'delete' => array_values($ipsToDelete), 'add' => array_values($ipsToAdd), 'status' => 1], $nodeId);
  40. foreach ($ipsToDelete as $ip) {
  41. $this->handleDdnsOperation('update', $dns, 'destroy', $ip, $recordType, $nodeId);
  42. }
  43. foreach ($ipsToAdd as $ip) {
  44. $this->handleDdnsOperation('update', $dns, 'store', $ip, $recordType, $nodeId);
  45. }
  46. }
  47. public function created(Node $node): void
  48. {
  49. // GEO
  50. $geo = $node->refresh_geo();
  51. if (isset($geo['update'])) {
  52. $this->broadcastMessage('create', ['operation' => 'refresh_geo', 'status' => 1]);
  53. } else {
  54. $this->broadcastMessage('create', ['operation' => 'refresh_geo', 'status' => 0]);
  55. }
  56. if ($node->auth()->create(['key' => Str::random(), 'secret' => Str::random(8)])) {
  57. $this->broadcastMessage('create', ['operation' => 'create_auth', 'status' => 1]);
  58. } else {
  59. $this->broadcastMessage('create', ['operation' => 'create_auth', 'status' => 0, 'message' => trans('admin.node.operation.auth_failed')]);
  60. }
  61. if (! $node->is_ddns && $node->server && sysConfig('ddns_mode')) {
  62. $currentDNS = new DDNS($node->server);
  63. $ips4 = $node->ips();
  64. $ips6 = $node->ips(6);
  65. // 发送DDNS操作开始信号及IP列表
  66. $this->broadcastMessage('create', ['operation' => 'handle_ddns', 'sub_operation' => 'list', 'add' => array_merge($ips4, $ips6), 'status' => 1]);
  67. // 处理IPv4地址
  68. foreach ($ips4 as $ip) {
  69. $this->handleDdnsOperation('create', $currentDNS, 'store', $ip, 'A');
  70. }
  71. // 处理IPv6地址
  72. foreach ($ips6 as $ip) {
  73. $this->handleDdnsOperation('create', $currentDNS, 'store', $ip, 'AAAA');
  74. }
  75. }
  76. }
  77. public function updated(Node $node): void
  78. {
  79. // 在任何可能修改模型的操作之前保存原始值
  80. $originalServer = $node->getOriginal('server');
  81. $originalIp = $node->getOriginal('ip') ?? '';
  82. $originalIpv6 = $node->getOriginal('ipv6') ?? '';
  83. // GEO
  84. $geo = $node->refresh_geo();
  85. if (isset($geo['update'])) {
  86. $this->broadcastMessage('update', ['operation' => 'refresh_geo', 'status' => 1], $node->id);
  87. } else {
  88. $this->broadcastMessage('update', ['operation' => 'refresh_geo', 'status' => 0], $node->id);
  89. }
  90. // DDNS
  91. if (! $node->is_ddns && sysConfig('ddns_mode')) {
  92. $changes = $node->getChanges();
  93. if (Arr::hasAny($changes, ['ip', 'ipv6', 'server'])) {
  94. $currentDNS = new DDNS($node->server);
  95. if (Arr::has($changes, 'server')) {
  96. $this->broadcastMessage('update', ['operation' => 'handle_ddns', 'sub_operation' => 'list', 'delete' => [$originalServer], 'add' => array_merge($node->ips(), $node->ips(6)), 'status' => 1], $node->id);
  97. if ($originalServer) {
  98. try {
  99. (new DDNS($originalServer))->destroy();
  100. $this->broadcastMessage('update', ['operation' => 'handle_ddns', 'sub_operation' => 'destroy', 'data' => $originalServer, 'status' => 1], $node->id);
  101. } catch (Exception $e) {
  102. $this->broadcastMessage('update', ['operation' => 'handle_ddns', 'sub_operation' => 'destroy', 'data' => $originalServer, 'status' => 0, 'message' => $e->getMessage()], $node->id);
  103. }
  104. }
  105. foreach ($node->ips() as $ip) {
  106. $this->handleDdnsOperation('update', $currentDNS, 'store', $ip, 'A', $node->id);
  107. }
  108. foreach ($node->ips(6) as $ip) {
  109. $this->handleDdnsOperation('update', $currentDNS, 'store', $ip, 'AAAA', $node->id);
  110. }
  111. } else {
  112. if (Arr::has($changes, 'ip')) {
  113. $this->updateIpChanges($currentDNS, $originalIp, $node->ips(), $node->id);
  114. }
  115. if (Arr::has($changes, 'ipv6')) {
  116. $this->updateIpChanges($currentDNS, $originalIpv6, $node->ips(6), $node->id, 'AAAA');
  117. }
  118. }
  119. } else {
  120. $this->broadcastMessage('update', ['operation' => 'handle_ddns', 'status' => 1, 'sub_operation' => 'unchanged'], $node->id);
  121. }
  122. }
  123. // Reload
  124. if ((int) $node->type === 4) {
  125. ReloadNode::dispatch($node);
  126. $this->broadcastMessage('update', ['operation' => 'reload_node', 'status' => 1], $node->id);
  127. }
  128. }
  129. public function deleted(Node $node): void
  130. {
  131. // 发送删除DDNS操作开始信号
  132. if ($node->server && sysConfig('ddns_mode')) {
  133. $this->broadcastMessage('delete', ['operation' => 'handle_ddns', 'sub_operation' => 'list', 'delete' => [$node->server], 'status' => 1], $node->id);
  134. try {
  135. (new DDNS($node->server))->destroy();
  136. $this->broadcastMessage('delete', ['operation' => 'handle_ddns', 'sub_operation' => 'destroy', 'data' => $node->server, 'status' => 1], $node->id);
  137. } catch (Exception $e) {
  138. $this->broadcastMessage('delete', ['operation' => 'handle_ddns', 'sub_operation' => 'destroy', 'data' => $node->server, 'status' => 0, 'message' => $e->getMessage()], $node->id);
  139. }
  140. }
  141. }
  142. }