GetOnlineUser.php 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. <?php
  2. namespace App\Jobs\Hysteria2;
  3. use App\Models\Node;
  4. use Exception;
  5. use Http;
  6. use Illuminate\Bus\Queueable;
  7. use Illuminate\Contracts\Queue\ShouldQueue;
  8. use Illuminate\Database\Eloquent\Collection;
  9. use Illuminate\Foundation\Bus\Dispatchable;
  10. use Illuminate\Queue\InteractsWithQueue;
  11. use Illuminate\Queue\SerializesModels;
  12. use Log;
  13. use Throwable;
  14. class GetOnlineUser implements ShouldQueue
  15. {
  16. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  17. private bool $isOffline = false;
  18. public function __construct(private Collection|Node $nodes)
  19. {
  20. if (! $nodes instanceof Collection) {
  21. $this->nodes = new Collection([$nodes]);
  22. }
  23. }
  24. public function handle(): void
  25. {
  26. foreach ($this->nodes as $node) {
  27. $totalOnlineUsers = 0;
  28. if ($node->is_ddns) {
  29. $totalOnlineUsers = $this->send($node->server.':'.$node->push_port, $node->auth->secret);
  30. } else { // 多IP支持
  31. foreach ($node->ips() as $ip) {
  32. // 对于多IP节点,累加所有IP上的在线用户数
  33. $totalOnlineUsers += $this->send($ip.':'.$node->push_port, $node->auth->secret);
  34. }
  35. }
  36. $node->onlineLogs()->create(['online_user' => $totalOnlineUsers, 'log_time' => time()]);
  37. // 如果成功获取在线用户数,说明节点正常,记录心跳
  38. if (! $this->isOffline) { // 即使没有在线用户也说明节点通信正常
  39. // 获取节点最后的心跳记录(在90秒内)以计算运行时间
  40. $lastHeartbeat = $node->heartbeats()
  41. ->where('log_time', '>=', time() - 90)
  42. ->latest('log_time')
  43. ->first();
  44. if ($lastHeartbeat) {
  45. // 如果之前有心跳记录且时间间隔不超过90秒,计算运行时间增量
  46. $uptime = $lastHeartbeat->uptime + (time() - $lastHeartbeat->log_time);
  47. } else {
  48. // 如果没有90秒内的心跳记录或间隔超过90秒,重新开始计时
  49. $uptime = 60; // 重新开始计时,初始运行时间为60秒
  50. }
  51. $node->heartbeats()->create([
  52. 'uptime' => $uptime,
  53. 'load' => 'N/A',
  54. 'log_time' => time(),
  55. ]);
  56. }
  57. }
  58. }
  59. private function send(string $host, string $secret): int
  60. {
  61. try {
  62. $request = Http::baseUrl($host)->timeout(15)->withHeader('Authorization', $secret);
  63. $response = $request->get('/online');
  64. $data = $response->json();
  65. if ($data) {
  66. return count($data);
  67. }
  68. if (! $response->ok()) {
  69. $this->isOffline = true;
  70. }
  71. } catch (Exception $exception) {
  72. Log::alert('【在线用户】获取异常:'.$exception->getMessage());
  73. }
  74. return 0;
  75. }
  76. // 队列失败处理
  77. public function failed(Throwable $exception): void
  78. {
  79. Log::alert('【在线用户】获取异常:'.$exception->getMessage());
  80. }
  81. }