nginx.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package nginx
  2. import (
  3. "os"
  4. "strconv"
  5. "strings"
  6. "sync"
  7. "time"
  8. "github.com/0xJacky/Nginx-UI/internal/docker"
  9. "github.com/0xJacky/Nginx-UI/settings"
  10. "github.com/shirou/gopsutil/v4/process"
  11. "github.com/uozi-tech/cosy/logger"
  12. )
  13. var (
  14. mutex sync.Mutex
  15. lastStdOut string
  16. lastStdErr error
  17. )
  18. // TestConfig tests the nginx config
  19. func TestConfig() (stdOut string, stdErr error) {
  20. mutex.Lock()
  21. defer mutex.Unlock()
  22. if settings.NginxSettings.TestConfigCmd != "" {
  23. return execShell(settings.NginxSettings.TestConfigCmd)
  24. }
  25. sbin := GetSbinPath()
  26. if sbin == "" {
  27. return execCommand("nginx", "-t")
  28. }
  29. return execCommand(sbin, "-t")
  30. }
  31. // Reload reloads the nginx
  32. func Reload() (stdOut string, stdErr error) {
  33. mutex.Lock()
  34. defer mutex.Unlock()
  35. // Clear the modules cache when reloading Nginx
  36. clearModulesCache()
  37. if !IsRunning() {
  38. restart()
  39. return
  40. }
  41. if settings.NginxSettings.ReloadCmd != "" {
  42. return execShell(settings.NginxSettings.ReloadCmd)
  43. }
  44. sbin := GetSbinPath()
  45. if sbin == "" {
  46. return execCommand("nginx", "-s", "reload")
  47. }
  48. return execCommand(sbin, "-s", "reload")
  49. }
  50. func restart() {
  51. // fix(docker): nginx restart always output network error
  52. time.Sleep(500 * time.Millisecond)
  53. if settings.NginxSettings.RestartCmd != "" {
  54. lastStdOut, lastStdErr = execShell(settings.NginxSettings.RestartCmd)
  55. return
  56. }
  57. pidPath := GetPIDPath()
  58. daemon := GetSbinPath()
  59. // Check if nginx is running before attempting to stop it
  60. if IsRunning() {
  61. lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
  62. if lastStdErr != nil {
  63. return
  64. }
  65. }
  66. if daemon == "" {
  67. lastStdOut, lastStdErr = execCommand("nginx")
  68. return
  69. }
  70. lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
  71. }
  72. // Restart restarts the nginx
  73. func Restart() {
  74. mutex.Lock()
  75. defer mutex.Unlock()
  76. // Clear the modules cache when restarting Nginx
  77. clearModulesCache()
  78. restart()
  79. }
  80. // GetLastResult returns the last output of the nginx command
  81. func GetLastResult() *ControlResult {
  82. mutex.Lock()
  83. defer mutex.Unlock()
  84. return &ControlResult{
  85. stdOut: lastStdOut,
  86. stdErr: lastStdErr,
  87. }
  88. }
  89. func IsRunning() bool {
  90. pidPath := GetPIDPath()
  91. switch settings.NginxSettings.RunningInAnotherContainer() {
  92. case true:
  93. return docker.StatPath(pidPath)
  94. case false:
  95. return isProcessRunning(pidPath)
  96. }
  97. return false
  98. }
  99. // isProcessRunning checks if the process with the PID from pidPath is actually running
  100. func isProcessRunning(pidPath string) bool {
  101. logger.Debugf("isProcessRunning pidPath: %s", pidPath)
  102. // Check if PID file exists
  103. if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
  104. logger.Debugf("isProcessRunning pidPath: %s, err: %v", pidPath, err)
  105. return false
  106. }
  107. // Read PID from file
  108. pidBytes, err := os.ReadFile(pidPath)
  109. if err != nil {
  110. logger.Debugf("isProcessRunning pidPath: %s, err: %v", pidPath, err)
  111. return false
  112. }
  113. pidStr := strings.TrimSpace(string(pidBytes))
  114. pid, err := strconv.Atoi(pidStr)
  115. if err != nil {
  116. logger.Debugf("isProcessRunning pidPath: %s, err: %v", pidPath, err)
  117. return false
  118. }
  119. // Use gopsutil for cross-platform process existence check
  120. exists, err := process.PidExists(int32(pid))
  121. if err != nil {
  122. logger.Debugf("isProcessRunning pidPath: %s, PidExists err: %v", pidPath, err)
  123. return false
  124. }
  125. if exists {
  126. logger.Debugf("isProcessRunning pidPath: %s, process exists", pidPath)
  127. return true
  128. }
  129. logger.Debugf("isProcessRunning pidPath: %s, process does not exist", pidPath)
  130. return false
  131. }