mihomo/config/update_ui.go
2023-09-18 19:21:30 +08:00

120 lines
2.4 KiB
Go

package config
import (
"archive/zip"
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"sync"
)
var (
ExternalUIURL string
ExternalUIPath string
ExternalUIFolder string
ExternalUIName string
)
var xdMutex sync.Mutex
func UpdateUI() error {
xdMutex.Lock()
defer xdMutex.Unlock()
if ExternalUIPath == "" || ExternalUIFolder == "" || ExternalUIName == "" {
return fmt.Errorf("ExternalUI configure incomplete")
}
err := cleanup(ExternalUIFolder)
if err != nil {
if !os.IsNotExist(err) {
return fmt.Errorf("cleanup exist file error: %w", err)
}
}
data, err := downloadForBytes(ExternalUIURL)
if err != nil {
return fmt.Errorf("can't download file: %w", err)
}
saved := path.Join(ExternalUIPath, "download.zip")
if saveFile(data, saved) != nil {
return fmt.Errorf("can't save zip file: %w", err)
}
defer os.Remove(saved)
unzipFolder, err := unzip(saved, ExternalUIPath)
if err != nil {
return fmt.Errorf("can't extract zip file: %w", err)
}
err = os.Rename(unzipFolder, ExternalUIFolder)
if err != nil {
return fmt.Errorf("can't rename folder: %w", err)
}
return nil
}
func unzip(src, dest string) (string, error) {
r, err := zip.OpenReader(src)
if err != nil {
return "", err
}
defer r.Close()
var extractedFolder string
for _, f := range r.File {
fpath := filepath.Join(dest, f.Name)
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return "", fmt.Errorf("invalid file path: %s", fpath)
}
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
continue
}
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return "", err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return "", err
}
rc, err := f.Open()
if err != nil {
return "", err
}
_, err = io.Copy(outFile, rc)
outFile.Close()
rc.Close()
if err != nil {
return "", err
}
if extractedFolder == "" {
extractedFolder = filepath.Dir(fpath)
}
}
return extractedFolder, nil
}
func cleanup(root string) error {
if _, err := os.Stat(root); os.IsNotExist(err) {
return nil
}
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
if err := os.RemoveAll(path); err != nil {
return err
}
} else {
if err := os.Remove(path); err != nil {
return err
}
}
return nil
})
}