optimize: the static files and handle

This commit is contained in:
mingcheng 2022-09-29 12:37:02 +08:00
parent 03c32f3fdd
commit 91478b54a2
8 changed files with 127 additions and 87 deletions

View File

@ -4,12 +4,7 @@ LABEL maintainer="mingcheng<mc@sf.com>"
COPY . /answer
WORKDIR /answer
RUN make install-ui-packages ui
RUN mv ui/build /tmp
CMD ls -al /tmp
RUN du -sh /tmp/build
RUN make install-ui-packages ui && mv ui/build /tmp
FROM golang:1.18 AS golang-builder
LABEL maintainer="aichy"
@ -23,7 +18,7 @@ ENV GOPRIVATE git.backyard.segmentfault.com
# Build
COPY . ${BUILD_DIR}
WORKDIR ${BUILD_DIR}
COPY --from=node-builder /tmp/build ${BUILD_DIR}/web/html
COPY --from=node-builder /tmp/build ${BUILD_DIR}/ui/build
RUN make clean build && \
cp answer /usr/bin/answer && \
mkdir -p /tmp/cache && chmod 777 /tmp/cache && \
@ -31,8 +26,6 @@ RUN make clean build && \
mkdir -p /data/upfiles && chmod 777 /data/upfiles && \
mkdir -p /data/i18n && chmod 777 /data/i18n && cp -r i18n/*.yaml /data/i18n
FROM debian:bullseye
ENV TZ "Asia/Shanghai"
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list \

View File

@ -11,7 +11,7 @@ func NewHTTPServer(debug bool,
staticRouter *router.StaticRouter,
answerRouter *router.AnswerAPIRouter,
swaggerRouter *router.SwaggerRouter,
viewRouter *router.ViewRouter,
viewRouter *router.UIRouter,
authUserMiddleware *middleware.AuthUserMiddleware) *gin.Engine {
if debug {
@ -22,7 +22,7 @@ func NewHTTPServer(debug bool,
r := gin.New()
r.GET("/healthz", func(ctx *gin.Context) { ctx.String(200, "OK") })
viewRouter.RegisterViewRouter(r)
viewRouter.Register(r)
rootGroup := r.Group("")
swaggerRouter.Register(rootGroup)

78
internal/router/ui.go Normal file
View File

@ -0,0 +1,78 @@
package router
import (
"embed"
"fmt"
"github.com/gin-gonic/gin"
"github.com/segmentfault/answer/ui"
"github.com/segmentfault/pacman/log"
"io/fs"
"net/http"
"os"
)
const UIIndexFilePath = "build/index.html"
const UIStaticPath = "build/static"
// UIRouter is an interface that provides ui static file routers
type UIRouter struct {
}
// NewUIRouter creates a new UIRouter instance with the embed resources
func NewUIRouter() *UIRouter {
return &UIRouter{}
}
// _resource is an interface that provides static file, it's a private interface
type _resource struct {
fs embed.FS
}
// Open to implement the interface by http.FS required
func (r *_resource) Open(name string) (fs.File, error) {
name = fmt.Sprintf(UIStaticPath+"/%s", name)
log.Debugf("open static path %s", name)
return r.fs.Open(name)
}
// Register a new static resource which generated by ui directory
func (a *UIRouter) Register(r *gin.Engine) {
staticPath := os.Getenv("ANSWER_STATIC_PATH")
info, err := os.Stat(staticPath)
// if ANSWER_STATIC_PATH is set and not empty, ignore embed resource
if staticPath != "" {
if err != nil || !info.IsDir() {
log.Error(err)
} else {
log.Debugf("registering static path %s", staticPath)
r.LoadHTMLGlob(staticPath + "/*.html")
r.Static("/static", staticPath+"/static")
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{})
})
// return immediately if the static path is set
return
}
}
// handle the static file by default ui static files
r.StaticFS("/static", http.FS(&_resource{
fs: ui.Build,
}))
// specify the not router for default routes and redirect
r.NoRoute(func(c *gin.Context) {
index, err := ui.Build.ReadFile(UIIndexFilePath)
if err != nil {
log.Error(err)
c.Status(http.StatusNotFound)
return
}
c.Header("content-type", "text/html;charset=utf-8")
c.String(http.StatusOK, string(index))
})
}

View File

@ -0,0 +1,36 @@
package router
import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)
func TestUIRouter_Register(t *testing.T) {
r := gin.Default()
NewUIRouter().Register(r)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestUIRouter_Static(t *testing.T) {
r := gin.Default()
NewUIRouter().Register(r)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/static/version.txt", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "OK", w.Body.String())
}

View File

@ -1,67 +0,0 @@
package router
import (
"embed"
"errors"
"io/fs"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
"github.com/segmentfault/answer/web"
)
// RegisterViewRouter
type ViewRouter struct {
}
// NewRegisterViewRouter
func NewViewRouter() *ViewRouter {
return &ViewRouter{}
}
type Resource struct {
fs embed.FS
path string
}
func NewResource() *Resource {
return &Resource{
fs: web.Static,
path: "html",
}
}
func (r *Resource) Open(name string) (fs.File, error) {
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
return nil, errors.New("http: invalid character in file path")
}
fullName := filepath.Join(r.path, filepath.FromSlash(path.Clean("/static/"+name)))
file, err := r.fs.Open(fullName)
return file, err
}
func (a *ViewRouter) RegisterViewRouter(r *gin.Engine) {
//export answer_html_static_path="../../web/static"
//export answer_html_page_path="../../web"
static := os.Getenv("answer_html_static_path")
index := os.Getenv("answer_html_page_path")
if len(static) > 0 && len(index) > 0 {
r.LoadHTMLGlob(index + "/*.html")
r.Static("/static", static)
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{})
})
return
} else {
r.StaticFS("/static", http.FS(NewResource()))
r.NoRoute(func(c *gin.Context) {
c.Header("content-type", "text/html;charset=utf-8")
c.String(200, string(web.Html))
})
}
}

9
ui/static.go Normal file
View File

@ -0,0 +1,9 @@
package ui
import (
"embed"
_ "embed"
)
//go:embed build
var Build embed.FS

View File

@ -1,9 +0,0 @@
package web
import "embed"
//go:embed html/index.html
var Html []byte
//go:embed html/static
var Static embed.FS