Files
backend/handlers/proxy.go
NanamiAdmin 489c37e095 refactor(global): move config to global package and consolidate handlers
- Move Config struct and related functions to global package
- Consolidate handler utilities into utils package
- Remove deprecated handlers and instance packages
- Add new handlers package with settings and proxy functionality
- Update config.json to include watchdog enabled flag
2026-04-22 19:52:33 +08:00

353 lines
13 KiB
Go

package handlers
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"super-frpc/config"
"super-frpc/database"
"super-frpc/utils"
"super-frpc/postLog"
"github.com/BurntSushi/toml"
)
func CreateProxyHandler(w http.ResponseWriter, r *http.Request) {
userID, err := utils.Auth(w, r, http.MethodPost, "superuser", "admin")
if err != nil {
utils.SendErrorResponse(w, http.StatusUnauthorized, err.Error())
postLog.Warning(fmt.Sprintf("[CreateProxyHandler] Auth failed: %v", err))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to read request body: %v", err))
utils.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("[CreateProxyHandler] Failed to unmarshal request body: %v", err))
utils.SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
return
}
instanceID := getStringFromMap(reqMap, "instanceID")
if instanceID == "" {
postLog.Error("[CreateProxyHandler] instanceID is required")
utils.SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
proxyInfoMap, ok := reqMap["proxyInfo"].(map[string]interface{})
if !ok {
postLog.Error("[CreateProxyHandler] Invalid proxyInfo format")
utils.SendErrorResponse(w, http.StatusBadRequest, "Invalid proxyInfo format")
return
}
proxyInfo := config.FrpcProxyInfo{
Name: getStringFromMap(proxyInfoMap, "name"),
Type: getStringFromMap(proxyInfoMap, "type"),
LocalIP: getStringFromMap(proxyInfoMap, "localIP"),
LocalPort: getNumFromMap(proxyInfoMap, "localPort"),
RemotePort: getNumFromMap(proxyInfoMap, "remotePort"),
}
if proxyInfo.Name == "" || proxyInfo.Type == "" || proxyInfo.LocalIP == "" ||
proxyInfo.LocalPort == 0 || proxyInfo.RemotePort == 0 {
postLog.Error("[CreateProxyHandler] Missing required fields in proxyInfo")
utils.SendErrorResponse(w, http.StatusBadRequest, "Missing required fields in proxyInfo")
return
}
var instance database.FrpcInstance
instanceIDInt, _ := strconv.Atoi(instanceID)
instance, err = database.DBQueryFrpcInstanceByID(instanceIDInt)
if err != nil {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to query instance: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
return
}
if instance.UserID != userID {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Instance not found for user %d", userID))
utils.SendErrorResponse(w, http.StatusNotFound, "Instance not found")
return
}
configContent, err := os.ReadFile(instance.ConfigPath)
if err != nil {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
return
}
updatedContent, err := config.AddFrpcProxy(string(configContent), proxyInfo)
if err != nil {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to add proxy: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to add proxy")
return
}
if err := os.WriteFile(instance.ConfigPath, []byte(updatedContent), 0644); err != nil {
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to write config file %s: %v", instance.ConfigPath, err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
return
}
utils.SendSuccessResponse(w, "Proxy created successfully", map[string]interface{}{
"instanceID": instance.ID,
"configPath": instance.ConfigPath,
"proxyName": proxyInfo.Name,
})
postLog.Info(fmt.Sprintf("[CreateProxyHandler] Proxy %s created successfully for instance %d", proxyInfo.Name, instance.ID))
}
func ModifyProxyHandler(w http.ResponseWriter, r *http.Request) {
userID, err := utils.Auth(w, r, http.MethodPost, "superuser", "admin")
if err != nil {
utils.SendErrorResponse(w, http.StatusUnauthorized, err.Error())
postLog.Warning(fmt.Sprintf("[ModifyProxyHandler] Auth failed: %v", err))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Failed to read request body: %v", err))
utils.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("[ModifyProxyHandler] Failed to unmarshal request body: %v", err))
utils.SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
return
}
instanceID := getStringFromMap(reqMap, "instanceID")
if instanceID == "" {
postLog.Error("[ModifyProxyHandler] instanceID is required")
utils.SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
proxyInfoMap, ok := reqMap["proxyInfo"].(map[string]interface{})
if !ok {
postLog.Error("[ModifyProxyHandler] Invalid proxyInfo format")
utils.SendErrorResponse(w, http.StatusBadRequest, "Invalid proxyInfo format")
return
}
proxyInfo := config.FrpcProxyInfo{
Name: getStringFromMap(proxyInfoMap, "name"),
Type: getStringFromMap(proxyInfoMap, "type"),
LocalIP: getStringFromMap(proxyInfoMap, "localIP"),
LocalPort: getNumFromMap(proxyInfoMap, "localPort"),
RemotePort: getNumFromMap(proxyInfoMap, "remotePort"),
}
if proxyInfo.Name == "" || proxyInfo.Type == "" || proxyInfo.LocalIP == "" ||
proxyInfo.LocalPort == 0 || proxyInfo.RemotePort == 0 {
postLog.Error("[ModifyProxyHandler] Missing required fields in proxyInfo")
utils.SendErrorResponse(w, http.StatusBadRequest, "Missing required fields in proxyInfo")
return
}
var instance database.FrpcInstance
instanceIDInt, _ := strconv.Atoi(instanceID)
instance, err = database.DBQueryFrpcInstanceByID(instanceIDInt)
if err != nil {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Failed to query instance: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
return
}
if instance.UserID != userID {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Instance not found for user %d", userID))
utils.SendErrorResponse(w, http.StatusNotFound, "Instance not found")
return
}
configContent, err := os.ReadFile(instance.ConfigPath)
if err != nil {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
return
}
updatedContent, err := config.ModifyFrpcProxy(string(configContent), proxyInfo)
if err != nil {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Failed to modify proxy: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to modify proxy")
return
}
if err := os.WriteFile(instance.ConfigPath, []byte(updatedContent), 0644); err != nil {
postLog.Error(fmt.Sprintf("[ModifyProxyHandler] Failed to write config file %s: %v", instance.ConfigPath, err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
return
}
utils.SendSuccessResponse(w, "Proxy modified successfully", map[string]interface{}{
"instanceID": instance.ID,
"configPath": instance.ConfigPath,
"proxyName": proxyInfo.Name,
})
postLog.Info(fmt.Sprintf("[ModifyProxyHandler] Proxy %s modified successfully for instance %d", proxyInfo.Name, instance.ID))
}
func DeleteProxyHandler(w http.ResponseWriter, r *http.Request) {
userID, err := utils.Auth(w, r, http.MethodPost, "superuser", "admin")
if err != nil {
utils.SendErrorResponse(w, http.StatusUnauthorized, err.Error())
postLog.Warning(fmt.Sprintf("[DeleteProxyHandler] Auth failed: %v", err))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to read request body: %v", err))
utils.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))
utils.SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
return
}
instanceID := getStringFromMap(reqMap, "instanceID")
if instanceID == "" {
postLog.Error("[DeleteProxyHandler] instanceID is required")
utils.SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
proxyName := getStringFromMap(reqMap, "proxyName")
if proxyName == "" {
postLog.Error("[DeleteProxyHandler] proxyName is required")
utils.SendErrorResponse(w, http.StatusBadRequest, "proxyName is required")
return
}
var instance database.FrpcInstance
instanceIDInt, _ := strconv.Atoi(instanceID)
instance, err = database.DBQueryFrpcInstanceByID(instanceIDInt)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to query instance: %v", err))
utils.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))
utils.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))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
return
}
updatedContent, err := config.RemoveFrpcProxy(string(configContent), proxyName)
if err != nil {
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to remove proxy: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to remove proxy")
return
}
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))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
return
}
utils.SendSuccessResponse(w, "Proxy deleted successfully", map[string]interface{}{
"instanceID": instance.ID,
"configPath": instance.ConfigPath,
"proxyName": proxyName,
})
postLog.Info(fmt.Sprintf("[DeleteProxyHandler] Proxy %s deleted successfully from instance %d", proxyName, instance.ID))
}
func ListProxiesHandler(w http.ResponseWriter, r *http.Request) {
userID, err := utils.Auth(w, r, http.MethodGet)
if err != nil {
utils.SendErrorResponse(w, http.StatusUnauthorized, err.Error())
postLog.Warning(fmt.Sprintf("[ListProxiesHandler] Auth failed: %v", err))
return
}
queryParams := r.URL.Query()
instanceID := queryParams.Get("instanceID")
if instanceID == "" {
postLog.Error("[ListProxiesHandler] instanceID is required")
utils.SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
return
}
var instance database.FrpcInstance
instanceIDInt, _ := strconv.Atoi(instanceID)
instance, err = database.DBQueryFrpcInstanceByID(instanceIDInt)
if err != nil {
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to query instance: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
return
}
if instance.UserID != userID {
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Instance not found for user %d", userID))
utils.SendErrorResponse(w, http.StatusNotFound, "Instance not found")
return
}
configContent, err := os.ReadFile(instance.ConfigPath)
if err != nil {
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
return
}
var cfg config.FrpcConfig
if _, err := toml.Decode(string(configContent), &cfg); err != nil {
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to parse config: %v", err))
utils.SendErrorResponse(w, http.StatusInternalServerError, "Failed to parse config file")
return
}
proxyList := make([]map[string]interface{}, len(cfg.Proxies))
for i, proxy := range cfg.Proxies {
proxyData := map[string]interface{}{
"name": proxy["name"],
"type": proxy["type"],
"localIP": proxy["localIP"],
"localPort": proxy["localPort"],
"remotePort": proxy["remotePort"],
}
proxyList[i] = proxyData
}
utils.SendSuccessResponse(w, "Proxies listed successfully", map[string]interface{}{
"instanceID": instance.ID,
"proxyCount": len(proxyList),
"proxies": proxyList,
})
postLog.Info(fmt.Sprintf("[ListProxiesHandler] Retrieved %d proxies for instance %d", len(proxyList), instance.ID))
}