- Move instance-related structs and functions to config.go - Remove serverAddr, serverPort, and authMethod from database schema - Implement new config parsing and encoding with nested key support - Update service management to use instanceID instead of username/name - Add GetServiceNameByInstanceID helper function - Update API documentation for auth.method field change
292 lines
10 KiB
Go
292 lines
10 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"super-frpc/postLog"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
func CreateProxyHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[CreateProxyHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] 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("[CreateProxyHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceID := getStringFromMap(reqMap, "instanceID")
|
|
if instanceID == "" {
|
|
postLog.Error("[CreateProxyHandler] instanceID is required")
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
proxyInfoMap, ok := reqMap["proxyInfo"].(map[string]interface{})
|
|
if !ok {
|
|
postLog.Error("[CreateProxyHandler] Invalid proxyInfo format")
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid proxyInfo format")
|
|
return
|
|
}
|
|
|
|
proxyInfo := FrpcProxyInfo{
|
|
Name: getStringFromMap(proxyInfoMap, "name"),
|
|
Type: getStringFromMap(proxyInfoMap, "type"),
|
|
LocalIP: getStringFromMap(proxyInfoMap, "localIP"),
|
|
LocalPort: getStringFromMap(proxyInfoMap, "localPort"),
|
|
RemotePort: getStringFromMap(proxyInfoMap, "remotePort"),
|
|
}
|
|
|
|
if proxyInfo.Name == "" || proxyInfo.Type == "" || proxyInfo.LocalIP == "" ||
|
|
proxyInfo.LocalPort == "" || proxyInfo.RemotePort == "" {
|
|
postLog.Error("[CreateProxyHandler] Missing required fields in proxyInfo")
|
|
SendErrorResponse(w, http.StatusBadRequest, "Missing required fields in proxyInfo")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] 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("[CreateProxyHandler] 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("[CreateProxyHandler] Failed to query instance: %v", err))
|
|
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))
|
|
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))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
|
|
return
|
|
}
|
|
|
|
updatedContent, err := addFrpcProxy(string(configContent), proxyInfo)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to add proxy: %v", err))
|
|
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))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
|
|
return
|
|
}
|
|
|
|
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 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
|
|
}
|
|
|
|
updatedContent, err := removeFrpcProxy(string(configContent), proxyName)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to remove proxy: %v", err))
|
|
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))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
|
|
return
|
|
}
|
|
|
|
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) {
|
|
if r.Method != http.MethodGet {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[ListProxiesHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
queryParams := r.URL.Query()
|
|
instanceID := queryParams.Get("instanceID")
|
|
if instanceID == "" {
|
|
postLog.Error("[ListProxiesHandler] instanceID is required")
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
var instance FrpcInstance
|
|
instanceIDInt, _ := strconv.Atoi(instanceID)
|
|
instance, err = DBQueryFrpcInstanceByID(instanceIDInt)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to query instance: %v", err))
|
|
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))
|
|
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))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
|
|
return
|
|
}
|
|
|
|
var config FrpcConfig
|
|
if _, err := toml.Decode(string(configContent), &config); err != nil {
|
|
postLog.Error(fmt.Sprintf("[ListProxiesHandler] Failed to parse config: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to parse config file")
|
|
return
|
|
}
|
|
|
|
proxyList := make([]map[string]interface{}, len(config.Proxies))
|
|
for i, proxy := range config.Proxies {
|
|
proxyData := map[string]interface{}{
|
|
"name": proxy["name"],
|
|
"type": proxy["type"],
|
|
"localIP": proxy["localIP"],
|
|
"localPort": proxy["localPort"],
|
|
"remotePort": proxy["remotePort"],
|
|
}
|
|
proxyList[i] = proxyData
|
|
}
|
|
|
|
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))
|
|
}
|