ledisdb/server/tcp_io.go

246 lines
4.6 KiB
Go
Raw Normal View History

package server
import (
"bufio"
"errors"
"github.com/siddontang/ledisdb/ledis"
"io"
"net"
"strconv"
)
type tcpContext struct {
conn net.Conn
}
type tcpWriter struct {
buff *bufio.Writer
}
type tcpReader struct {
buff *bufio.Reader
}
// tcp context
func newTcpContext(conn net.Conn) *tcpContext {
ctx := new(tcpContext)
ctx.conn = conn
return ctx
}
func (ctx *tcpContext) addr() string {
return ctx.conn.RemoteAddr().String()
}
func (ctx *tcpContext) release() {
if ctx.conn != nil {
ctx.conn.Close()
ctx.conn = nil
}
}
// tcp reader
func newTcpReader(conn net.Conn) *tcpReader {
r := new(tcpReader)
r.buff = bufio.NewReaderSize(conn, 256)
return r
}
func (r *tcpReader) readLine() ([]byte, error) {
return ReadLine(r.buff)
}
//A client sends to the Redis server a RESP Array consisting of just Bulk Strings.
func (r *tcpReader) read() ([][]byte, error) {
l, err := r.readLine()
if err != nil {
return nil, err
} else if len(l) == 0 || l[0] != '*' {
return nil, errReadRequest
}
var nparams int
if nparams, err = strconv.Atoi(ledis.String(l[1:])); err != nil {
return nil, err
} else if nparams <= 0 {
return nil, errReadRequest
}
reqData := make([][]byte, 0, nparams)
var n int
for i := 0; i < nparams; i++ {
if l, err = r.readLine(); err != nil {
return nil, err
}
if len(l) == 0 {
return nil, errReadRequest
} else if l[0] == '$' {
//handle resp string
if n, err = strconv.Atoi(ledis.String(l[1:])); err != nil {
return nil, err
} else if n == -1 {
reqData = append(reqData, nil)
} else {
buf := make([]byte, n)
if _, err = io.ReadFull(r.buff, buf); err != nil {
return nil, err
}
if l, err = r.readLine(); err != nil {
return nil, err
} else if len(l) != 0 {
return nil, errors.New("bad bulk string format")
}
reqData = append(reqData, buf)
}
} else {
return nil, errReadRequest
}
}
return reqData, nil
}
// tcp writer
func newTcpWriter(conn net.Conn) *tcpWriter {
w := new(tcpWriter)
w.buff = bufio.NewWriterSize(conn, 256)
return w
}
func (w *tcpWriter) writeError(err error) {
w.buff.Write(ledis.Slice("-ERR"))
if err != nil {
w.buff.WriteByte(' ')
w.buff.Write(ledis.Slice(err.Error()))
}
w.buff.Write(Delims)
}
func (w *tcpWriter) writeStatus(status string) {
w.buff.WriteByte('+')
w.buff.Write(ledis.Slice(status))
w.buff.Write(Delims)
}
func (w *tcpWriter) writeInteger(n int64) {
w.buff.WriteByte(':')
w.buff.Write(ledis.StrPutInt64(n))
w.buff.Write(Delims)
}
func (w *tcpWriter) writeBulk(b []byte) {
w.buff.WriteByte('$')
if b == nil {
w.buff.Write(NullBulk)
} else {
w.buff.Write(ledis.Slice(strconv.Itoa(len(b))))
w.buff.Write(Delims)
w.buff.Write(b)
}
w.buff.Write(Delims)
}
func (w *tcpWriter) writeArray(lst []interface{}) {
w.buff.WriteByte('*')
if lst == nil {
w.buff.Write(NullArray)
w.buff.Write(Delims)
} else {
w.buff.Write(ledis.Slice(strconv.Itoa(len(lst))))
w.buff.Write(Delims)
for i := 0; i < len(lst); i++ {
switch v := lst[i].(type) {
case []interface{}:
w.writeArray(v)
case []byte:
w.writeBulk(v)
case nil:
w.writeBulk(nil)
case int64:
w.writeInteger(v)
default:
panic("invalid array type")
}
}
}
}
func (w *tcpWriter) writeSliceArray(lst [][]byte) {
w.buff.WriteByte('*')
if lst == nil {
w.buff.Write(NullArray)
w.buff.Write(Delims)
} else {
w.buff.Write(ledis.Slice(strconv.Itoa(len(lst))))
w.buff.Write(Delims)
for i := 0; i < len(lst); i++ {
w.writeBulk(lst[i])
}
}
}
func (w *tcpWriter) writeFVPairArray(lst []ledis.FVPair) {
w.buff.WriteByte('*')
if lst == nil {
w.buff.Write(NullArray)
w.buff.Write(Delims)
} else {
w.buff.Write(ledis.Slice(strconv.Itoa(len(lst) * 2)))
w.buff.Write(Delims)
for i := 0; i < len(lst); i++ {
w.writeBulk(lst[i].Field)
w.writeBulk(lst[i].Value)
}
}
}
func (w *tcpWriter) writeScorePairArray(lst []ledis.ScorePair, withScores bool) {
w.buff.WriteByte('*')
if lst == nil {
w.buff.Write(NullArray)
w.buff.Write(Delims)
} else {
if withScores {
w.buff.Write(ledis.Slice(strconv.Itoa(len(lst) * 2)))
w.buff.Write(Delims)
} else {
w.buff.Write(ledis.Slice(strconv.Itoa(len(lst))))
w.buff.Write(Delims)
}
for i := 0; i < len(lst); i++ {
w.writeBulk(lst[i].Member)
if withScores {
w.writeBulk(ledis.StrPutInt64(lst[i].Score))
}
}
}
}
func (w *tcpWriter) writeBulkFrom(n int64, rb io.Reader) {
w.buff.WriteByte('$')
w.buff.Write(ledis.Slice(strconv.FormatInt(n, 10)))
w.buff.Write(Delims)
io.Copy(w.buff, rb)
w.buff.Write(Delims)
}
func (w *tcpWriter) flush() {
w.buff.Flush()
}