commit dc13f589c504b09836c301fc6994445163cc0c33 Author: jiangyong Date: Tue Dec 20 23:45:07 2022 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b31355 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.idea/ +output/ +dockerfiles/ +log +.DS_Store +doc +cmd/test +go.sum +pkg +test.go diff --git a/array.go b/array.go new file mode 100644 index 0000000..c760df7 --- /dev/null +++ b/array.go @@ -0,0 +1,93 @@ +package goutil + +import "reflect" + +func Sort(data interface{}, fun interface{}) { + fValue := reflect.ValueOf(fun) + fType := fValue.Type() + dValue := reflect.Indirect(reflect.ValueOf(data)) + dType := dValue.Type() + + if (dType.Kind() != reflect.Slice && dType.Kind() != reflect.Array) || + fType.Kind() != reflect.Func || fType.NumIn() != 2 || fType.NumOut() != 1 { + panic("sort paramter type format error") + } + + firstType := fType.In(0) + secondType := fType.In(1) + outType := fType.Out(0) + elemType := dType.Elem() + if elemType.Kind() != firstType.Kind() || elemType.Kind() != secondType.Kind() || + outType.Kind() != reflect.Bool { + panic("sort elem type format error") + } + + tmp := reflect.Indirect(reflect.New(elemType)) + for i := 0; i < dValue.Len(); i++ { + for j := i + 1; j < dValue.Len(); j++ { + out := fValue.Call([]reflect.Value{dValue.Index(i), dValue.Index(j)}) + if out[0].Bool() { + continue + } + + tmp.Set(dValue.Index(i)) + dValue.Index(i).Set(dValue.Index(j)) + dValue.Index(j).Set(tmp) + } + } + +} + +func Filter(data interface{}, fun interface{}) { + fValue := reflect.ValueOf(fun) + fType := fValue.Type() + dValue := reflect.Indirect(reflect.ValueOf(data)) + dType := dValue.Type() + + if (dType.Kind() != reflect.Slice && dType.Kind() != reflect.Array) || + fType.Kind() != reflect.Func || fType.NumIn() != 1 || fType.NumOut() != 1 { + panic("sort paramter type format error") + } + + firstType := fType.In(0) + outType := fType.Out(0) + elemType := dType.Elem() + if elemType.Kind() != firstType.Kind() || outType.Kind() != reflect.Bool { + panic("sort elem type format error") + } + + pos := 0 + for i := 0; i < dValue.Len(); i++ { + out := fValue.Call([]reflect.Value{dValue.Index(i)}) + if !out[0].Bool() { + continue + } + + dValue.Index(pos).Set(dValue.Index(i)) + pos++ + } + + dValue.SetLen(pos) +} + +func Traverse(data interface{}, fun interface{}) { + fValue := reflect.ValueOf(fun) + fType := fValue.Type() + dValue := reflect.Indirect(reflect.ValueOf(data)) + dType := dValue.Type() + + if (dType.Kind() != reflect.Slice && dType.Kind() != reflect.Array) || + fType.Kind() != reflect.Func || fType.NumIn() != 1 || fType.NumOut() != 0 { + panic("sort paramter type format error") + } + + firstType := fType.In(0) + elemType := dType.Elem() + if elemType.Kind() != firstType.Kind() { + panic("sort elem type format error") + } + + for i := 0; i < dValue.Len(); i++ { + fValue.Call([]reflect.Value{dValue.Index(i)}) + } +} diff --git a/encoding.go b/encoding.go new file mode 100644 index 0000000..c099883 --- /dev/null +++ b/encoding.go @@ -0,0 +1,30 @@ +package goutil + +import ( + "encoding/json" + "encoding/xml" +) + +// EncodeJSON encode anything to json string +func EncodeJSON(v interface{}) string { + b, _ := json.Marshal(v) + return string(b) +} + +// EncodeJSON encode anything to json string +func EncodeJSONIndent(v interface{}) string { + b, _ := json.MarshalIndent(v, " ", " ") + return string(b) +} + +// EncodeJSON encode anything to json string +func EncodeXML(v interface{}) string { + b, _ := xml.Marshal(v) + return string(b) +} + +// EncodeJSON encode anything to json string +func EncodeXMLIndent(v interface{}) string { + b, _ := xml.MarshalIndent(v, " ", " ") + return string(b) +} diff --git a/file.go b/file.go new file mode 100644 index 0000000..6dce1b5 --- /dev/null +++ b/file.go @@ -0,0 +1,19 @@ +package goutil + +import "io/ioutil" + +func FileList(dirPath string) ([]string, error) { + lis, err := ioutil.ReadDir(dirPath) + if err != nil { + return nil, err + } + + fileList := make([]string, 0) + for _, f := range lis { + if f.IsDir() { + continue + } + fileList = append(fileList, f.Name()) + } + return fileList, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..46c1b78 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/smbrave/goutil + +go 1.19 diff --git a/http.go b/http.go new file mode 100644 index 0000000..4e885d5 --- /dev/null +++ b/http.go @@ -0,0 +1,73 @@ +package goutil + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "net/http" + "net/url" + "time" +) + +// PostJson 请求 +func HttpPost(link string, params map[string]string, json []byte) ([]byte, error) { + client := &http.Client{Timeout: 20 * time.Second} + //忽略https的证书 + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + p := url.Values{} + u, _ := url.Parse(link) + if params != nil { + for k, v := range params { + p.Set(k, v) + } + } + u.RawQuery = p.Encode() + req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(json)) + if err != nil { + return nil, err + } + req.Header.Add("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) + } + return io.ReadAll(resp.Body) +} + +// Get 请求 link:请求url +func HttpGet(link string, params map[string]string) ([]byte, error) { + client := &http.Client{Timeout: 20 * time.Second} + //忽略https的证书 + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + p := url.Values{} + u, _ := url.Parse(link) + if params != nil { + for k, v := range params { + p.Set(k, v) + } + } + u.RawQuery = p.Encode() + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d:%s", resp.StatusCode, resp.Status) + } + return io.ReadAll(resp.Body) +} diff --git a/network.go b/network.go new file mode 100644 index 0000000..9ce5bd3 --- /dev/null +++ b/network.go @@ -0,0 +1,20 @@ +package goutil + +import "net" + +func GetIp() string { + addrs, err := net.InterfaceAddrs() + + if err != nil { + return err.Error() + } + + for _, address := range addrs { + if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + return ipnet.IP.String() + } + } + } + return "none" +} diff --git a/number.go b/number.go new file mode 100644 index 0000000..d7d0554 --- /dev/null +++ b/number.go @@ -0,0 +1,70 @@ +package goutil + +import ( + "crypto/md5" + "sync" + "sync/atomic" + "time" +) + +func IsNumber(str string) bool { + for i := 0; i < len(str); i++ { + if str[i] != '-' && (str[i] < '0' || str[i] > '9') { + return false + } + } + return true +} + +// ID生成规则:32B secondtime + 6B sid + 6B flag + 20B autoinc, 每秒最大调用量为1048576 +var auto_inc_sig uint64 = 0 +var big_id_lock = new(sync.RWMutex) + +func GetBigID(sid int, flag int) uint64 { + localSig := atomic.AddUint64(&auto_inc_sig, 1) + bigID := uint64(time.Now().Unix()) + bigID = bigID<<20 | (localSig % (1 << 20)) //避免产生连续ID + bigID = bigID<<6 | (uint64(sid) % (1 << 6)) + bigID = bigID<<6 | (uint64(flag) % (1 << 6)) + return bigID +} + +func ParseBigID(bigID uint64) (int, int, int64) { + flag := int(bigID % (1 << 6)) + sid := int(bigID >> 6 % (1 << 6)) + tiemstamp := int64(bigID >> 32) + return sid, flag, tiemstamp +} + +// 取低8个字节作为digest的值 +func Hash64(s string) uint64 { + sum := md5.Sum([]byte(s)) + digest := uint64(0) + for i := 0; i < 8; i++ { + idx := uint64(sum[i]) + digest += (idx << uint64(i*8)) + } + return digest +} + +// 取低8个字节作为digest的值 +func Hash56(s string) uint64 { + sum := md5.Sum([]byte(s)) + digest := uint64(0) + for i := 0; i < 7; i++ { + idx := uint64(sum[i]) + digest += (idx << uint64(i*8)) + } + return digest +} + +// 取低8个字节作为digest的值 +func Hash32(s string) uint32 { + sum := md5.Sum([]byte(s)) + digest := uint32(0) + for i := 0; i < 4; i++ { + idx := uint32(sum[i]) + digest += (idx << uint64(i*8)) + } + return digest +} diff --git a/string.go b/string.go new file mode 100644 index 0000000..80a3e4e --- /dev/null +++ b/string.go @@ -0,0 +1,77 @@ +package goutil + +import ( + "crypto/md5" + "encoding/hex" + "math/rand" + "strings" + "time" +) + +func Md5(str string) string { + h := md5.New() + h.Write([]byte(str)) + return hex.EncodeToString(h.Sum(nil)) +} + +func StrInField(key string, str string) bool { + str = strings.ReplaceAll(str, ",", ",") + s1 := strings.Split(str, ",") + for _, v := range s1 { + if v == key { + return true + } + } + return false +} + +func StrInSlice(key string, slice []string) bool { + if len(slice) == 0 { + return false + } + + for _, v := range slice { + if v == key { + return true + } + } + + return false +} + +func StrInPrefix(s string, arr []string) bool { + for _, a := range arr { + if strings.HasPrefix(s, a) { + return true + } + } + return false +} + +// ArrayUnique 数组去重 +func StrUnique(arr []string) []string { + set := make(map[string]bool) + j := 0 + for _, v := range arr { + _, ok := set[v] + if ok { + continue + } + set[v] = true + arr[j] = v + j++ + } + return arr[:j] +} + +// 生成随机字符串 +func RandomStr(length int64) string { + str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + bytes := []byte(str) + result := []byte{} + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for i := int64(0); i < length; i++ { + result = append(result, bytes[r.Intn(len(bytes))]) + } + return string(result) +} diff --git a/time.go b/time.go new file mode 100644 index 0000000..d1d137a --- /dev/null +++ b/time.go @@ -0,0 +1,117 @@ +package goutil + +import ( + "fmt" + "time" +) + +// 时间戳转为日期 +func TimeToDate(t int64) string { + tm := time.Unix(t, 0) + return tm.Format("2006-01-02") +} + +// 时间戳转为datetime格式 +func TimeToDateTime(t int64) string { + tm := time.Unix(t, 0) + return tm.Format("2006-01-02 15:04:05") +} + +// 日期转为时间戳 +func DateTimeToTime(date string) int64 { + var LOC, _ = time.LoadLocation("Asia/Shanghai") + tim, _ := time.ParseInLocation("2006-01-02 15:04:05", date, LOC) + return tim.Unix() +} + +func GetNowTime() string { + return time.Now().Format("2006-01-02 15:04:05") +} + +// 获取一天开始的时间戳 +func GetTodayStartTime() int64 { + now := time.Now().Unix() + return now - (now+28800)%86400 +} + +// 获取一周开始的时间戳 +func GetWeekStartTime() int64 { + now := time.Now() + week := int(now.Weekday()) + if week == 0 { + week = 7 + } + t := now.AddDate(0, 0, 1-week).Unix() + return t - (t+28800)%86400 +} + +// 获取一月开始的时间戳 +func GetMonthStartTime() int64 { + now := time.Now().AddDate(0, 0, 1-time.Now().Day()).Unix() + return now - (now+28800)%86400 +} + +func TimeToWeek(t int64) string { + week := time.Unix(t, 0) + switch week.Weekday() { + case time.Monday: + return "星期一" + case time.Tuesday: + return "星期二" + case time.Wednesday: + return "星期三" + case time.Thursday: + return "星期四" + case time.Friday: + return "星期五" + case time.Saturday: + return "星期六" + case time.Sunday: + return "星期天" + } + return "" +} + +// 时间戳转时间提示 +func TimeToTips(t int64) string { + now := time.Now().Unix() + span := now - t + + result := "" + if span > 0 { + if span < 60 { + result = "刚刚" + } else if span <= 1800 { + result = fmt.Sprintf("%d分钟前", span/60) + } else if span <= 3600 { + result = "半小时前" + } else if span <= 86400 { + result = fmt.Sprintf("%d小时前", span/3600) + } else if span <= 86400*30 { + result = fmt.Sprintf("%d天前", span/(86400)) + } else if span <= 86400*30*12 { + result = fmt.Sprintf("%d月前", span/(86400*30)) + } else { + result = fmt.Sprintf("%d年前", span/(86400*30*12)) + } + } else { + span = 0 - span + if span < 60 { + result = fmt.Sprintf("%d秒后", span) + } else if span <= 1800 { + result = fmt.Sprintf("%d分钟后", span/60) + } else if span <= 3600 { + result = "半小时后" + } else if span <= 86400 { + result = fmt.Sprintf("%d小时后", span/3600) + } else if span <= 86400*30 { + result = fmt.Sprintf("%d天后", span/(86400)) + } else if span <= 86400*30*12 { + result = fmt.Sprintf("%d月后", span/(86400*30)) + } else { + result = fmt.Sprintf("%d年后", span/(86400*30*12)) + } + } + + return result +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..05aecc6 --- /dev/null +++ b/util.go @@ -0,0 +1,77 @@ +package goutil + +import ( + "errors" + "fmt" + "reflect" +) + +// format bytes number friendly +func BytesToTips(bytes uint64) string { + switch { + case bytes < 1024: + return fmt.Sprintf("%dB", bytes) + case bytes < 1024*1024: + return fmt.Sprintf("%.2fK", float64(bytes)/1024) + case bytes < 1024*1024*1024: + return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024) + default: + return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024) + } +} + +func If[T any](condition bool, trueVal, falseVal T) T { + if condition { + return trueVal + } + return falseVal +} + +func CopyStruct(dst interface{}, src interface{}) { + + dtype := reflect.TypeOf(dst) + stype := reflect.TypeOf(src) + + if stype.Kind() != reflect.Ptr || stype.Kind() != dtype.Kind() { + panic(errors.New("src/dst must ptr")) + } + if reflect.ValueOf(dst).IsNil() || reflect.ValueOf(src).IsNil() { + panic(errors.New("src/dst is nil")) + } + + dval := reflect.ValueOf(dst).Elem() + sval := reflect.ValueOf(src).Elem() + + for i := 0; i < sval.NumField(); i++ { + sValue := sval.Field(i) + + dValue := dval.FieldByName(sval.Type().Field(i).Name) + if sValue.IsZero() || dValue.IsValid() == false || !dValue.CanSet() { + continue + } + if sValue.Kind() != dValue.Kind() { + continue + } + + switch sValue.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + dValue.SetInt(sValue.Int()) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + dValue.SetUint(sValue.Uint()) + + case reflect.Float32, reflect.Float64: + dValue.SetFloat(sValue.Float()) + + case reflect.String: + dValue.SetString(sValue.String()) + + case reflect.Bool: + dValue.SetBool(sValue.Bool()) + + case reflect.Ptr: + CopyStruct(dValue.Interface(), sValue.Interface()) + } + } + +}