feat(proxy): add proxy deletion API endpoint

Implement handler for deleting frpc proxies with proper validation and error handling. The endpoint checks user permissions, validates input, removes the proxy configuration from the instance file, and returns appropriate responses.
This commit is contained in:
2026-03-19 22:25:00 +08:00
parent cf6e040c49
commit c7fc0136b0
3 changed files with 118 additions and 1 deletions
+1
View File
@@ -65,6 +65,7 @@ For detailed API documentation, please see [docs/api.md](docs/api.md)
- [ ] Add user config modify API
- [ ] Add frpc instance running status management API
- [ ] Add frpc instance log display API
- [ ] Fix random database lock when processing logs
## License
+115
View File
@@ -135,3 +135,118 @@ func addFrpcProxy(info FrpcProxyInfo) string {
return sb.String()
}
func DeleteProxyHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
postLog.Debug(fmt.Sprintf("[DeleteProxyHandler] Invalid request method: %s", r.Method))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to read request body: %v", err))
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
return
}
defer r.Body.Close()
var reqMap map[string]interface{}
if err := json.Unmarshal(body, &reqMap); err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to unmarshal request body: %v", err))
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
return
}
instanceID := getStringFromMap(reqMap, "instanceID")
if instanceID == "" {
postLog.Error("[DeleteProxyHandler] instanceID is required")
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
proxyName := getStringFromMap(reqMap, "proxyName")
if proxyName == "" {
postLog.Error("[DeleteProxyHandler] proxyName is required")
SendErrorResponse(w, http.StatusBadRequest, "proxyName is required")
return
}
userID, _, err := ValidateRequestWithHeader(w, r)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to validate request header: %v", err))
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
return
}
userType, err := GetUserType(userID)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to get user type: %v", err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
return
} else if userType != "admin" && userType != "superuser" {
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
return
}
var instance FrpcInstance
instanceIDInt, _ := strconv.Atoi(instanceID)
instance, err = DBQueryFrpcInstanceByID(instanceIDInt)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to query instance: %v", err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
return
}
if instance.UserID != userID {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Instance not found for user %d", userID))
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
return
}
configContent, err := os.ReadFile(instance.ConfigPath)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
return
}
lines := strings.Split(string(configContent), "\n")
var newLines []string
var i int
for i < len(lines) {
if strings.HasPrefix(lines[i], "[[proxies]]") {
nameLine := i + 1
if nameLine < len(lines) && strings.HasPrefix(lines[nameLine], "name = ") {
currentProxyName := strings.TrimSpace(strings.TrimPrefix(lines[nameLine], "name = "))
if currentProxyName == proxyName {
i += 6
continue
}
}
}
newLines = append(newLines, lines[i])
i++
}
if len(newLines) == len(lines) {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Proxy %s not found in config file %s", proxyName, instance.ConfigPath))
SendErrorResponse(w, http.StatusNotFound, "Proxy not found")
return
}
updatedContent := strings.Join(newLines, "\n")
if err := os.WriteFile(instance.ConfigPath, []byte(updatedContent), 0644); err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to write config file %s: %v", instance.ConfigPath, err))
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
return
}
SendSuccessResponse(w, "Proxy deleted successfully", map[string]interface{}{
"instanceName": instance.Name,
"instanceID": instance.ID,
"configPath": instance.ConfigPath,
"proxyName": proxyName,
})
postLog.Info(fmt.Sprintf("[DeleteProxyHandler] Proxy %s deleted successfully from instance %s", proxyName, instance.Name))
}
+1
View File
@@ -30,6 +30,7 @@ func setupRoutes() {
http.HandleFunc("/frpcAct/instanceMgr/modify", ModifyInstanceHandler)
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)
http.HandleFunc("/frpcAct/proxyMgr/create", CreateProxyHandler)
http.HandleFunc("/frpcAct/proxyMgr/delete", DeleteProxyHandler)
http.HandleFunc("/", NotFoundHandler)