github.com/GuanceCloud/cliutils@v1.1.21/utils.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the MIT License.
     3  // This product includes software developed at Guance Cloud (https://www.guance.com/).
     4  // Copyright 2021-present Guance, Inc.
     5  
     6  package cliutils
     7  
     8  import (
     9  	"bytes"
    10  	"compress/gzip"
    11  	"crypto/aes"
    12  	"crypto/cipher"
    13  
    14  	// nolint:gosec
    15  	"crypto/md5"
    16  	crand "crypto/rand"
    17  	"encoding/hex"
    18  	"fmt"
    19  	"io"
    20  	"math"
    21  	mrand "math/rand"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/rs/xid"
    26  )
    27  
    28  type Sem struct {
    29  	sem chan interface{}
    30  }
    31  
    32  func NewSem() *Sem {
    33  	return &Sem{sem: make(chan interface{})}
    34  }
    35  
    36  func (s *Sem) Close() {
    37  	select {
    38  	case <-s.sem:
    39  	// pass: s.sem has been closed before
    40  	default:
    41  		close(s.sem)
    42  	}
    43  }
    44  
    45  func (s *Sem) Wait() <-chan interface{} {
    46  	return s.sem
    47  }
    48  
    49  func WgWait(wg *sync.WaitGroup, timeout int) {
    50  	c := make(chan interface{})
    51  
    52  	go func() {
    53  		defer close(c)
    54  		wg.Wait()
    55  	}()
    56  
    57  	if timeout > 0 {
    58  		select {
    59  		case <-c:
    60  		case <-time.After(time.Second * time.Duration(timeout)):
    61  		}
    62  	} else {
    63  		<-c
    64  	}
    65  }
    66  
    67  var (
    68  	letterBytes   = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    69  	letterIdxBits = uint(6)              //nolint:gomnd // 6 bits to represent a letter index
    70  	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    71  	letterIdxMax  = 63 / letterIdxBits   //nolint:gomnd
    72  )
    73  
    74  func CreateRandomString(n int) string {
    75  	src := mrand.NewSource(time.Now().UnixNano())
    76  
    77  	b := make([]byte, n)
    78  	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
    79  		if remain == 0 {
    80  			cache, remain = src.Int63(), letterIdxMax
    81  		}
    82  		if idx := int(cache & int64(letterIdxMask)); idx < len(letterBytes) {
    83  			b[i] = letterBytes[idx]
    84  			i--
    85  		}
    86  		cache >>= letterIdxBits
    87  		remain--
    88  	}
    89  
    90  	return string(b)
    91  }
    92  
    93  func XID(p string) string {
    94  	return p + xid.New().String()
    95  }
    96  
    97  func SizeFmt(n int64) string {
    98  	f := float64(n)
    99  
   100  	unit := []string{"", "K", "M", "G", "T", "P", "E", "Z"}
   101  	for _, u := range unit {
   102  		if math.Abs(f) < 1024.0 { //nolint:gomnd
   103  			return fmt.Sprintf("%3.4f%sB", f, u)
   104  		}
   105  		f /= 1024.0 //nolint:gomnd
   106  	}
   107  	return fmt.Sprintf("%3.4fYB", f)
   108  }
   109  
   110  func Md5Hash(data []byte) string {
   111  	hasher := md5.New() //nolint:gosec
   112  	if _, err := hasher.Write(data); err != nil {
   113  		panic(err)
   114  	}
   115  
   116  	return hex.EncodeToString(hasher.Sum(nil))
   117  }
   118  
   119  func Encrypt(data, phrase []byte) ([]byte, error) {
   120  	md5Cipher := Md5Hash(phrase)
   121  
   122  	block, _ := aes.NewCipher([]byte(md5Cipher))
   123  	gcm, err := cipher.NewGCM(block)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	nonce := make([]byte, gcm.NonceSize())
   129  	if _, err = io.ReadFull(crand.Reader, nonce); err != nil {
   130  		return nil, err
   131  	}
   132  	return gcm.Seal(nonce, nonce, data, nil), nil
   133  }
   134  
   135  func Decrypt(endata, phrase []byte) ([]byte, error) {
   136  	md5Cipher := Md5Hash(phrase)
   137  
   138  	block, err := aes.NewCipher([]byte(md5Cipher))
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	gcm, err := cipher.NewGCM(block)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	nonceSize := gcm.NonceSize()
   149  	nonce, ciphertext := endata[:nonceSize], endata[nonceSize:]
   150  	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	return plaintext, nil
   155  }
   156  
   157  func StringTrim(s string, n int) string {
   158  	if len(s) > n {
   159  		return fmt.Sprintf("%s...(%d trimmed)", s[:n], len(s)-n)
   160  	} else {
   161  		return s
   162  	}
   163  }
   164  
   165  func LeftStringTrim(s string, n int) string {
   166  	if len(s) > n {
   167  		pos := len(s) - n
   168  		return fmt.Sprintf("...%s(%d trimmed)", s[pos:], pos)
   169  	} else {
   170  		return s
   171  	}
   172  }
   173  
   174  func GZipStr(str string) ([]byte, error) {
   175  	var z bytes.Buffer
   176  	zw := gzip.NewWriter(&z)
   177  	if _, err := io.WriteString(zw, str); err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	if err := zw.Flush(); err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	if err := zw.Close(); err != nil {
   186  		return nil, err
   187  	}
   188  	return z.Bytes(), nil
   189  }
   190  
   191  func MustGZip(data []byte) []byte {
   192  	data, err := GZip(data)
   193  	if err != nil {
   194  		panic(err.Error())
   195  	}
   196  
   197  	return data
   198  }
   199  
   200  func GZip(data []byte) ([]byte, error) {
   201  	var z bytes.Buffer
   202  	zw := gzip.NewWriter(&z)
   203  
   204  	if _, err := zw.Write(data); err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	if err := zw.Flush(); err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	if err := zw.Close(); err != nil {
   213  		return nil, err
   214  	}
   215  	return z.Bytes(), nil
   216  }