From b96fcd1a54a46a95f98467b49a051564bc21c23c Mon Sep 17 00:00:00 2001 From: Anshul Gupta Date: Mon, 5 Aug 2024 18:55:10 -0700 Subject: Initial Commit --- backend/internal/server/server.go | 130 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 backend/internal/server/server.go (limited to 'backend/internal/server/server.go') diff --git a/backend/internal/server/server.go b/backend/internal/server/server.go new file mode 100644 index 0000000..7270b56 --- /dev/null +++ b/backend/internal/server/server.go @@ -0,0 +1,130 @@ +package server + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net/http" + "time" + + "ibd-trader/internal/auth" + "ibd-trader/internal/config" + "ibd-trader/internal/database" + "ibd-trader/internal/ibd" + "ibd-trader/internal/server/api/ibd/creds" + "ibd-trader/internal/server/api/ibd/ibd50" + "ibd-trader/internal/server/api/ibd/scrape" + "ibd-trader/internal/server/auth/callback" + "ibd-trader/internal/server/auth/login" + "ibd-trader/internal/server/auth/user" + middleware2 "ibd-trader/internal/server/middleware" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/redis/go-redis/v9" +) + +func StartServer( + ctx context.Context, + cfg *config.Config, + logger *slog.Logger, + db database.Database, + auth *auth.Authenticator, + client *ibd.Client, + rClient *redis.Client, +) error { + r := chi.NewRouter() + + r.Use(middleware.RealIP) + r.Use(middleware.RequestID) + r.Use(middleware.Recoverer) + r.Use(middleware.Heartbeat("/healthz")) + + _ = NewMainHandler(logger, db, r) + r.Route("/auth", func(r chi.Router) { + r.Get("/login", login.Handler(logger, db, auth)) + r.Get("/callback", callback.Handler(logger, db, db, auth)) + r.Route("/user", func(r chi.Router) { + r.Use(middleware2.Auth(db)) + r.Get("/", user.Handler(logger, auth)) + }) + }) + r.Route("/api", func(r chi.Router) { + r.Use(middleware.NoCache) + r.Use(middleware2.Auth(db)) + r.Route("/ibd", func(r chi.Router) { + r.Put("/creds", creds.Handler(logger, db)) + r.Get("/ibd50", ibd50.Handler(logger, client)) + r.Put("/scrape", scrape.Handler(logger, rClient)) + }) + }) + + logger.Info("Starting server", "port", cfg.Server.Port) + srv := &http.Server{ + Addr: fmt.Sprintf("0.0.0.0:%d", cfg.Server.Port), + Handler: r, + //ReadTimeout: 1 * time.Minute, + //WriteTimeout: 1 * time.Minute, + ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError), + } + + finishedCh := make(chan error) + go func() { + err := srv.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + logger.Error("Server failed", "error", err) + } + finishedCh <- err + close(finishedCh) + }() + + select { + case err := <-finishedCh: + // Server failed + return err + case <-ctx.Done(): + logger.Info("Shutting down server") + } + + // Shutdown server + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := srv.Shutdown(ctx); err != nil { + logger.Error("Failed to shutdown server", "error", err) + return err + } + + // Wait for the server to finish + err := <-finishedCh + if errors.Is(err, http.ErrServerClosed) { + return nil + } + return err +} + +type MainHandler struct { + logger *slog.Logger + db database.Database +} + +func NewMainHandler(logger *slog.Logger, db database.Database, r *chi.Mux) *MainHandler { + h := &MainHandler{logger, db} + r.Get("/readyz", h.Ready) + + return h +} + +func (h *MainHandler) Ready(w http.ResponseWriter, r *http.Request) { + // Check we can ping DB + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) + defer cancel() + err := h.db.Ping(ctx) + if err != nil { + http.Error(w, "DB not ready", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("OK")) +} -- cgit v1.2.3