diff --git a/docs/api.md b/docs/api.md index cff7906..245bafc 100644 --- a/docs/api.md +++ b/docs/api.md @@ -129,6 +129,32 @@ X-Timestamp: 1704067200000 --- +## Restart Server + +**Endpoint:** `/system/restart` +**Method:** GET +**Permission Level:** Admin + +**Request Headers:** +``` +X-Token: your_token +X-Timestamp: 1704067200000 +``` +| Header | Type | Required | Description | +|--------|------|----------|-------------| +| X-Token | string | Yes | Authentication token | +| X-Timestamp | int64 | Yes | Client timestamp in milliseconds | + +**Response:** +```json +{ + "success": true, + "message": "Restarting server..." +} +``` + +--- + ## Register User **Endpoint:** `/register` diff --git a/router.go b/router.go index d9a5d11..1e88ed3 100644 --- a/router.go +++ b/router.go @@ -18,6 +18,7 @@ func setupRoutes() { http.HandleFunc("/api/system/getStatus", GetStatusHandler) http.HandleFunc("/api/system/getSoftwareInfo", GetSoftwareInfoHandler) http.HandleFunc("/api/system/selfCheck", sys.SelfCheckHandler) + http.HandleFunc("/api/system/restart", utils.RestartHandler) http.HandleFunc("/api/system/settings/get", handlers.GetSettingsHandler) http.HandleFunc("/api/system/settings/set", handlers.SetSettingsHandler) diff --git a/utils/handlers.go b/utils/handlers.go index 429eec4..dd33912 100644 --- a/utils/handlers.go +++ b/utils/handlers.go @@ -4,10 +4,11 @@ import ( "encoding/json" "fmt" "net/http" - "strconv" "os" - "time" + "os/exec" + "strconv" "strings" + "time" "super-frpc/database" "super-frpc/global" @@ -166,4 +167,36 @@ func GetCmdParams(source string, param string) string { func IsFileExist(filePath string) bool { _, err := os.Stat(filePath) return !os.IsNotExist(err) -} \ No newline at end of file +} + +func RestartHandler(w http.ResponseWriter, r *http.Request) { + userID, err := Auth(w, r, http.MethodGet, "superuser", "admin") + if err != nil { + SendErrorResponse(w, http.StatusUnauthorized, "invalid token or timestamp") + postLog.Warning(fmt.Sprintf("[RestartHandler] Auth failed: %v, userID: %d", err, userID)) + return + } + err = RestartProcess() + if err != nil { + SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("failed to restart: %v", err)) + postLog.Error(fmt.Sprintf("[RestartHandler] [%d] failed to restart: %v", userID, err)) + return + } + SendSuccessResponse(w, "Restarting server...", nil) + postLog.Info(fmt.Sprintf("[RestartHandler] [%d] Restarting server", userID)) +} + +func RestartProcess() error { + executable, err := os.Executable() + if err != nil { + return fmt.Errorf("failed to get executable path: %w", err) + } + cmd := exec.Command(executable) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start new process: %w", err) + } + os.Exit(0) + return nil +}