mirror of
https://github.com/rishikanthc/Scriberr.git
synced 2026-06-28 06:46:25 +00:00
146 lines
4.1 KiB
Go
146 lines
4.1 KiB
Go
package web
|
|
|
|
import (
|
|
"embed"
|
|
"io/fs"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"scriberr/internal/auth"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
//go:embed dist/*
|
|
var staticFiles embed.FS
|
|
|
|
// GetStaticHandler returns a handler for serving embedded static files
|
|
func GetStaticHandler() http.Handler {
|
|
// Get the dist subdirectory from embedded files
|
|
distFS, err := fs.Sub(staticFiles, "dist")
|
|
if err != nil {
|
|
panic("failed to get dist subdirectory: " + err.Error())
|
|
}
|
|
|
|
return http.FileServer(http.FS(distFS))
|
|
}
|
|
|
|
// GetIndexHTML returns the index.html content
|
|
func GetIndexHTML() ([]byte, error) {
|
|
return staticFiles.ReadFile("dist/index.html")
|
|
}
|
|
|
|
// SetupStaticRoutes configures static file serving in Gin
|
|
func SetupStaticRoutes(router *gin.Engine, authService *auth.AuthService) {
|
|
|
|
// Serve static assets (CSS, JS, images) directly from embedded filesystem
|
|
router.GET("/assets/*filepath", func(c *gin.Context) {
|
|
// Extract the file path
|
|
filepath := c.Param("filepath")
|
|
// Remove leading slash if present
|
|
if filepath[0] == '/' {
|
|
filepath = filepath[1:]
|
|
}
|
|
fullPath := "assets/" + filepath
|
|
|
|
// Try to read the file from embedded filesystem
|
|
fileContent, err := staticFiles.ReadFile("dist/" + fullPath)
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Set appropriate content type based on file extension
|
|
if strings.Contains(fullPath, ".css") {
|
|
c.Data(http.StatusOK, "text/css", fileContent)
|
|
} else if strings.Contains(fullPath, ".js") {
|
|
c.Data(http.StatusOK, "application/javascript", fileContent)
|
|
} else {
|
|
c.Data(http.StatusOK, "application/octet-stream", fileContent)
|
|
}
|
|
})
|
|
|
|
// Serve vite.svg
|
|
router.GET("/vite.svg", func(c *gin.Context) {
|
|
fileContent, err := staticFiles.ReadFile("dist/vite.svg")
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "image/svg+xml", fileContent)
|
|
})
|
|
|
|
// Serve scriberr-logo.png
|
|
router.GET("/scriberr-logo.png", func(c *gin.Context) {
|
|
fileContent, err := staticFiles.ReadFile("dist/scriberr-logo.png")
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "image/png", fileContent)
|
|
})
|
|
|
|
// Serve scriberr-thumb.png
|
|
router.GET("/scriberr-thumb.png", func(c *gin.Context) {
|
|
fileContent, err := staticFiles.ReadFile("dist/scriberr-thumb.png")
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "image/png", fileContent)
|
|
})
|
|
|
|
// Serve index.html for root and any unmatched routes (SPA behavior)
|
|
router.NoRoute(func(c *gin.Context) {
|
|
// For API routes, return 404
|
|
if strings.HasPrefix(c.Request.URL.Path, "/api") {
|
|
c.JSON(404, gin.H{"error": "API endpoint not found"})
|
|
return
|
|
}
|
|
|
|
// Try to serve file from dist directly (for PWA assets like sw.js, manifest.webmanifest)
|
|
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
|
|
|
// Prevent directory traversal (basic check, though embed.FS is safe)
|
|
if strings.Contains(path, "..") {
|
|
c.Status(http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
// Try to read the file from embedded filesystem
|
|
fileContent, err := staticFiles.ReadFile("dist/" + path)
|
|
if err == nil {
|
|
// File exists, serve it
|
|
contentType := "application/octet-stream"
|
|
if strings.HasSuffix(path, ".css") {
|
|
contentType = "text/css"
|
|
} else if strings.HasSuffix(path, ".js") {
|
|
contentType = "application/javascript"
|
|
} else if strings.HasSuffix(path, ".png") {
|
|
contentType = "image/png"
|
|
} else if strings.HasSuffix(path, ".svg") {
|
|
contentType = "image/svg+xml"
|
|
} else if strings.HasSuffix(path, ".ico") {
|
|
contentType = "image/x-icon"
|
|
} else if strings.HasSuffix(path, ".webmanifest") {
|
|
contentType = "application/manifest+json"
|
|
} else if strings.HasSuffix(path, ".html") {
|
|
contentType = "text/html; charset=utf-8"
|
|
}
|
|
|
|
c.Data(http.StatusOK, contentType, fileContent)
|
|
return
|
|
}
|
|
|
|
// For all other routes, serve the React app
|
|
// The React app will handle authentication client-side
|
|
indexHTML, err := GetIndexHTML()
|
|
if err != nil {
|
|
c.String(http.StatusInternalServerError, "Error loading page")
|
|
return
|
|
}
|
|
|
|
c.Data(http.StatusOK, "text/html; charset=utf-8", indexHTML)
|
|
})
|
|
}
|