diff --git a/backend/types/view_type.go b/backend/types/view_type.go index be148f2..d62d264 100644 --- a/backend/types/view_type.go +++ b/backend/types/view_type.go @@ -9,4 +9,5 @@ const DECODE_NONE = "None" const DECODE_BASE64 = "Base64" const DECODE_GZIP = "GZip" const DECODE_DEFLATE = "Deflate" +const DECODE_ZSTD = "ZStd" const DECODE_BROTLI = "Brotli" diff --git a/backend/utils/string/convert.go b/backend/utils/string/convert.go index 1fe97da..f1f09f2 100644 --- a/backend/utils/string/convert.go +++ b/backend/utils/string/convert.go @@ -2,14 +2,15 @@ package strutil import ( "bytes" - "compress/flate" - "compress/gzip" "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" "io" "strconv" "strings" @@ -70,8 +71,17 @@ func decodeWith(str, decodeType string) (value, resultDecode string) { return case types.DECODE_DEFLATE: - if gzipStr, ok := decodeDeflate(str); ok { - value = gzipStr + 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 } @@ -79,8 +89,8 @@ func decodeWith(str, decodeType string) (value, resultDecode string) { return case types.DECODE_BROTLI: - if gzipStr, ok := decodeBrotli(str); ok { - value = gzipStr + if brotliStr, ok := decodeBrotli(str); ok { + value = brotliStr } else { value = str } @@ -112,6 +122,11 @@ func autoDecode(str string) (value, resultDecode string) { return } + if value, ok = decodeZStd(str); ok { + resultDecode = types.DECODE_ZSTD + return + } + if value, ok = decodeBrotli(str); ok { resultDecode = types.DECODE_BROTLI return @@ -244,6 +259,16 @@ func decodeDeflate(str string) (string, bool) { 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 { @@ -304,6 +329,14 @@ func SaveAs(str, viewType, decodeType string) (value string, err error) { } 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 @@ -391,6 +424,26 @@ func encodeDeflate(str string) (string, bool) { 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 diff --git a/frontend/src/consts/value_view_type.js b/frontend/src/consts/value_view_type.js index 45ca85d..1ee37bd 100644 --- a/frontend/src/consts/value_view_type.js +++ b/frontend/src/consts/value_view_type.js @@ -20,6 +20,7 @@ export const decodeTypes = { BASE64: 'Base64', GZIP: 'GZip', DEFLATE: 'Deflate', + ZSTD: 'ZStd', BROTLI: 'Brotli', // PHP: 'PHP', // Java: 'Java',