176 lines
5.0 KiB
Go
176 lines
5.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
// =====================================================
|
|
// Реализации — конструкторы возвращают интерфейсы.
|
|
// Один тип → один интерфейс → Fx разруливает автоматически.
|
|
//
|
|
// DB и Cache используют fx.Lifecycle для регистрации хуков:
|
|
// OnStart — пинг/проверка соединения при запуске
|
|
// OnStop — корректное закрытие при остановке
|
|
//
|
|
// Fx сам вызывает хуки в правильном порядке:
|
|
// Старт: DB → Cache → ... → HTTP-сервер
|
|
// Остановка: HTTP-сервер → ... → Cache → DB
|
|
// =====================================================
|
|
|
|
// --- Инфраструктура ---
|
|
|
|
type dbImpl struct{ dsn string }
|
|
|
|
func (db *dbImpl) Query(query string) error { return nil }
|
|
func (db *dbImpl) QueryRow(query string) error { return nil }
|
|
func (db *dbImpl) Exec(query string) error { return nil }
|
|
func (db *dbImpl) BeginTx() error { return nil }
|
|
func (db *dbImpl) BulkInsert(query string, args ...any) error { return nil }
|
|
func (db *dbImpl) Close() error {
|
|
slog.Info("БД: соединение закрыто")
|
|
return nil
|
|
}
|
|
|
|
func newDB(lc fx.Lifecycle) (DB, error) {
|
|
db := &dbImpl{dsn: "postgres://localhost:5432/demo"}
|
|
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
slog.Info("БД: подключение установлено", "dsn", db.dsn)
|
|
return nil // здесь был бы db.Ping(ctx)
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
return db.Close()
|
|
},
|
|
})
|
|
|
|
return db, nil
|
|
}
|
|
|
|
type cacheImpl struct{}
|
|
|
|
func (c *cacheImpl) Get(key string) (string, error) { return "", nil }
|
|
func (c *cacheImpl) Set(key, value string) error { return nil }
|
|
func (c *cacheImpl) Close() error {
|
|
slog.Info("Кэш: соединение закрыто")
|
|
return nil
|
|
}
|
|
|
|
func newCache(lc fx.Lifecycle) Cache {
|
|
c := &cacheImpl{}
|
|
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
slog.Info("Кэш: подключение установлено")
|
|
return nil // здесь был бы c.Ping(ctx)
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
return c.Close()
|
|
},
|
|
})
|
|
|
|
return c
|
|
}
|
|
|
|
type eventBusImpl struct{}
|
|
|
|
func (b *eventBusImpl) Publish(event string) { slog.Info("событие", "event", event) }
|
|
func (b *eventBusImpl) Subscribe(event string, handler func()) { slog.Info("подписка", "event", event) }
|
|
|
|
func newEventBus(lc fx.Lifecycle) EventBus {
|
|
bus := &eventBusImpl{}
|
|
|
|
lc.Append(fx.Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
slog.Info("EventBus: запущен")
|
|
return nil
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
slog.Info("EventBus: очередь событий дренирована")
|
|
return nil
|
|
},
|
|
})
|
|
|
|
return bus
|
|
}
|
|
|
|
// --- Репозитории ---
|
|
|
|
type userRepo struct{ db DB }
|
|
type sessionRepo struct {
|
|
db DB
|
|
cache Cache
|
|
}
|
|
type notificationRepo struct{ db DB }
|
|
|
|
func newUserRepo(db DB) UserRepository {
|
|
return &userRepo{db: db}
|
|
}
|
|
|
|
func newSessionRepo(db DB, cache Cache) SessionRepository {
|
|
return &sessionRepo{db: db, cache: cache}
|
|
}
|
|
|
|
func newNotificationRepo(db DB) NotificationRepository {
|
|
return ¬ificationRepo{db: db}
|
|
}
|
|
|
|
// --- Сервисы ---
|
|
|
|
type authServiceImpl struct {
|
|
userRepo UserRepository
|
|
sessionRepo SessionRepository
|
|
cache Cache
|
|
events EventBus
|
|
}
|
|
|
|
func newAuthService(userRepo UserRepository, sessionRepo SessionRepository, cache Cache, events EventBus) AuthService {
|
|
return &authServiceImpl{userRepo: userRepo, sessionRepo: sessionRepo, cache: cache, events: events}
|
|
}
|
|
|
|
type userServiceImpl struct {
|
|
userRepo UserRepository
|
|
authService AuthService
|
|
events EventBus
|
|
}
|
|
|
|
func newUserService(userRepo UserRepository, authService AuthService, events EventBus) UserService {
|
|
return &userServiceImpl{userRepo: userRepo, authService: authService, events: events}
|
|
}
|
|
|
|
type notificationServiceImpl struct {
|
|
notificationRepo NotificationRepository
|
|
userService UserService
|
|
events EventBus
|
|
}
|
|
|
|
func newNotificationService(notificationRepo NotificationRepository, userService UserService, events EventBus) NotificationService {
|
|
return ¬ificationServiceImpl{notificationRepo: notificationRepo, userService: userService, events: events}
|
|
}
|
|
|
|
// --- Handler ---
|
|
|
|
type handler struct {
|
|
userService UserService
|
|
authService AuthService
|
|
notificationService NotificationService
|
|
}
|
|
|
|
func newHandler(userService UserService, authService AuthService, notificationService NotificationService) *handler {
|
|
return &handler{userService: userService, authService: authService, notificationService: notificationService}
|
|
}
|
|
|
|
func (h *handler) routes() http.Handler {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintln(w, "ok")
|
|
})
|
|
return mux
|
|
}
|