discovery_darwin.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. //go:build darwin
  2. package discovery
  3. import (
  4. "os/exec"
  5. "regexp"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "ai-status-light/internal/logger"
  10. )
  11. func findByPID() []int {
  12. var ports []int
  13. pidRegex := regexp.MustCompile(`(?:^|/)opencode(?:\s|$)`)
  14. out, err := exec.Command("ps", "aux").Output()
  15. if err != nil {
  16. logger.Debug("执行 ps aux 失败: %v", err)
  17. return ports
  18. }
  19. var pids []int
  20. for _, line := range strings.Split(string(out), "\n") {
  21. if pidRegex.MatchString(line) && !strings.Contains(line, "grep") && !strings.Contains(line, "opencode-monitor") {
  22. fields := strings.Fields(line)
  23. if len(fields) > 1 {
  24. if pid, err := strconv.Atoi(fields[1]); err == nil {
  25. pids = append(pids, pid)
  26. }
  27. }
  28. }
  29. }
  30. if len(pids) == 0 {
  31. logger.Debug("未找到 opencode 进程")
  32. return ports
  33. }
  34. logger.Debug("发现 opencode 进程 PID: %v", pids)
  35. for _, pid := range pids {
  36. lsofOut, err := exec.Command("lsof", "-p", strconv.Itoa(pid), "-i", "TCP", "-s", "TCP:LISTEN").Output()
  37. if err != nil {
  38. logger.Debug("执行 lsof 失败: %v", err)
  39. continue
  40. }
  41. for _, line := range strings.Split(string(lsofOut), "\n") {
  42. if strings.Contains(line, "LISTEN") {
  43. // lsof 输出格式: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
  44. // NAME 部分格式: *:port 或 host:port
  45. fields := strings.Fields(line)
  46. if len(fields) >= 9 {
  47. nameField := fields[len(fields)-1]
  48. if strings.Contains(nameField, ":") {
  49. parts := strings.Split(nameField, ":")
  50. if len(parts) >= 2 {
  51. if port, err := strconv.Atoi(parts[len(parts)-1]); err == nil {
  52. if port > 0 && port < 65535 && !contains(ports, port) {
  53. ports = append(ports, port)
  54. }
  55. }
  56. }
  57. }
  58. }
  59. }
  60. }
  61. }
  62. sort.Ints(ports)
  63. return ports
  64. }
  65. func findByCmdline() []int {
  66. var ports []int
  67. out, err := exec.Command("ps", "aux").Output()
  68. if err != nil {
  69. logger.Debug("执行 ps aux 失败: %v", err)
  70. return ports
  71. }
  72. for _, line := range strings.Split(string(out), "\n") {
  73. if strings.Contains(line, "opencode") && !strings.Contains(line, "opencode-monitor") && !strings.Contains(line, "grep") {
  74. if strings.Contains(line, "--port") {
  75. fields := strings.Fields(line)
  76. for i, f := range fields {
  77. if f == "--port" && i+1 < len(fields) {
  78. if port, err := strconv.Atoi(fields[i+1]); err == nil {
  79. if !contains(ports, port) {
  80. ports = append(ports, port)
  81. }
  82. }
  83. }
  84. }
  85. }
  86. }
  87. }
  88. sort.Ints(ports)
  89. return ports
  90. }