| package utils |
|
|
| import ( |
| "archive/zip" |
| "bytes" |
| "encoding/gob" |
| "encoding/json" |
| "fmt" |
| "html/template" |
| "io" |
| "math" |
| "net/http" |
| "net/url" |
| "os" |
| "path/filepath" |
| "reflect" |
| "regexp" |
| "strconv" |
| "strings" |
| textTmpl "text/template" |
| "time" |
|
|
| "github.com/NebulousLabs/fastrand" |
| ) |
|
|
| func Uuid(length int64) string { |
| ele := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "v", "k", |
| "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "Driver", "E", "F", "G", |
| "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"} |
| ele, _ = Random(ele) |
| uuid := "" |
| var i int64 |
| for i = 0; i < length; i++ { |
| uuid += ele[fastrand.Intn(59)] |
| } |
| return uuid |
| } |
|
|
| func Random(strings []string) ([]string, error) { |
| for i := len(strings) - 1; i > 0; i-- { |
| num := fastrand.Intn(i + 1) |
| strings[i], strings[num] = strings[num], strings[i] |
| } |
|
|
| str := make([]string, 0) |
| for i := 0; i < len(strings); i++ { |
| str = append(str, strings[i]) |
| } |
| return str, nil |
| } |
|
|
| func CompressedContent(h *template.HTML) { |
| st := strings.Split(string(*h), "\n") |
| var ss []string |
| for i := 0; i < len(st); i++ { |
| st[i] = strings.TrimSpace(st[i]) |
| if st[i] != "" { |
| ss = append(ss, st[i]) |
| } |
| } |
| *h = template.HTML(strings.Join(ss, "\n")) |
| } |
|
|
| func ReplaceNth(s, old, new string, n int) string { |
| i := 0 |
| for m := 1; m <= n; m++ { |
| x := strings.Index(s[i:], old) |
| if x < 0 { |
| break |
| } |
| i += x |
| if m == n { |
| return s[:i] + new + s[i+len(old):] |
| } |
| i += len(old) |
| } |
| return s |
| } |
|
|
| func InArray(arr []string, str string) bool { |
| for _, v := range arr { |
| if v == str { |
| return true |
| } |
| } |
| return false |
| } |
|
|
| func WrapURL(u string) string { |
| uarr := strings.Split(u, "?") |
| if len(uarr) < 2 { |
| return url.QueryEscape(strings.ReplaceAll(u, "/", "_")) |
| } |
| v, err := url.ParseQuery(uarr[1]) |
| if err != nil { |
| return url.QueryEscape(strings.ReplaceAll(u, "/", "_")) |
| } |
| return url.QueryEscape(strings.ReplaceAll(uarr[0], "/", "_")) + "?" + |
| strings.ReplaceAll(v.Encode(), "%7B%7B.Id%7D%7D", "{{.Id}}") |
| } |
|
|
| func JSON(a interface{}) string { |
| if a == nil { |
| return "" |
| } |
| b, _ := json.Marshal(a) |
| return string(b) |
| } |
|
|
| func ParseBool(s string) bool { |
| b1, _ := strconv.ParseBool(s) |
| return b1 |
| } |
|
|
| func ReplaceAll(s string, oldnew ...string) string { |
| repl := strings.NewReplacer(oldnew...) |
| return repl.Replace(s) |
| } |
|
|
| func PackageName(v interface{}) string { |
| if v == nil { |
| return "" |
| } |
|
|
| val := reflect.ValueOf(v) |
| if val.Kind() == reflect.Ptr { |
| return val.Elem().Type().PkgPath() |
| } |
| return val.Type().PkgPath() |
| } |
|
|
| func ParseFloat32(f string) float32 { |
| s, _ := strconv.ParseFloat(f, 32) |
| return float32(s) |
| } |
|
|
| func SetDefault(value, condition, def string) string { |
| if value == condition { |
| return def |
| } |
| return value |
| } |
|
|
| func AorB(condition bool, a, b string) string { |
| if condition { |
| return a |
| } |
| return b |
| } |
|
|
| func IsJSON(str string) bool { |
| var js json.RawMessage |
| return json.Unmarshal([]byte(str), &js) == nil |
| } |
|
|
| func CopyMap(m map[string]string) map[string]string { |
| var buf bytes.Buffer |
| enc := gob.NewEncoder(&buf) |
| dec := gob.NewDecoder(&buf) |
| err := enc.Encode(m) |
| if err != nil { |
| panic(err) |
| } |
| var cm map[string]string |
| err = dec.Decode(&cm) |
| if err != nil { |
| panic(err) |
| } |
| return cm |
| } |
|
|
| func ParseTime(stringTime string) time.Time { |
| loc, _ := time.LoadLocation("Local") |
| theTime, _ := time.ParseInLocation("2006-01-02 15:04:05", stringTime, loc) |
| return theTime |
| } |
|
|
| func ParseHTML(name, tmpl string, param interface{}) template.HTML { |
| t := template.New(name) |
| t, err := t.Parse(tmpl) |
| if err != nil { |
| fmt.Println("utils parseHTML error", err) |
| return "" |
| } |
| buf := new(bytes.Buffer) |
| err = t.Execute(buf, param) |
| if err != nil { |
| fmt.Println("utils parseHTML error", err) |
| return "" |
| } |
| return template.HTML(buf.String()) |
| } |
|
|
| func ParseText(name, tmpl string, param interface{}) string { |
| t := textTmpl.New(name) |
| t, err := t.Parse(tmpl) |
| if err != nil { |
| fmt.Println("utils parseHTML error", err) |
| return "" |
| } |
| buf := new(bytes.Buffer) |
| err = t.Execute(buf, param) |
| if err != nil { |
| fmt.Println("utils parseHTML error", err) |
| return "" |
| } |
| return buf.String() |
| } |
|
|
| func CompareVersion(src, toCompare string) bool { |
| if toCompare == "" { |
| return false |
| } |
|
|
| exp, _ := regexp.Compile(`-(.*)`) |
| src = exp.ReplaceAllString(src, "") |
| toCompare = exp.ReplaceAllString(toCompare, "") |
|
|
| srcs := strings.Split(src, "v") |
| srcArr := strings.Split(srcs[1], ".") |
| op := ">" |
| srcs[0] = strings.TrimSpace(srcs[0]) |
| if InArray([]string{">=", "<=", "=", ">", "<"}, srcs[0]) { |
| op = srcs[0] |
| } |
|
|
| toCompare = strings.ReplaceAll(toCompare, "v", "") |
|
|
| if op == "=" { |
| return srcs[1] == toCompare |
| } |
|
|
| if srcs[1] == toCompare && (op == "<=" || op == ">=") { |
| return true |
| } |
|
|
| toCompareArr := strings.Split(strings.ReplaceAll(toCompare, "v", ""), ".") |
| for i := 0; i < len(srcArr); i++ { |
| v, err := strconv.Atoi(srcArr[i]) |
| if err != nil { |
| return false |
| } |
| vv, err := strconv.Atoi(toCompareArr[i]) |
| if err != nil { |
| return false |
| } |
| switch op { |
| case ">", ">=": |
| if v < vv { |
| return true |
| } else if v > vv { |
| return false |
| } else { |
| continue |
| } |
| case "<", "<=": |
| if v > vv { |
| return true |
| } else if v < vv { |
| return false |
| } else { |
| continue |
| } |
| } |
| } |
|
|
| return false |
| } |
|
|
| const ( |
| Byte = 1 |
| KByte = Byte * 1024 |
| MByte = KByte * 1024 |
| GByte = MByte * 1024 |
| TByte = GByte * 1024 |
| PByte = TByte * 1024 |
| EByte = PByte * 1024 |
| ) |
|
|
| func logn(n, b float64) float64 { |
| return math.Log(n) / math.Log(b) |
| } |
|
|
| func humanateBytes(s uint64, base float64, sizes []string) string { |
| if s < 10 { |
| return fmt.Sprintf("%d B", s) |
| } |
| e := math.Floor(logn(float64(s), base)) |
| suffix := sizes[int(e)] |
| val := float64(s) / math.Pow(base, math.Floor(e)) |
| f := "%.0f" |
| if val < 10 { |
| f = "%.1f" |
| } |
|
|
| return fmt.Sprintf(f+" %s", val, suffix) |
| } |
|
|
| |
| func FileSize(s uint64) string { |
| sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"} |
| return humanateBytes(s, 1024, sizes) |
| } |
|
|
| func FileExist(path string) bool { |
| _, err := os.Stat(path) |
| if err != nil { |
| return os.IsExist(err) |
| } |
| return true |
| } |
|
|
| |
| func TimeSincePro(then time.Time, m map[string]string) string { |
| now := time.Now() |
| diff := now.Unix() - then.Unix() |
|
|
| if then.After(now) { |
| return "future" |
| } |
|
|
| var timeStr, diffStr string |
| for { |
| if diff == 0 { |
| break |
| } |
|
|
| diff, diffStr = computeTimeDiff(diff, m) |
| timeStr += ", " + diffStr |
| } |
| return strings.TrimPrefix(timeStr, ", ") |
| } |
|
|
| |
| const ( |
| Minute = 60 |
| Hour = 60 * Minute |
| Day = 24 * Hour |
| Week = 7 * Day |
| Month = 30 * Day |
| Year = 12 * Month |
| ) |
|
|
| func computeTimeDiff(diff int64, m map[string]string) (int64, string) { |
| diffStr := "" |
| switch { |
| case diff <= 0: |
| diff = 0 |
| diffStr = "now" |
| case diff < 2: |
| diff = 0 |
| diffStr = "1 " + m["second"] |
| case diff < 1*Minute: |
| diffStr = fmt.Sprintf("%d "+m["seconds"], diff) |
| diff = 0 |
|
|
| case diff < 2*Minute: |
| diff -= 1 * Minute |
| diffStr = "1 " + m["minute"] |
| case diff < 1*Hour: |
| diffStr = fmt.Sprintf("%d "+m["minutes"], diff/Minute) |
| diff -= diff / Minute * Minute |
|
|
| case diff < 2*Hour: |
| diff -= 1 * Hour |
| diffStr = "1 " + m["hour"] |
| case diff < 1*Day: |
| diffStr = fmt.Sprintf("%d "+m["hours"], diff/Hour) |
| diff -= diff / Hour * Hour |
|
|
| case diff < 2*Day: |
| diff -= 1 * Day |
| diffStr = "1 " + m["day"] |
| case diff < 1*Week: |
| diffStr = fmt.Sprintf("%d "+m["days"], diff/Day) |
| diff -= diff / Day * Day |
|
|
| case diff < 2*Week: |
| diff -= 1 * Week |
| diffStr = "1 " + m["week"] |
| case diff < 1*Month: |
| diffStr = fmt.Sprintf("%d "+m["weeks"], diff/Week) |
| diff -= diff / Week * Week |
|
|
| case diff < 2*Month: |
| diff -= 1 * Month |
| diffStr = "1 " + m["month"] |
| case diff < 1*Year: |
| diffStr = fmt.Sprintf("%d "+m["months"], diff/Month) |
| diff -= diff / Month * Month |
|
|
| case diff < 2*Year: |
| diff -= 1 * Year |
| diffStr = "1 " + m["year"] |
| default: |
| diffStr = fmt.Sprintf("%d "+m["years"], diff/Year) |
| diff = 0 |
| } |
| return diff, diffStr |
| } |
|
|
| func DownloadTo(url, output string) error { |
|
|
| req, err := http.NewRequest("GET", url, nil) |
|
|
| if err != nil { |
| return err |
| } |
|
|
| res, err := http.DefaultClient.Do(req) |
|
|
| if err != nil { |
| return err |
| } |
|
|
| defer func() { |
| _ = res.Body.Close() |
| }() |
|
|
| file, err := os.Create(output) |
|
|
| if err != nil { |
| return err |
| } |
|
|
| _, err = io.Copy(file, res.Body) |
|
|
| if err != nil { |
| return err |
| } |
|
|
| return nil |
| } |
|
|
| func UnzipDir(src, dest string) error { |
| r, err := zip.OpenReader(src) |
| if err != nil { |
| return err |
| } |
| defer func() { |
| if err := r.Close(); err != nil { |
| panic(err) |
| } |
| }() |
|
|
| err = os.MkdirAll(dest, 0750) |
|
|
| if err != nil { |
| return err |
| } |
|
|
| |
| extractAndWriteFile := func(f *zip.File) error { |
| rc, err := f.Open() |
| if err != nil { |
| return err |
| } |
| defer func() { |
| if err := rc.Close(); err != nil { |
| panic(err) |
| } |
| }() |
|
|
| path := filepath.Join(dest, f.Name) |
|
|
| if f.FileInfo().IsDir() { |
| err = os.MkdirAll(path, f.Mode()) |
| if err != nil { |
| return err |
| } |
| } else { |
| err = os.MkdirAll(filepath.Dir(path), f.Mode()) |
| if err != nil { |
| return err |
| } |
| f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) |
| if err != nil { |
| return err |
| } |
| defer func() { |
| if err := f.Close(); err != nil { |
| panic(err) |
| } |
| }() |
|
|
| _, err = io.Copy(f, rc) |
| if err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
|
|
| for _, f := range r.File { |
| err := extractAndWriteFile(f) |
| if err != nil { |
| return err |
| } |
| } |
|
|
| return nil |
| } |
|
|