package util import ( "crypto/md5" "crypto/sha1" "encoding/base64" "encoding/hex" "fmt" "hash" "io" "net/http" "os" "path" "runtime" "strings" ) type File struct { Id string `json:"id"` Sha1 string `json:"sha1"` Size int64 `json:"size"` Url string `json:"url"` Path string `json:"path"` } func (f File) Retrieve() ([]byte, error) { return GetFromUrl(f.Url, f.Sha1, "sha1", f.Size) } func (f *File) GetName() string { if f.Id == "" { return f.Path } return f.Id } func GetFromUrl(url string, hash, hashType string, fSize int64) ([]byte, error) { resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("status code returned is %d", resp.StatusCode) } if fSize != -1 && resp.ContentLength != -1 && resp.ContentLength != fSize { return nil, fmt.Errorf("response size mismatch. %d != %d", resp.ContentLength, fSize) } data, err := io.ReadAll(resp.Body) if err != nil { return nil, err } if fSize != -1 && len(data) != int(fSize) { return nil, fmt.Errorf("body size mismatch. %d != %d", len(data), fSize) } if hash != "" { if err := CheckHash(data, hash, hashType); err != nil { return nil, err } } return data, nil } func IsFileExist(path string) bool { _, err := os.Stat(path) return err == nil } func WriteFile(fPath string, data []byte) error { if err := os.MkdirAll(path.Dir(fPath), 0777); err != nil { return err } if err := os.WriteFile(fPath, data, 0666); err != nil { return err } return nil } func ReadFile(fPath string) ([]byte, error) { if !IsFileExist(fPath) { return nil, fmt.Errorf("File %s not found", fPath) } data, err := os.ReadFile(fPath) if err != nil { return nil, err } return data, nil } // LoadOrDownloadFile will check if file exists and correct, will download it otherwise. func LoadOrDownloadFile(fPath, url string, hash, hashType string, fSize int64) ([]byte, error) { if IsFileExist(fPath) { data, err := os.ReadFile(fPath) if err != nil { return nil, err } if hash != "" { if err := CheckHash(data, hash, hashType); err != nil { return nil, err } } return data, nil } return GetFromUrl(url, hash, hashType, fSize) } func CheckHash(data []byte, fHash, hashType string) error { var hasher hash.Hash switch hashType { case "sha1": hasher = sha1.New() case "md5": hasher = md5.New() default: return fmt.Errorf("unsupported hash type %s", hashType) } if _, err := hasher.Write(data); err != nil { return err } resultedHash := hasher.Sum(nil) if (strings.Contains(fHash, "=") && base64.StdEncoding.EncodeToString(resultedHash) == fHash) || hex.EncodeToString(resultedHash) == fHash { return nil } return fmt.Errorf("hash mismatch: %s != %s", hex.EncodeToString(resultedHash), fHash) } func PathSeparator() string { if runtime.GOOS == "windows" { return ";" } return ":" }