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
This commit is contained in:
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -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}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
27
README.md
27
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
|
### 6. List frpc Instances
|
||||||
|
|||||||
BIN
database.db
BIN
database.db
Binary file not shown.
19
frpc.go
19
frpc.go
@@ -350,7 +350,7 @@ func ModifyInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if modifyType != "configFile" && modifyType != "systemConfig" { // Detect valid modify type
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,6 +501,7 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
|
|||||||
newRunUser := instance.RunUser
|
newRunUser := instance.RunUser
|
||||||
newBootAtStart := instance.BootAtStart
|
newBootAtStart := instance.BootAtStart
|
||||||
oldBootAtStart := instance.BootAtStart
|
oldBootAtStart := instance.BootAtStart
|
||||||
|
var bootServiceError string
|
||||||
|
|
||||||
if v, ok := modifiedData["name"].(string); ok && v != "" {
|
if v, ok := modifiedData["name"].(string); ok && v != "" {
|
||||||
newName = v
|
newName = v
|
||||||
@@ -556,27 +557,38 @@ func handleSystemConfigModify(w http.ResponseWriter, r *http.Request, instance F
|
|||||||
if oldBootAtStart && !newBootAtStart {
|
if oldBootAtStart && !newBootAtStart {
|
||||||
if err := removeBootService(user.Username, instance.Name); err != nil {
|
if err := removeBootService(user.Username, instance.Name); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove boot service: %v", err))
|
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 {
|
} else if !oldBootAtStart && newBootAtStart {
|
||||||
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create boot service: %v", err))
|
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) {
|
} else if oldBootAtStart && newBootAtStart && (instance.Name != newName || instance.RunUser != newRunUser) {
|
||||||
if err := removeBootService(user.Username, instance.Name); err != nil {
|
if err := removeBootService(user.Username, instance.Name); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to remove old boot service: %v", err))
|
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 {
|
if err := createBootService(user.Username, newName, newConfigPath, newRunUser); err != nil {
|
||||||
postLog.Error(fmt.Sprintf("[handleSystemConfigModify] Failed to create new boot service: %v", err))
|
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,
|
"instanceName": newName,
|
||||||
"instanceID": instance.ID,
|
"instanceID": instance.ID,
|
||||||
"configPath": newConfigPath,
|
"configPath": newConfigPath,
|
||||||
"bootAtStart": newBootAtStart,
|
"bootAtStart": newBootAtStart,
|
||||||
"runUser": newRunUser,
|
"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))
|
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{}
|
var responseInstances []map[string]interface{}
|
||||||
for _, instance := range instanceList {
|
for _, instance := range instanceList {
|
||||||
instanceData := map[string]interface{}{
|
instanceData := map[string]interface{}{
|
||||||
|
"instanceID": instance.ID,
|
||||||
"name": instance.Name,
|
"name": instance.Name,
|
||||||
"serverAddr": instance.ServerAddr,
|
"serverAddr": instance.ServerAddr,
|
||||||
"serverPort": instance.ServerPort,
|
"serverPort": instance.ServerPort,
|
||||||
|
|||||||
Reference in New Issue
Block a user