mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-11-08 11:10:27 +01:00
Factored connection handling into separate file.
This commit is contained in:
parent
8a8351e8c1
commit
095164a6c8
206
connection.go
Normal file
206
connection.go
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
leveldb "github.com/jmhodges/levigo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
redisOk = []byte("+OK\r\n")
|
||||||
|
redisDbError = []byte("-FAIL\r\n")
|
||||||
|
redisNoSuchBlock = []byte("$-1\r\n")
|
||||||
|
redisCrnl = []byte("\r\n")
|
||||||
|
redisEmptyArray = []byte("*0\r\n")
|
||||||
|
redisQueued = []byte("+QUEUED\r\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
conn net.Conn
|
||||||
|
db *leveldb.DB
|
||||||
|
tx *leveldb.WriteBatch
|
||||||
|
intArray []int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnection(conn net.Conn, db *leveldb.DB) *Connection {
|
||||||
|
return &Connection{
|
||||||
|
conn,
|
||||||
|
db,
|
||||||
|
nil,
|
||||||
|
[]int{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Run() {
|
||||||
|
defer c.conn.Close()
|
||||||
|
rce := NewRedisCommandExecutor(c)
|
||||||
|
r := bufio.NewReader(c.conn)
|
||||||
|
parser := NewRedisParser(r, rce)
|
||||||
|
parser.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func logError(err error) {
|
||||||
|
log.Printf("ERROR: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Hget(hash, key []byte) bool {
|
||||||
|
log.Printf("client requested block: %q", key)
|
||||||
|
var err error
|
||||||
|
var data []byte
|
||||||
|
ro := leveldb.NewReadOptions()
|
||||||
|
defer ro.Close()
|
||||||
|
if data, err = c.db.Get(ro, key); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return c.writeError()
|
||||||
|
}
|
||||||
|
return c.writeBlock(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Hset(hash, key, block []byte) bool {
|
||||||
|
log.Printf("client wants to store block: %q", key)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var exists int
|
||||||
|
|
||||||
|
if exists, err = c.keyExists(key); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return c.writeError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.tx != nil {
|
||||||
|
c.tx.Put(key, block)
|
||||||
|
c.intArray = append(c.intArray, exists)
|
||||||
|
return c.writeQueued()
|
||||||
|
}
|
||||||
|
|
||||||
|
wo := leveldb.NewWriteOptions()
|
||||||
|
defer wo.Close()
|
||||||
|
if err = c.db.Put(wo, key, block); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return c.writeError()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.writeInteger(exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) keyExists(key []byte) (exists int, err error) {
|
||||||
|
ro := leveldb.NewReadOptions()
|
||||||
|
defer ro.Close()
|
||||||
|
var data []byte
|
||||||
|
if data, err = c.db.Get(ro, key); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if data != nil {
|
||||||
|
exists = 1
|
||||||
|
} else {
|
||||||
|
exists = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Multi() bool {
|
||||||
|
if c.tx != nil {
|
||||||
|
log.Println("WARN: Already running transaction.")
|
||||||
|
} else {
|
||||||
|
c.tx = leveldb.NewWriteBatch()
|
||||||
|
}
|
||||||
|
return c.writeOk()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Exec() bool {
|
||||||
|
var err error
|
||||||
|
if c.tx == nil {
|
||||||
|
return c.writeEmptyArray()
|
||||||
|
}
|
||||||
|
tx := c.tx
|
||||||
|
c.tx = nil
|
||||||
|
defer tx.Close()
|
||||||
|
arr := c.intArray
|
||||||
|
c.intArray = []int{}
|
||||||
|
wo := leveldb.NewWriteOptions()
|
||||||
|
defer wo.Close()
|
||||||
|
if err = c.db.Write(wo, tx); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return c.writeError()
|
||||||
|
}
|
||||||
|
return c.writeIntegerArray(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeError() bool {
|
||||||
|
if _, err := c.conn.Write(redisDbError); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeEmptyArray() bool {
|
||||||
|
if _, err := c.conn.Write(redisDbError); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeInteger(v int) bool {
|
||||||
|
if _, err := c.conn.Write([]byte(fmt.Sprintf(":%d\r\n", v))); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeIntegerArray(arr []int) bool {
|
||||||
|
if _, err := c.conn.Write([]byte(fmt.Sprintf("*%d\r\n", len(arr)))); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for x := range arr {
|
||||||
|
if !c.writeInteger(x) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeOk() bool {
|
||||||
|
if _, err := c.conn.Write(redisOk); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeQueued() bool {
|
||||||
|
if _, err := c.conn.Write(redisQueued); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeBlock(data []byte) bool {
|
||||||
|
if err := c.writeBulkString(data); err != nil {
|
||||||
|
logError(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) writeBulkString(data []byte) (err error) {
|
||||||
|
con := c.conn
|
||||||
|
if data == nil {
|
||||||
|
_, err = con.Write(redisNoSuchBlock)
|
||||||
|
} else {
|
||||||
|
if _, err = con.Write([]byte(fmt.Sprintf("$%d\r\n", len(data)))); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err = con.Write(data); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = con.Write(redisCrnl)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
194
main.go
194
main.go
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
@ -12,197 +11,6 @@ import (
|
||||||
leveldb "github.com/jmhodges/levigo"
|
leveldb "github.com/jmhodges/levigo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type connection struct {
|
|
||||||
conn net.Conn
|
|
||||||
db *leveldb.DB
|
|
||||||
tx *leveldb.WriteBatch
|
|
||||||
intArray []int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newConnection(conn net.Conn, db *leveldb.DB) *connection {
|
|
||||||
return &connection{
|
|
||||||
conn,
|
|
||||||
db,
|
|
||||||
nil,
|
|
||||||
[]int{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) run() {
|
|
||||||
defer c.conn.Close()
|
|
||||||
rce := NewRedisCommandExecutor(c)
|
|
||||||
r := bufio.NewReader(c.conn)
|
|
||||||
parser := NewRedisParser(r, rce)
|
|
||||||
parser.Parse()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Hget(hash, key []byte) bool {
|
|
||||||
log.Printf("client requested block: %q", key)
|
|
||||||
var err error
|
|
||||||
var data []byte
|
|
||||||
ro := leveldb.NewReadOptions()
|
|
||||||
defer ro.Close()
|
|
||||||
if data, err = c.db.Get(ro, key); err != nil {
|
|
||||||
log.Printf("Something is wrong with db: %s", err)
|
|
||||||
return c.writeError()
|
|
||||||
}
|
|
||||||
return c.writeBlock(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Hset(hash, key, block []byte) bool {
|
|
||||||
log.Printf("client wants to store block: %q", key)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
var exists int
|
|
||||||
|
|
||||||
if exists, err = c.keyExists(key); err != nil {
|
|
||||||
log.Printf("Something is wrong with db: %s", err)
|
|
||||||
return c.writeError()
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.tx != nil {
|
|
||||||
c.tx.Put(key, block)
|
|
||||||
c.intArray = append(c.intArray, exists)
|
|
||||||
return c.writeQueued()
|
|
||||||
}
|
|
||||||
|
|
||||||
wo := leveldb.NewWriteOptions()
|
|
||||||
defer wo.Close()
|
|
||||||
if err = c.db.Put(wo, key, block); err != nil {
|
|
||||||
log.Printf("Something is wrong with db: %s", err)
|
|
||||||
return c.writeError()
|
|
||||||
}
|
|
||||||
return c.writeInteger(exists)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) keyExists(key []byte) (exists int, err error) {
|
|
||||||
ro := leveldb.NewReadOptions()
|
|
||||||
defer ro.Close()
|
|
||||||
var data []byte
|
|
||||||
if data, err = c.db.Get(ro, key); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if data != nil {
|
|
||||||
exists = 1
|
|
||||||
} else {
|
|
||||||
exists = 0
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Multi() bool {
|
|
||||||
if c.tx != nil {
|
|
||||||
log.Println("WARN: Already running transaction.")
|
|
||||||
} else {
|
|
||||||
c.tx = leveldb.NewWriteBatch()
|
|
||||||
}
|
|
||||||
return c.writeOk()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Exec() bool {
|
|
||||||
var err error
|
|
||||||
if c.tx == nil {
|
|
||||||
return c.writeEmptyArray()
|
|
||||||
}
|
|
||||||
tx := c.tx
|
|
||||||
c.tx = nil
|
|
||||||
defer tx.Close()
|
|
||||||
arr := c.intArray
|
|
||||||
c.intArray = []int{}
|
|
||||||
wo := leveldb.NewWriteOptions()
|
|
||||||
defer wo.Close()
|
|
||||||
if err = c.db.Write(wo, tx); err != nil {
|
|
||||||
log.Printf("Something went wrong in writing transaction: %s", err)
|
|
||||||
return c.writeError()
|
|
||||||
}
|
|
||||||
return c.writeIntegerArray(arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
redisOk = []byte("+OK\r\n")
|
|
||||||
redisDbError = []byte("-FAIL\r\n")
|
|
||||||
redisNoSuchBlock = []byte("$-1\r\n")
|
|
||||||
redisCrnl = []byte("\r\n")
|
|
||||||
redisEmptyArray = []byte("*0\r\n")
|
|
||||||
redisQueued = []byte("+QUEUED\r\n")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *connection) writeError() bool {
|
|
||||||
if _, err := c.conn.Write(redisDbError); err != nil {
|
|
||||||
log.Printf("Something went wrong writing to client %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeEmptyArray() bool {
|
|
||||||
if _, err := c.conn.Write(redisDbError); err != nil {
|
|
||||||
log.Printf("Writing message to client failed: %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeInteger(v int) bool {
|
|
||||||
if _, err := c.conn.Write([]byte(fmt.Sprintf(":%d\r\n", v))); err != nil {
|
|
||||||
log.Printf("Writing message to client failed: %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeIntegerArray(arr []int) bool {
|
|
||||||
if _, err := c.conn.Write([]byte(fmt.Sprintf("*%d\r\n", len(arr)))); err != nil {
|
|
||||||
log.Printf("Writing message to client failed: %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for x := range arr {
|
|
||||||
if !c.writeInteger(x) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeOk() bool {
|
|
||||||
if _, err := c.conn.Write(redisOk); err != nil {
|
|
||||||
log.Printf("Something went wrong writing to client %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeQueued() bool {
|
|
||||||
if _, err := c.conn.Write(redisQueued); err != nil {
|
|
||||||
log.Printf("Something went wrong writing to client %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeBlock(data []byte) bool {
|
|
||||||
if err := c.writeBulkString(data); err != nil {
|
|
||||||
log.Printf("Something went wrong writing to client %s", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) writeBulkString(data []byte) (err error) {
|
|
||||||
con := c.conn
|
|
||||||
if data == nil {
|
|
||||||
_, err = con.Write(redisNoSuchBlock)
|
|
||||||
} else {
|
|
||||||
if _, err = con.Write([]byte(fmt.Sprintf("$%d\r\n", len(data)))); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err = con.Write(data); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = con.Write(redisCrnl)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var port int
|
var port int
|
||||||
|
@ -263,7 +71,7 @@ func main() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case conn := <-connChan:
|
case conn := <-connChan:
|
||||||
go newConnection(conn, db).run()
|
go NewConnection(conn, db).Run()
|
||||||
case <-sigChan:
|
case <-sigChan:
|
||||||
log.Println("Shutting down")
|
log.Println("Shutting down")
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue
Block a user