feat: implement core functionality for super-frpc service
This commit introduces the core functionality for the super-frpc service including: - Configuration management - User authentication and authorization - Database integration - FRPC instance management - API endpoints for user operations - Token-based authentication system - Password hashing and validation
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
configPath := flag.String("config", "./config.json", "path to config file")
|
||||
dbPath := flag.String("db", "./database.db", "path to database file")
|
||||
flag.Parse()
|
||||
|
||||
if _, err := os.Stat(*configPath); os.IsNotExist(err) {
|
||||
defaultConfig := `{
|
||||
listenAddr": " "0.0.0.0",
|
||||
"listenPort": "8080",
|
||||
"configDir": "./configs"
|
||||
}`
|
||||
if err := os.WriteFile(*configPath, []byte(defaultConfig), 0644); err != nil {
|
||||
log.Fatalf("failed to create default config file: %v", err)
|
||||
}
|
||||
log.Printf("created default config file at %s", *configPath)
|
||||
}
|
||||
|
||||
_, err := LoadConfig(*configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
if err := InitDatabase(*dbPath); err != nil {
|
||||
log.Fatalf("failed to initialize database: %v", err)
|
||||
}
|
||||
log.Println("database initialized successfully")
|
||||
|
||||
if err := InitFrpcDatabase(*dbPath); err != nil {
|
||||
log.Printf("warning: failed to initialize frpc database: %v", err)
|
||||
}
|
||||
|
||||
config, err := GetConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get config: %v", err)
|
||||
}
|
||||
|
||||
setupRoutes()
|
||||
|
||||
addr := fmt.Sprintf("%s:%s", config.ListenAddr, config.ListenPort)
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Printf("server starting on %s", addr)
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("shutting down server...")
|
||||
|
||||
if err := server.Close(); err != nil {
|
||||
log.Printf("server closed with error: %v", err)
|
||||
}
|
||||
|
||||
if err := CloseDatabase(); err != nil {
|
||||
log.Printf("error closing database: %v", err)
|
||||
}
|
||||
|
||||
if err := CloseFrpcDatabase(); err != nil {
|
||||
log.Printf("error closing frpc database: %v", err)
|
||||
}
|
||||
|
||||
log.Println("server stopped")
|
||||
}
|
||||
|
||||
func setupRoutes() {
|
||||
http.HandleFunc("/register", RegisterHandler)
|
||||
http.HandleFunc("/login", LoginHandler)
|
||||
|
||||
http.HandleFunc("/frpcAct/instanceMgr/create", CreateInstanceHandler)
|
||||
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)
|
||||
|
||||
http.HandleFunc("/frpcAct/instanceMgr/", func(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
if len(path) < len("/frpcAct/instanceMgr/") {
|
||||
SendErrorResponse(w, http.StatusNotFound, "invalid path")
|
||||
return
|
||||
}
|
||||
|
||||
remainingPath := path[len("/frpcAct/instanceMgr/"):]
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
if remainingPath == "create" {
|
||||
CreateInstanceHandler(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if remainingPath == "list" {
|
||||
ListInstancesHandler(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasSuffix(remainingPath, "/delete") {
|
||||
instanceName := strings.TrimSuffix(remainingPath, "/delete")
|
||||
instanceName = strings.Trim(instanceName, "/")
|
||||
DeleteInstanceHandler(w, r, instanceName)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(remainingPath, "/modify/") {
|
||||
parts := strings.SplitN(remainingPath, "/modify/", 2)
|
||||
if len(parts) == 2 {
|
||||
instanceName := strings.Trim(parts[0], "/")
|
||||
ModifyInstanceHandler(w, r, instanceName)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
instanceName := strings.Trim(remainingPath, "/")
|
||||
if instanceName != "" {
|
||||
ListInstancesHandler(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
SendErrorResponse(w, http.StatusNotFound, "endpoint not found")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user