Files
YMhut-box-C-/server/unified-management/internal/config/preflight.go
T
QWQLwToo 079ee4eaeb
build-winui / winui (push) Has been cancelled
Add server components
2026-06-26 13:28:09 +08:00

133 lines
4.2 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
webassets "ymhut-box/server/unified-management/web"
)
type Check struct {
Name string `json:"name"`
Status string `json:"status"`
Path string `json:"path,omitempty"`
Message string `json:"message,omitempty"`
}
func Preflight(cfg *Config) []Check {
checks := []Check{
checkDir("storage", cfg.StorageDir, true),
checkParent("sqlite", cfg.Database.SQLitePath),
checkDir("update public", cfg.UpdatePublicDir, false),
checkDir("update notice", cfg.UpdateNoticeDir, false),
checkDir("downloads", cfg.DownloadsDir, false),
checkFile("legacy update-info", filepath.Join(cfg.UpdatePublicDir, "update-info.json"), false),
checkFile("legacy media-types", filepath.Join(cfg.UpdatePublicDir, "media-types.json"), false),
checkFile("version notice index", filepath.Join(cfg.UpdateNoticeDir, "total.json"), false),
checkWebBuild("admin web dist", cfg.AdminWebDir, "admin/dist"),
checkWebBuild("portal web dist", cfg.PortalWebDir, "portal/dist"),
checkWebBuild("setup web dist", cfg.SetupWebDir, "setup/dist"),
}
return checks
}
func checkDir(name, path string, create bool) Check {
if create {
if err := os.MkdirAll(path, 0o750); err != nil {
return Check{Name: name, Status: "error", Path: path, Message: err.Error()}
}
}
info, err := os.Stat(path)
if err != nil {
return Check{Name: name, Status: "missing", Path: path, Message: "directory not found"}
}
if !info.IsDir() {
return Check{Name: name, Status: "error", Path: path, Message: "path is not a directory"}
}
return Check{Name: name, Status: "ok", Path: path}
}
func checkParent(name, path string) Check {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0o750); err != nil {
return Check{Name: name, Status: "error", Path: path, Message: err.Error()}
}
return Check{Name: name, Status: "ok", Path: path}
}
func checkFile(name, path string, required bool) Check {
info, err := os.Stat(path)
if err != nil {
status := "missing"
if required {
status = "error"
}
return Check{Name: name, Status: status, Path: path, Message: "file not found"}
}
if info.IsDir() {
return Check{Name: name, Status: "error", Path: path, Message: "path is a directory"}
}
return Check{Name: name, Status: "ok", Path: path}
}
func checkWebBuild(name, path, embedRoot string) Check {
dir := checkDir(name, path, false)
if dir.Status != "ok" {
if embeddedWebBuildOK(embedRoot) {
return Check{Name: name, Status: "ok", Path: path, Message: "using embedded frontend assets"}
}
dir.Message = "frontend dist missing; run npm install && npm run build, or build release with -tags embed_web"
return dir
}
index := filepath.Join(path, "index.html")
if file := checkFile(name+" index", index, true); file.Status != "ok" {
if embeddedWebBuildOK(embedRoot) {
return Check{Name: name, Status: "ok", Path: path, Message: "disk index missing; using embedded frontend assets"}
}
return Check{Name: name, Status: "missing", Path: index, Message: "index.html missing; run npm run build"}
}
assets := filepath.Join(path, "assets")
if assetDir := checkDir(name+" assets", assets, false); assetDir.Status != "ok" {
if embeddedWebBuildOK(embedRoot) {
return Check{Name: name, Status: "ok", Path: path, Message: "disk assets missing; using embedded frontend assets"}
}
return Check{Name: name, Status: "missing", Path: assets, Message: "assets directory missing; run npm run build"}
}
return Check{Name: name, Status: "ok", Path: path}
}
func embeddedWebBuildOK(embedRoot string) bool {
if !webassets.Embedded {
return false
}
if _, err := webassets.ReadFile(filepath.ToSlash(filepath.Join(embedRoot, "index.html"))); err != nil {
return false
}
entries, err := webassets.ReadDir(filepath.ToSlash(filepath.Join(embedRoot, "assets")))
if err != nil {
return false
}
for _, entry := range entries {
if !entry.IsDir() {
return true
}
}
return false
}
func FormatPreflight(checks []Check) []string {
lines := make([]string, 0, len(checks))
for _, check := range checks {
line := fmt.Sprintf("[%s] %s", check.Status, check.Name)
if check.Path != "" {
line += " -> " + check.Path
}
if check.Message != "" {
line += " (" + check.Message + ")"
}
lines = append(lines, line)
}
return lines
}