136 lines
3.5 KiB
Go
136 lines
3.5 KiB
Go
package bootstrap
|
||
|
||
import (
|
||
"bufio"
|
||
"encoding/json"
|
||
"io"
|
||
"io/fs"
|
||
"net/http"
|
||
"path/filepath"
|
||
|
||
"github.com/pkg/errors"
|
||
|
||
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
|
||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||
|
||
"github.com/gin-contrib/static"
|
||
)
|
||
|
||
const StaticFolder = "statics"
|
||
|
||
type GinFS struct {
|
||
FS http.FileSystem
|
||
}
|
||
|
||
type staticVersion struct {
|
||
Name string `json:"name"`
|
||
Version string `json:"version"`
|
||
}
|
||
|
||
// StaticFS 内置静态文件资源
|
||
var StaticFS static.ServeFileSystem
|
||
|
||
// Open 打开文件
|
||
func (b *GinFS) Open(name string) (http.File, error) {
|
||
return b.FS.Open(name)
|
||
}
|
||
|
||
// Exists 文件是否存在
|
||
func (b *GinFS) Exists(prefix string, filepath string) bool {
|
||
if _, err := b.FS.Open(filepath); err != nil {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// InitStatic 初始化静态资源文件
|
||
func InitStatic(statics fs.FS) {
|
||
if util.Exists(util.RelativePath(StaticFolder)) {
|
||
util.Log().Info("Folder with name \"statics\" already exists, it will be used to serve static files.")
|
||
StaticFS = static.LocalFile(util.RelativePath("statics"), false)
|
||
} else {
|
||
// 初始化静态资源
|
||
embedFS, err := fs.Sub(statics, "assets/build")
|
||
if err != nil {
|
||
util.Log().Panic("Failed to initialize static resources: %s", err)
|
||
}
|
||
|
||
StaticFS = &GinFS{
|
||
FS: http.FS(embedFS),
|
||
}
|
||
}
|
||
// 检查静态资源的版本
|
||
f, err := StaticFS.Open("version.json")
|
||
if err != nil {
|
||
util.Log().Warning("Missing version identifier file in static resources, please delete \"statics\" folder and rebuild it.")
|
||
return
|
||
}
|
||
|
||
b, err := io.ReadAll(f)
|
||
if err != nil {
|
||
util.Log().Warning("Failed to read version identifier file in static resources, please delete \"statics\" folder and rebuild it.")
|
||
return
|
||
}
|
||
|
||
var v staticVersion
|
||
if err := json.Unmarshal(b, &v); err != nil {
|
||
util.Log().Warning("Failed to parse version identifier file in static resources: %s", err)
|
||
return
|
||
}
|
||
|
||
staticName := "cloudreve-frontend"
|
||
if conf.IsPro == "true" {
|
||
staticName += "-pro"
|
||
}
|
||
|
||
if v.Name != staticName {
|
||
util.Log().Warning("Static resource version mismatch, please delete \"statics\" folder and rebuild it.")
|
||
return
|
||
}
|
||
|
||
if v.Version != conf.RequiredStaticVersion {
|
||
util.Log().Warning("Static resource version mismatch [Current %s, Desired: %s],please delete \"statics\" folder and rebuild it.", v.Version, conf.RequiredStaticVersion)
|
||
return
|
||
}
|
||
}
|
||
|
||
// Eject 抽离内置静态资源
|
||
func Eject(statics fs.FS) {
|
||
// 初始化静态资源
|
||
embedFS, err := fs.Sub(statics, "assets/build")
|
||
if err != nil {
|
||
util.Log().Panic("Failed to initialize static resources: %s", err)
|
||
}
|
||
|
||
var walk func(relPath string, d fs.DirEntry, err error) error
|
||
walk = func(relPath string, d fs.DirEntry, err error) error {
|
||
if err != nil {
|
||
return errors.Errorf("Failed to read info of %q: %s, skipping...", relPath, err)
|
||
}
|
||
|
||
if !d.IsDir() {
|
||
// 写入文件
|
||
out, err := util.CreatNestedFile(filepath.Join(util.RelativePath(""), StaticFolder, relPath))
|
||
defer out.Close()
|
||
|
||
if err != nil {
|
||
return errors.Errorf("Failed to create file %q: %s, skipping...", relPath, err)
|
||
}
|
||
|
||
util.Log().Info("Ejecting %q...", relPath)
|
||
obj, _ := embedFS.Open(relPath)
|
||
if _, err := io.Copy(out, bufio.NewReader(obj)); err != nil {
|
||
return errors.Errorf("Cannot write file %q: %s, skipping...", relPath, err)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// util.Log().Info("开始导出内置静态资源...")
|
||
err = fs.WalkDir(embedFS, ".", walk)
|
||
if err != nil {
|
||
util.Log().Error("Error occurs while ejecting static resources: %s", err)
|
||
return
|
||
}
|
||
util.Log().Info("Finish ejecting static resources.")
|
||
}
|