Compare commits
4 Commits
7a579d0d0b
...
7faca878a3
Author | SHA1 | Date |
---|---|---|
Lykin | 7faca878a3 | |
Lykin | 74d789ac8e | |
Lykin | fd58357a04 | |
Lykin | f09ee89a96 |
|
@ -21,6 +21,7 @@ import (
|
||||||
"tinyrdm/backend/consts"
|
"tinyrdm/backend/consts"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
"tinyrdm/backend/utils/coll"
|
"tinyrdm/backend/utils/coll"
|
||||||
|
convutil "tinyrdm/backend/utils/convert"
|
||||||
redis2 "tinyrdm/backend/utils/redis"
|
redis2 "tinyrdm/backend/utils/redis"
|
||||||
sliceutil "tinyrdm/backend/utils/slice"
|
sliceutil "tinyrdm/backend/utils/slice"
|
||||||
strutil "tinyrdm/backend/utils/string"
|
strutil "tinyrdm/backend/utils/string"
|
||||||
|
@ -781,7 +782,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
Value: val,
|
Value: val,
|
||||||
})
|
})
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
if dv, _, _ := convutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
||||||
items[len(items)-1].DisplayValue = dv
|
items[len(items)-1].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -828,7 +829,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
Value: strutil.EncodeRedisKey(loadedVal[i+1]),
|
Value: strutil.EncodeRedisKey(loadedVal[i+1]),
|
||||||
})
|
})
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(loadedVal[i+1], param.Decode, param.Format); dv != loadedVal[i+1] {
|
if dv, _, _ := convutil.ConvertTo(loadedVal[i+1], param.Decode, param.Format); dv != loadedVal[i+1] {
|
||||||
items[len(items)-1].DisplayValue = dv
|
items[len(items)-1].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +854,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
items[i/2].Key = loadedVal[i]
|
items[i/2].Key = loadedVal[i]
|
||||||
items[i/2].Value = strutil.EncodeRedisKey(loadedVal[i+1])
|
items[i/2].Value = strutil.EncodeRedisKey(loadedVal[i+1])
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(loadedVal[i+1], param.Decode, param.Format); dv != loadedVal[i+1] {
|
if dv, _, _ := convutil.ConvertTo(loadedVal[i+1], param.Decode, param.Format); dv != loadedVal[i+1] {
|
||||||
items[i/2].DisplayValue = dv
|
items[i/2].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -898,7 +899,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
Value: val,
|
Value: val,
|
||||||
})
|
})
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
if dv, _, _ := convutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
||||||
items[len(items)-1].DisplayValue = dv
|
items[len(items)-1].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -918,7 +919,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
for i, val := range loadedKey {
|
for i, val := range loadedKey {
|
||||||
items[i].Value = val
|
items[i].Value = val
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
if dv, _, _ := convutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
||||||
items[i].DisplayValue = dv
|
items[i].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -966,7 +967,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
Score: score,
|
Score: score,
|
||||||
})
|
})
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(loadedVal[i], param.Decode, param.Format); dv != loadedVal[i] {
|
if dv, _, _ := convutil.ConvertTo(loadedVal[i], param.Decode, param.Format); dv != loadedVal[i] {
|
||||||
items[len(items)-1].DisplayValue = dv
|
items[len(items)-1].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1001,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
Value: val,
|
Value: val,
|
||||||
})
|
})
|
||||||
if doConvert {
|
if doConvert {
|
||||||
if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
if dv, _, _ := convutil.ConvertTo(val, param.Decode, param.Format); dv != val {
|
||||||
items[len(items)-1].DisplayValue = dv
|
items[len(items)-1].DisplayValue = dv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1062,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
if vb, merr := json.Marshal(msg.Values); merr != nil {
|
if vb, merr := json.Marshal(msg.Values); merr != nil {
|
||||||
it.DisplayValue = "{}"
|
it.DisplayValue = "{}"
|
||||||
} else {
|
} else {
|
||||||
it.DisplayValue, _, _ = strutil.ConvertTo(string(vb), types.DECODE_NONE, types.FORMAT_JSON)
|
it.DisplayValue, _, _ = convutil.ConvertTo(string(vb), types.DECODE_NONE, types.FORMAT_JSON)
|
||||||
}
|
}
|
||||||
if doFilter && !strings.Contains(it.DisplayValue, param.MatchPattern) {
|
if doFilter && !strings.Contains(it.DisplayValue, param.MatchPattern) {
|
||||||
continue
|
continue
|
||||||
|
@ -1095,7 +1096,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
|
||||||
// blank format indicate auto format
|
// blank format indicate auto format
|
||||||
func (b *browserService) ConvertValue(value any, decode, format string) (resp types.JSResp) {
|
func (b *browserService) ConvertValue(value any, decode, format string) (resp types.JSResp) {
|
||||||
str := strutil.DecodeRedisKey(value)
|
str := strutil.DecodeRedisKey(value)
|
||||||
value, decode, format = strutil.ConvertTo(str, decode, format)
|
value, decode, format = convutil.ConvertTo(str, decode, format)
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = map[string]any{
|
||||||
"value": value,
|
"value": value,
|
||||||
|
@ -1138,7 +1139,7 @@ func (b *browserService) SetKeyValue(param types.SetKeyParam) (resp types.JSResp
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
var saveStr string
|
var saveStr string
|
||||||
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
if saveStr, err = convutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1249,12 +1250,12 @@ func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSRe
|
||||||
key := strutil.DecodeRedisKey(param.Key)
|
key := strutil.DecodeRedisKey(param.Key)
|
||||||
str := strutil.DecodeRedisKey(param.Value)
|
str := strutil.DecodeRedisKey(param.Value)
|
||||||
var saveStr, displayStr string
|
var saveStr, displayStr string
|
||||||
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
if saveStr, err = convutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
displayStr, _, _ = convutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
}
|
}
|
||||||
var updated, added, removed []types.HashEntryItem
|
var updated, added, removed []types.HashEntryItem
|
||||||
var replaced []types.HashReplaceItem
|
var replaced []types.HashReplaceItem
|
||||||
|
@ -1472,7 +1473,7 @@ func (b *browserService) SetListItem(param types.SetListParam) (resp types.JSRes
|
||||||
} else {
|
} else {
|
||||||
// replace index value
|
// replace index value
|
||||||
var saveStr string
|
var saveStr string
|
||||||
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
if saveStr, err = convutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1483,7 +1484,7 @@ func (b *browserService) SetListItem(param types.SetListParam) (resp types.JSRes
|
||||||
}
|
}
|
||||||
var displayStr string
|
var displayStr string
|
||||||
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
displayStr, _, _ = convutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
}
|
}
|
||||||
replaced = append(replaced, types.ListReplaceItem{
|
replaced = append(replaced, types.ListReplaceItem{
|
||||||
Index: param.Index,
|
Index: param.Index,
|
||||||
|
@ -1574,7 +1575,7 @@ func (b *browserService) UpdateSetItem(param types.SetSetParam) (resp types.JSRe
|
||||||
// insert new value
|
// insert new value
|
||||||
str = strutil.DecodeRedisKey(param.NewValue)
|
str = strutil.DecodeRedisKey(param.NewValue)
|
||||||
var saveStr string
|
var saveStr string
|
||||||
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
if saveStr, err = convutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1582,7 +1583,7 @@ func (b *browserService) UpdateSetItem(param types.SetSetParam) (resp types.JSRe
|
||||||
// add new item
|
// add new item
|
||||||
var displayStr string
|
var displayStr string
|
||||||
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
displayStr, _, _ = convutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
}
|
}
|
||||||
added = append(added, types.SetEntryItem{
|
added = append(added, types.SetEntryItem{
|
||||||
Value: saveStr,
|
Value: saveStr,
|
||||||
|
@ -1629,7 +1630,7 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var saveVal string
|
var saveVal string
|
||||||
if saveVal, err = strutil.SaveAs(newVal, param.Format, param.Decode); err != nil {
|
if saveVal, err = convutil.SaveAs(newVal, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1639,7 +1640,7 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
Score: param.Score,
|
Score: param.Score,
|
||||||
Member: saveVal,
|
Member: saveVal,
|
||||||
}).Result()
|
}).Result()
|
||||||
displayValue, _, _ := strutil.ConvertTo(val, param.RetDecode, param.RetFormat)
|
displayValue, _, _ := convutil.ConvertTo(val, param.RetDecode, param.RetFormat)
|
||||||
if affect > 0 {
|
if affect > 0 {
|
||||||
// add new item
|
// add new item
|
||||||
added = append(added, types.ZSetEntryItem{
|
added = append(added, types.ZSetEntryItem{
|
||||||
|
@ -1667,7 +1668,7 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
Score: param.Score,
|
Score: param.Score,
|
||||||
Member: saveVal,
|
Member: saveVal,
|
||||||
}).Result()
|
}).Result()
|
||||||
displayValue, _, _ := strutil.ConvertTo(saveVal, param.RetDecode, param.RetFormat)
|
displayValue, _, _ := convutil.ConvertTo(saveVal, param.RetDecode, param.RetFormat)
|
||||||
if affect <= 0 {
|
if affect <= 0 {
|
||||||
// no new value added, just update exists item
|
// no new value added, just update exists item
|
||||||
removed = append(removed, types.ZSetEntryItem{
|
removed = append(removed, types.ZSetEntryItem{
|
||||||
|
@ -1793,7 +1794,7 @@ func (b *browserService) AddStreamValue(server string, db int, k any, ID string,
|
||||||
updateValues[fieldItems[i].(string)] = fieldItems[i+1]
|
updateValues[fieldItems[i].(string)] = fieldItems[i+1]
|
||||||
}
|
}
|
||||||
vb, _ := json.Marshal(updateValues)
|
vb, _ := json.Marshal(updateValues)
|
||||||
displayValue, _, _ := strutil.ConvertTo(string(vb), types.DECODE_NONE, types.FORMAT_JSON)
|
displayValue, _, _ := convutil.ConvertTo(string(vb), types.DECODE_NONE, types.FORMAT_JSON)
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = struct {
|
resp.Data = struct {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
strutil "tinyrdm/backend/utils/string"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Base64Convert struct{}
|
||||||
|
|
||||||
|
func (Base64Convert) Encode(str string) (string, bool) {
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(str)), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Base64Convert) Decode(str string) (string, bool) {
|
||||||
|
if decodedStr, err := base64.StdEncoding.DecodeString(str); err == nil {
|
||||||
|
if s := string(decodedStr); !strutil.ContainsBinary(s) {
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BinaryConvert struct{}
|
||||||
|
|
||||||
|
func (BinaryConvert) Encode(str string) (string, bool) {
|
||||||
|
var result strings.Builder
|
||||||
|
total := len(str)
|
||||||
|
for i := 0; i < total; i += 8 {
|
||||||
|
b, _ := strconv.ParseInt(str[i:i+8], 2, 8)
|
||||||
|
result.WriteByte(byte(b))
|
||||||
|
}
|
||||||
|
return result.String(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BinaryConvert) Decode(str string) (string, bool) {
|
||||||
|
var binary strings.Builder
|
||||||
|
for _, char := range str {
|
||||||
|
binary.WriteString(fmt.Sprintf("%08b", int(char)))
|
||||||
|
}
|
||||||
|
return binary.String(), true
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/andybalholm/brotli"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BrotliConvert struct{}
|
||||||
|
|
||||||
|
func (BrotliConvert) Encode(str string) (string, bool) {
|
||||||
|
var compress = func(b []byte) (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writer := brotli.NewWriter(&buf)
|
||||||
|
if _, err := writer.Write([]byte(str)); err != nil {
|
||||||
|
writer.Close()
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
return string(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
if brotliStr, err := compress([]byte(str)); err == nil {
|
||||||
|
return brotliStr, true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BrotliConvert) Decode(str string) (string, bool) {
|
||||||
|
reader := brotli.NewReader(strings.NewReader(str))
|
||||||
|
if decompressed, err := io.ReadAll(reader); err == nil {
|
||||||
|
return string(decompressed), true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -0,0 +1,302 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"regexp"
|
||||||
|
"tinyrdm/backend/types"
|
||||||
|
strutil "tinyrdm/backend/utils/string"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DataConvert interface {
|
||||||
|
Encode(string) (string, bool)
|
||||||
|
Decode(string) (string, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
jsonConv JsonConvert
|
||||||
|
yamlConv YamlConvert
|
||||||
|
xmlConv XmlConvert
|
||||||
|
base64Conv Base64Convert
|
||||||
|
binaryConv BinaryConvert
|
||||||
|
hexConv HexConvert
|
||||||
|
gzipConv GZipConvert
|
||||||
|
deflateConv DeflateConvert
|
||||||
|
zstdConv ZStdConvert
|
||||||
|
brotliConv BrotliConvert
|
||||||
|
msgpackConv MsgpackConvert
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConvertTo convert string to specified type
|
||||||
|
// @param decodeType empty string indicates automatic detection
|
||||||
|
// @param formatType empty string indicates automatic detection
|
||||||
|
func ConvertTo(str, decodeType, formatType string) (value, resultDecode, resultFormat string) {
|
||||||
|
if len(str) <= 0 {
|
||||||
|
// empty content
|
||||||
|
if len(formatType) <= 0 {
|
||||||
|
resultFormat = types.FORMAT_RAW
|
||||||
|
} else {
|
||||||
|
resultFormat = formatType
|
||||||
|
}
|
||||||
|
if len(decodeType) <= 0 {
|
||||||
|
resultDecode = types.DECODE_NONE
|
||||||
|
} else {
|
||||||
|
resultDecode = decodeType
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode first
|
||||||
|
value, resultDecode = decodeWith(str, decodeType)
|
||||||
|
// then format content
|
||||||
|
value, resultFormat = viewAs(value, formatType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeWith(str, decodeType string) (value, resultDecode string) {
|
||||||
|
if len(decodeType) > 0 {
|
||||||
|
switch decodeType {
|
||||||
|
case types.DECODE_NONE:
|
||||||
|
value = str
|
||||||
|
|
||||||
|
case types.DECODE_BASE64:
|
||||||
|
if base64Str, ok := base64Conv.Decode(str); ok {
|
||||||
|
value = base64Str
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECODE_GZIP:
|
||||||
|
if gzipStr, ok := gzipConv.Decode(str); ok {
|
||||||
|
value = gzipStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECODE_DEFLATE:
|
||||||
|
if falteStr, ok := deflateConv.Decode(str); ok {
|
||||||
|
value = falteStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECODE_ZSTD:
|
||||||
|
if zstdStr, ok := zstdConv.Decode(str); ok {
|
||||||
|
value = zstdStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECODE_BROTLI:
|
||||||
|
if brotliStr, ok := brotliConv.Decode(str); ok {
|
||||||
|
value = brotliStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECODE_MSGPACK:
|
||||||
|
if msgpackStr, ok := msgpackConv.Decode(str); ok {
|
||||||
|
value = msgpackStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultDecode = decodeType
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return autoDecode(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt try possible decode method
|
||||||
|
// if no decode is possible, it will return the origin string value and "none" decode type
|
||||||
|
func autoDecode(str string) (value, resultDecode string) {
|
||||||
|
if len(str) > 0 {
|
||||||
|
// pure digit content may incorrect regard as some encoded type, skip decode
|
||||||
|
if match, _ := regexp.MatchString(`^\d+$`, str); !match {
|
||||||
|
var ok bool
|
||||||
|
if len(str)%4 == 0 && len(str) >= 12 && !strutil.IsSameChar(str) {
|
||||||
|
if value, ok = base64Conv.Decode(str); ok {
|
||||||
|
resultDecode = types.DECODE_BASE64
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok = gzipConv.Decode(str); ok {
|
||||||
|
resultDecode = types.DECODE_GZIP
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: skip decompress with deflate due to incorrect format checking
|
||||||
|
//if value, ok = decodeDeflate(str); ok {
|
||||||
|
// resultDecode = types.DECODE_DEFLATE
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
if value, ok = zstdConv.Decode(str); ok {
|
||||||
|
resultDecode = types.DECODE_ZSTD
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: skip decompress with brotli due to incorrect format checking
|
||||||
|
//if value, ok = decodeBrotli(str); ok {
|
||||||
|
// resultDecode = types.DECODE_BROTLI
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
if value, ok = msgpackConv.Decode(str); ok {
|
||||||
|
resultDecode = types.DECODE_MSGPACK
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = str
|
||||||
|
resultDecode = types.DECODE_NONE
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewAs(str, formatType string) (value, resultFormat string) {
|
||||||
|
if len(formatType) > 0 {
|
||||||
|
switch formatType {
|
||||||
|
case types.FORMAT_RAW, types.FORMAT_YAML, types.FORMAT_XML:
|
||||||
|
value = str
|
||||||
|
|
||||||
|
case types.FORMAT_JSON:
|
||||||
|
if jsonStr, ok := jsonConv.Decode(str); ok {
|
||||||
|
value = jsonStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.FORMAT_HEX:
|
||||||
|
if hexStr, ok := hexConv.Decode(str); ok {
|
||||||
|
value = hexStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.FORMAT_BINARY:
|
||||||
|
if binStr, ok := binaryConv.Decode(str); ok {
|
||||||
|
value = binStr
|
||||||
|
} else {
|
||||||
|
value = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultFormat = formatType
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return autoViewAs(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt automatic convert to possible types
|
||||||
|
// if no conversion is possible, it will return the origin string value and "plain text" type
|
||||||
|
func autoViewAs(str string) (value, resultFormat string) {
|
||||||
|
if len(str) > 0 {
|
||||||
|
var ok bool
|
||||||
|
if value, ok = jsonConv.Decode(str); ok {
|
||||||
|
resultFormat = types.FORMAT_JSON
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok = yamlConv.Decode(str); ok {
|
||||||
|
resultFormat = types.FORMAT_YAML
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok = xmlConv.Decode(str); ok {
|
||||||
|
resultFormat = types.FORMAT_XML
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strutil.ContainsBinary(str) {
|
||||||
|
if value, ok = hexConv.Decode(str); ok {
|
||||||
|
resultFormat = types.FORMAT_HEX
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = str
|
||||||
|
resultFormat = types.FORMAT_RAW
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveAs(str, format, decode string) (value string, err error) {
|
||||||
|
value = str
|
||||||
|
switch format {
|
||||||
|
case types.FORMAT_JSON:
|
||||||
|
if jsonStr, ok := jsonConv.Encode(str); ok {
|
||||||
|
value = jsonStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("invalid json data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.FORMAT_HEX:
|
||||||
|
if hexStr, ok := hexConv.Encode(str); ok {
|
||||||
|
value = hexStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("invalid hex data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.FORMAT_BINARY:
|
||||||
|
if binStr, ok := binaryConv.Encode(str); ok {
|
||||||
|
value = binStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("invalid binary data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch decode {
|
||||||
|
case types.DECODE_NONE:
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_BASE64:
|
||||||
|
value, _ = base64Conv.Encode(value)
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_GZIP:
|
||||||
|
if gzipStr, ok := gzipConv.Encode(str); ok {
|
||||||
|
value = gzipStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("fail to build gzip")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_DEFLATE:
|
||||||
|
if deflateStr, ok := deflateConv.Encode(str); ok {
|
||||||
|
value = deflateStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("fail to build deflate")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_ZSTD:
|
||||||
|
if zstdStr, ok := zstdConv.Encode(str); ok {
|
||||||
|
value = zstdStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("fail to build zstd")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_BROTLI:
|
||||||
|
if brotliStr, ok := brotliConv.Encode(str); ok {
|
||||||
|
value = brotliStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("fail to build brotli")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case types.DECODE_MSGPACK:
|
||||||
|
if msgpackStr, ok := msgpackConv.Encode(str); ok {
|
||||||
|
value = msgpackStr
|
||||||
|
} else {
|
||||||
|
err = errors.New("fail to build msgpack")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return str, nil
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/klauspost/compress/flate"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeflateConvert struct{}
|
||||||
|
|
||||||
|
func (d DeflateConvert) Encode(str string) (string, bool) {
|
||||||
|
var compress = func(b []byte) (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writer, err := flate.NewWriter(&buf, flate.DefaultCompression)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err = writer.Write([]byte(str)); err != nil {
|
||||||
|
writer.Close()
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
return string(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
if deflateStr, err := compress([]byte(str)); err == nil {
|
||||||
|
return deflateStr, true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d DeflateConvert) Decode(str string) (string, bool) {
|
||||||
|
reader := flate.NewReader(strings.NewReader(str))
|
||||||
|
defer reader.Close()
|
||||||
|
if decompressed, err := io.ReadAll(reader); err == nil {
|
||||||
|
return string(decompressed), true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/klauspost/compress/gzip"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GZipConvert struct{}
|
||||||
|
|
||||||
|
func (GZipConvert) Encode(str string) (string, bool) {
|
||||||
|
var compress = func(b []byte) (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writer := gzip.NewWriter(&buf)
|
||||||
|
if _, err := writer.Write([]byte(str)); err != nil {
|
||||||
|
writer.Close()
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
return string(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if gzipStr, err := compress([]byte(str)); err == nil {
|
||||||
|
return gzipStr, true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (GZipConvert) Decode(str string) (string, bool) {
|
||||||
|
if reader, err := gzip.NewReader(strings.NewReader(str)); err == nil {
|
||||||
|
defer reader.Close()
|
||||||
|
var decompressed []byte
|
||||||
|
if decompressed, err = io.ReadAll(reader); err == nil {
|
||||||
|
return string(decompressed), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HexConvert struct{}
|
||||||
|
|
||||||
|
func (HexConvert) Encode(str string) (string, bool) {
|
||||||
|
hexStrArr := strings.Split(str, "\\x")
|
||||||
|
hexStr := strings.Join(hexStrArr, "")
|
||||||
|
if decodeStr, err := hex.DecodeString(hexStr); err == nil {
|
||||||
|
return string(decodeStr), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HexConvert) Decode(str string) (string, bool) {
|
||||||
|
decodeStr := hex.EncodeToString([]byte(str))
|
||||||
|
decodeStr = strings.ToUpper(decodeStr)
|
||||||
|
var resultStr strings.Builder
|
||||||
|
for i := 0; i < len(decodeStr); i += 2 {
|
||||||
|
resultStr.WriteString("\\x")
|
||||||
|
resultStr.WriteString(decodeStr[i : i+2])
|
||||||
|
}
|
||||||
|
return resultStr.String(), true
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JsonConvert struct{}
|
||||||
|
|
||||||
|
func (JsonConvert) Decode(str string) (string, bool) {
|
||||||
|
trimedStr := strings.TrimSpace(str)
|
||||||
|
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
||||||
|
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
||||||
|
return out.String(), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (JsonConvert) Encode(str string) (string, bool) {
|
||||||
|
var dst bytes.Buffer
|
||||||
|
if err := json.Compact(&dst, []byte(str)); err != nil {
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
return dst.String(), true
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/vmihailenco/msgpack/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MsgpackConvert struct{}
|
||||||
|
|
||||||
|
func (MsgpackConvert) Encode(str string) (string, bool) {
|
||||||
|
var obj map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(str), &obj); err == nil {
|
||||||
|
if b, err := msgpack.Marshal(obj); err == nil {
|
||||||
|
return string(b), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, err := msgpack.Marshal(str); err != nil {
|
||||||
|
return string(b), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (MsgpackConvert) Decode(str string) (string, bool) {
|
||||||
|
var decodedStr string
|
||||||
|
if err := msgpack.Unmarshal([]byte(str), &decodedStr); err == nil {
|
||||||
|
return decodedStr, true
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj map[string]any
|
||||||
|
if err := msgpack.Unmarshal([]byte(str), &obj); err == nil {
|
||||||
|
if b, err := json.Marshal(obj); err == nil {
|
||||||
|
return string(b), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type XmlConvert struct{}
|
||||||
|
|
||||||
|
func (XmlConvert) Encode(str string) (string, bool) {
|
||||||
|
return str, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (XmlConvert) Decode(str string) (string, bool) {
|
||||||
|
trimedStr := strings.TrimSpace(str)
|
||||||
|
if !strings.HasPrefix(trimedStr, "<") && !strings.HasSuffix(trimedStr, ">") {
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
var obj any
|
||||||
|
err := xml.Unmarshal([]byte(trimedStr), &obj)
|
||||||
|
return str, err == nil
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type YamlConvert struct{}
|
||||||
|
|
||||||
|
func (YamlConvert) Encode(str string) (string, bool) {
|
||||||
|
return str, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (YamlConvert) Decode(str string) (string, bool) {
|
||||||
|
var obj map[string]any
|
||||||
|
err := yaml.Unmarshal([]byte(str), &obj)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
|
} else {
|
||||||
|
log.Println(obj)
|
||||||
|
}
|
||||||
|
return str, err == nil
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package convutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/klauspost/compress/zstd"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ZStdConvert struct{}
|
||||||
|
|
||||||
|
func (ZStdConvert) Encode(str string) (string, bool) {
|
||||||
|
var compress = func(b []byte) (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writer, err := zstd.NewWriter(&buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err = writer.Write([]byte(str)); err != nil {
|
||||||
|
writer.Close()
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
return string(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
if zstdStr, err := compress([]byte(str)); err == nil {
|
||||||
|
return zstdStr, true
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ZStdConvert) Decode(str string) (string, bool) {
|
||||||
|
if reader, err := zstd.NewReader(strings.NewReader(str)); err == nil {
|
||||||
|
defer reader.Close()
|
||||||
|
if decompressed, err := io.ReadAll(reader); err == nil {
|
||||||
|
return string(decompressed), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str, false
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func containsBinary(str string) bool {
|
func ContainsBinary(str string) bool {
|
||||||
//buf := []byte(str)
|
//buf := []byte(str)
|
||||||
//size := 0
|
//size := 0
|
||||||
//for start := 0; start < len(buf); start += size {
|
//for start := 0; start < len(buf); start += size {
|
||||||
|
@ -25,7 +25,7 @@ func containsBinary(str string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSameChar(str string) bool {
|
func IsSameChar(str string) bool {
|
||||||
if len(str) <= 0 {
|
if len(str) <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,505 +0,0 @@
|
||||||
package strutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/andybalholm/brotli"
|
|
||||||
"github.com/klauspost/compress/flate"
|
|
||||||
"github.com/klauspost/compress/gzip"
|
|
||||||
"github.com/klauspost/compress/zstd"
|
|
||||||
"github.com/vmihailenco/msgpack/v5"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"tinyrdm/backend/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConvertTo convert string to specified type
|
|
||||||
// @param decodeType empty string indicates automatic detection
|
|
||||||
// @param formatType empty string indicates automatic detection
|
|
||||||
func ConvertTo(str, decodeType, formatType string) (value, resultDecode, resultFormat string) {
|
|
||||||
if len(str) <= 0 {
|
|
||||||
// empty content
|
|
||||||
if len(formatType) <= 0 {
|
|
||||||
resultFormat = types.FORMAT_RAW
|
|
||||||
} else {
|
|
||||||
resultFormat = formatType
|
|
||||||
}
|
|
||||||
if len(decodeType) <= 0 {
|
|
||||||
resultDecode = types.DECODE_NONE
|
|
||||||
} else {
|
|
||||||
resultDecode = decodeType
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode first
|
|
||||||
value, resultDecode = decodeWith(str, decodeType)
|
|
||||||
// then format content
|
|
||||||
value, resultFormat = viewAs(value, formatType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeWith(str, decodeType string) (value, resultDecode string) {
|
|
||||||
if len(decodeType) > 0 {
|
|
||||||
switch decodeType {
|
|
||||||
case types.DECODE_NONE:
|
|
||||||
value = str
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_BASE64:
|
|
||||||
if base64Str, ok := decodeBase64(str); ok {
|
|
||||||
value = base64Str
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_GZIP:
|
|
||||||
if gzipStr, ok := decodeGZip(str); ok {
|
|
||||||
value = gzipStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_DEFLATE:
|
|
||||||
if falteStr, ok := decodeDeflate(str); ok {
|
|
||||||
value = falteStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_ZSTD:
|
|
||||||
if zstdStr, ok := decodeZStd(str); ok {
|
|
||||||
value = zstdStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_BROTLI:
|
|
||||||
if brotliStr, ok := decodeBrotli(str); ok {
|
|
||||||
value = brotliStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultDecode = decodeType
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return autoDecode(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt try possible decode method
|
|
||||||
// if no decode is possible, it will return the origin string value and "none" decode type
|
|
||||||
func autoDecode(str string) (value, resultDecode string) {
|
|
||||||
if len(str) > 0 {
|
|
||||||
// pure digit content may incorrect regard as some encoded type, skip decode
|
|
||||||
if match, _ := regexp.MatchString(`^\d+$`, str); !match {
|
|
||||||
var ok bool
|
|
||||||
if len(str)%4 == 0 && len(str) >= 12 && !isSameChar(str) {
|
|
||||||
if value, ok = decodeBase64(str); ok {
|
|
||||||
resultDecode = types.DECODE_BASE64
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if value, ok = decodeGZip(str); ok {
|
|
||||||
resultDecode = types.DECODE_GZIP
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: skip decompress with deflate due to incorrect format checking
|
|
||||||
//if value, ok = decodeDeflate(str); ok {
|
|
||||||
// resultDecode = types.DECODE_DEFLATE
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
if value, ok = decodeZStd(str); ok {
|
|
||||||
resultDecode = types.DECODE_ZSTD
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: skip decompress with brotli due to incorrect format checking
|
|
||||||
//if value, ok = decodeBrotli(str); ok {
|
|
||||||
// resultDecode = types.DECODE_BROTLI
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
if value, ok = decodeMsgpack(str); ok {
|
|
||||||
resultDecode = types.DECODE_MSGPACK
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = str
|
|
||||||
resultDecode = types.DECODE_NONE
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func viewAs(str, formatType string) (value, resultFormat string) {
|
|
||||||
if len(formatType) > 0 {
|
|
||||||
switch formatType {
|
|
||||||
case types.FORMAT_RAW, types.FORMAT_YAML, types.FORMAT_XML:
|
|
||||||
value = str
|
|
||||||
resultFormat = formatType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.FORMAT_JSON:
|
|
||||||
if jsonStr, ok := decodeJson(str); ok {
|
|
||||||
value = jsonStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultFormat = formatType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.FORMAT_HEX:
|
|
||||||
if hexStr, ok := decodeToHex(str); ok {
|
|
||||||
value = hexStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultFormat = formatType
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.FORMAT_BINARY:
|
|
||||||
if binStr, ok := decodeBinary(str); ok {
|
|
||||||
value = binStr
|
|
||||||
} else {
|
|
||||||
value = str
|
|
||||||
}
|
|
||||||
resultFormat = formatType
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return autoViewAs(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt automatic convert to possible types
|
|
||||||
// if no conversion is possible, it will return the origin string value and "plain text" type
|
|
||||||
func autoViewAs(str string) (value, resultFormat string) {
|
|
||||||
if len(str) > 0 {
|
|
||||||
var ok bool
|
|
||||||
if value, ok = decodeJson(str); ok {
|
|
||||||
resultFormat = types.FORMAT_JSON
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if containsBinary(str) {
|
|
||||||
if value, ok = decodeToHex(str); ok {
|
|
||||||
resultFormat = types.FORMAT_HEX
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = str
|
|
||||||
resultFormat = types.FORMAT_RAW
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeJson(str string) (string, bool) {
|
|
||||||
trimedStr := strings.TrimSpace(str)
|
|
||||||
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
|
||||||
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
|
||||||
var out bytes.Buffer
|
|
||||||
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
|
||||||
return out.String(), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeBase64(str string) (string, bool) {
|
|
||||||
if decodedStr, err := base64.StdEncoding.DecodeString(str); err == nil {
|
|
||||||
if s := string(decodedStr); !containsBinary(s) {
|
|
||||||
return s, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeBinary(str string) (string, bool) {
|
|
||||||
var binary strings.Builder
|
|
||||||
for _, char := range str {
|
|
||||||
binary.WriteString(fmt.Sprintf("%08b", int(char)))
|
|
||||||
}
|
|
||||||
return binary.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeToHex(str string) (string, bool) {
|
|
||||||
decodeStr := hex.EncodeToString([]byte(str))
|
|
||||||
var resultStr strings.Builder
|
|
||||||
for i := 0; i < len(decodeStr); i += 2 {
|
|
||||||
resultStr.WriteString("\\x")
|
|
||||||
resultStr.WriteString(strings.ToUpper(decodeStr[i : i+2]))
|
|
||||||
}
|
|
||||||
return resultStr.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeGZip(str string) (string, bool) {
|
|
||||||
if reader, err := gzip.NewReader(strings.NewReader(str)); err == nil {
|
|
||||||
defer reader.Close()
|
|
||||||
var decompressed []byte
|
|
||||||
if decompressed, err = io.ReadAll(reader); err == nil {
|
|
||||||
return string(decompressed), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeDeflate(str string) (string, bool) {
|
|
||||||
reader := flate.NewReader(strings.NewReader(str))
|
|
||||||
defer reader.Close()
|
|
||||||
if decompressed, err := io.ReadAll(reader); err == nil {
|
|
||||||
return string(decompressed), true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeZStd(str string) (string, bool) {
|
|
||||||
if reader, err := zstd.NewReader(strings.NewReader(str)); err == nil {
|
|
||||||
defer reader.Close()
|
|
||||||
if decompressed, err := io.ReadAll(reader); err == nil {
|
|
||||||
return string(decompressed), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeBrotli(str string) (string, bool) {
|
|
||||||
reader := brotli.NewReader(strings.NewReader(str))
|
|
||||||
if decompressed, err := io.ReadAll(reader); err == nil {
|
|
||||||
return string(decompressed), true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeMsgpack(str string) (string, bool) {
|
|
||||||
var decodedStr string
|
|
||||||
if err := msgpack.Unmarshal([]byte(str), &decodedStr); err == nil {
|
|
||||||
return decodedStr, true
|
|
||||||
}
|
|
||||||
|
|
||||||
var decodedObj map[string]any
|
|
||||||
if err := msgpack.Unmarshal([]byte(str), &decodedObj); err == nil {
|
|
||||||
if b, err := json.Marshal(decodedObj); err == nil {
|
|
||||||
return string(b), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveAs(str, format, decode string) (value string, err error) {
|
|
||||||
value = str
|
|
||||||
switch format {
|
|
||||||
case types.FORMAT_JSON:
|
|
||||||
if jsonStr, ok := encodeJson(str); ok {
|
|
||||||
value = jsonStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("invalid json data")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case types.FORMAT_HEX:
|
|
||||||
if hexStr, ok := encodeHex(str); ok {
|
|
||||||
value = hexStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("invalid hex data")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case types.FORMAT_BINARY:
|
|
||||||
if binStr, ok := encodeBinary(str); ok {
|
|
||||||
value = binStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("invalid binary data")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch decode {
|
|
||||||
case types.DECODE_NONE:
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_BASE64:
|
|
||||||
value, _ = encodeBase64(value)
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_GZIP:
|
|
||||||
if gzipStr, ok := encodeGZip(str); ok {
|
|
||||||
value = gzipStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("fail to build gzip")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_DEFLATE:
|
|
||||||
if deflateStr, ok := encodeDeflate(str); ok {
|
|
||||||
value = deflateStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("fail to build deflate")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_ZSTD:
|
|
||||||
if zstdStr, ok := encodeZStd(str); ok {
|
|
||||||
value = zstdStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("fail to build zstd")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_BROTLI:
|
|
||||||
if brotliStr, ok := encodeBrotli(str); ok {
|
|
||||||
value = brotliStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("fail to build brotli")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case types.DECODE_MSGPACK:
|
|
||||||
if msgpackStr, ok := encodeMsgpack(str); ok {
|
|
||||||
value = msgpackStr
|
|
||||||
} else {
|
|
||||||
err = errors.New("fail to build msgpack")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return str, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeJson(str string) (string, bool) {
|
|
||||||
var dst bytes.Buffer
|
|
||||||
if err := json.Compact(&dst, []byte(str)); err != nil {
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
return dst.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeBase64(str string) (string, bool) {
|
|
||||||
return base64.StdEncoding.EncodeToString([]byte(str)), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeBinary(str string) (string, bool) {
|
|
||||||
var result strings.Builder
|
|
||||||
total := len(str)
|
|
||||||
for i := 0; i < total; i += 8 {
|
|
||||||
b, _ := strconv.ParseInt(str[i:i+8], 2, 8)
|
|
||||||
result.WriteByte(byte(b))
|
|
||||||
}
|
|
||||||
return result.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeHex(str string) (string, bool) {
|
|
||||||
hexStrArr := strings.Split(str, "\\x")
|
|
||||||
hexStr := strings.Join(hexStrArr, "")
|
|
||||||
if decodeStr, err := hex.DecodeString(hexStr); err == nil {
|
|
||||||
return string(decodeStr), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeGZip(str string) (string, bool) {
|
|
||||||
var compress = func(b []byte) (string, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
writer := gzip.NewWriter(&buf)
|
|
||||||
if _, err := writer.Write([]byte(str)); err != nil {
|
|
||||||
writer.Close()
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
writer.Close()
|
|
||||||
return string(buf.Bytes()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if gzipStr, err := compress([]byte(str)); err == nil {
|
|
||||||
return gzipStr, true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeDeflate(str string) (string, bool) {
|
|
||||||
var compress = func(b []byte) (string, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
writer, err := flate.NewWriter(&buf, flate.DefaultCompression)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if _, err = writer.Write([]byte(str)); err != nil {
|
|
||||||
writer.Close()
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
writer.Close()
|
|
||||||
return string(buf.Bytes()), nil
|
|
||||||
}
|
|
||||||
if deflateStr, err := compress([]byte(str)); err == nil {
|
|
||||||
return deflateStr, true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeZStd(str string) (string, bool) {
|
|
||||||
var compress = func(b []byte) (string, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
writer, err := zstd.NewWriter(&buf)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if _, err = writer.Write([]byte(str)); err != nil {
|
|
||||||
writer.Close()
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
writer.Close()
|
|
||||||
return string(buf.Bytes()), nil
|
|
||||||
}
|
|
||||||
if zstdStr, err := compress([]byte(str)); err == nil {
|
|
||||||
return zstdStr, true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeBrotli(str string) (string, bool) {
|
|
||||||
var compress = func(b []byte) (string, error) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
writer := brotli.NewWriter(&buf)
|
|
||||||
if _, err := writer.Write([]byte(str)); err != nil {
|
|
||||||
writer.Close()
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
writer.Close()
|
|
||||||
return string(buf.Bytes()), nil
|
|
||||||
}
|
|
||||||
if brotliStr, err := compress([]byte(str)); err == nil {
|
|
||||||
return brotliStr, true
|
|
||||||
}
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodeMsgpack(str string) (string, bool) {
|
|
||||||
var err error
|
|
||||||
var buf bytes.Buffer
|
|
||||||
enc := msgpack.NewEncoder(&buf)
|
|
||||||
if err = enc.EncodeString(str); err == nil {
|
|
||||||
return buf.String(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return str, false
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
// EncodeRedisKey encode the redis key to integer array
|
// EncodeRedisKey encode the redis key to integer array
|
||||||
// if key contains binary which could not display on ui, convert the key to char array
|
// if key contains binary which could not display on ui, convert the key to char array
|
||||||
func EncodeRedisKey(key string) any {
|
func EncodeRedisKey(key string) any {
|
||||||
if containsBinary(key) {
|
if ContainsBinary(key) {
|
||||||
b := []byte(key)
|
b := []byte(key)
|
||||||
arr := make([]int, len(b))
|
arr := make([]int, len(b))
|
||||||
for i, bb := range b {
|
for i, bb := range b {
|
||||||
|
|
|
@ -498,6 +498,7 @@ const pasteFromClipboard = async () => {
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
|
<!-- Alias pane -->
|
||||||
<n-tab-pane :tab="$t('dialogue.connection.alias.title')" display-directive="show:lazy" name="alias">
|
<n-tab-pane :tab="$t('dialogue.connection.alias.title')" display-directive="show:lazy" name="alias">
|
||||||
<n-form
|
<n-form
|
||||||
:model="generalForm.alias"
|
:model="generalForm.alias"
|
||||||
|
|
|
@ -108,6 +108,7 @@ const onClose = () => {
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="prefStore.general.fontFamily"
|
v-model:value="prefStore.general.fontFamily"
|
||||||
:options="prefStore.fontOption"
|
:options="prefStore.fontOption"
|
||||||
|
:placeholder="$t('preferences.general.font_tip')"
|
||||||
:render-label="({ label, value }) => (value === '' ? $t(label) : label)"
|
:render-label="({ label, value }) => (value === '' ? $t(label) : label)"
|
||||||
filterable
|
filterable
|
||||||
multiple
|
multiple
|
||||||
|
@ -166,6 +167,7 @@ const onClose = () => {
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="prefStore.editor.fontFamily"
|
v-model:value="prefStore.editor.fontFamily"
|
||||||
:options="prefStore.fontOption"
|
:options="prefStore.fontOption"
|
||||||
|
:placeholder="$t('preferences.general.font_tip')"
|
||||||
:render-label="({ label, value }) => value || $t(label)"
|
:render-label="({ label, value }) => value || $t(label)"
|
||||||
filterable
|
filterable
|
||||||
multiple
|
multiple
|
||||||
|
@ -206,6 +208,7 @@ const onClose = () => {
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="prefStore.cli.fontFamily"
|
v-model:value="prefStore.cli.fontFamily"
|
||||||
:options="prefStore.fontOption"
|
:options="prefStore.fontOption"
|
||||||
|
:placeholder="$t('preferences.general.font_tip')"
|
||||||
:render-label="({ label, value }) => value || $t(label)"
|
:render-label="({ label, value }) => value || $t(label)"
|
||||||
filterable
|
filterable
|
||||||
multiple
|
multiple
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"system_lang": "Use System Language",
|
"system_lang": "Use System Language",
|
||||||
"font": "Font",
|
"font": "Font",
|
||||||
|
"font_tip": "Please Select or Input Font Name",
|
||||||
"font_size": "Font Size",
|
"font_size": "Font Size",
|
||||||
"scan_size": "Default Size for SCAN Command",
|
"scan_size": "Default Size for SCAN Command",
|
||||||
"key_icon_style": "Key Icon Style",
|
"key_icon_style": "Key Icon Style",
|
||||||
|
@ -139,6 +140,7 @@
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"cli_welcome": "Welcome to Tiny RDM Redis Console",
|
"cli_welcome": "Welcome to Tiny RDM Redis Console",
|
||||||
|
"retrieving_version": "Retrieving for new version",
|
||||||
"sub_tab": {
|
"sub_tab": {
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"key_detail": "Key Detail",
|
"key_detail": "Key Detail",
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"language": "语言",
|
"language": "语言",
|
||||||
"system_lang": "使用系统语言",
|
"system_lang": "使用系统语言",
|
||||||
"font": "字体",
|
"font": "字体",
|
||||||
|
"font_tip": "请选择或手动输入字体名",
|
||||||
"font_size": "字体尺寸",
|
"font_size": "字体尺寸",
|
||||||
"scan_size": "SCAN命令默认数量",
|
"scan_size": "SCAN命令默认数量",
|
||||||
"key_icon_style": "键图标样式",
|
"key_icon_style": "键图标样式",
|
||||||
|
@ -139,6 +140,7 @@
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"type": "类型",
|
"type": "类型",
|
||||||
"cli_welcome": "欢迎使用Tiny RDM的Redis命令行控制台",
|
"cli_welcome": "欢迎使用Tiny RDM的Redis命令行控制台",
|
||||||
|
"retrieving_version": "正在检索新版本",
|
||||||
"sub_tab": {
|
"sub_tab": {
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
"key_detail": "键详情",
|
"key_detail": "键详情",
|
||||||
|
@ -153,7 +155,7 @@
|
||||||
"browser": "数据浏览",
|
"browser": "数据浏览",
|
||||||
"log": "日志",
|
"log": "日志",
|
||||||
"wechat_official": "微信公众号",
|
"wechat_official": "微信公众号",
|
||||||
"follow_x": "关注的我\uD835\uDD4F",
|
"follow_x": "关注我的\uD835\uDD4F",
|
||||||
"github": "Github"
|
"github": "Github"
|
||||||
},
|
},
|
||||||
"dialogue": {
|
"dialogue": {
|
||||||
|
|
|
@ -338,7 +338,7 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
async checkForUpdate(manual = false) {
|
async checkForUpdate(manual = false) {
|
||||||
let msgRef = null
|
let msgRef = null
|
||||||
if (manual) {
|
if (manual) {
|
||||||
msgRef = $message.loading('Retrieving for new version', { duration: 0 })
|
msgRef = $message.loading(i18nGlobal.t('interface.retrieving_version'), { duration: 0 })
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const { success, data = {} } = await CheckForUpdate()
|
const { success, data = {} } = await CheckForUpdate()
|
||||||
|
|
Loading…
Reference in New Issue