feat(handlers): add duplicate login check and improve request handling
refactor: move postLog package to root directory and enhance logging fix(frpc): improve request parsing and type handling for instance creation chore: update config paths and enable debug mode
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
[common]
|
||||
server_addr = 127.0.0.1
|
||||
server_port = 7000
|
||||
auth_method = token
|
||||
=
|
||||
BIN
Binary file not shown.
@@ -10,18 +10,19 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InstanceInfo struct {
|
||||
Name string `json:"name"`
|
||||
ServerAddr string `json:"serverAddr"`
|
||||
ServerPort string `json:"serverPort"`
|
||||
AuthMethod string `json:"auth_method"`
|
||||
Name string `json:"name"`
|
||||
ServerAddr string `json:"serverAddr"`
|
||||
ServerPort string `json:"serverPort"`
|
||||
AuthMethod string `json:"auth_method"`
|
||||
// BootAtStart bool `json:"bootAtStart"`
|
||||
RunUser string `json:"runUser"`
|
||||
Additional map[string]interface{} `json:"additionalProperties"`
|
||||
RunUser string `json:"runUser"`
|
||||
Additional map[string]interface{} `json:"additionalProperties"`
|
||||
}
|
||||
|
||||
type CreateInstanceRequest struct {
|
||||
@@ -102,13 +103,79 @@ func CreateInstanceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
var req CreateInstanceRequest
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
// 先解析为map,处理类型不匹配的情况
|
||||
var reqMap map[string]interface{}
|
||||
if err := json.Unmarshal(body, &reqMap); err != nil {
|
||||
SendErrorResponse(w, http.StatusBadRequest, "invalid request format")
|
||||
return
|
||||
}
|
||||
|
||||
userID, _, err := ValidateRequestWithBody(w, r, body)
|
||||
// 处理timeStamp字段
|
||||
timeStamp := int64(0)
|
||||
if ts, ok := reqMap["timeStamp"]; ok {
|
||||
switch v := ts.(type) {
|
||||
case float64:
|
||||
timeStamp = int64(v)
|
||||
case string:
|
||||
if v != "" {
|
||||
if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
timeStamp = parsed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理bootAtStart字段
|
||||
bootAtStart := false
|
||||
if bas, ok := reqMap["bootAtStart"]; ok {
|
||||
switch v := bas.(type) {
|
||||
case bool:
|
||||
bootAtStart = v
|
||||
case string:
|
||||
if v == "true" {
|
||||
bootAtStart = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理instanceInfo字段
|
||||
instanceInfoMap, ok := reqMap["instanceInfo"].(map[string]interface{})
|
||||
if !ok {
|
||||
SendErrorResponse(w, http.StatusBadRequest, "invalid instanceInfo format")
|
||||
return
|
||||
}
|
||||
|
||||
instanceInfo := InstanceInfo{
|
||||
Name: getStringFromMap(instanceInfoMap, "name"),
|
||||
ServerAddr: getStringFromMap(instanceInfoMap, "serverAddr"),
|
||||
ServerPort: getStringFromMap(instanceInfoMap, "serverPort"),
|
||||
AuthMethod: getStringFromMap(instanceInfoMap, "auth_method"),
|
||||
RunUser: getStringFromMap(reqMap, "runUser"),
|
||||
}
|
||||
|
||||
// 处理additionalProperties字段
|
||||
if additional, ok := reqMap["additionalProperties"].(map[string]interface{}); ok {
|
||||
instanceInfo.Additional = additional
|
||||
}
|
||||
|
||||
// 构建请求结构体
|
||||
req := CreateInstanceRequest{
|
||||
Token: getStringFromMap(reqMap, "token"),
|
||||
TimeStamp: timeStamp,
|
||||
InstanceInfo: instanceInfo,
|
||||
BootAtStart: bootAtStart,
|
||||
RunUser: instanceInfo.RunUser,
|
||||
Additional: instanceInfo.Additional,
|
||||
}
|
||||
|
||||
// 重新序列化为JSON,用于ValidateRequestWithBody
|
||||
reqBody, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
SendErrorResponse(w, http.StatusBadRequest, "invalid request format")
|
||||
return
|
||||
}
|
||||
|
||||
userID, _, err := ValidateRequestWithBody(w, r, reqBody)
|
||||
if err != nil {
|
||||
SendErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
@@ -745,3 +812,10 @@ func GetUserInstances(userID int) ([]FrpcInstance, error) {
|
||||
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func getStringFromMap(m map[string]interface{}, key string) string {
|
||||
if v, ok := m[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
+7
-1
@@ -7,7 +7,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"super-frpc/modules"
|
||||
"super-frpc/postLog"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -150,6 +150,12 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
existingTokenInfo, err := GetTokenInfo(user.UserID)
|
||||
if err == nil && existingTokenInfo != nil {
|
||||
SendErrorResponse(w, http.StatusConflict, "user is already logged in")
|
||||
return
|
||||
}
|
||||
|
||||
token, err := GenerateToken(user.UserID)
|
||||
if err != nil {
|
||||
SendErrorResponse(w, http.StatusInternalServerError, "failed to generate token")
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"super-frpc/modules"
|
||||
"super-frpc/postLog"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
@@ -23,31 +23,31 @@ func main() {
|
||||
"configDir": "./configs"
|
||||
}`
|
||||
if err := os.WriteFile(*configPath, []byte(defaultConfig), 0644); err != nil {
|
||||
postLog.Fatal(fmt.Sprintf("failed to create default config file: %v", err))
|
||||
postLog.Fatal(fmt.Sprintf("Failed to create default config file: %v", err))
|
||||
}
|
||||
postLog.Info(fmt.Sprintf("created default config file at %s", *configPath))
|
||||
postLog.Info(fmt.Sprintf("Created default config file at %s", *configPath))
|
||||
}
|
||||
|
||||
config, err := LoadConfig(*configPath)
|
||||
if err != nil {
|
||||
postLog.Fatal(fmt.Sprintf("failed to load config: %v", err))
|
||||
postLog.Fatal(fmt.Sprintf("Failed to load config: %v", err))
|
||||
}
|
||||
|
||||
// Initialize logger with debug mode
|
||||
postLog.SetDebugMode(config.Debug)
|
||||
|
||||
if err := InitDatabase(*dbPath); err != nil {
|
||||
postLog.Fatal(fmt.Sprintf("failed to initialize database: %v", err))
|
||||
postLog.Fatal(fmt.Sprintf("Failed to initialize database: %v", err))
|
||||
}
|
||||
postLog.Info("database initialized successfully")
|
||||
postLog.Info("Database initialized successfully")
|
||||
|
||||
if err := InitFrpcDatabase(*dbPath); err != nil {
|
||||
postLog.Warning(fmt.Sprintf("failed to initialize frpc database: %v", err))
|
||||
postLog.Warning(fmt.Sprintf("Failed to initialize frpc database: %v", err))
|
||||
}
|
||||
|
||||
_, err = GetConfig()
|
||||
if err != nil {
|
||||
postLog.Fatal(fmt.Sprintf("failed to get config: %v", err))
|
||||
postLog.Fatal(fmt.Sprintf("Failed to get config: %v", err))
|
||||
}
|
||||
|
||||
setupRoutes()
|
||||
@@ -61,9 +61,9 @@ func main() {
|
||||
}
|
||||
|
||||
go func() {
|
||||
postLog.Info(fmt.Sprintf("server starting on %s", addr))
|
||||
postLog.Info(fmt.Sprintf("Server starting on %s", addr))
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
postLog.Fatal(fmt.Sprintf("failed to start server: %v", err))
|
||||
postLog.Fatal(fmt.Sprintf("Failed to start server: %v", err))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -71,19 +71,19 @@ func main() {
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
postLog.Info("shutting down server...")
|
||||
postLog.Info("Shutting down server...")
|
||||
|
||||
if err := server.Close(); err != nil {
|
||||
postLog.Error(fmt.Sprintf("server closed with error: %v", err))
|
||||
postLog.Error(fmt.Sprintf("Server closed with error: %v", err))
|
||||
}
|
||||
|
||||
if err := CloseDatabase(); err != nil {
|
||||
postLog.Error(fmt.Sprintf("error closing database: %v", err))
|
||||
postLog.Error(fmt.Sprintf("Error closing database: %v", err))
|
||||
}
|
||||
|
||||
if err := CloseFrpcDatabase(); err != nil {
|
||||
postLog.Error(fmt.Sprintf("error closing frpc database: %v", err))
|
||||
postLog.Error(fmt.Sprintf("Error closing frpc database: %v", err))
|
||||
}
|
||||
|
||||
postLog.Info("server stopped")
|
||||
postLog.Info("Server stopped")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user