ledisdb/server/client.go

187 lines
3.3 KiB
Go
Raw Normal View History

2014-08-25 10:18:23 +04:00
package server
import (
"bytes"
// "fmt"
2014-08-25 10:18:23 +04:00
"io"
"time"
2015-05-04 17:42:28 +03:00
"github.com/siddontang/go/sync2"
"github.com/siddontang/ledisdb/ledis"
2014-08-25 10:18:23 +04:00
)
// var txUnsupportedCmds = map[string]struct{}{
// "select": struct{}{},
// "slaveof": struct{}{},
// "fullsync": struct{}{},
// "sync": struct{}{},
// "begin": struct{}{},
// "flushall": struct{}{},
// "flushdb": struct{}{},
// "eval": struct{}{},
// "xmigrate": struct{}{},
// "xmigratedb": struct{}{},
// }
// var scriptUnsupportedCmds = map[string]struct{}{
// "slaveof": struct{}{},
// "fullsync": struct{}{},
// "sync": struct{}{},
// "begin": struct{}{},
// "commit": struct{}{},
// "rollback": struct{}{},
// "flushall": struct{}{},
// "flushdb": struct{}{},
// "xmigrate": struct{}{},
// "xmigratedb": struct{}{},
// }
2014-08-25 10:18:23 +04:00
type responseWriter interface {
writeError(error)
writeStatus(string)
writeInteger(int64)
writeBulk([]byte)
writeArray([]interface{})
writeSliceArray([][]byte)
writeFVPairArray([]ledis.FVPair)
writeScorePairArray([]ledis.ScorePair, bool)
writeBulkFrom(int64, io.Reader)
flush()
}
type syncAck struct {
id uint64
ch chan uint64
}
2014-08-25 10:18:23 +04:00
type client struct {
app *App
ldb *ledis.Ledis
2014-09-02 13:55:12 +04:00
db *ledis.DB
2014-08-25 10:18:23 +04:00
remoteAddr string
cmd string
args [][]byte
2015-09-13 05:50:56 +03:00
isAuthed bool
2015-09-13 03:47:10 +03:00
2014-08-25 10:18:23 +04:00
resp responseWriter
2014-09-27 06:08:45 +04:00
syncBuf bytes.Buffer
2014-08-25 10:18:23 +04:00
2014-11-01 18:28:28 +03:00
lastLogID sync2.AtomicUint64
2014-10-30 04:03:58 +03:00
// reqErr chan error
2014-08-25 10:18:23 +04:00
buf bytes.Buffer
// tx *ledis.Tx
2014-09-25 06:44:07 +04:00
// script *ledis.Multi
2014-10-21 13:35:03 +04:00
slaveListeningAddr string
2014-08-25 10:18:23 +04:00
}
func newClient(app *App) *client {
c := new(client)
c.app = app
c.ldb = app.ldb
2015-09-13 10:13:02 +03:00
c.isAuthed = false
2014-08-25 10:18:23 +04:00
c.db, _ = app.ldb.Select(0) //use default db
return c
}
func (c *client) close() {
}
func (c *client) authEnabled() bool {
return len(c.app.cfg.AuthPassword) > 0
}
2014-08-25 10:18:23 +04:00
func (c *client) perform() {
var err error
start := time.Now()
if len(c.cmd) == 0 {
err = ErrEmptyCommand
} else if exeCmd, ok := regCmds[c.cmd]; !ok {
err = ErrNotFound
2015-09-13 05:50:56 +03:00
} else if c.authEnabled() && !c.isAuthed && c.cmd != "auth" {
2015-09-13 03:47:10 +03:00
err = ErrNotAuthenticated
2014-08-25 10:18:23 +04:00
} else {
// if c.db.IsTransaction() {
// if _, ok := txUnsupportedCmds[c.cmd]; ok {
// err = fmt.Errorf("%s not supported in transaction", c.cmd)
// }
// } else if c.db.IsInMulti() {
// if _, ok := scriptUnsupportedCmds[c.cmd]; ok {
// err = fmt.Errorf("%s not supported in multi", c.cmd)
// }
// }
// if err == nil {
// err = exeCmd(c)
// }
err = exeCmd(c)
2014-08-25 10:18:23 +04:00
}
if c.app.access != nil {
2014-10-29 19:01:19 +03:00
duration := time.Since(start)
2014-08-25 10:18:23 +04:00
fullCmd := c.catGenericCommand()
cost := duration.Nanoseconds() / 1000000
truncateLen := len(fullCmd)
if truncateLen > 256 {
truncateLen = 256
}
c.app.access.Log(c.remoteAddr, cost, fullCmd[:truncateLen], err)
}
if err != nil {
c.resp.writeError(err)
}
c.resp.flush()
return
}
func (c *client) catGenericCommand() []byte {
buffer := c.buf
buffer.Reset()
buffer.Write([]byte(c.cmd))
for _, arg := range c.args {
buffer.WriteByte(' ')
buffer.Write(arg)
}
return buffer.Bytes()
}
2014-09-02 13:55:12 +04:00
func writeValue(w responseWriter, value interface{}) {
switch v := value.(type) {
case []interface{}:
w.writeArray(v)
case [][]byte:
w.writeSliceArray(v)
case []byte:
w.writeBulk(v)
case string:
w.writeStatus(v)
case nil:
w.writeBulk(nil)
case int64:
w.writeInteger(v)
default:
panic("invalid value type")
}
}