mirror of
https://github.com/redis/go-redis.git
synced 2025-07-31 05:04:23 +03:00
Init
This commit is contained in:
16
extra/rediscmd/go.mod
Normal file
16
extra/rediscmd/go.mod
Normal file
@ -0,0 +1,16 @@
|
||||
module github.com/redis/go-redis/extra/rediscmd/v9
|
||||
|
||||
go 1.19
|
||||
|
||||
replace github.com/redis/go-redis/v9 => ../..
|
||||
|
||||
require (
|
||||
github.com/bsm/ginkgo/v2 v2.12.0
|
||||
github.com/bsm/gomega v1.27.10
|
||||
github.com/redis/go-redis/v9 v9.5.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
)
|
8
extra/rediscmd/go.sum
Normal file
8
extra/rediscmd/go.sum
Normal file
@ -0,0 +1,8 @@
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
149
extra/rediscmd/rediscmd.go
Normal file
149
extra/rediscmd/rediscmd.go
Normal file
@ -0,0 +1,149 @@
|
||||
package rediscmd
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
func CmdString(cmd redis.Cmder) string {
|
||||
b := make([]byte, 0, 32)
|
||||
b = AppendCmd(b, cmd)
|
||||
return String(b)
|
||||
}
|
||||
|
||||
func CmdsString(cmds []redis.Cmder) (string, string) {
|
||||
const numCmdLimit = 100
|
||||
const numNameLimit = 10
|
||||
|
||||
seen := make(map[string]struct{}, numNameLimit)
|
||||
unqNames := make([]string, 0, numNameLimit)
|
||||
|
||||
b := make([]byte, 0, 32*len(cmds))
|
||||
|
||||
for i, cmd := range cmds {
|
||||
if i > numCmdLimit {
|
||||
break
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
b = AppendCmd(b, cmd)
|
||||
|
||||
if len(unqNames) >= numNameLimit {
|
||||
continue
|
||||
}
|
||||
|
||||
name := cmd.FullName()
|
||||
if _, ok := seen[name]; !ok {
|
||||
seen[name] = struct{}{}
|
||||
unqNames = append(unqNames, name)
|
||||
}
|
||||
}
|
||||
|
||||
summary := strings.Join(unqNames, " ")
|
||||
return summary, String(b)
|
||||
}
|
||||
|
||||
func AppendCmd(b []byte, cmd redis.Cmder) []byte {
|
||||
const numArgLimit = 32
|
||||
|
||||
for i, arg := range cmd.Args() {
|
||||
if i > numArgLimit {
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
b = append(b, ' ')
|
||||
}
|
||||
b = appendArg(b, arg)
|
||||
}
|
||||
|
||||
if err := cmd.Err(); err != nil {
|
||||
b = append(b, ": "...)
|
||||
b = append(b, err.Error()...)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func appendArg(b []byte, v interface{}) []byte {
|
||||
const argLenLimit = 64
|
||||
|
||||
switch v := v.(type) {
|
||||
case nil:
|
||||
return append(b, "<nil>"...)
|
||||
case string:
|
||||
if len(v) > argLenLimit {
|
||||
v = v[:argLenLimit]
|
||||
}
|
||||
return appendUTF8String(b, Bytes(v))
|
||||
case []byte:
|
||||
if len(v) > argLenLimit {
|
||||
v = v[:argLenLimit]
|
||||
}
|
||||
return appendUTF8String(b, v)
|
||||
case int:
|
||||
return strconv.AppendInt(b, int64(v), 10)
|
||||
case int8:
|
||||
return strconv.AppendInt(b, int64(v), 10)
|
||||
case int16:
|
||||
return strconv.AppendInt(b, int64(v), 10)
|
||||
case int32:
|
||||
return strconv.AppendInt(b, int64(v), 10)
|
||||
case int64:
|
||||
return strconv.AppendInt(b, v, 10)
|
||||
case uint:
|
||||
return strconv.AppendUint(b, uint64(v), 10)
|
||||
case uint8:
|
||||
return strconv.AppendUint(b, uint64(v), 10)
|
||||
case uint16:
|
||||
return strconv.AppendUint(b, uint64(v), 10)
|
||||
case uint32:
|
||||
return strconv.AppendUint(b, uint64(v), 10)
|
||||
case uint64:
|
||||
return strconv.AppendUint(b, v, 10)
|
||||
case float32:
|
||||
return strconv.AppendFloat(b, float64(v), 'f', -1, 64)
|
||||
case float64:
|
||||
return strconv.AppendFloat(b, v, 'f', -1, 64)
|
||||
case bool:
|
||||
if v {
|
||||
return append(b, "true"...)
|
||||
}
|
||||
return append(b, "false"...)
|
||||
case time.Time:
|
||||
return v.AppendFormat(b, time.RFC3339Nano)
|
||||
default:
|
||||
return append(b, fmt.Sprint(v)...)
|
||||
}
|
||||
}
|
||||
|
||||
func appendUTF8String(dst []byte, src []byte) []byte {
|
||||
if isSimple(src) {
|
||||
dst = append(dst, src...)
|
||||
return dst
|
||||
}
|
||||
|
||||
s := len(dst)
|
||||
dst = append(dst, make([]byte, hex.EncodedLen(len(src)))...)
|
||||
hex.Encode(dst[s:], src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func isSimple(b []byte) bool {
|
||||
for _, c := range b {
|
||||
if !isSimpleByte(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isSimpleByte(c byte) bool {
|
||||
return c >= 0x21 && c <= 0x7e
|
||||
}
|
31
extra/rediscmd/rediscmd_test.go
Normal file
31
extra/rediscmd/rediscmd_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package rediscmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/bsm/ginkgo/v2"
|
||||
. "github.com/bsm/gomega"
|
||||
)
|
||||
|
||||
func TestGinkgo(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "redisext")
|
||||
}
|
||||
|
||||
var _ = Describe("AppendArg", func() {
|
||||
DescribeTable("...",
|
||||
func(src string, wanted string) {
|
||||
b := appendArg(nil, src)
|
||||
Expect(string(b)).To(Equal(wanted))
|
||||
},
|
||||
|
||||
Entry("", "-inf", "-inf"),
|
||||
Entry("", "+inf", "+inf"),
|
||||
Entry("", "foo.bar", "foo.bar"),
|
||||
Entry("", "foo:bar", "foo:bar"),
|
||||
Entry("", "foo{bar}", "foo{bar}"),
|
||||
Entry("", "foo-123_BAR", "foo-123_BAR"),
|
||||
Entry("", "foo\nbar", "666f6f0a626172"),
|
||||
Entry("", "\000", "00"),
|
||||
)
|
||||
})
|
12
extra/rediscmd/safe.go
Normal file
12
extra/rediscmd/safe.go
Normal file
@ -0,0 +1,12 @@
|
||||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
package rediscmd
|
||||
|
||||
func String(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func Bytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
21
extra/rediscmd/unsafe.go
Normal file
21
extra/rediscmd/unsafe.go
Normal file
@ -0,0 +1,21 @@
|
||||
//go:build !appengine
|
||||
// +build !appengine
|
||||
|
||||
package rediscmd
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// String converts byte slice to string.
|
||||
func String(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// Bytes converts string to byte slice.
|
||||
func Bytes(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(
|
||||
&struct {
|
||||
string
|
||||
Cap int
|
||||
}{s, len(s)},
|
||||
))
|
||||
}
|
Reference in New Issue
Block a user