new proxy

This commit is contained in:
2026-03-18 21:18:17 +03:00
parent 971332c283
commit b51a8850bc
17 changed files with 126 additions and 516 deletions

View File

@@ -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)
}