Files
inventory-plus-plus/internal/server/server.go
T

161 lines
3.7 KiB
Go

package server
import (
"context"
"net/http"
"path"
"strings"
"github.com/gin-gonic/gin"
"ruben/inventory2/internal/domains/accounts"
"ruben/inventory2/internal/domains/authentication"
etsy_platform "ruben/inventory2/internal/domains/platforms/etsy"
"ruben/inventory2/internal/domains/raw_events"
"ruben/inventory2/internal/logging"
accounts_api "ruben/inventory2/internal/server/api/accounts"
auth_api "ruben/inventory2/internal/server/api/auth"
sse_api "ruben/inventory2/internal/server/api/sse"
templates_api "ruben/inventory2/internal/server/api/templates"
"ruben/inventory2/internal/server/api/webhooks"
etsy_webhooks "ruben/inventory2/internal/server/api/webhooks/etsy"
"ruben/inventory2/internal/server/middleware"
"ruben/inventory2/internal/server/response"
"ruben/inventory2/internal/server/sse"
)
// r gin.IRouter, // TODO: use this everywhere
type Router struct {
*gin.Engine
sse *sse.Queue
}
func NewRouter(
logger *logging.Logger,
contentDir string,
rawEvents *raw_events.Store,
accts *accounts.Store,
etsy *etsy_platform.Platform,
auth *authentication.Authenticator,
) *Router {
r := gin.Default()
r.Use(
response.HandleResponses,
response.HandleErrors,
)
// TODO: shouldn't this ACTUALLY be a middleware?
// - only try to make this an actual middleware AFTER all the routers are broken out, so that way how the middleware is supposed to work can be known
authMiddleware := middleware.NewAuth(
logger.WithGroup("auth-middleware"),
auth,
auth_api.NewLoginURL,
accts,
)
// webpage content
// non-html content: scripts, styles, images, etc
r.Use(fileServer("/scripts", contentDir+"/scripts", func(c *gin.Context) {
w := c.Writer
w.Header().Set("Content-Type", "text/javascript")
if path.Ext(c.Request.URL.Path) == ".gz" {
w.Header().Set("Content-Encoding", "gzip")
}
}))
r.Static("/styles", "./styles")
r.Static("/favicon", "./favicon")
r.Static("/images", "./images")
// html (must be before the api endpoints, because the webpage middleware has to be installed beforehand
r.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/ui")
})
// kind of a dumb way to capture routes for webpages
templates_api.SetupRoutes(
logger.WithGroup("templates"),
r.Group("/ui"),
contentDir,
rawEvents,
accts,
etsy,
authMiddleware,
)
// sse setup
sq := sse.NewQueue()
unp := middleware.NewUpdateNotificationPublisher(
logger.WithGroup("update.notification.publisher"),
sq,
)
// api endpoints
api := r.Group("/api")
apiLogger := logger.WithGroup("/api")
unp = unp.Trim("/api")
auth_api.Routes(
api.Group("/auth"),
apiLogger.WithGroup("/auth"),
auth,
)
sse_api.Routes(
api.Group("/events"),
apiLogger.WithGroup("/events"),
sq,
authMiddleware,
)
accounts_api.Routes(
api.Group("/accounts", authMiddleware.AuthenticateAndAddIdentityGin()),
apiLogger.WithGroup("/accounts"),
accts,
unp.Group("/accounts"),
)
// api webhooks (TODO: make a router for these)
webhooks.Webhooks(
api.Group("/webhooks"),
logger.WithGroup("webhooks"),
rawEvents,
etsy,
webhooks.Config{
Etsy: etsy_webhooks.Config{
OAuthRedirectURIWithAcctIDParam: "/oauth/account/{acctID}/auth_code",
},
},
)
return &Router{
Engine: r,
sse: sq,
}
}
func (r *Router) RunSSE(ctx context.Context) error {
return r.sse.Start(ctx)
}
func fileServer(urlPrefix, dir string, beforeServe func(c *gin.Context)) gin.HandlerFunc {
scfs := http.StripPrefix(urlPrefix, http.FileServer(http.Dir(dir)))
return func(c *gin.Context) {
r := c.Request
if r.URL.Path == urlPrefix || strings.HasPrefix(r.URL.Path, path.Join(urlPrefix, "/")) {
if beforeServe != nil {
beforeServe(c)
}
scfs.ServeHTTP(c.Writer, r)
c.Abort()
}
// TODO: need a c.Next()?
}
}