github.com/kotovmak/go-admin@v1.1.1/modules/utils/utils.go (about)

     1  package utils
     2  
     3  import (
     4  	"archive/zip"
     5  	"bytes"
     6  	"encoding/gob"
     7  	"encoding/json"
     8  	"fmt"
     9  	"html/template"
    10  	"io"
    11  	"math"
    12  	"net/http"
    13  	"net/url"
    14  	"os"
    15  	"path/filepath"
    16  	"reflect"
    17  	"regexp"
    18  	"strconv"
    19  	"strings"
    20  	textTmpl "text/template"
    21  	"time"
    22  
    23  	"github.com/NebulousLabs/fastrand"
    24  )
    25  
    26  func Uuid(length int64) string {
    27  	ele := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "v", "k",
    28  		"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "Driver", "E", "F", "G",
    29  		"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
    30  	ele, _ = Random(ele)
    31  	uuid := ""
    32  	var i int64
    33  	for i = 0; i < length; i++ {
    34  		uuid += ele[fastrand.Intn(59)]
    35  	}
    36  	return uuid
    37  }
    38  
    39  func Random(strings []string) ([]string, error) {
    40  	for i := len(strings) - 1; i > 0; i-- {
    41  		num := fastrand.Intn(i + 1)
    42  		strings[i], strings[num] = strings[num], strings[i]
    43  	}
    44  
    45  	str := make([]string, 0)
    46  	for i := 0; i < len(strings); i++ {
    47  		str = append(str, strings[i])
    48  	}
    49  	return str, nil
    50  }
    51  
    52  func CompressedContent(h *template.HTML) {
    53  	st := strings.Split(string(*h), "\n")
    54  	var ss []string
    55  	for i := 0; i < len(st); i++ {
    56  		st[i] = strings.TrimSpace(st[i])
    57  		if st[i] != "" {
    58  			ss = append(ss, st[i])
    59  		}
    60  	}
    61  	*h = template.HTML(strings.Join(ss, "\n"))
    62  }
    63  
    64  func ReplaceNth(s, old, new string, n int) string {
    65  	i := 0
    66  	for m := 1; m <= n; m++ {
    67  		x := strings.Index(s[i:], old)
    68  		if x < 0 {
    69  			break
    70  		}
    71  		i += x
    72  		if m == n {
    73  			return s[:i] + new + s[i+len(old):]
    74  		}
    75  		i += len(old)
    76  	}
    77  	return s
    78  }
    79  
    80  func InArray(arr []string, str string) bool {
    81  	for _, v := range arr {
    82  		if v == str {
    83  			return true
    84  		}
    85  	}
    86  	return false
    87  }
    88  
    89  func WrapURL(u string) string {
    90  	uarr := strings.Split(u, "?")
    91  	if len(uarr) < 2 {
    92  		return url.QueryEscape(strings.ReplaceAll(u, "/", "_"))
    93  	}
    94  	v, err := url.ParseQuery(uarr[1])
    95  	if err != nil {
    96  		return url.QueryEscape(strings.ReplaceAll(u, "/", "_"))
    97  	}
    98  	return url.QueryEscape(strings.ReplaceAll(uarr[0], "/", "_")) + "?" +
    99  		strings.ReplaceAll(v.Encode(), "%7B%7B.Id%7D%7D", "{{.Id}}")
   100  }
   101  
   102  func JSON(a interface{}) string {
   103  	if a == nil {
   104  		return ""
   105  	}
   106  	b, _ := json.Marshal(a)
   107  	return string(b)
   108  }
   109  
   110  func ParseBool(s string) bool {
   111  	b1, _ := strconv.ParseBool(s)
   112  	return b1
   113  }
   114  
   115  func ReplaceAll(s string, oldnew ...string) string {
   116  	repl := strings.NewReplacer(oldnew...)
   117  	return repl.Replace(s)
   118  }
   119  
   120  func PackageName(v interface{}) string {
   121  	if v == nil {
   122  		return ""
   123  	}
   124  
   125  	val := reflect.ValueOf(v)
   126  	if val.Kind() == reflect.Ptr {
   127  		return val.Elem().Type().PkgPath()
   128  	}
   129  	return val.Type().PkgPath()
   130  }
   131  
   132  func ParseFloat32(f string) float32 {
   133  	s, _ := strconv.ParseFloat(f, 32)
   134  	return float32(s)
   135  }
   136  
   137  func SetDefault(value, condition, def string) string {
   138  	if value == condition {
   139  		return def
   140  	}
   141  	return value
   142  }
   143  
   144  func AorB(condition bool, a, b string) string {
   145  	if condition {
   146  		return a
   147  	}
   148  	return b
   149  }
   150  
   151  func IsJSON(str string) bool {
   152  	var js json.RawMessage
   153  	return json.Unmarshal([]byte(str), &js) == nil
   154  }
   155  
   156  func CopyMap(m map[string]string) map[string]string {
   157  	var buf bytes.Buffer
   158  	enc := gob.NewEncoder(&buf)
   159  	dec := gob.NewDecoder(&buf)
   160  	err := enc.Encode(m)
   161  	if err != nil {
   162  		panic(err)
   163  	}
   164  	var cm map[string]string
   165  	err = dec.Decode(&cm)
   166  	if err != nil {
   167  		panic(err)
   168  	}
   169  	return cm
   170  }
   171  
   172  func ParseTime(stringTime string) time.Time {
   173  	loc, _ := time.LoadLocation("Local")
   174  	theTime, _ := time.ParseInLocation("2006-01-02 15:04:05", stringTime, loc)
   175  	return theTime
   176  }
   177  
   178  func ParseHTML(name, tmpl string, param interface{}) template.HTML {
   179  	t := template.New(name)
   180  	t, err := t.Parse(tmpl)
   181  	if err != nil {
   182  		fmt.Println("utils parseHTML error", err)
   183  		return ""
   184  	}
   185  	buf := new(bytes.Buffer)
   186  	err = t.Execute(buf, param)
   187  	if err != nil {
   188  		fmt.Println("utils parseHTML error", err)
   189  		return ""
   190  	}
   191  	return template.HTML(buf.String())
   192  }
   193  
   194  func ParseText(name, tmpl string, param interface{}) string {
   195  	t := textTmpl.New(name)
   196  	t, err := t.Parse(tmpl)
   197  	if err != nil {
   198  		fmt.Println("utils parseHTML error", err)
   199  		return ""
   200  	}
   201  	buf := new(bytes.Buffer)
   202  	err = t.Execute(buf, param)
   203  	if err != nil {
   204  		fmt.Println("utils parseHTML error", err)
   205  		return ""
   206  	}
   207  	return buf.String()
   208  }
   209  
   210  func CompareVersion(src, toCompare string) bool {
   211  	if toCompare == "" {
   212  		return false
   213  	}
   214  
   215  	exp, _ := regexp.Compile(`-(.*)`)
   216  	src = exp.ReplaceAllString(src, "")
   217  	toCompare = exp.ReplaceAllString(toCompare, "")
   218  
   219  	srcs := strings.Split(src, "v")
   220  	srcArr := strings.Split(srcs[1], ".")
   221  	op := ">"
   222  	srcs[0] = strings.TrimSpace(srcs[0])
   223  	if InArray([]string{">=", "<=", "=", ">", "<"}, srcs[0]) {
   224  		op = srcs[0]
   225  	}
   226  
   227  	toCompare = strings.ReplaceAll(toCompare, "v", "")
   228  
   229  	if op == "=" {
   230  		return srcs[1] == toCompare
   231  	}
   232  
   233  	if srcs[1] == toCompare && (op == "<=" || op == ">=") {
   234  		return true
   235  	}
   236  
   237  	toCompareArr := strings.Split(strings.ReplaceAll(toCompare, "v", ""), ".")
   238  	for i := 0; i < len(srcArr); i++ {
   239  		v, err := strconv.Atoi(srcArr[i])
   240  		if err != nil {
   241  			return false
   242  		}
   243  		vv, err := strconv.Atoi(toCompareArr[i])
   244  		if err != nil {
   245  			return false
   246  		}
   247  		switch op {
   248  		case ">", ">=":
   249  			if v < vv {
   250  				return true
   251  			} else if v > vv {
   252  				return false
   253  			} else {
   254  				continue
   255  			}
   256  		case "<", "<=":
   257  			if v > vv {
   258  				return true
   259  			} else if v < vv {
   260  				return false
   261  			} else {
   262  				continue
   263  			}
   264  		}
   265  	}
   266  
   267  	return false
   268  }
   269  
   270  const (
   271  	Byte  = 1
   272  	KByte = Byte * 1024
   273  	MByte = KByte * 1024
   274  	GByte = MByte * 1024
   275  	TByte = GByte * 1024
   276  	PByte = TByte * 1024
   277  	EByte = PByte * 1024
   278  )
   279  
   280  func logn(n, b float64) float64 {
   281  	return math.Log(n) / math.Log(b)
   282  }
   283  
   284  func humanateBytes(s uint64, base float64, sizes []string) string {
   285  	if s < 10 {
   286  		return fmt.Sprintf("%d B", s)
   287  	}
   288  	e := math.Floor(logn(float64(s), base))
   289  	suffix := sizes[int(e)]
   290  	val := float64(s) / math.Pow(base, math.Floor(e))
   291  	f := "%.0f"
   292  	if val < 10 {
   293  		f = "%.1f"
   294  	}
   295  
   296  	return fmt.Sprintf(f+" %s", val, suffix)
   297  }
   298  
   299  // FileSize calculates the file size and generate user-friendly string.
   300  func FileSize(s uint64) string {
   301  	sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
   302  	return humanateBytes(s, 1024, sizes)
   303  }
   304  
   305  func FileExist(path string) bool {
   306  	_, err := os.Stat(path)
   307  	if err != nil {
   308  		return os.IsExist(err)
   309  	}
   310  	return true
   311  }
   312  
   313  // TimeSincePro calculates the time interval and generate full user-friendly string.
   314  func TimeSincePro(then time.Time, m map[string]string) string {
   315  	now := time.Now()
   316  	diff := now.Unix() - then.Unix()
   317  
   318  	if then.After(now) {
   319  		return "future"
   320  	}
   321  
   322  	var timeStr, diffStr string
   323  	for {
   324  		if diff == 0 {
   325  			break
   326  		}
   327  
   328  		diff, diffStr = computeTimeDiff(diff, m)
   329  		timeStr += ", " + diffStr
   330  	}
   331  	return strings.TrimPrefix(timeStr, ", ")
   332  }
   333  
   334  // Seconds-based time units
   335  const (
   336  	Minute = 60
   337  	Hour   = 60 * Minute
   338  	Day    = 24 * Hour
   339  	Week   = 7 * Day
   340  	Month  = 30 * Day
   341  	Year   = 12 * Month
   342  )
   343  
   344  func computeTimeDiff(diff int64, m map[string]string) (int64, string) {
   345  	diffStr := ""
   346  	switch {
   347  	case diff <= 0:
   348  		diff = 0
   349  		diffStr = "now"
   350  	case diff < 2:
   351  		diff = 0
   352  		diffStr = "1 " + m["second"]
   353  	case diff < 1*Minute:
   354  		diffStr = fmt.Sprintf("%d "+m["seconds"], diff)
   355  		diff = 0
   356  
   357  	case diff < 2*Minute:
   358  		diff -= 1 * Minute
   359  		diffStr = "1 " + m["minute"]
   360  	case diff < 1*Hour:
   361  		diffStr = fmt.Sprintf("%d "+m["minutes"], diff/Minute)
   362  		diff -= diff / Minute * Minute
   363  
   364  	case diff < 2*Hour:
   365  		diff -= 1 * Hour
   366  		diffStr = "1 " + m["hour"]
   367  	case diff < 1*Day:
   368  		diffStr = fmt.Sprintf("%d "+m["hours"], diff/Hour)
   369  		diff -= diff / Hour * Hour
   370  
   371  	case diff < 2*Day:
   372  		diff -= 1 * Day
   373  		diffStr = "1 " + m["day"]
   374  	case diff < 1*Week:
   375  		diffStr = fmt.Sprintf("%d "+m["days"], diff/Day)
   376  		diff -= diff / Day * Day
   377  
   378  	case diff < 2*Week:
   379  		diff -= 1 * Week
   380  		diffStr = "1 " + m["week"]
   381  	case diff < 1*Month:
   382  		diffStr = fmt.Sprintf("%d "+m["weeks"], diff/Week)
   383  		diff -= diff / Week * Week
   384  
   385  	case diff < 2*Month:
   386  		diff -= 1 * Month
   387  		diffStr = "1 " + m["month"]
   388  	case diff < 1*Year:
   389  		diffStr = fmt.Sprintf("%d "+m["months"], diff/Month)
   390  		diff -= diff / Month * Month
   391  
   392  	case diff < 2*Year:
   393  		diff -= 1 * Year
   394  		diffStr = "1 " + m["year"]
   395  	default:
   396  		diffStr = fmt.Sprintf("%d "+m["years"], diff/Year)
   397  		diff = 0
   398  	}
   399  	return diff, diffStr
   400  }
   401  
   402  func DownloadTo(url, output string) error {
   403  
   404  	req, err := http.NewRequest("GET", url, nil)
   405  
   406  	if err != nil {
   407  		return err
   408  	}
   409  
   410  	res, err := http.DefaultClient.Do(req)
   411  
   412  	if err != nil {
   413  		return err
   414  	}
   415  
   416  	defer func() {
   417  		_ = res.Body.Close()
   418  	}()
   419  
   420  	file, err := os.Create(output)
   421  
   422  	if err != nil {
   423  		return err
   424  	}
   425  
   426  	_, err = io.Copy(file, res.Body)
   427  
   428  	if err != nil {
   429  		return err
   430  	}
   431  
   432  	return nil
   433  }
   434  
   435  func UnzipDir(src, dest string) error {
   436  	r, err := zip.OpenReader(src)
   437  	if err != nil {
   438  		return err
   439  	}
   440  	defer func() {
   441  		if err := r.Close(); err != nil {
   442  			panic(err)
   443  		}
   444  	}()
   445  
   446  	err = os.MkdirAll(dest, 0750)
   447  
   448  	if err != nil {
   449  		return err
   450  	}
   451  
   452  	// Closure to address file descriptors issue with all the deferred .Close() methods
   453  	extractAndWriteFile := func(f *zip.File) error {
   454  		rc, err := f.Open()
   455  		if err != nil {
   456  			return err
   457  		}
   458  		defer func() {
   459  			if err := rc.Close(); err != nil {
   460  				panic(err)
   461  			}
   462  		}()
   463  
   464  		path := filepath.Join(dest, f.Name)
   465  
   466  		if f.FileInfo().IsDir() {
   467  			err = os.MkdirAll(path, f.Mode())
   468  			if err != nil {
   469  				return err
   470  			}
   471  		} else {
   472  			err = os.MkdirAll(filepath.Dir(path), f.Mode())
   473  			if err != nil {
   474  				return err
   475  			}
   476  			f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
   477  			if err != nil {
   478  				return err
   479  			}
   480  			defer func() {
   481  				if err := f.Close(); err != nil {
   482  					panic(err)
   483  				}
   484  			}()
   485  
   486  			_, err = io.Copy(f, rc)
   487  			if err != nil {
   488  				return err
   489  			}
   490  		}
   491  		return nil
   492  	}
   493  
   494  	for _, f := range r.File {
   495  		err := extractAndWriteFile(f)
   496  		if err != nil {
   497  			return err
   498  		}
   499  	}
   500  
   501  	return nil
   502  }