resp3

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2020 License: Apache-2.0 Imports: 9 Imported by: 2

README

resp3

License GoDoc travis Go Report Card coveralls

The first redis RESP3 protocol library, written in Go.

You can use it to communicte with Redis 6 via RESP3, or you can wrap it as redis client lib.

Value represents a redis command or an redis response, which supports all RESP3 types:

Types equivalent to RESP version 2
  • Array: an ordered collection of N other types
  • Blob string: binary safe strings
  • Simple string: a space efficient non binary safe string
  • Simple error: a space efficient non binary safe error code and message
  • Number: an integer in the signed 64 bit range
Types introduced by RESP3
  • Null: a single null value replacing RESP v2 *-1 and $-1 null values.
  • Double: a floating point number
  • Boolean: true or false
  • Blob error: binary safe error code and message.
  • Verbatim string: a binary safe string that should be displayed to humans without any escaping or filtering. For instance the output of LATENCY DOCTOR in Redis.
  • Map: an ordered collection of key-value pairs. Keys and values can be any other RESP3 type.
  • Set: an unordered collection of N other types.
  • Attribute: Like the Map type, but the client should keep reading the reply ignoring the attribute type, and return it to the client as additional information.
  • Push: Out of band data. The format is like the Array type, but the client should just check the first string element, stating the type of the out of band data, a call a callback if there is one registered for this specific type of push information. Push types are not related to replies, since they are information that the server may push at any time in the connection, so the client should keep reading if it is reading the reply of a command.
  • Hello: Like the Map type, but is sent only when the connection between the client and the server is established, in order to welcome the client with different information like the name of the server, its version, and so forth.
  • Big number: a large number non representable by the Number type

Reader is used to read a Value object from the connection. It can be used by both redis clients and redis servers.

Examples

Client Cache (Tracking)

you can use it to test the client cache feature in Redis 6.0.

func TestReader_IT_Tracking(t *testing.T) {
	conn, err := net.DialTimeout("tcp", "127.0.0.1:6379", 5*time.Second)
	if err != nil {
		t.Logf("can't found one of redis 6.0 server")
		return
	}
	defer conn.Close()

	w := NewWriter(conn)
	r := NewReader(conn)

	w.WriteCommand("HELLO", "3")
	helloResp, _, err := r.ReadValue()
	if err != nil {
		t.Fatalf("failed to send a HELLO 3")
	}
	if helloResp.KV.Size() == 0 {
		t.Fatalf("expect some info but got %+v", helloResp)
	}
	t.Logf("hello response: %c, %v", helloResp.Type, helloResp.SmartResult())

	w.WriteCommand("CLIENT", "TRACKING", "on")
	resp, _, err := r.ReadValue()
	if err != nil {
		t.Fatalf("failed to TRACKING: %v", err)
	}
	t.Logf("TRACKING result: %c, %+v", resp.Type, resp.SmartResult())

	w.WriteCommand("GET", "a")
	resp, _, err = r.ReadValue()
	if err != nil {
		t.Fatalf("failed to GET: %v", err)
	}
	t.Logf("GET result: %c, %+v", resp.Type, resp.SmartResult())

	go func() {
		conn, err := net.DialTimeout("tcp", "127.0.0.1:9999", 5*time.Second)
		if err != nil {
			t.Logf("can't found one of redis 6.0 server")
			return
		}
		defer conn.Close()
		w := NewWriter(conn)
		r := NewReader(conn)

		for i := 0; i < 10; i++ {
			//PUBLISH
			w.WriteCommand("set", "a", strconv.Itoa(i))
			resp, _, err = r.ReadValue()
			if err != nil {
				t.Fatalf("failed to set: %v", err)
			}
			t.Logf("set result: %c, %+v", resp.Type, resp.SmartResult())
			time.Sleep(200 * time.Millisecond)
		}

	}()

	for i := 0; i < 10; i++ {
		resp, _, err = r.ReadValue()
		if err != nil {
			t.Fatalf("failed to receive a message: %v", err)
		}
		if resp.Type == TypePush && len(resp.Elems) >= 2 && resp.Elems[0].SmartResult().(string) == "invalidate" {
			t.Logf("received TRACKING result: %c, %+v", resp.Type, resp.SmartResult())

			// refresh cache "a"
			w.WriteCommand("GET", "a")
			resp, _, err = r.ReadValue()
		}
	}
}

Documentation

Overview

Package resp3 implements redis RESP3 protocol, which is used from redis 6.0.

RESP (REdis Serialization Protocol) is the protocol used in the Redis database, however the protocol is designed to be used by other projects. With the version 3 of the protocol, currently a work in progress design, the protocol aims to become even more generally useful to other systems that want to implement a protocol which is simple, efficient, and with a very large landscape of client libraries implementations. That means you can use this library to access other RESP3 projects.

This library contains three important components: Value, Reader and Writer.

Value represents a redis command or a redis response. It is a common struct for all RESP3 types.

Reader can parse redis responses from redis servers or commands from redis clients. You can use it to implement redis 6.0 clients, no need to pay attention to underlying parsing. Those new features of redis 6.0 can be implemented based on it.

Writer is redis writer. You can use it to send commands to redis servers.

RESP3 spec can be found at https://github.com/antirez/RESP3.

A redis client based on it is just as the below:

conn, err := net.DialTimeout("tcp", "127.0.0.1:6379", 5*time.Second)
if err != nil {
	t.Logf("can't found one of redis 6.0 server")
	return
}
defer conn.Close()

w := NewWriter(conn)
r := NewReader(conn)

// send protocol version 3, get a map result
w.WriteCommand("HELLO", "3")
resp, _, _ := r.ReadValue()
log.Printf("%v", resp.SmartResult())

// set
w.WriteCommand("SET", "A", "123")
resp, _, _ := r.ReadValue()
log.Printf("%v", resp.SmartResult())

// get
w.WriteCommand("GET", "A")
resp, _, _ = r.ReadValue()
log.Printf("%v", resp.SmartResult())

Index

Constants

View Source
const (
	TypeBlobString     = '$' // $<length>\r\n<bytes>\r\n
	TypeSimpleString   = '+' // +<string>\r\n
	TypeSimpleError    = '-' // -<string>\r\n
	TypeNumber         = ':' // :<number>\r\n
	TypeNull           = '_' // _\r\n
	TypeDouble         = ',' // ,<floating-point-number>\r\n
	TypeBoolean        = '#' // #t\r\n or #f\r\n
	TypeBlobError      = '!' // !<length>\r\n<bytes>\r\n
	TypeVerbatimString = '=' // =<length>\r\n<format(3 bytes):><bytes>\r\n
	TypeBigNumber      = '(' // (<big number>\n

	TypeArray     = '*' // *<elements number>\r\n... numelements other types ...
	TypeMap       = '%' // %<elements number>\r\n... numelements key/value pair of other types ...
	TypeSet       = '~' // ~<elements number>\r\n... numelements other types ...
	TypeAttribute = '|' // |~<elements number>\r\n... numelements map type ...
	TypePush      = '>' // ><elements number>\r\n<first item is String>\r\n... numelements-1 other types ...

	//special type
	TypeStream = "$EOF:" // $EOF:<40 bytes marker><CR><LF>... any number of bytes of data here not containing the marker ...<40 bytes marker>
)

resp3 type char

View Source
const CRLF = "\r\n"

Variables

View Source
var (
	ErrInvalidSyntax      = errors.New("resp: invalid syntax")
	ErrStreamingUnsupport = errors.New("resp: unsupported streaming")
	ErrUnknown            = errors.New("resp: unknown")
)

Errors

View Source
var CRLFByte = []byte(CRLF)
View Source
var StreamMarkerPrefix = []byte("$EOF:")

Functions

This section is empty.

Types

type Reader

type Reader struct {
	*bufio.Reader
}

Reader is reader to parse responses/requests from the underlying reader.

func NewReader

func NewReader(reader io.Reader) *Reader

NewReader returns a RESP3 reader.

func NewReaderSize

func NewReaderSize(reader io.Reader, size int) *Reader

NewReaderSize returns a new Reader whose buffer has at least the specified size.

func (*Reader) ReadRaw

func (r *Reader) ReadRaw() ([]byte, error)

ReadRaw parses a RESP3 raw byte slice.

func (*Reader) ReadValue

func (r *Reader) ReadValue() (*Value, []byte, error)

ReadValue parses a RESP3 value.

type Value

type Value struct {
	Type         byte
	Str          string
	StrFmt       string
	Err          string
	Integer      int64
	Boolean      bool
	Double       float64
	BigInt       *big.Int
	Elems        []*Value           // for array & set
	KV           *linkedhashmap.Map //TODO sorted map, for map & attr
	Attrs        *linkedhashmap.Map
	StreamMarker string
}

Value is a common struct for all RESP3 type. There is no exact field for NULL type because the type field is enough. It is not used for Stream type.

func FromString

func FromString(data string) (*Value, error)

FromString convert a string into a Value.

func (*Value) SmartResult

func (r *Value) SmartResult() interface{}

SmartResult converts itself to a real object. Attributes are dropped. simple objects are converted their Go types. String -> go string Interger -> go int64 Double -> go float64 Boolean -> go bool Err -> go string BigInt -> big.Int Array -> go array Map --> github.com/emirpasic/gods/maps/linkedhashmap.Map Set -> go array Push -> go array NULL -> nil

func (*Value) ToRESP3String

func (r *Value) ToRESP3String() string

ToRESP3String converts this value to redis RESP3 string.

type Writer

type Writer struct {
	*bufio.Writer
}

Writer is a redis client writer. he RESP3 protocol can be used asymmetrically, as it is in Redis: only a subset can be sent by the client to the server, while the server can return the full set of types available. This is due to the fact that RESP is designed to send non structured commands like SET mykey somevalue or SADD myset a b c d. Such commands can be represented as arrays, where each argument is an array element, so this is the only type the client needs to send to a server.

func NewWriter

func NewWriter(writer io.Writer) *Writer

NewWriter returns a redis client writer.

func (*Writer) WriteByteCommand

func (w *Writer) WriteByteCommand(args ...[]byte) (err error)

WriteByteCommand writes a redis command in bytes.

func (*Writer) WriteCommand

func (w *Writer) WriteCommand(args ...string) (err error)

WriteCommand writes a redis command.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL