redcon

package module
v0.9.1 Latest Latest
Warning

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

Go to latest
Published: May 27, 2020 License: MIT Imports: 10 Imported by: 6

README

REDCON
Build Status GoDoc

Fast Redis compatible server framework for Go

cloned from tidwall/redcon but have add some features independently.

Features

  • Create a Fast custom Redis compatible server in Go
  • Simple interface. One function ListenAndServe and two types Conn & Command
  • Support for pipelining and telnet commands
  • Works with Redis clients such as redigo, redis-py, node_redis, and jedis
  • TLS Support

Installing

go get -u github.com/smallnest/redcon

Example

Here's a full example of a Redis clone that accepts:

  • SET key value
  • GET key
  • DEL key
  • PING
  • QUIT

You can run this example from a terminal:

package main

import (
	"log"
	"strings"
	"sync"

	"github.com/smallnest/redcon"
)

var addr = ":6380"

func main() {
	var mu sync.RWMutex
	var items = make(map[string][]byte)
	go log.Printf("started server at %s", addr)
	err := redcon.ListenAndServe(addr,
		func(conn redcon.Conn, cmd redcon.Command) {
			switch strings.ToLower(string(cmd.Args[0])) {
			default:
				conn.WriteError("ERR unknown command '" + string(cmd.Args[0]) + "'")
			case "ping":
				conn.WriteString("PONG")
			case "quit":
				conn.WriteString("OK")
				conn.Close()
			case "set":
				if len(cmd.Args) != 3 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.Lock()
				items[string(cmd.Args[1])] = cmd.Args[2]
				mu.Unlock()
				conn.WriteString("OK")
			case "get":
				if len(cmd.Args) != 2 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.RLock()
				val, ok := items[string(cmd.Args[1])]
				mu.RUnlock()
				if !ok {
					conn.WriteNull()
				} else {
					conn.WriteBulk(val)
				}
			case "del":
				if len(cmd.Args) != 2 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.Lock()
				_, ok := items[string(cmd.Args[1])]
				delete(items, string(cmd.Args[1]))
				mu.Unlock()
				if !ok {
					conn.WriteInt(0)
				} else {
					conn.WriteInt(1)
				}
			}
		},
		func(conn redcon.Conn) bool {
			// use this function to accept or deny the connection.
			// log.Printf("accept: %s", conn.RemoteAddr())
			return true
		},
		func(conn redcon.Conn, err error) {
			// this is called when the connection has been closed
			// log.Printf("closed: %s, err: %v", conn.RemoteAddr(), err)
		},
	)
	if err != nil {
		log.Fatal(err)
	}
}

License

Redcon source code is available under the MIT License.

Documentation

Overview

Package redcon implements a Redis compatible server framework

Index

Constants

This section is empty.

Variables

View Source
var (
	InitReaderBufferSize = 40960
)

Functions

func AppendArray

func AppendArray(b []byte, n int) []byte

AppendArray appends a Redis protocol array to the input bytes.

func AppendBulk

func AppendBulk(b []byte, bulk []byte) []byte

AppendBulk appends a Redis protocol bulk byte slice to the input bytes.

func AppendBulkString

func AppendBulkString(b []byte, bulk string) []byte

AppendBulkString appends a Redis protocol bulk string to the input bytes.

func AppendError

func AppendError(b []byte, s string) []byte

AppendError appends a Redis protocol error to the input bytes.

func AppendInt

func AppendInt(b []byte, n int64) []byte

AppendInt appends a Redis protocol int64 to the input bytes.

func AppendNull

func AppendNull(b []byte) []byte

AppendNull appends a Redis protocol null to the input bytes.

func AppendOK

func AppendOK(b []byte) []byte

AppendOK appends a Redis protocol OK to the input bytes.

func AppendString

func AppendString(b []byte, s string) []byte

AppendString appends a Redis protocol string to the input bytes.

func AppendTile38

func AppendTile38(b []byte, data []byte) []byte

AppendTile38 appends a Tile38 message to the input bytes.

func AppendUint

func AppendUint(b []byte, n uint64) []byte

AppendUint appends a Redis protocol uint64 to the input bytes.

func ListenAndServe

func ListenAndServe(addr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
) error

ListenAndServe creates a new server and binds to addr configured on "tcp" network net.

func ListenAndServeNetwork

func ListenAndServeNetwork(
	net, laddr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
) error

ListenAndServeNetwork creates a new server and binds to addr. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket"

func ListenAndServeNetworkTLS

func ListenAndServeNetworkTLS(
	net, laddr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
	config *tls.Config,
) error

ListenAndServeNetworkTLS creates a new TLS server and binds to addr. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket"

func ListenAndServeTLS

func ListenAndServeTLS(addr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
	config *tls.Config,
) error

ListenAndServeTLS creates a new TLS server and binds to addr configured on "tcp" network net.

func NewNonBlockingReader added in v0.9.1

func NewNonBlockingReader(conn net.Conn) net.Conn

NewNonBlockingReader returns a non-blocking reader for net.Conn.

func Serve added in v0.9.1

func Serve(ln net.Listener,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
) error

Serve creates a new server and serves with the given net.Listener.

Types

type Command

type Command struct {
	// Raw is a encoded RESP message.
	Raw []byte
	// Args is a series of arguments that make up the command.
	Args [][]byte

	Time  int64
	ATime int64 //再次发送时的时间
	// contains filtered or unexported fields
}

Command represent a command

func Parse

func Parse(raw []byte) (Command, error)

Parse parses a raw RESP message and returns a command.

func (Command) GetAllArgs added in v0.9.1

func (c Command) GetAllArgs() [][]byte

func (Command) GetArgCount added in v0.9.1

func (c Command) GetArgCount() int

GetArgCount get count of args.

func (Command) GetArgs added in v0.9.1

func (c Command) GetArgs(i int) []byte

GetArgs get args for zero allocations for args.

type Conn

type Conn interface {
	// RemoteAddr returns the remote address of the client connection.
	RemoteAddr() string
	// Close closes the connection.
	Close() error
	// WriteError writes an error to the client.
	WriteError(msg string)
	// WriteString writes a string to the client.
	WriteString(str string)
	// WriteBulk writes bulk bytes to the client.
	WriteBulk(bulk []byte)
	// WriteBulkString writes a bulk string to the client.
	WriteBulkString(bulk string)
	// WriteInt writes an integer to the client.
	WriteInt(num int)
	// WriteInt64 writes a 64-but signed integer to the client.
	WriteInt64(num int64)
	// WriteArray writes an array header. You must then write additional
	// sub-responses to the client to complete the response.
	// For example to write two strings:
	//
	//   c.WriteArray(2)
	//   c.WriteBulk("item 1")
	//   c.WriteBulk("item 2")
	WriteArray(count int)
	// WriteNull writes a null to the client
	WriteNull()
	// WriteRaw writes raw data to the client.
	WriteRaw(data []byte)
	// Context returns a user-defined context
	Context() interface{}
	// SetContext sets a user-defined context
	SetContext(v interface{})
	// SetReadBuffer updates the buffer read size for the connection
	SetReadBuffer(bytes int)
	// Detach return a connection that is detached from the server.
	// Useful for operations like PubSub.
	//
	//   dconn := conn.Detach()
	//   go func(){
	//       defer dconn.Close()
	//       cmd, err := dconn.ReadCommand()
	//       if err != nil{
	//           fmt.Printf("read failed: %v\n", err)
	//	         return
	//       }
	//       fmt.Printf("received command: %v", cmd)
	//       hconn.WriteString("OK")
	//       if err := dconn.Flush(); err != nil{
	//           fmt.Printf("write failed: %v\n", err)
	//	         return
	//       }
	//   }()
	Detach() DetachedConn
	// ReadPipeline returns all commands in current pipeline, if any
	// The commands are removed from the pipeline.
	ReadPipeline() []Command
	// PeekPipeline returns all commands in current pipeline, if any.
	// The commands remain in the pipeline.
	PeekPipeline() []Command
	// NetConn returns the base net.Conn connection
	NetConn() net.Conn
}

Conn represents a client connection

type DetachedConn

type DetachedConn interface {
	// Conn is the original connection
	Conn
	// ReadCommand reads the next client command.
	ReadCommand() (Command, error)
	// Flush flushes any writes to the network.
	Flush() error
}

DetachedConn represents a connection that is detached from the server

type Kind

type Kind int

Kind is the kind of command

const (
	// Redis is returned for Redis protocol commands
	Redis Kind = iota
	// Tile38 is returnd for Tile38 native protocol commands
	Tile38
	// Telnet is returnd for plain telnet commands
	Telnet
)

func ReadNextCommand

func ReadNextCommand(packet []byte, argsbuf [][]byte) (
	complete bool, args [][]byte, kind Kind, leftover []byte, err error,
)

ReadNextCommand reads the next command from the provided packet. It's possible that the packet contains multiple commands, or zero commands when the packet is incomplete. 'argsbuf' is an optional reusable buffer and it can be nil. 'complete' indicates that a command was read. false means no more commands. 'args' are the output arguments for the command. 'kind' is the type of command that was read. 'leftover' is any remaining unused bytes which belong to the next command. 'err' is returned when a protocol error was encountered.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader represent a reader for RESP or telnet commands.

func NewReader

func NewReader(rd io.Reader) *Reader

NewReader returns a command reader which will read RESP or telnet commands.

func (*Reader) ReadCommand

func (rd *Reader) ReadCommand() (Command, error)

ReadCommand reads the next command.

func (*Reader) ReadCommands added in v0.9.1

func (rd *Reader) ReadCommands() ([]Command, error)

ReadCommands reads multiple commands for pipeline mode.

func (*Reader) ReadRefCommand added in v0.9.1

func (rd *Reader) ReadRefCommand() (*Command, error)

ReadCommand reads the next command.

func (*Reader) ReadRefCommands added in v0.9.1

func (rd *Reader) ReadRefCommands() ([]*Command, error)

ReadCommands reads multiple commands for pipeline mode.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server defines a server for clients for managing client connections.

func NewServer

func NewServer(addr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
) *Server

NewServer returns a new Redcon server configured on "tcp" network net.

func NewServerNetwork

func NewServerNetwork(
	net, laddr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
) *Server

NewServerNetwork returns a new Redcon server. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket"

func (*Server) Addr

func (s *Server) Addr() net.Addr

Addr returns server's listen address

func (*Server) Close

func (s *Server) Close() error

Close stops listening on the TCP address. Already Accepted connections will be closed.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe serves incoming connections.

func (*Server) ListenServeAndSignal

func (s *Server) ListenServeAndSignal(signal chan error) error

ListenServeAndSignal serves incoming connections and passes nil or error when listening. signal can be nil.

func (*Server) Serve added in v0.9.1

func (s *Server) Serve(ln net.Listener) error

Serve serves incoming connections with the given net.Listener.

type TLSServer

type TLSServer struct {
	*Server
	// contains filtered or unexported fields
}

TLSServer defines a server for clients for managing client connections.

func NewServerNetworkTLS

func NewServerNetworkTLS(
	net, laddr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
	config *tls.Config,
) *TLSServer

NewServerNetworkTLS returns a new TLS Redcon server. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket"

func NewServerTLS

func NewServerTLS(addr string,
	handler func(conn Conn, cmd Command),
	accept func(conn Conn) bool,
	closed func(conn Conn, err error),
	config *tls.Config,
) *TLSServer

NewServerTLS returns a new Redcon TLS server configured on "tcp" network net.

func (*TLSServer) Close

func (s *TLSServer) Close() error

Close stops listening on the TCP address. Already Accepted connections will be closed.

func (*TLSServer) ListenAndServe

func (s *TLSServer) ListenAndServe() error

ListenAndServe serves incoming connections.

func (*TLSServer) ListenServeAndSignal

func (s *TLSServer) ListenServeAndSignal(signal chan error) error

ListenServeAndSignal serves incoming connections and passes nil or error when listening. signal can be nil.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer allows for writing RESP messages.

func BaseWriter

func BaseWriter(c Conn) *Writer

BaseWriter returns the underlying connection writer, if any

func NewWriter

func NewWriter(wr io.Writer) *Writer

NewWriter creates a new RESP writer.

func (*Writer) Buffer

func (w *Writer) Buffer() []byte

Buffer returns the unflushed buffer. This is a copy so changes to the resulting []byte will not affect the writer.

func (*Writer) Flush

func (w *Writer) Flush() error

Flush writes all unflushed Write* calls to the underlying writer.

func (*Writer) SetBuffer

func (w *Writer) SetBuffer(raw []byte)

SetBuffer replaces the unflushed buffer with new bytes.

func (*Writer) WriteArray

func (w *Writer) WriteArray(count int)

WriteArray writes an array header. You must then write additional sub-responses to the client to complete the response. For example to write two strings:

c.WriteArray(2)
c.WriteBulk("item 1")
c.WriteBulk("item 2")

func (*Writer) WriteBulk

func (w *Writer) WriteBulk(bulk []byte)

WriteBulk writes bulk bytes to the client.

func (*Writer) WriteBulkString

func (w *Writer) WriteBulkString(bulk string)

WriteBulkString writes a bulk string to the client.

func (*Writer) WriteError

func (w *Writer) WriteError(msg string)

WriteError writes an error to the client.

func (*Writer) WriteInt

func (w *Writer) WriteInt(num int)

WriteInt writes an integer to the client.

func (*Writer) WriteInt64

func (w *Writer) WriteInt64(num int64)

WriteInt64 writes a 64-bit signed integer to the client.

func (*Writer) WriteNull

func (w *Writer) WriteNull()

WriteNull writes a null to the client

func (*Writer) WriteRaw

func (w *Writer) WriteRaw(data []byte)

WriteRaw writes raw data to the client.

func (*Writer) WriteString

func (w *Writer) WriteString(msg string)

WriteString writes a string to the client.

Jump to

Keyboard shortcuts

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