restart.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package route
  2. import (
  3. "fmt"
  4. "net/http"
  5. "os"
  6. "os/exec"
  7. "runtime"
  8. "syscall"
  9. "github.com/metacubex/mihomo/hub/executor"
  10. "github.com/metacubex/mihomo/log"
  11. "github.com/go-chi/chi/v5"
  12. "github.com/go-chi/render"
  13. )
  14. func restartRouter() http.Handler {
  15. r := chi.NewRouter()
  16. r.Post("/", restart)
  17. return r
  18. }
  19. func restart(w http.ResponseWriter, r *http.Request) {
  20. // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L108
  21. execPath, err := os.Executable()
  22. if err != nil {
  23. render.Status(r, http.StatusInternalServerError)
  24. render.JSON(w, r, newError(fmt.Sprintf("getting path: %s", err)))
  25. return
  26. }
  27. render.JSON(w, r, render.M{"status": "ok"})
  28. if f, ok := w.(http.Flusher); ok {
  29. f.Flush()
  30. }
  31. // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180
  32. // The background context is used because the underlying functions wrap it
  33. // with timeout and shut down the server, which handles current request. It
  34. // also should be done in a separate goroutine for the same reason.
  35. go restartExecutable(execPath)
  36. }
  37. func restartExecutable(execPath string) {
  38. var err error
  39. executor.Shutdown()
  40. if runtime.GOOS == "windows" {
  41. cmd := exec.Command(execPath, os.Args[1:]...)
  42. log.Infoln("restarting: %q %q", execPath, os.Args[1:])
  43. cmd.Stdin = os.Stdin
  44. cmd.Stdout = os.Stdout
  45. cmd.Stderr = os.Stderr
  46. err = cmd.Start()
  47. if err != nil {
  48. log.Fatalln("restarting: %s", err)
  49. }
  50. os.Exit(0)
  51. }
  52. log.Infoln("restarting: %q %q", execPath, os.Args[1:])
  53. err = syscall.Exec(execPath, os.Args, os.Environ())
  54. if err != nil {
  55. log.Fatalln("restarting: %s", err)
  56. }
  57. }