Files
backend/main.go
NanamiAdmin f3fca7f07b feat(user): add createdAt field to user model
- Add createdAt field to User struct and database schema
- Update all user queries to include createdAt field
- Document new field in API documentation
- Fix server online status flag timing
2026-03-10 14:34:16 +08:00

141 lines
3.5 KiB
Go

package main
import (
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"super-frpc/postLog"
"syscall"
"time"
)
type SoftwareInfo struct {
Name string
Version string
Developer string
BuildVer int16
Description string
BuildType string
}
var softwareInfo SoftwareInfo
type StatusInfo struct {
Status string
}
var isDebug bool
var isOnline bool
func main() {
softwareInfo = SoftwareInfo{
Name: "Super-frpc",
Version: "0.0.1",
Developer: "Madobi Nanami",
BuildVer: 1,
BuildType: "debug",
}
postLog.Info(fmt.Sprintf("%s %s (Build %d.%s) by %s", softwareInfo.Name, softwareInfo.Version, softwareInfo.BuildVer, softwareInfo.BuildType, softwareInfo.Developer))
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 {
postLog.Warning(fmt.Sprintf("Failed to create default config file: %v", err))
}
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))
}
// Initialize logger with debug mode
postLog.SetDebugMode(config.Debug)
isDebug = config.Debug
if err := InitDatabase(*dbPath); err != nil {
postLog.Fatal(fmt.Sprintf("Failed to initialize database: %v", err))
}
postLog.Info("Database initialized successfully")
if err := InitFrpcDatabase(*dbPath); err != nil {
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))
}
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() {
postLog.Info(fmt.Sprintf("Server starting on %s", addr))
isOnline = true
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
postLog.Fatal(fmt.Sprintf("Failed to start server: %v", err))
}
}()
go func() {
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for range ticker.C {
CleanupExpiredTokens()
CleanupExpiredSessions()
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
postLog.Info("Shutting down server...")
if err := server.Close(); err != nil {
postLog.Error(fmt.Sprintf("Server closed with error: %v", err))
}
if err := CloseDatabase(); err != nil {
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.Info("Server stopped")
}
func GetStatusHandler(w http.ResponseWriter, r *http.Request) {
statusInfo := StatusInfo{
Status: "Online",
}
if !isOnline {
statusInfo.Status = "Offline"
}
SendSuccessResponse(w, "getStatus", statusInfo)
}
func GetSoftwareInfoHandler(w http.ResponseWriter, r *http.Request) {
SendSuccessResponse(w, "getSoftwareInfo", softwareInfo)
}