forked from templates/template-go-backend
new proxy
This commit is contained in:
116
src/main.go
116
src/main.go
@@ -1,110 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"backend/ent"
|
||||
"backend/src/internal/config"
|
||||
"backend/src/internal/gateway"
|
||||
"backend/src/internal/logging"
|
||||
"backend/src/logic"
|
||||
|
||||
_ "github.com/lib/pq" // побочный импорт драйвера PostgreSQL
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
const (
|
||||
AppName = "Backend"
|
||||
AppName = "Ollama Proxy"
|
||||
AppVersion = "1.0.0"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
logger := logging.New("info")
|
||||
slog.SetDefault(logger)
|
||||
|
||||
logger.Info(fmt.Sprintf("Starting %s version %s\n", AppName, AppVersion))
|
||||
logger.Info(fmt.Sprintf("Starting %s version %s", AppName, AppVersion))
|
||||
|
||||
cfg, err := config.LoadConfig(logger)
|
||||
if err != nil {
|
||||
logger.Error("Configuration loading error", "error", err)
|
||||
logger.Error("Ошибка конфигурации", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// adjust logger according to LOG_LEVEL
|
||||
level := logging.ParseLevel(cfg.LoggingConfig.Level)
|
||||
if level != slog.LevelInfo {
|
||||
logger.Info("Adjusting log level from env", "level", level.String())
|
||||
logger.Info("Уровень логирования из env", "level", level.String())
|
||||
}
|
||||
logger = logging.New(cfg.LoggingConfig.Level)
|
||||
slog.SetDefault(logger)
|
||||
cfg.LoggingConfig.Instance = logger
|
||||
|
||||
// создаем контекст с отменой для управления жизненным циклом сервиса.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// подключаемся к базе данных
|
||||
dbURL, err := config.GetDatabaseURLForLogging(&cfg.DatabaseConfig)
|
||||
target, err := url.Parse(cfg.BackendURL)
|
||||
if err != nil {
|
||||
logger.Error("Failed getting database URL for logging", "error", err)
|
||||
return
|
||||
}
|
||||
logger.Info("Connecting to database...", "url", dbURL)
|
||||
|
||||
dsn, err := config.GetDatabaseDSN(&cfg.DatabaseConfig)
|
||||
if err != nil {
|
||||
logger.Error("Failed getting database DSN", "error", err)
|
||||
return
|
||||
}
|
||||
db, err := ent.Open(cfg.DatabaseConfig.Kind, dsn)
|
||||
if err != nil {
|
||||
logger.Error("Failed opening connection to postgres", "error", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Применяем миграции
|
||||
if err := db.Schema.Create(ctx); err != nil {
|
||||
logger.Error("Failed creating schema resources", "error", err)
|
||||
logger.Error("Неверный URL бэкенда", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// инициализируем бизнес логику
|
||||
business := logic.NewBusinessLogic(ctx, db)
|
||||
|
||||
// регистрируем обработчик WebSocket по адресу /ws
|
||||
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
gateway.WebSocketHandler(ctx, cfg, w, r, business)
|
||||
})
|
||||
|
||||
// создаём CORS middleware
|
||||
corsMiddleware := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"http://localhost:4200"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
||||
AllowCredentials: true,
|
||||
})
|
||||
|
||||
// оборачиваем стандартный mux (DefaultServeMux)
|
||||
handler := corsMiddleware.Handler(http.DefaultServeMux)
|
||||
|
||||
// адрес сервера должен быть без схемы
|
||||
clearURL := cfg.ServiceURL
|
||||
if strings.Contains(clearURL, "://") {
|
||||
if u, err := url.Parse(clearURL); err == nil && u.Host != "" {
|
||||
clearURL = u.Host
|
||||
}
|
||||
proxy := &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(target)
|
||||
r.Out.Host = target.Host
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
logger.Error("Ошибка прокси", "method", r.Method, "path", r.URL.Path, "error", err)
|
||||
http.Error(w, "Bad Gateway", http.StatusBadGateway)
|
||||
},
|
||||
}
|
||||
|
||||
logger.Info("WebSocket server is on", cfg.ServiceURL)
|
||||
if err := http.ListenAndServe(clearURL, handler); err != nil {
|
||||
logger.Error("WebSocket server is unable to start", "error", err)
|
||||
return
|
||||
handler := loggingMiddleware(logger, proxy)
|
||||
|
||||
logger.Info("Прокси запущен", "addr", cfg.ListenAddr, "backend", cfg.BackendURL)
|
||||
if err := http.ListenAndServe(cfg.ListenAddr, handler); err != nil {
|
||||
logger.Error("Ошибка сервера", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func loggingMiddleware(logger *slog.Logger, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
rw := &responseWriter{ResponseWriter: w, status: http.StatusOK}
|
||||
next.ServeHTTP(rw, r)
|
||||
logger.Info("запрос",
|
||||
"method", r.Method,
|
||||
"path", r.URL.Path,
|
||||
"status", rw.status,
|
||||
"duration", time.Since(start).String(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
type responseWriter struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(code int) {
|
||||
rw.status = code
|
||||
rw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user