package servicelib import ( "crypto/sha256" "encoding/hex" "fmt" "io" "net" "net/url" "os" "path/filepath" "strings" ) func IsAddrInUse(network, addr string) bool { ln, err := net.Listen(network, addr) if err != nil { return true } _ = ln.Close() return false } func WriteVersionFile(dir, version string) error { file := filepath.Join(dir, "version.txt") tmp := file + ".tmp" if err := os.MkdirAll(dir, 0755); err != nil { return err } if err := os.WriteFile(tmp, []byte(version+"\n"), 0644); err != nil { return err } return os.Rename(tmp, file) } func ReadVersionFile(dir string) (string, error) { file := filepath.Join(dir, "version.txt") data, err := os.ReadFile(file) if err != nil { return "", err } return strings.TrimSpace(string(data)), nil } type UpgradeURL struct { Scheme string Host string User string Pass string Path string } func ParseUpgradeURL(rawURL string) (*UpgradeURL, error) { u, err := url.Parse(rawURL) if err != nil { return nil, fmt.Errorf("invalid url: %w", err) } if u.Scheme == "" { return nil, fmt.Errorf("scheme is required") } scheme := strings.ToLower(u.Scheme) switch scheme { case "ftp", "ftps", "http", "https": default: return nil, fmt.Errorf("unsupported scheme: %s", scheme) } if u.Host == "" { return nil, fmt.Errorf("host is required") } result := &UpgradeURL{ Scheme: scheme, Host: u.Host, Path: u.Path, } if u.User != nil { result.User = u.User.Username() if pass, ok := u.User.Password(); ok { result.Pass = pass } } return result, nil } func CheckFileSHA256(file string, expected string) error { f, err := os.Open(file) if err != nil { return err } defer f.Close() hash := sha256.New() if _, err := io.Copy(hash, f); err != nil { return err } actual := hex.EncodeToString(hash.Sum(nil)) if !strings.EqualFold(actual, expected) { return fmt.Errorf("文件校验失败: 期望 %s, 实际 %s", expected, actual) } return nil }