forked from templates/template-go-backend
87 lines
2.1 KiB
Go
87 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"time"
|
|
|
|
"backend/src/internal/config"
|
|
"backend/src/internal/logging"
|
|
)
|
|
|
|
const (
|
|
AppName = "Ollama Proxy"
|
|
AppVersion = "1.0.0"
|
|
)
|
|
|
|
func main() {
|
|
logger := logging.New("info")
|
|
slog.SetDefault(logger)
|
|
logger.Info(fmt.Sprintf("Starting %s version %s", AppName, AppVersion))
|
|
|
|
cfg, err := config.LoadConfig(logger)
|
|
if err != nil {
|
|
logger.Error("Ошибка конфигурации", "error", err)
|
|
return
|
|
}
|
|
|
|
level := logging.ParseLevel(cfg.LoggingConfig.Level)
|
|
if level != slog.LevelInfo {
|
|
logger.Info("Уровень логирования из env", "level", level.String())
|
|
}
|
|
logger = logging.New(cfg.LoggingConfig.Level)
|
|
slog.SetDefault(logger)
|
|
cfg.LoggingConfig.Instance = logger
|
|
|
|
target, err := url.Parse(cfg.BackendURL)
|
|
if err != nil {
|
|
logger.Error("Неверный URL бэкенда", "error", err)
|
|
return
|
|
}
|
|
|
|
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)
|
|
},
|
|
}
|
|
|
|
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)
|
|
}
|