2015-07-26 16:33:29 +02:00
|
|
|
// Copyright 2014, 2015 by Sascha L. Teichmann
|
2014-08-03 15:59:56 +02:00
|
|
|
// Use of this source code is governed by the MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2014-08-03 09:20:47 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"log"
|
|
|
|
"net"
|
2015-05-27 16:48:51 +02:00
|
|
|
"strconv"
|
2014-08-03 09:20:47 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
redisOk = []byte("+OK\r\n")
|
2015-05-26 18:12:55 +02:00
|
|
|
redisPong = []byte("+PONG\r\n")
|
2014-08-03 11:25:25 +02:00
|
|
|
redisError = []byte("-ERR\r\n")
|
2014-08-03 09:20:47 +02:00
|
|
|
redisNoSuchBlock = []byte("$-1\r\n")
|
|
|
|
redisCrnl = []byte("\r\n")
|
|
|
|
redisEmptyArray = []byte("*0\r\n")
|
|
|
|
redisQueued = []byte("+QUEUED\r\n")
|
2015-05-26 19:25:26 +02:00
|
|
|
redisTrue = []byte(":1\r\n")
|
|
|
|
redisFalse = []byte(":0\r\n")
|
2014-08-03 09:20:47 +02:00
|
|
|
)
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
type connection struct {
|
2015-03-14 19:01:00 +01:00
|
|
|
conn net.Conn
|
2024-01-07 10:54:21 +01:00
|
|
|
session session
|
2015-03-14 19:01:00 +01:00
|
|
|
maxBulkStringSize int64
|
|
|
|
boolArray []bool
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 10:54:21 +01:00
|
|
|
func newConnection(conn net.Conn, sess session, maxBulkStringSize int64) *connection {
|
2024-01-07 04:22:22 +01:00
|
|
|
return &connection{
|
2015-03-14 19:01:00 +01:00
|
|
|
conn: conn,
|
2024-01-07 10:54:21 +01:00
|
|
|
session: sess,
|
2015-03-14 19:01:00 +01:00
|
|
|
maxBulkStringSize: maxBulkStringSize,
|
|
|
|
boolArray: []bool{}}
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) run() {
|
2014-08-06 01:11:41 +02:00
|
|
|
defer func() {
|
2024-01-07 10:54:21 +01:00
|
|
|
c.session.close()
|
2014-08-06 01:11:41 +02:00
|
|
|
c.conn.Close()
|
|
|
|
}()
|
2014-08-08 13:45:24 +02:00
|
|
|
r := bufio.NewReaderSize(c.conn, 8*1024)
|
2024-01-07 11:04:29 +01:00
|
|
|
parser := newRedisParser(r, c, c.maxBulkStringSize)
|
|
|
|
parser.parse()
|
2014-08-04 15:18:32 +02:00
|
|
|
log.Println("client disconnected")
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2015-06-02 20:10:56 +02:00
|
|
|
func logError(err error) bool {
|
2015-06-21 13:17:10 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("ERROR: %s\n", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) hdel(hash, key []byte) bool {
|
2016-07-26 16:15:10 +02:00
|
|
|
|
2024-01-07 10:54:21 +01:00
|
|
|
success, err := c.session.del(hash, key)
|
2016-07-26 16:15:10 +02:00
|
|
|
if err != nil {
|
|
|
|
return c.writeError(err)
|
|
|
|
}
|
|
|
|
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeBool(success)
|
2016-07-26 16:15:10 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) hget(hash, key []byte) bool {
|
2014-08-03 11:25:25 +02:00
|
|
|
|
2014-08-03 09:20:47 +02:00
|
|
|
var err error
|
|
|
|
var data []byte
|
2024-01-07 10:54:21 +01:00
|
|
|
if data, err = c.session.fetch(hash, key); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeError(err)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
2014-08-03 11:25:25 +02:00
|
|
|
|
2014-08-03 09:20:47 +02:00
|
|
|
return c.writeBlock(data)
|
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) hset(hash, key, data []byte) bool {
|
2014-08-03 09:20:47 +02:00
|
|
|
|
|
|
|
var err error
|
2014-08-03 11:25:25 +02:00
|
|
|
var exists bool
|
2024-01-07 10:54:21 +01:00
|
|
|
if exists, err = c.session.store(hash, key, data); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeError(err)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 10:54:21 +01:00
|
|
|
if c.session.inTransaction() {
|
2014-08-03 11:25:25 +02:00
|
|
|
c.boolArray = append(c.boolArray, exists)
|
2014-08-03 09:20:47 +02:00
|
|
|
return c.writeQueued()
|
|
|
|
}
|
|
|
|
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeBool(exists)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) multi() bool {
|
2024-01-07 10:54:21 +01:00
|
|
|
if c.session.inTransaction() {
|
2014-08-03 09:20:47 +02:00
|
|
|
log.Println("WARN: Already running transaction.")
|
|
|
|
} else {
|
2024-01-07 10:54:21 +01:00
|
|
|
if err := c.session.beginTransaction(); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeError(err)
|
|
|
|
}
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
return c.writeOk()
|
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) exec() bool {
|
2024-01-07 10:54:21 +01:00
|
|
|
if !c.session.inTransaction() {
|
2014-08-03 09:20:47 +02:00
|
|
|
return c.writeEmptyArray()
|
|
|
|
}
|
2014-08-03 11:25:25 +02:00
|
|
|
arr := c.boolArray
|
|
|
|
c.boolArray = []bool{}
|
2024-01-07 10:54:21 +01:00
|
|
|
if err := c.session.commitTransaction(); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeError(err)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
2014-08-03 11:25:25 +02:00
|
|
|
return c.writeBoolArray(arr)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) hkeys(hash []byte) bool {
|
2014-08-31 19:21:58 +02:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
n int
|
2016-04-24 20:47:55 +02:00
|
|
|
keys <-chan []byte
|
2014-08-31 19:21:58 +02:00
|
|
|
done = make(chan struct{})
|
|
|
|
)
|
|
|
|
defer close(done)
|
|
|
|
|
2024-01-07 10:54:21 +01:00
|
|
|
if keys, n, err = c.session.allKeys(hash, done); err != nil {
|
2014-08-11 14:56:01 +02:00
|
|
|
return c.writeError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
return c.writeEmptyArray()
|
|
|
|
}
|
|
|
|
|
2015-05-27 16:48:51 +02:00
|
|
|
if _, err := c.conn.Write(redisLength('*', n)); err != nil {
|
2015-06-02 20:10:56 +02:00
|
|
|
return logError(err)
|
2014-08-11 14:56:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for key := range keys {
|
2014-09-01 00:19:47 +02:00
|
|
|
if err = c.writeBulkString(key); err != nil {
|
2015-06-02 20:10:56 +02:00
|
|
|
return logError(err)
|
2014-09-01 00:19:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) ping() bool {
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeMessage(redisPong)
|
2015-05-26 18:12:55 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 11:04:29 +01:00
|
|
|
func (c *connection) hSpatial(hash, first, second []byte) bool {
|
2014-09-01 00:19:47 +02:00
|
|
|
var (
|
|
|
|
err error
|
2024-01-07 10:54:21 +01:00
|
|
|
blocks <-chan block
|
2014-09-01 00:19:47 +02:00
|
|
|
done = make(chan struct{})
|
|
|
|
)
|
|
|
|
defer close(done)
|
|
|
|
|
2024-01-07 10:54:21 +01:00
|
|
|
if blocks, err = c.session.spatialQuery(hash, first, second, done); err != nil {
|
2014-09-01 00:19:47 +02:00
|
|
|
return c.writeError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for block := range blocks {
|
|
|
|
if err = c.writeBulkString(block.Key); err != nil {
|
2015-06-02 20:10:56 +02:00
|
|
|
return logError(err)
|
2014-09-01 00:19:47 +02:00
|
|
|
}
|
|
|
|
if err = c.writeBulkString(block.Data); err != nil {
|
2015-06-02 20:10:56 +02:00
|
|
|
return logError(err)
|
2014-08-11 14:56:01 +02:00
|
|
|
}
|
|
|
|
}
|
2014-09-01 00:19:47 +02:00
|
|
|
|
2015-06-21 13:17:10 +02:00
|
|
|
return logError(c.writeBulkString(nil))
|
2014-08-11 14:56:01 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeError(err error) bool {
|
2014-08-03 11:25:25 +02:00
|
|
|
logError(err)
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeMessage(redisError)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeEmptyArray() bool {
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeMessage(redisEmptyArray)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeBool(b bool) bool {
|
2014-08-03 11:25:25 +02:00
|
|
|
if b {
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeMessage(redisTrue)
|
2014-08-03 11:25:25 +02:00
|
|
|
}
|
2016-07-26 16:32:24 +02:00
|
|
|
return c.writeMessage(redisFalse)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2015-05-27 16:48:51 +02:00
|
|
|
func redisLength(prefix byte, s int) []byte {
|
|
|
|
buf := append(make([]byte, 0, 16), prefix)
|
|
|
|
return append(strconv.AppendInt(buf, int64(s), 10), '\r', '\n')
|
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeBoolArray(arr []bool) bool {
|
2015-05-27 16:48:51 +02:00
|
|
|
if _, err := c.conn.Write(redisLength('*', len(arr))); err != nil {
|
2015-06-02 20:10:56 +02:00
|
|
|
return logError(err)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
2014-08-03 11:25:25 +02:00
|
|
|
for _, b := range arr {
|
|
|
|
if !c.writeBool(b) {
|
2014-08-03 09:20:47 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeMessage(msg []byte) bool {
|
2016-07-26 16:15:10 +02:00
|
|
|
_, err := c.conn.Write(msg)
|
2015-06-21 13:17:10 +02:00
|
|
|
return logError(err)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeOk() bool {
|
2016-07-26 16:15:10 +02:00
|
|
|
return c.writeMessage(redisOk)
|
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeQueued() bool {
|
2016-07-26 16:15:10 +02:00
|
|
|
return c.writeMessage(redisQueued)
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeBlock(data []byte) bool {
|
2015-06-21 13:17:10 +02:00
|
|
|
return logError(c.writeBulkString(data))
|
2014-08-03 09:20:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-07 04:22:22 +01:00
|
|
|
func (c *connection) writeBulkString(data []byte) (err error) {
|
2014-08-03 09:20:47 +02:00
|
|
|
con := c.conn
|
|
|
|
if data == nil {
|
|
|
|
_, err = con.Write(redisNoSuchBlock)
|
|
|
|
} else {
|
2015-05-27 16:48:51 +02:00
|
|
|
if _, err = con.Write(redisLength('$', len(data))); err != nil {
|
2014-08-03 09:20:47 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if _, err = con.Write(data); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
_, err = con.Write(redisCrnl)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|