forked from mirror/redcon
commit
56fff5d1ec
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/tidwall/redcon"
|
||||
)
|
||||
|
||||
var addr = ":6380"
|
||||
|
||||
func main() {
|
||||
log.Printf("started server at %s", addr)
|
||||
|
||||
handler := NewHandler()
|
||||
|
||||
mux := redcon.NewServeMux()
|
||||
mux.HandleFunc("detach", handler.detach)
|
||||
mux.HandleFunc("ping", handler.ping)
|
||||
mux.HandleFunc("quit", handler.quit)
|
||||
mux.HandleFunc("set", handler.set)
|
||||
mux.HandleFunc("get", handler.get)
|
||||
mux.HandleFunc("del", handler.delete)
|
||||
|
||||
err := redcon.ListenAndServe(addr,
|
||||
mux.ServeRESP,
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/tidwall/redcon"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
itemsMux sync.RWMutex
|
||||
items map[string][]byte
|
||||
}
|
||||
|
||||
func NewHandler() *Handler {
|
||||
return &Handler{
|
||||
items: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) detach(conn redcon.Conn, cmd redcon.Command) {
|
||||
detachedConn := conn.Detach()
|
||||
log.Printf("connection has been detached")
|
||||
go func(c redcon.DetachedConn) {
|
||||
defer c.Close()
|
||||
|
||||
c.WriteString("OK")
|
||||
c.Flush()
|
||||
}(detachedConn)
|
||||
}
|
||||
|
||||
func (h *Handler) ping(conn redcon.Conn, cmd redcon.Command) {
|
||||
conn.WriteString("PONG")
|
||||
}
|
||||
|
||||
func (h *Handler) quit(conn redcon.Conn, cmd redcon.Command) {
|
||||
conn.WriteString("OK")
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
func (h *Handler) set(conn redcon.Conn, cmd redcon.Command) {
|
||||
if len(cmd.Args) != 3 {
|
||||
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
|
||||
return
|
||||
}
|
||||
|
||||
h.itemsMux.Lock()
|
||||
h.items[string(cmd.Args[1])] = cmd.Args[2]
|
||||
h.itemsMux.Unlock()
|
||||
|
||||
conn.WriteString("OK")
|
||||
}
|
||||
|
||||
func (h *Handler) get(conn redcon.Conn, cmd redcon.Command) {
|
||||
if len(cmd.Args) != 2 {
|
||||
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
|
||||
return
|
||||
}
|
||||
|
||||
h.itemsMux.RLock()
|
||||
val, ok := h.items[string(cmd.Args[1])]
|
||||
h.itemsMux.RUnlock()
|
||||
|
||||
if !ok {
|
||||
conn.WriteNull()
|
||||
} else {
|
||||
conn.WriteBulk(val)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) delete(conn redcon.Conn, cmd redcon.Command) {
|
||||
if len(cmd.Args) != 2 {
|
||||
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
|
||||
return
|
||||
}
|
||||
|
||||
h.itemsMux.Lock()
|
||||
_, ok := h.items[string(cmd.Args[1])]
|
||||
delete(h.items, string(cmd.Args[1]))
|
||||
h.itemsMux.Unlock()
|
||||
|
||||
if !ok {
|
||||
conn.WriteInt(0)
|
||||
} else {
|
||||
conn.WriteInt(1)
|
||||
}
|
||||
}
|
64
redcon.go
64
redcon.go
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -900,3 +901,66 @@ func Parse(raw []byte) (Command, error) {
|
|||
return cmds[0], nil
|
||||
|
||||
}
|
||||
|
||||
// A Handler responds to an RESP request.
|
||||
type Handler interface {
|
||||
ServeRESP(conn Conn, cmd Command)
|
||||
}
|
||||
|
||||
// The HandlerFunc type is an adapter to allow the use of
|
||||
// ordinary functions as RESP handlers. If f is a function
|
||||
// with the appropriate signature, HandlerFunc(f) is a
|
||||
// Handler that calls f.
|
||||
type HandlerFunc func(conn Conn, cmd Command)
|
||||
|
||||
// ServeRESP calls f(w, r)
|
||||
func (f HandlerFunc) ServeRESP(conn Conn, cmd Command) {
|
||||
f(conn, cmd)
|
||||
}
|
||||
|
||||
// ServeMux is an RESP command multiplexer.
|
||||
type ServeMux struct {
|
||||
handlers map[string]Handler
|
||||
}
|
||||
|
||||
// NewServeMux allocates and returns a new ServeMux.
|
||||
func NewServeMux() *ServeMux {
|
||||
return &ServeMux{
|
||||
handlers: make(map[string]Handler),
|
||||
}
|
||||
}
|
||||
|
||||
// HandleFunc registers the handler function for the given command.
|
||||
func (m *ServeMux) HandleFunc(command string, handler func(conn Conn, cmd Command)) {
|
||||
if handler == nil {
|
||||
panic("redcon: nil handler")
|
||||
}
|
||||
m.Handle(command, HandlerFunc(handler))
|
||||
}
|
||||
|
||||
// Handle registers the handler for the given command.
|
||||
// If a handler already exists for command, Handle panics.
|
||||
func (m *ServeMux) Handle(command string, handler Handler) {
|
||||
if command == "" {
|
||||
panic("redcon: invalid command")
|
||||
}
|
||||
if handler == nil {
|
||||
panic("redcon: nil handler")
|
||||
}
|
||||
if _, exist := m.handlers[command]; exist {
|
||||
panic("redcon: multiple registrations for " + command)
|
||||
}
|
||||
|
||||
m.handlers[command] = handler
|
||||
}
|
||||
|
||||
// ServeRESP dispatches the command to the handler.
|
||||
func (m *ServeMux) ServeRESP(conn Conn, cmd Command) {
|
||||
command := strings.ToLower(string(cmd.Args[0]))
|
||||
|
||||
if handler, ok := m.handlers[command]; ok {
|
||||
handler.ServeRESP(conn, cmd)
|
||||
} else {
|
||||
conn.WriteError("ERR unknown command '" + command + "'")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue