| | 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 |
| | } |
| |
|