From: bruce Date: Thu, 21 Nov 2024 10:37:57 +0000 (+0000) Subject: feat(utils): 1, merge utils from local files. X-Git-Tag: v0.3.2~1 X-Git-Url: https://git.uzoombox.com/git/?a=commitdiff_plain;h=20194c25d2d32f42a69581b7e25d8f2c4e93fd2c;p=uzsdk-v0.3.2.git feat(utils): 1, merge utils from local files. --- diff --git a/utils/dsutil/array.go b/utils/dsutil/array.go index ca9710d..807fe9c 100644 --- a/utils/dsutil/array.go +++ b/utils/dsutil/array.go @@ -28,6 +28,24 @@ func Equal(array interface{}, val interface{}) bool { return i == na } +// Includes returns true if an array includes a certain value. +func Includes(array interface{}, val interface{}) bool { + va := reflect.ValueOf(array) + if va.Kind() != reflect.Array && va.Kind() != reflect.Slice { + return false + } + if 0 >= va.Len() || reflect.TypeOf(val) != reflect.TypeOf(va.Index(0).Interface()) { + return false + } + + for i := 0; i < va.Len(); i++ { + if va.Index(i).Interface() == val { + return true + } + } + return false +} + // IncludesAt returns index if array includes val. func IncludesAt(array interface{}, val interface{}) int { va, vv := reflect.ValueOf(array), reflect.ValueOf(val) diff --git a/utils/dsutil/crypto.go b/utils/dsutil/crypto.go new file mode 100644 index 0000000..3f424a1 --- /dev/null +++ b/utils/dsutil/crypto.go @@ -0,0 +1,33 @@ +// Copyright 2010-2024 nanzoom.com. All Rights Reserved. + +package dsutil + +import ( + "crypto/rand" + "fmt" + "io" +) + +// GenerateRandomBytes returns an random bytes with length:n. +func GenerateRandomBytes(n int) ([]byte, error) { + b := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return nil, err + } + return b, nil +} + +// GenerateUUID returns an UUID followin RFC 4122 +func GenerateUUID() (string, error) { + uuid, err := GenerateRandomBytes(16) + if err != nil { + return "", err + } + + // set version:4(0100) + uuid[6] = (uuid[6] & 0x0f) | 0x40 + // set variant:8(1000) + uuid[8] = (uuid[8] & 0x3f) | 0x80 + + return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil +} diff --git a/utils/fsutil/archive.go b/utils/fsutil/archive.go index 1f5f692..a3a6aa6 100644 --- a/utils/fsutil/archive.go +++ b/utils/fsutil/archive.go @@ -10,10 +10,38 @@ import ( "os" "path/filepath" "strings" + "time" "git.uzoombox.com/git/uzsdk/utils/osutil" ) +type ZipNode struct { + Path string // realpath on filesystem of the file. + Size int64 // length in bytes of the file. + Mtime time.Time // modification time. + Isdir bool // is directory. +} + +// ZipNamedTree use zip to archive a tree(an kvs that key is relative filepath and value is a zipnode) and output to zipfile, +// returns nil if succeed, else returns an error. +// the tree MUST sorted by key with ASC. +func ZipNamedTree(tree map[string]ZipNode, target string) error { + zf, err := os.Create(target) + if err != nil { + return err + } + defer zf.Close() + + zw := zip.NewWriter(zf) + defer zw.Close() + + for key, node := range tree { + zipZipnode(zw, key, &node) + } + + return nil +} + // ZipFilepath use zip to archive a path(s) and output to zipfile, // if successful, it return nil, else return an error. // options will be [recursive, files]: @@ -182,3 +210,36 @@ func unzipFilenode(_ *zip.ReadCloser, root string, zf *zip.File) error { _, err = io.Copy(f, fr) return err } + +func zipZipnode(w *zip.Writer, key string, node *ZipNode) error { + // create a local file header. + var fh = &zip.FileHeader{ + Name: key, + Method: zip.Deflate, + Modified: node.Mtime, + UncompressedSize64: uint64(node.Size), + } + if node.Isdir { + fh.Name += "/" + } + + // create writer for this file header. + fw, err := w.CreateHeader(fh) + if err != nil { + return err + } + + if node.Isdir { + return nil + } + + // save content of the file. + f, err := os.Open(node.Path) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(fw, f) + return err +} diff --git a/utils/fsutil/crypto.go b/utils/fsutil/crypto.go index d6b3949..aac6e83 100644 --- a/utils/fsutil/crypto.go +++ b/utils/fsutil/crypto.go @@ -4,10 +4,13 @@ package fsutil import ( "bytes" + "crypto" "crypto/aes" "crypto/cipher" "crypto/md5" + "crypto/sha256" "fmt" + "hash" "io" "os" "path/filepath" @@ -47,26 +50,57 @@ func Md5sum(path string) (sum string) { return } -// Md5file returns the MD5 checksum of a file. -func Md5file(path string) string { - var sum string - if f, err := os.Open(path); err == nil { - h := md5.New() - if _, err := io.Copy(h, f); err == nil { - sum = fmt.Sprintf("%x", h.Sum(nil)) +// Sha256sum returns the SHA256 checksum of file path. +func Sha256sum(path string) (sum string) { + fi, err := os.Stat(path) + if err != nil { + return + } + + if fi.IsDir() { + if false { + names := make([]string, 0) + filepath.WalkDir(path, func(p string, d os.DirEntry, err error) error { + if err != nil { + return err + } + names = append(names, p) + if d.IsDir() && path != p { + return filepath.SkipDir + } + return nil + }) + + sort.Strings(names) + sum = Sha256string(names...) + } else { + sum = "" } - f.Close() + } else { + sum = Sha256file(path) } - return sum + + return +} + +// Md5file returns the MD5 checksum of a file. +func Md5file(path string) string { + return hashFile(crypto.MD5, path) +} + +// Sha256file returns the SHA256 checksum of a file. +func Sha256file(path string) string { + return hashFile(crypto.SHA256, path) } // Md5string returns the MD5 checksum of string(s). func Md5string(ss ...string) string { - h := md5.New() - for _, s := range ss { - io.WriteString(h, s) - } - return fmt.Sprintf("%x", h.Sum(nil)) + return hashString(crypto.MD5, ss...) +} + +// Sha256string returns the SHA256 checksum of string(s). +func Sha256string(ss ...string) string { + return hashString(crypto.SHA256, ss...) } // AesEncrypt use keyval to encrypt data with AES, and returns the result. @@ -164,3 +198,41 @@ func Aes256Key(val []byte) []byte { } return key } + +func hashFile(t crypto.Hash, path string) string { + var h hash.Hash + switch t { + case crypto.MD5: + h = md5.New() + case crypto.SHA256: + h = sha256.New() + default: + return "" + } + + var sum string + if f, err := os.Open(path); err == nil { + if _, err := io.Copy(h, f); err == nil { + sum = fmt.Sprintf("%x", h.Sum(nil)) + } + f.Close() + } + return sum +} + +func hashString(t crypto.Hash, ss ...string) string { + var h hash.Hash + switch t { + case crypto.MD5: + h = md5.New() + case crypto.SHA256: + h = sha256.New() + default: + return "" + } + + for _, s := range ss { + io.WriteString(h, s) + } + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/utils/netutil/mime.go b/utils/netutil/mime.go index d043494..979847a 100644 --- a/utils/netutil/mime.go +++ b/utils/netutil/mime.go @@ -14,7 +14,11 @@ import ( // Mimetype returns the MIME type associated with the file path, // if path is a directory, returns "httpd/unix-directory". -// Parameters WOULD include [fi:string/fs.FileInfo, re:*regexp.Regexp] +// options would be: +// +// file string: path of file. +// fi fs.FileInfo: fileinfo. +// re *regexp.Regexp: regexp. func Mimetype(options ...interface{}) string { var fi fs.FileInfo var re *regexp.Regexp