package utils import ( "encoding/base64" "net/http" "reflect" "strings" "time" "unicode/utf8" "git.rosy.net.cn/baseapi" uuid "github.com/satori/go.uuid" ) const ( APIPin = "jxadmin" ) func DictKeysMan(data interface{}, keysToRemove []string, keysToKeep []string) interface{} { if data == nil || (keysToKeep == nil && keysToRemove == nil) { return data } var keysToRemoveMap map[string]int var keysToKeepMap map[string]int if keysToKeep != nil { keysToKeepMap = make(map[string]int) for _, v := range keysToKeep { keysToKeepMap[v] = 1 } } else if keysToRemove != nil { keysToRemoveMap = make(map[string]int) for _, v := range keysToRemove { keysToRemoveMap[v] = 1 } } dataIsSlice := true valueOfData := reflect.ValueOf(data) if valueOfData.Kind() != reflect.Slice { dataIsSlice = false valueOfData = reflect.ValueOf([]interface{}{data}) } else if valueOfData.Len() == 0 { return data } retVal := make([]interface{}, valueOfData.Len()) for index := 0; index < valueOfData.Len(); index++ { realV := GetConcretValue(valueOfData.Index(index)) if keysToRemoveMap != nil || keysToKeepMap != nil { mapV := make(map[string]interface{}) for _, key := range realV.MapKeys() { fieldName := key.String() wantThisField := true if keysToKeepMap != nil { if _, ok := keysToKeepMap[fieldName]; !ok { wantThisField = false } } else if keysToRemoveMap != nil { if _, ok := keysToRemoveMap[fieldName]; ok { wantThisField = false } } if wantThisField { mapV[fieldName] = GetConcretValue(realV.MapIndex(key)).Interface() } } retVal[index] = mapV } else { retVal[index] = realV.Interface() } } if !dataIsSlice { return retVal[0] } return retVal } // 去除-号,全部大写,比如:929ADB626EB911E893E452540009DAB3 func GetUUID() string { return strings.Replace(GetUpperUUID(), "-", "", -1) } func GetUpperUUID() string { return strings.ToUpper(uuid.Must(uuid.NewV1()).String()) } func GetCurTimeStr() string { return Time2Str(time.Now()) } func GetCurDate() time.Time { now := time.Now() year, month, day := now.Date() return time.Date(year, month, day, 0, 0, 0, 0, now.Location()) } func GetDate(dateTime time.Time) time.Time { year, month, day := dateTime.Date() return time.Date(year, month, day, 0, 0, 0, 0, dateTime.Location()) } func GetTimeRange(baseTime time.Time, dayNum int, includeBaseTime bool) (beginTime, endTime time.Time) { if dayNum <= 0 { dayNum = 1 } baseTime = GetDate(baseTime) if includeBaseTime { dayNum = dayNum - 1 endTime = baseTime.Add(time.Hour*24 - time.Second) } else { endTime = baseTime.Add(-time.Second) } beginTime = baseTime.Add(-time.Hour * 24 * time.Duration(dayNum)) return beginTime, endTime } // timestamp is in second func GetCurTimestamp() int64 { return time.Now().Unix() } func GetAPIOperator(userName string) string { retVal := APIPin if userName != "" { retVal += "-" + userName } retVal = LimitUTF8StringLen(retVal, 50) return retVal } func CallFuncLogError(funcToCall func() error, msg string, params ...interface{}) error { err := funcToCall() if err != nil { baseapi.SugarLogger.Warnf("Failed "+msg+" error:%v", append(params, err.Error())...) } return err } func CallFuncLogErrorIgnore(funcToCall func() error, msg string, ignoreErr error, params ...interface{}) error { err := funcToCall() if err != nil && err != ignoreErr { baseapi.SugarLogger.Warnf("Failed "+msg+" error:%v", append(params, err.Error())...) } return err } func CallFuncLogErrorWithInfo(funcToCall func() error, msg string, params ...interface{}) error { err := funcToCall() if err != nil { baseapi.SugarLogger.Infof("Failed "+msg+" error:%v", append(params, err.Error())...) } return err } func CallFuncAsync(funcToCall func()) { go func() { defer func() { if r := recover(); r != nil { baseapi.SugarLogger.Errorf("error when calling func:%v, r:%v", funcToCall, r) } }() funcToCall() }() } func AfterFuncWithRecover(duration time.Duration, funcToCall func()) *time.Timer { return time.AfterFunc(duration, func() { defer func() { if r := recover(); r != nil { baseapi.SugarLogger.Errorf("error when calling func:%v, r:%v", funcToCall, r) } }() funcToCall() }) } func CallFuncRetryAsync(handler func(int) error, duration time.Duration, retryCount int) (err error) { err = handler(retryCount) if err != nil && retryCount > 0 { AfterFuncWithRecover(duration, func() { CallFuncRetryAsync(handler, duration, retryCount-1) }) } return err } func GenerateGetURL(baseURL, apiStr string, params map[string]interface{}) string { queryString := "" if params != nil { queryString = "?" + Map2URLValues(params).Encode() } if apiStr != "" { return baseURL + "/" + apiStr + queryString } return baseURL + queryString } func BuildRequest(method, url, body, contentType string) (request *http.Request) { request, _ = http.NewRequest(method, url, strings.NewReader(body)) if contentType == "" { contentType = "application/x-www-form-urlencoded" } request.Header.Set("Content-Type", contentType) return request } func SendFakeRequest(method, url, body, contentType string) (*http.Response, error) { client := &http.Client{} return client.Do(BuildRequest(method, url, body, contentType)) } // 过滤 utf8mb4(比如emoji表情) func FilterMb4(content string) string { newContent := &strings.Builder{} for _, value := range content { size := utf8.RuneLen(value) if size >= 1 && size <= 3 { newContent.WriteRune(value) } } return newContent.String() } func TrimBlankChar(str string) string { return strings.Trim(str, "\n\r\t ") } func RemoveGeneralMapKeys(obj map[string]interface{}, keys ...string) map[string]interface{} { if obj != nil { for _, key := range keys { if _, ok := obj[key]; ok { delete(obj, key) } } } return obj } func FilterMapNilMembers(mapData map[string]interface{}) map[string]interface{} { for k, v := range mapData { if v == nil { delete(mapData, k) } } return mapData } func Base64DecodeMultiString(strs ...string) (decodedData [][]byte, err error) { decodedData = make([][]byte, len(strs)) for k, v := range strs { if decodedData[k], err = base64.StdEncoding.DecodeString(v); err != nil { return nil, err } } return decodedData, nil } // 限制的是字节数,只适合纯英文的情况,推荐使用LimitMixedStringLen,除非确定是纯英文,且对性能相当敏感 func LimitStringLen(str string, maxByteCount int) (limitedStr string) { if maxByteCount > 0 { if strLen := len(str); strLen > maxByteCount { str = str[:maxByteCount] } } return str } // 限制的是字符数,不是字节数 func LimitUTF8StringLen(str string, maxRuneCount int) (limitedStr string) { if maxRuneCount > 0 { if len(str) > maxRuneCount { runeList := []rune(str) if len(runeList) > maxRuneCount { str = string(runeList[:maxRuneCount]) } } } return str } // 限制的是字节数,正常处理乱码 func LimitMixedStringLen(str string, maxByteCount int) (limitedStr string) { if maxByteCount <= 0 { return str } length := len(str) if maxByteCount >= length { return str } bs := []byte(str)[:maxByteCount] bl := 0 for i := len(bs) - 1; i >= 0; i-- { switch { case bs[i] >= 0 && bs[i] <= 127: return string(bs[:i+1]) case bs[i] >= 128 && bs[i] <= 191: bl++ case bs[i] >= 192 && bs[i] <= 253: cl := 0 switch { case bs[i]&252 == 252: cl = 6 case bs[i]&248 == 248: cl = 5 case bs[i]&240 == 240: cl = 4 case bs[i]&224 == 224: cl = 3 default: cl = 2 } if bl+1 == cl { return string(bs[:i+cl]) } return string(bs[:i]) } } return "" }