package web import ( "context" "database/sql" "errors" "net/http" "time" "github.com/gorilla/sessions" echo "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" "git.janky.solutions/finn/go-project-template/config" ) var server *echo.Echo func ListenAndServe() { sessionStore = sessions.NewCookieStore([]byte(config.C.Web.SessionKey)) server = echo.New() server.HideBanner = true server.HidePort = true server.HTTPErrorHandler = handleError server.Renderer = &Template{} server.Use(accessLogMiddleware, sessionMiddleware) server.RouteNotFound("/*", notFoundHandler) server.GET("/auth/begin", authBegin) server.GET("/auth/finish", authFinish) server.GET("/", index, authMiddleware) server.StaticFS("/static", Static) logrus.WithField("address", config.C.Web.Bind).Info("starting http server") err := server.Start(config.C.Web.Bind) if err != http.ErrServerClosed { logrus.WithError(err).Fatal("error starting http server") } } func Shutdown(ctx context.Context) error { if server == nil { return nil } return server.Shutdown(ctx) } func accessLogMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { start := time.Now() err := next(c) log := logrus.WithFields(logrus.Fields{ "method": c.Request().Method, "path": c.Request().URL.Path, "duration": time.Since(start), "status": c.Response().Status, "source": c.Request().RemoteAddr, }) if err != nil { log = log.WithError(err) } log.Debug("request handled") return err } } func handleError(err error, c echo.Context) { if errors.Is(err, sql.ErrNoRows) { logrus.Debug("sending 404 because handler threw sql.ErrNoRows") err = notFoundHandler(c) if err == nil { return } } logrus.WithFields(logrus.Fields{ "path": c.Request().URL.Path, "method": c.Request().Method, "error": err, }).Error("error handling request") _ = c.Render(http.StatusNotFound, "500.html", nil) } func notFoundHandler(c echo.Context) error { return c.Render(http.StatusNotFound, "404.html", nil) } func sessionMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { session, err := sessionStore.Get(c.Request(), sessionName) if err != nil { return err } c.Set(contextKeySession, session) return next(c) } }