102 lines
2.1 KiB
Go
102 lines
2.1 KiB
Go
//go:build web
|
|
|
|
package ext
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"demo-server/pkg/str"
|
|
"embed"
|
|
"fmt"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/vearutop/statigz"
|
|
"go.uber.org/zap"
|
|
"io"
|
|
"io/fs"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
/*
|
|
embed static web learn insp opensource license MIT
|
|
see "github.com/v2rayA/v2rayA/server/router/index.go"
|
|
*/
|
|
|
|
func init() {
|
|
initEngQueue = append(initEngQueue, initGUI)
|
|
}
|
|
|
|
// webRootFS 嵌入静态文件
|
|
//
|
|
//go:embed web
|
|
var webRootFS embed.FS
|
|
|
|
func initGUI(r *gin.Engine) {
|
|
webFS, err := fs.Sub(webRootFS, "web")
|
|
if err != nil {
|
|
zap.S().Panic("init gui err, cause: ", err)
|
|
}
|
|
|
|
guiStaticResource(r, webFS)
|
|
guiIndexHTML(r, webFS)
|
|
}
|
|
|
|
// html 缓存 HTML 页面
|
|
func html(html []byte) func(ctx *gin.Context) {
|
|
etag := fmt.Sprintf("W/%x", md5.Sum(html))
|
|
h := str.B2S(html)
|
|
return func(ctx *gin.Context) {
|
|
if ctx.IsAborted() {
|
|
return
|
|
}
|
|
ctx.Header("Content-Type", "text/html; charset=utf-8")
|
|
ctx.Header("Cache-Control", "public, must-revalidate")
|
|
ctx.Header("ETag", etag)
|
|
if match := ctx.GetHeader("If-None-Match"); match != "" {
|
|
if strings.Contains(match, etag) {
|
|
ctx.Status(http.StatusNotModified)
|
|
return
|
|
}
|
|
}
|
|
ctx.String(http.StatusOK, h)
|
|
}
|
|
}
|
|
|
|
func guiStaticResource(r *gin.Engine, sfs fs.FS) {
|
|
|
|
const (
|
|
assetsPrefix = "/assets"
|
|
staticPrefix = "/static"
|
|
|
|
stripPrefix = ""
|
|
)
|
|
|
|
staticResource := http.StripPrefix(stripPrefix, statigz.FileServer(sfs.(fs.ReadDirFS)))
|
|
r.GET(assetsPrefix+"/*w", func(c *gin.Context) {
|
|
staticResource.ServeHTTP(c.Writer, c.Request)
|
|
})
|
|
r.GET(staticPrefix+"/*w", func(c *gin.Context) {
|
|
staticResource.ServeHTTP(c.Writer, c.Request)
|
|
})
|
|
r.GET("/favicon.ico", func(c *gin.Context) {
|
|
staticResource.ServeHTTP(c.Writer, c.Request)
|
|
})
|
|
}
|
|
|
|
func guiIndexHTML(r *gin.Engine, sfs fs.FS) {
|
|
var indexHTML []byte
|
|
{
|
|
const indexFileName = "index.html"
|
|
index, err := sfs.Open(indexFileName)
|
|
if err != nil {
|
|
zap.S().Panicf("open [%s] err! cause: %e", indexFileName, err)
|
|
}
|
|
indexHTML, err = io.ReadAll(index)
|
|
if err != nil {
|
|
zap.S().Panicf("read [%s] err! cause: %e", indexFileName, err)
|
|
}
|
|
}
|
|
|
|
r.GET("/", html(indexHTML))
|
|
r.NoRoute(html(indexHTML))
|
|
}
|