github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/bootstrap/static.go (about)

     1  package bootstrap
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"io"
     7  	"io/fs"
     8  	"net/http"
     9  	"path/filepath"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/cloudreve/Cloudreve/v3/pkg/conf"
    14  	"github.com/cloudreve/Cloudreve/v3/pkg/util"
    15  
    16  	"github.com/gin-contrib/static"
    17  )
    18  
    19  const StaticFolder = "statics"
    20  
    21  type GinFS struct {
    22  	FS http.FileSystem
    23  }
    24  
    25  type staticVersion struct {
    26  	Name    string `json:"name"`
    27  	Version string `json:"version"`
    28  }
    29  
    30  // StaticFS 内置静态文件资源
    31  var StaticFS static.ServeFileSystem
    32  
    33  // Open 打开文件
    34  func (b *GinFS) Open(name string) (http.File, error) {
    35  	return b.FS.Open(name)
    36  }
    37  
    38  // Exists 文件是否存在
    39  func (b *GinFS) Exists(prefix string, filepath string) bool {
    40  	if _, err := b.FS.Open(filepath); err != nil {
    41  		return false
    42  	}
    43  	return true
    44  }
    45  
    46  // InitStatic 初始化静态资源文件
    47  func InitStatic(statics fs.FS) {
    48  	if util.Exists(util.RelativePath(StaticFolder)) {
    49  		util.Log().Info("Folder with name \"statics\" already exists, it will be used to serve static files.")
    50  		StaticFS = static.LocalFile(util.RelativePath("statics"), false)
    51  	} else {
    52  		// 初始化静态资源
    53  		embedFS, err := fs.Sub(statics, "assets/build")
    54  		if err != nil {
    55  			util.Log().Panic("Failed to initialize static resources: %s", err)
    56  		}
    57  
    58  		StaticFS = &GinFS{
    59  			FS: http.FS(embedFS),
    60  		}
    61  	}
    62  	// 检查静态资源的版本
    63  	f, err := StaticFS.Open("version.json")
    64  	if err != nil {
    65  		util.Log().Warning("Missing version identifier file in static resources, please delete \"statics\" folder and rebuild it.")
    66  		return
    67  	}
    68  
    69  	b, err := io.ReadAll(f)
    70  	if err != nil {
    71  		util.Log().Warning("Failed to read version identifier file in static resources, please delete \"statics\" folder and rebuild it.")
    72  		return
    73  	}
    74  
    75  	var v staticVersion
    76  	if err := json.Unmarshal(b, &v); err != nil {
    77  		util.Log().Warning("Failed to parse version identifier file in static resources: %s", err)
    78  		return
    79  	}
    80  
    81  	staticName := "cloudreve-frontend"
    82  	if conf.IsPro == "true" {
    83  		staticName += "-pro"
    84  	}
    85  
    86  	if v.Name != staticName {
    87  		util.Log().Warning("Static resource version mismatch, please delete \"statics\" folder and rebuild it.")
    88  		return
    89  	}
    90  
    91  	if v.Version != conf.RequiredStaticVersion {
    92  		util.Log().Warning("Static resource version mismatch [Current %s, Desired: %s],please delete \"statics\" folder and rebuild it.", v.Version, conf.RequiredStaticVersion)
    93  		return
    94  	}
    95  }
    96  
    97  // Eject 抽离内置静态资源
    98  func Eject(statics fs.FS) {
    99  	// 初始化静态资源
   100  	embedFS, err := fs.Sub(statics, "assets/build")
   101  	if err != nil {
   102  		util.Log().Panic("Failed to initialize static resources: %s", err)
   103  	}
   104  
   105  	var walk func(relPath string, d fs.DirEntry, err error) error
   106  	walk = func(relPath string, d fs.DirEntry, err error) error {
   107  		if err != nil {
   108  			return errors.Errorf("Failed to read info of %q: %s, skipping...", relPath, err)
   109  		}
   110  
   111  		if !d.IsDir() {
   112  			// 写入文件
   113  			out, err := util.CreatNestedFile(filepath.Join(util.RelativePath(""), StaticFolder, relPath))
   114  			defer out.Close()
   115  
   116  			if err != nil {
   117  				return errors.Errorf("Failed to create file %q: %s, skipping...", relPath, err)
   118  			}
   119  
   120  			util.Log().Info("Ejecting %q...", relPath)
   121  			obj, _ := embedFS.Open(relPath)
   122  			if _, err := io.Copy(out, bufio.NewReader(obj)); err != nil {
   123  				return errors.Errorf("Cannot write file %q: %s, skipping...", relPath, err)
   124  			}
   125  		}
   126  		return nil
   127  	}
   128  
   129  	// util.Log().Info("开始导出内置静态资源...")
   130  	err = fs.WalkDir(embedFS, ".", walk)
   131  	if err != nil {
   132  		util.Log().Error("Error occurs while ejecting static resources: %s", err)
   133  		return
   134  	}
   135  	util.Log().Info("Finish ejecting static resources.")
   136  }