Compare commits
1 Commits
192ec80010
...
0751ddb88a
| Author | SHA1 | Date | |
|---|---|---|---|
| 0751ddb88a |
@@ -2,9 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gitea.mrixs.me/minecraft-platform/backend/internal/api"
|
"gitea.mrixs.me/minecraft-platform/backend/internal/api"
|
||||||
"gitea.mrixs.me/minecraft-platform/backend/internal/core"
|
"gitea.mrixs.me/minecraft-platform/backend/internal/core"
|
||||||
@@ -15,6 +18,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// --- Инициализация логгера (slog) ---
|
||||||
|
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
||||||
|
slog.SetDefault(logger)
|
||||||
|
|
||||||
|
slog.Info("Starting backend server initialization...")
|
||||||
|
|
||||||
dbPool := database.Connect()
|
dbPool := database.Connect()
|
||||||
defer dbPool.Close()
|
defer dbPool.Close()
|
||||||
|
|
||||||
@@ -30,25 +39,32 @@ func main() {
|
|||||||
|
|
||||||
keyPath := os.Getenv("RSA_PRIVATE_KEY_PATH")
|
keyPath := os.Getenv("RSA_PRIVATE_KEY_PATH")
|
||||||
if keyPath == "" {
|
if keyPath == "" {
|
||||||
log.Fatal("RSA_PRIVATE_KEY_PATH environment variable is not set")
|
slog.Error("RSA_PRIVATE_KEY_PATH environment variable is not set")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
domain := os.Getenv("APP_DOMAIN")
|
domain := os.Getenv("APP_DOMAIN")
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
log.Fatal("APP_DOMAIN environment variable is not set")
|
slog.Error("APP_DOMAIN environment variable is not set")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
profileService, err := core.NewProfileService(userRepo, keyPath, domain)
|
profileService, err := core.NewProfileService(userRepo, keyPath, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to create profile service: %v", err)
|
slog.Error("Failed to create profile service", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
modpacksStoragePath := os.Getenv("MODPACKS_STORAGE_PATH")
|
modpacksStoragePath := os.Getenv("MODPACKS_STORAGE_PATH")
|
||||||
if modpacksStoragePath == "" {
|
if modpacksStoragePath == "" {
|
||||||
log.Fatal("MODPACKS_STORAGE_PATH environment variable is not set")
|
slog.Error("MODPACKS_STORAGE_PATH environment variable is not set")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
janitorService := core.NewFileJanitorService(modpackRepo, modpacksStoragePath)
|
janitorService := core.NewFileJanitorService(modpackRepo, modpacksStoragePath)
|
||||||
|
|
||||||
// --- Запуск фоновых задач ---
|
// --- Запуск фоновых задач ---
|
||||||
go serverPoller.Start(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
go serverPoller.Start(ctx) // Передаем контекст для отмены
|
||||||
|
|
||||||
// --- Инициализация хендлеров ---
|
// --- Инициализация хендлеров ---
|
||||||
userHandler := &api.UserHandler{Service: userService}
|
userHandler := &api.UserHandler{Service: userService}
|
||||||
@@ -60,13 +76,19 @@ func main() {
|
|||||||
ModpackRepo: modpackRepo,
|
ModpackRepo: modpackRepo,
|
||||||
JanitorService: janitorService,
|
JanitorService: janitorService,
|
||||||
}
|
}
|
||||||
adminUserHandler := &api.AdminUserHandler{UserRepo: userRepo} // Этот хендлер мы создали для админских функций
|
adminUserHandler := &api.AdminUserHandler{UserRepo: userRepo}
|
||||||
|
|
||||||
// --- Настройка роутера ---
|
// --- Настройка роутера ---
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
r.Use(middleware.Logger)
|
r.Use(middleware.Logger) // Можно заменить на slog middleware, но пока оставим standard
|
||||||
r.Use(middleware.Recoverer)
|
r.Use(middleware.Recoverer)
|
||||||
|
|
||||||
|
// Health Check
|
||||||
|
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("OK"))
|
||||||
|
})
|
||||||
|
|
||||||
// --- Публичные роуты ---
|
// --- Публичные роуты ---
|
||||||
r.Route("/api", func(r chi.Router) {
|
r.Route("/api", func(r chi.Router) {
|
||||||
r.Post("/register", userHandler.Register)
|
r.Post("/register", userHandler.Register)
|
||||||
@@ -103,15 +125,40 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
r.Route("/users", func(r chi.Router) {
|
r.Route("/users", func(r chi.Router) {
|
||||||
// ИСПРАВЛЕНО: Используем adminUserHandler
|
|
||||||
r.Get("/", adminUserHandler.GetAllUsers)
|
r.Get("/", adminUserHandler.GetAllUsers)
|
||||||
r.Patch("/{id}/role", adminUserHandler.UpdateUserRole)
|
r.Patch("/{id}/role", adminUserHandler.UpdateUserRole)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Println("Starting backend server on :8080")
|
// --- Graceful Shutdown ---
|
||||||
if err := http.ListenAndServe(":8080", r); err != nil {
|
srv := &http.Server{
|
||||||
log.Fatalf("Failed to start server: %v", err)
|
Addr: ":8080",
|
||||||
|
Handler: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
slog.Info("Starting backend server on :8080")
|
||||||
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
slog.Error("Failed to start server", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for interrupt signal to gracefully shutdown the server with a timeout.
|
||||||
|
quit := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-quit
|
||||||
|
slog.Info("Shutting down server...")
|
||||||
|
|
||||||
|
// The context is used to inform the server it has 5 seconds to finish
|
||||||
|
// the request it is currently handling
|
||||||
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer shutdownCancel()
|
||||||
|
|
||||||
|
if err := srv.Shutdown(shutdownCtx); err != nil {
|
||||||
|
slog.Error("Server forced to shutdown", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("Server exiting")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"gitea.mrixs.me/minecraft-platform/backend/internal/core"
|
"gitea.mrixs.me/minecraft-platform/backend/internal/core"
|
||||||
@@ -40,7 +40,7 @@ func (h *AuthHandler) Authenticate(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Другие ошибки - внутренние
|
// Другие ошибки - внутренние
|
||||||
log.Printf("internal server error during authentication: %v", err)
|
slog.Error("internal server error during authentication", "error", err)
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ func (h *AuthHandler) Join(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("internal server error during join: %v", err)
|
slog.Error("internal server error during join", "error", err)
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
|
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("internal server error during login: %v", err)
|
slog.Error("internal server error during login", "error", err)
|
||||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log/slog"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.mrixs.me/minecraft-platform/backend/internal/database"
|
"gitea.mrixs.me/minecraft-platform/backend/internal/database"
|
||||||
@@ -29,7 +29,7 @@ type ServerPoller struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ServerPoller) Start(ctx context.Context) {
|
func (p *ServerPoller) Start(ctx context.Context) {
|
||||||
log.Println("Starting server poller...")
|
slog.Info("Starting server poller...")
|
||||||
ticker := time.NewTicker(60 * time.Second)
|
ticker := time.NewTicker(60 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ func (p *ServerPoller) Start(ctx context.Context) {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
p.pollAllServers(ctx)
|
p.pollAllServers(ctx)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Println("Stopping server poller...")
|
slog.Info("Stopping server poller...")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ func (p *ServerPoller) Start(ctx context.Context) {
|
|||||||
func (p *ServerPoller) pollAllServers(ctx context.Context) {
|
func (p *ServerPoller) pollAllServers(ctx context.Context) {
|
||||||
servers, err := p.Repo.GetAllEnabledServers(ctx)
|
servers, err := p.Repo.GetAllEnabledServers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Poller: failed to get servers: %v", err)
|
slog.Error("Poller: failed to get servers", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,13 +61,13 @@ func (p *ServerPoller) pollAllServers(ctx context.Context) {
|
|||||||
func (p *ServerPoller) pollServer(ctx context.Context, server *models.GameServer) {
|
func (p *ServerPoller) pollServer(ctx context.Context, server *models.GameServer) {
|
||||||
resp, delay, err := bot.PingAndList(server.Address)
|
resp, delay, err := bot.PingAndList(server.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Poller: failed to ping %s (%s): %v", server.Name, server.Address, err)
|
slog.Warn("Poller: failed to ping server", "server", server.Name, "address", server.Address, "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var status pingResponse
|
var status pingResponse
|
||||||
if err := json.Unmarshal(resp, &status); err != nil {
|
if err := json.Unmarshal(resp, &status); err != nil {
|
||||||
log.Printf("Poller: failed to unmarshal status for %s: %v", server.Name, err)
|
slog.Error("Poller: failed to unmarshal status", "server", server.Name, "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ func (p *ServerPoller) pollServer(ctx context.Context, server *models.GameServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := p.Repo.UpdateServerStatus(ctx, server.ID, updateData); err != nil {
|
if err := p.Repo.UpdateServerStatus(ctx, server.ID, updateData); err != nil {
|
||||||
log.Printf("Poller: failed to update status for %s: %v", server.Name, err)
|
slog.Error("Poller: failed to update status", "server", server.Name, "error", err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Poller: successfully polled %s", server.Name)
|
slog.Info("Poller: successfully polled server", "server", server.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user