mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 21:24:10 +00:00
102 lines
2 KiB
Go
102 lines
2 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/fs"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type assetManifest map[string]string
|
|
|
|
type assetResolver struct {
|
|
basePath string
|
|
debug bool
|
|
manifest assetManifest
|
|
}
|
|
|
|
func newAssetResolver(basePath string, debug bool, manifest assetManifest) assetResolver {
|
|
return assetResolver{
|
|
basePath: basePath,
|
|
debug: debug,
|
|
manifest: manifest,
|
|
}
|
|
}
|
|
|
|
func (r assetResolver) URL(logical string) string {
|
|
target := logical
|
|
if !r.debug {
|
|
hashed, ok := r.manifest[logical]
|
|
if !ok {
|
|
panic(fmt.Sprintf("missing asset manifest entry for %q", logical))
|
|
}
|
|
target = hashed
|
|
}
|
|
return path.Join(r.basePath, "assets", target)
|
|
}
|
|
|
|
func loadAssetManifest(raw []byte) (assetManifest, error) {
|
|
if len(raw) == 0 {
|
|
return nil, fmt.Errorf("asset manifest is empty")
|
|
}
|
|
var manifest assetManifest
|
|
if err := json.Unmarshal(raw, &manifest); err != nil {
|
|
return nil, err
|
|
}
|
|
if len(manifest) == 0 {
|
|
return nil, fmt.Errorf("asset manifest has no entries")
|
|
}
|
|
return manifest, nil
|
|
}
|
|
|
|
func assetCacheControl(requestPath string) string {
|
|
if hasFingerprint(requestPath) {
|
|
return "public, max-age=31536000, immutable"
|
|
}
|
|
return "public, max-age=300"
|
|
}
|
|
|
|
func assetRequestCacheControl(requestPath string, exists bool) string {
|
|
if exists {
|
|
return assetCacheControl(requestPath)
|
|
}
|
|
return "public, max-age=300"
|
|
}
|
|
|
|
func assetExists(assetsFS fs.FS, assetPath string) bool {
|
|
if assetPath == "" {
|
|
return false
|
|
}
|
|
if _, err := fs.Stat(assetsFS, assetPath); err != nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func hasFingerprint(requestPath string) bool {
|
|
base := path.Base(requestPath)
|
|
parts := strings.Split(base, ".")
|
|
if len(parts) < 2 {
|
|
return false
|
|
}
|
|
if isFingerprintHash(parts[len(parts)-1]) {
|
|
return true
|
|
}
|
|
if len(parts) >= 3 && isFingerprintHash(parts[len(parts)-2]) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isFingerprintHash(hash string) bool {
|
|
if len(hash) < 6 || len(hash) > 64 {
|
|
return false
|
|
}
|
|
for _, ch := range hash {
|
|
if !strings.ContainsRune("0123456789abcdef", ch) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|