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"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -900,3 +901,66 @@ func Parse(raw []byte) (Command, error) {
|
||||||
return cmds[0], nil
|
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