github.com/metacubex/mihomo@v1.18.5/hub/route/restart.go (about)

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