spark-server/internal/transport/http/docs.go
DESKTOP-L8OUL9F\gfl0034 b10c5d63a3 feat(brand): 三站替换四色火焰 logo 与 favicon
官网/docs 嵌入新品牌图;sparkapi nginx 可在未重建镜像时提供 /favicon.ico 与页头 logo。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 10:25:44 +08:00

74 lines
1.8 KiB
Go

package httpx
import (
"io/fs"
"net/http"
"path"
"strings"
"github.com/gin-gonic/gin"
)
func registerDocs(r *gin.Engine) {
r.GET("/openapi.yaml", func(c *gin.Context) {
c.Data(http.StatusOK, "application/yaml; charset=utf-8", openAPISpec)
})
serve := func(c *gin.Context) {
c.Data(http.StatusOK, "text/html; charset=utf-8", docsHTML)
}
r.GET("/docs", serve)
r.GET("/docs/enums", serve)
r.GET("/docs/errors", serve)
r.GET("/docs/", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/docs")
})
staticRoot, err := fs.Sub(docsStatic, "docs/static")
if err != nil {
panic("docs static embed: " + err.Error())
}
serveStaticFile := func(name, contentType string) gin.HandlerFunc {
return func(c *gin.Context) {
b, err := fs.ReadFile(staticRoot, name)
if err != nil {
c.Status(http.StatusNotFound)
return
}
c.Header("Cache-Control", "public, max-age=604800")
c.Data(http.StatusOK, contentType, b)
}
}
r.GET("/favicon.ico", serveStaticFile("favicon.ico", "image/x-icon"))
r.GET("/apple-touch-icon.png", serveStaticFile("apple-touch-icon.png", "image/png"))
r.GET("/docs/static/*filepath", func(c *gin.Context) {
rel := strings.TrimPrefix(c.Param("filepath"), "/")
rel = path.Clean("/" + rel)
rel = strings.TrimPrefix(rel, "/")
if rel == "" || strings.Contains(rel, "..") {
c.Status(http.StatusNotFound)
return
}
b, err := fs.ReadFile(staticRoot, rel)
if err != nil {
c.Status(http.StatusNotFound)
return
}
ct := contentTypeFor(rel)
c.Header("Cache-Control", "public, max-age=604800")
c.Data(http.StatusOK, ct, b)
})
}
func contentTypeFor(name string) string {
switch strings.ToLower(path.Ext(name)) {
case ".png":
return "image/png"
case ".ico":
return "image/x-icon"
case ".svg":
return "image/svg+xml"
default:
return "application/octet-stream"
}
}