From 0b12c764a225053d6445b3144bbef1eb92b97a30 Mon Sep 17 00:00:00 2001 From: NanamiAdmin Date: Tue, 3 Mar 2026 22:31:39 +0800 Subject: [PATCH] feat(frpc): improve boot service error handling and response - Add bootServiceError field to system config modify response when boot service operations fail - Include instanceID in list instances response - Update error message for unknown modify type - Document bootServiceError behavior in README --- .vscode/launch.json | 15 +++++++++++++++ README.md | 27 +++++++++++++++++++++++++++ database.db | Bin 24576 -> 24576 bytes frpc.go | 19 ++++++++++++++++--- 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..608d3c6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index d90cbdb..b17e50d 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,33 @@ Modify system-level settings such as instance name, boot-at-start configuration, } ``` +**Response with bootServiceError (when boot service operations fail):** +```json +{ + "success": true, + "message": "System config modified successfully", + "data": { + "instanceName": "new_frpc_name", + "instanceID": 1, + "configPath": "./configs/superfrpc_user_new_frpc_name.toml", + "bootAtStart": true, + "runUser": "www-data", + "bootServiceError": "Failed to create boot service: unsupported init system" + } +} +``` + +> **Note about bootServiceError:** +> - The `bootServiceError` field appears in the response when boot service operations (create/remove) fail +> - This field is only present when there is an error; it will not be included in the response if operations succeed +> - The overall request still returns `success: true` because the system config modification (database update, config file rename, etc.) succeeded +> - Common scenarios where `bootServiceError` may appear: +> - Enabling `bootAtStart` when the init system is not supported (e.g., on Windows or systems without systemd/init.d) +> - Disabling `bootAtStart` when the service file cannot be removed due to permission issues +> - Changing instance name or run user when `bootAtStart` is enabled (requires removing old service and creating new one) +> - The error message provides detailed information about what went wrong, which should be displayed to the user +> - Frontend applications should check for this field and display the error message to the user, even though the request was technically successful + --- ### 6. List frpc Instances diff --git a/database.db b/database.db index 48bc0498ecbd6afbf0e5c970ed1d3a1422f97b1e..32f8d0cb3e0c1579ef5f60e6b9258238833288d0 100644 GIT binary patch delta 208 zcmZoTz}Rqrae_3X$V3@uMv;vPOYPbD_Av09@a@?wD6oOgtc;DDfm2;sRGd>b-aaq2 zJU*?cAUQrSF*nuF(n!zH%tFsl&(Pe!z@Q{QJ2kJoyj(XWu_SSFoWHm>ifX-*{M;NP z10yqC17lqSqYy(&D-%;I69a7n3o8SI$tM1pjA@hS`6qMpe`a9fzs$^kng7{lL51V| kxWnC6vGK5QN;8(E7MB|3n#QM*fWnOYPbDO&Iu1_~&gF6wu(GY~r8E$TE4Je=;`%0|OKP nGiLtJ{LeNED%|3i;$h*GW-Li9E-^GRX60nz6a{nG3X)j>^mG;* diff --git a/frpc.go b/frpc.go index 3cde13c..c3876fa 100644 --- a/frpc.go +++ b/frpc.go @@ -350,7 +350,7 @@ func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) { } if modifyType != "configFile" && modifyType != "systemConfig" { // Detect valid modify type - SendErrorResponse(w, http.StatusBadRequest, "type must be 'configFile' or 'systemConfig'") + SendErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("Unknown modify type %s", modifyType)) return } @@ -501,6 +501,7 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F newRunUser := instance.RunUser newBootAtStart := instance.BootAtStart oldBootAtStart := instance.BootAtStart + var bootServiceError string if v, ok := modifiedData["name"].(string); ok && v != "" { newName = v @@ -556,27 +557,38 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F if oldBootAtStart && !newBootAtStart { if err := removeBootService(user.Username, instance.Name); err != nil { postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot service: %v", err)) + bootServiceError = fmt.Sprintf("Failed to remove boot service: %v", err) } } else if !oldBootAtStart && newBootAtStart { if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil { postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create boot service: %v", err)) + bootServiceError = fmt.Sprintf("Failed to create boot service: %v", err) } } else if oldBootAtStart && newBootAtStart && (instance.Name != newName || instance.RunUser != newRunUser) { if err := removeBootService(user.Username, instance.Name); err != nil { postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove old boot service: %v", err)) + bootServiceError = fmt.Sprintf("Failed to remove old boot service: %v", err) } if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil { postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create new boot service: %v", err)) + if bootServiceError != "" { + bootServiceError += "; " + } + bootServiceError += fmt.Sprintf("Failed to create new boot service: %v", err) } } - SendSuccessResponse(w, "System config modified successfully", map[string]interface{}{ + data := map[string]interface{}{ "instanceName": newName, "instanceID": instance.ID, "configPath": newConfigPath, "bootAtStart": newBootAtStart, "runUser": newRunUser, - }) + } + if bootServiceError != "" { + data["bootServiceError"] = bootServiceError + } + SendSuccessResponse(w, "System config modified successfully", data) postLog.Info(fmt.Sprintf("[handleSystemConfigModify] System config for instance %s modified successfully: bootAtStart=%v, runUser=%s", newName, newBootAtStart, newRunUser)) } @@ -614,6 +626,7 @@ func ListInstancesHandler(w http.ResponseWriter, r *http.Request) { var responseInstances []map[string]interface{} for _, instance := range instanceList { instanceData := map[string]interface{}{ + "instanceID": instance.ID, "name": instance.Name, "serverAddr": instance.ServerAddr, "serverPort": instance.ServerPort,