Skip to content

Instantly share code, notes, and snippets.

@rbrick
Last active November 19, 2018 01:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbrick/16b3d5ba711dea0f9a1089170a0c0375 to your computer and use it in GitHub Desktop.
Save rbrick/16b3d5ba711dea0f9a1089170a0c0375 to your computer and use it in GitHub Desktop.
a minimal implementation of RESP/Redis client
package main
import (
"bytes"
"errors"
"fmt"
"io"
)
const (
SimpleString = byte('+')
Error = byte('-')
Integer = byte(':')
BulkString = byte('$')
Array = byte('*')
)
var Terminator = []byte{'\r', '\n'}
var (
ErrNull = errors.New("null value")
ErrNotArray = errors.New("not an array")
)
type ValueEncoder interface {
Encode(value interface{}, w io.Writer) error
}
type SimpleStringEncoder struct{}
func (*SimpleStringEncoder) Encode(value interface{}, w io.Writer) error {
if value == nil {
return ErrNull
}
message := []byte{SimpleString}
message = append(message, []byte(fmt.Sprint(value))...)
message = append(message, Terminator...)
_, err := w.Write(message)
return err
}
type BulkStringEncoder struct{}
func (*BulkStringEncoder) Encode(value interface{}, w io.Writer) error {
if value == nil {
return ErrNull
}
v := fmt.Sprint(value)
message := []byte{BulkString}
message = append(message, []byte(fmt.Sprintf("%d%s", len(v), Terminator))...)
message = append(message, []byte(v)...)
message = append(message, Terminator...)
_, err := w.Write(message)
return err
}
type ArrayEncoder struct{}
func (*ArrayEncoder) Encode(value interface{}, w io.Writer) error {
if value == nil {
return ErrNull
}
array := value.([]interface{})
message := []byte{Array}
message = append(message, []byte(fmt.Sprintf("%d%s", len(array), Terminator))...)
// todo: interpret these better
encoder := BulkStringEncoder{}
for _, v := range array {
w := bytes.NewBuffer([]byte{})
encoder.Encode(v, w)
message = append(message, w.Bytes()...)
}
_, err := w.Write(message)
return err
}
package main
import (
"log"
"net"
)
type Client struct {
conn net.Conn
}
func (c *Client) SendCommand(args ...interface{}) {
encoder := ArrayEncoder{}
encoder.Encode(args, c.conn)
}
func main() {
conn, err := net.Dial("tcp", ":6379")
if err != nil {
log.Fatalln(err)
}
c := Client{conn}
c.SendCommand( "PUBLISH", "test", "Hello, World" )
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment