312 lines
7.2 KiB
Go
312 lines
7.2 KiB
Go
package utils
|
||
|
||
import (
|
||
"encoding/base64"
|
||
"fmt"
|
||
"net/http"
|
||
"net/url"
|
||
"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())
|
||
}
|
||
|
||
// 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 {
|
||
for k, v := range params {
|
||
if queryString == "" {
|
||
queryString = "?"
|
||
} else {
|
||
queryString += "&"
|
||
}
|
||
queryString += k + "=" + url.QueryEscape(fmt.Sprint(v))
|
||
}
|
||
}
|
||
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 ""
|
||
}
|