add server mux

This commit is contained in:
Oleg Ozimok 2019-04-07 21:03:47 +03:00 committed by Oleg Ozimok
parent c964c660ad
commit a6727f990d
3 changed files with 190 additions and 0 deletions

39
example/mux/clone.go Normal file
View File

@ -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)
}
}

87
example/mux/handler.go Normal file
View File

@ -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)
}
}

View File

@ -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 + "'")
}
}