MCPcopy Index your code
hub / github.com/tidwall/redcon

github.com/tidwall/redcon @v1.6.2 sqlite

repository ↗ · DeepWiki ↗ · release v1.6.2 ↗
189 symbols 510 edges 8 files 112 documented · 59%
README

REDCON

GoDoc

Redis compatible server framework for Go

Features

  • Create a Fast custom Redis compatible server in Go
  • Simple interface. One function ListenAndServe and two types Conn & Command
  • Support for pipelining and telnet commands
  • Works with Redis clients such as redigo, redis-py, node_redis, and jedis
  • TLS Support
  • Compatible pub/sub support
  • Multithreaded

Installing

go get -u github.com/tidwall/redcon

Example

Here's a full example of a Redis clone that accepts:

  • SET key value
  • GET key
  • DEL key
  • PING
  • QUIT
  • PUBLISH channel message
  • SUBSCRIBE channel

You can run this example from a terminal:

go run example/clone.go
package main

import (
    "log"
    "strings"
    "sync"

    "github.com/tidwall/redcon"
)

var addr = ":6380"

func main() {
    var mu sync.RWMutex
    var items = make(map[string][]byte)
    var ps redcon.PubSub
    go log.Printf("started server at %s", addr)
    err := redcon.ListenAndServe(addr,
        func(conn redcon.Conn, cmd redcon.Command) {
            switch strings.ToLower(string(cmd.Args[0])) {
            default:
                conn.WriteError("ERR unknown command '" + string(cmd.Args[0]) + "'")
            case "ping":
                conn.WriteString("PONG")
            case "quit":
                conn.WriteString("OK")
                conn.Close()
            case "set":
                if len(cmd.Args) != 3 {
                    conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
                    return
                }
                mu.Lock()
                items[string(cmd.Args[1])] = cmd.Args[2]
                mu.Unlock()
                conn.WriteString("OK")
            case "get":
                if len(cmd.Args) != 2 {
                    conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
                    return
                }
                mu.RLock()
                val, ok := items[string(cmd.Args[1])]
                mu.RUnlock()
                if !ok {
                    conn.WriteNull()
                } else {
                    conn.WriteBulk(val)
                }
            case "del":
                if len(cmd.Args) != 2 {
                    conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
                    return
                }
                mu.Lock()
                _, ok := items[string(cmd.Args[1])]
                delete(items, string(cmd.Args[1]))
                mu.Unlock()
                if !ok {
                    conn.WriteInt(0)
                } else {
                    conn.WriteInt(1)
                }
            case "publish":
                if len(cmd.Args) != 3 {
                    conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
                    return
                }
                conn.WriteInt(ps.Publish(string(cmd.Args[1]), string(cmd.Args[2])))
            case "subscribe", "psubscribe":
                if len(cmd.Args) < 2 {
                    conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
                    return
                }
                command := strings.ToLower(string(cmd.Args[0]))
                for i := 1; i < len(cmd.Args); i++ {
                    if command == "psubscribe" {
                        ps.Psubscribe(conn, string(cmd.Args[i]))
                    } else {
                        ps.Subscribe(conn, string(cmd.Args[i]))
                    }
                }
            }
        },
        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)
    }
}

TLS Example

Redcon has full TLS support through the ListenAndServeTLS function.

The same example is also provided for serving Redcon over TLS.

go run example/tls/clone.go

Benchmarks

Redis: Single-threaded, no disk persistence.

$ redis-server --port 6379 --appendonly no
redis-benchmark -p 6379 -t set,get -n 10000000 -q -P 512 -c 512
SET: 941265.12 requests per second
GET: 1189909.50 requests per second

Redcon: Single-threaded, no disk persistence.

$ GOMAXPROCS=1 go run example/clone.go
redis-benchmark -p 6380 -t set,get -n 10000000 -q -P 512 -c 512
SET: 2018570.88 requests per second
GET: 2403846.25 requests per second

Redcon: Multi-threaded, no disk persistence.

$ GOMAXPROCS=0 go run example/clone.go
$ redis-benchmark -p 6380 -t set,get -n 10000000 -q -P 512 -c 512
SET: 1944390.38 requests per second
GET: 3993610.25 requests per second

Running on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7

Contact

Josh Baker @tidwall

License

Redcon source code is available under the MIT License.

Extension points exported contracts — how you extend this code

Conn (Interface)
Conn represents a client connection [1 implementers]
redcon.go
Marshaler (Interface)
Marshaler is the interface implemented by types that can marshal themselves into a Redis response type from an *Any call
resp.go
DetachedConn (Interface)
DetachedConn represents a connection that is detached from the server [1 implementers]
redcon.go
Handler (Interface)
A Handler responds to an RESP request. [1 implementers]
redcon.go
HandlerFunc (FuncType)
The HandlerFunc type is an adapter to allow the use of ordinary functions as RESP handlers. If f is a function with the
redcon.go

Core symbols most depended-on inside this repo

WriteError
called by 24
redcon.go
Close
called by 22
redcon.go
WriteString
called by 20
redcon.go
String
called by 18
resp.go
WriteBulkString
called by 18
redcon.go
Flush
called by 16
redcon.go
WriteInt
called by 13
redcon.go
Int
called by 10
resp.go

Shape

Method 98
Function 66
Struct 15
TypeAlias 5
Interface 4
FuncType 1

Languages

Go100%

Modules by API surface

redcon.go118 symbols
resp.go38 symbols
resp_test.go11 symbols
redcon_test.go11 symbols
example/mux/handler.go8 symbols
example/tls/clone.go1 symbols
example/mux/clone.go1 symbols
example/clone.go1 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

Dependencies from manifests, versioned

github.com/tidwall/btreev1.1.0 · 1×
github.com/tidwall/matchv1.1.1 · 1×

For agents

$ claude mcp add redcon \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact