]> git.uzoombox.com Git - uzsdk.git/commitdiff
feat(utils): 1, merge utils from local files.
authorbruce <bruce@nanzoom.com>
Thu, 21 Nov 2024 10:37:57 +0000 (10:37 +0000)
committerbruce <bruce@nanzoom.com>
Thu, 21 Nov 2024 10:37:57 +0000 (10:37 +0000)
utils/dsutil/array.go
utils/dsutil/crypto.go [new file with mode: 0644]
utils/fsutil/archive.go
utils/fsutil/crypto.go
utils/netutil/mime.go

index ca9710d5792264c9f01b028c6f9066d78e02f5cb..807fe9ca0fca1eab90ab562cffc7d02a15b38897 100644 (file)
@@ -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 (file)
index 0000000..3f424a1
--- /dev/null
@@ -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
+}
index 1f5f69206f745e0fa777d868e0e20b16284d858f..a3a6aa638b74415cbb41eaa121826ac5e491469e 100644 (file)
@@ -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
+}
index d6b3949e6aeee691fbf80ae556afab98407f9356..aac6e8315d424c1d09bbfba7fd49b77d2a108f35 100644 (file)
@@ -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))
+}
index d043494b4ebd52e1068a29db1e792cd0dc78ea1b..979847abb35b305885854ca33f10a98ac8d91d91 100644 (file)
@@ -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