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