mirror of https://github.com/ledisdb/ledisdb.git
http api of bit cmds
This commit is contained in:
parent
f85da1db91
commit
1513d055f5
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
. "github.com/siddontang/ledisdb/server/http"
|
||||
"net"
|
||||
"net/http"
|
||||
"path"
|
||||
|
@ -133,8 +134,8 @@ func (app *App) httpServe() {
|
|||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/ws", &wsHandler{app})
|
||||
mux.Handle("/", &cmdHandler{app})
|
||||
mux.Handle("/ws", &WsHandler{app.Ledis()})
|
||||
mux.Handle("/", &CmdHandler{app.Ledis()})
|
||||
|
||||
svr := http.Server{Handler: mux}
|
||||
svr.Serve(app.httpListener)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const ERR_ARGUMENT_FORMAT = "ERR wrong number of arguments for '%s' command"
|
||||
|
||||
var ErrValue = errors.New("ERR value is not an integer or out of range")
|
||||
|
||||
type commondFunc func(*ledis.DB, ...string) (interface{}, error)
|
||||
|
||||
var regCmds = map[string]commondFunc{}
|
||||
|
||||
func register(name string, f commondFunc) {
|
||||
if _, ok := regCmds[strings.ToLower(name)]; ok {
|
||||
panic(fmt.Sprintf("%s has been registered", name))
|
||||
}
|
||||
regCmds[name] = f
|
||||
}
|
||||
func lookup(name string) commondFunc {
|
||||
return regCmds[strings.ToLower(name)]
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func bgetCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bget")
|
||||
}
|
||||
if v, err := db.BGet(ledis.Slice(args[0])); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
func bdeleteCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bdelete")
|
||||
}
|
||||
if n, err := db.BDelete(ledis.Slice(args[0])); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
func bsetbitCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 3 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bsetbit")
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
offset, err := strconv.ParseInt(args[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, ErrValue
|
||||
}
|
||||
val, err := strconv.ParseUint(args[2], 10, 8)
|
||||
if ori, err := db.BSetBit(key, int32(offset), uint8(val)); err != nil {
|
||||
return nil, err
|
||||
|
||||
} else {
|
||||
return ori, nil
|
||||
}
|
||||
}
|
||||
|
||||
func bgetbitCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bgetbit")
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
offset, err := strconv.ParseInt(args[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, ErrValue
|
||||
}
|
||||
|
||||
if v, err := db.BGetBit(key, int32(offset)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func bmsetbitCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) < 3 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bmsetbit")
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if len(args[1:])%2 != 0 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bmsetbit")
|
||||
} else {
|
||||
args = args[1:]
|
||||
}
|
||||
pairs := make([]ledis.BitPair, len(args)/2)
|
||||
for i := 0; i < len(pairs); i++ {
|
||||
offset, err := strconv.ParseInt(args[i*2], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, err := strconv.ParseUint(args[i*2+1], 10, 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pairs[i].Pos = int32(offset)
|
||||
pairs[i].Val = uint8(val)
|
||||
}
|
||||
if place, err := db.BMSetBit(key, pairs...); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return place, nil
|
||||
}
|
||||
}
|
||||
|
||||
func bcountCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
argCnt := len(args)
|
||||
if argCnt > 3 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bcount")
|
||||
}
|
||||
|
||||
var err error
|
||||
var start, end int64 = 0, -1
|
||||
if argCnt > 1 {
|
||||
if start, err = strconv.ParseInt(args[1], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if argCnt > 2 {
|
||||
if end, err = strconv.ParseInt(args[1], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if cnt, err := db.BCount(key, int32(start), int32(end)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return cnt, nil
|
||||
}
|
||||
}
|
||||
|
||||
func boptCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) < 2 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bopt")
|
||||
}
|
||||
opDesc := strings.ToLower(args[0])
|
||||
dstKey := ledis.Slice(args[1])
|
||||
|
||||
var srcKeys = [][]byte{}
|
||||
if len(args) >= 3 {
|
||||
srcKeys = make([][]byte, len(args[2:]))
|
||||
for i, arg := range args[2:] {
|
||||
srcKeys[i] = ledis.Slice(arg)
|
||||
}
|
||||
}
|
||||
|
||||
var op uint8
|
||||
switch opDesc {
|
||||
case "and":
|
||||
op = ledis.OPand
|
||||
case "or":
|
||||
op = ledis.OPor
|
||||
case "xor":
|
||||
op = ledis.OPxor
|
||||
case "not":
|
||||
op = ledis.OPnot
|
||||
default:
|
||||
return nil, fmt.Errorf("ERR invalid argument '%s' for 'bopt' command", opDesc)
|
||||
}
|
||||
if blen, err := db.BOperation(op, dstKey, srcKeys...); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return blen, nil
|
||||
}
|
||||
}
|
||||
|
||||
func bexpireCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bexpire")
|
||||
}
|
||||
duration, err := strconv.ParseInt(args[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if v, err := db.BExpire(key, duration); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, err
|
||||
}
|
||||
}
|
||||
|
||||
func bexpireatCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 2 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bexpireat")
|
||||
}
|
||||
when, err := strconv.ParseInt(args[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if v, err := db.BExpireAt(key, when); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
func bttlCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bttl")
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if v, err := db.BTTL(key); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, err
|
||||
}
|
||||
}
|
||||
|
||||
func bpersistCommand(db *ledis.DB, args ...string) (interface{}, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, fmt.Errorf(ERR_ARGUMENT_FORMAT, "bpersist")
|
||||
}
|
||||
key := ledis.Slice(args[0])
|
||||
if n, err := db.BPersist(key); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
register("bget", bgetCommand)
|
||||
register("bdelete", bdeleteCommand)
|
||||
register("bsetbit", bsetbitCommand)
|
||||
register("bgetbit", bgetbitCommand)
|
||||
register("bmsetbit", bmsetbitCommand)
|
||||
register("bcount", bcountCommand)
|
||||
register("bopt", boptCommand)
|
||||
register("bexpire", bexpireCommand)
|
||||
register("bexpireat", bexpireatCommand)
|
||||
register("bttl", bttlCommand)
|
||||
register("bpersist", bpersistCommand)
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
//"github.com/siddontang/go-websocket/websocket"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CmdHandler struct {
|
||||
Ldb *ledis.Ledis
|
||||
}
|
||||
|
||||
func (h *CmdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
idx, cmd, args := h.parseReqPath(r.URL.Path)
|
||||
cmdFunc := lookup(cmd)
|
||||
if cmdFunc == nil {
|
||||
h.cmdNotFound(cmd, w)
|
||||
return
|
||||
}
|
||||
var db *ledis.DB
|
||||
var err error
|
||||
if db, err = h.Ldb.Select(idx); err != nil {
|
||||
h.serverError(cmd, err, w)
|
||||
return
|
||||
}
|
||||
result, err := cmdFunc(db, args...)
|
||||
if err != nil {
|
||||
h.serverError(cmd, err, w)
|
||||
return
|
||||
}
|
||||
h.write(cmd, result, w)
|
||||
}
|
||||
|
||||
func (h *CmdHandler) parseReqPath(path string) (db int, cmd string, args []string) {
|
||||
substrings := strings.Split(strings.TrimLeft(path, "/"), "/")
|
||||
if len(substrings) == 1 {
|
||||
return 0, substrings[0], substrings[1:]
|
||||
}
|
||||
db, err := strconv.Atoi(substrings[0])
|
||||
if err != nil {
|
||||
// db = 0
|
||||
cmd = substrings[0]
|
||||
args = substrings[1:]
|
||||
} else {
|
||||
cmd = substrings[1]
|
||||
args = substrings[2:]
|
||||
}
|
||||
return
|
||||
}
|
||||
func (h *CmdHandler) cmdNotFound(cmd string, w http.ResponseWriter) {
|
||||
result := [2]interface{}{
|
||||
false,
|
||||
fmt.Sprintf("ERR unknown command '%s'", cmd),
|
||||
}
|
||||
h.write(cmd, result, w)
|
||||
}
|
||||
|
||||
func (h *CmdHandler) write(cmd string, result interface{}, w http.ResponseWriter) {
|
||||
m := map[string]interface{}{
|
||||
cmd: result,
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(&m)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-type", "application/json; charset=utf-8")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
|
||||
|
||||
_, err = w.Write(buf)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CmdHandler) serverError(cmd string, err error, w http.ResponseWriter) {
|
||||
result := [2]interface{}{
|
||||
false,
|
||||
fmt.Sprintf("ERR %s", err.Error()),
|
||||
}
|
||||
h.write(cmd, result, w)
|
||||
}
|
||||
|
||||
type WsHandler struct {
|
||||
Ldb *ledis.Ledis
|
||||
}
|
||||
|
||||
func (h *WsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("ws handler"))
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
//"github.com/siddontang/go-websocket/websocket"
|
||||
)
|
||||
|
||||
type cmdHandler struct {
|
||||
app *App
|
||||
}
|
||||
|
||||
func (h *cmdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("cmd handler"))
|
||||
}
|
||||
|
||||
type wsHandler struct {
|
||||
app *App
|
||||
}
|
||||
|
||||
func (h *wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("ws handler"))
|
||||
}
|
Loading…
Reference in New Issue