resp config
This commit is contained in:
parent
a47377ae49
commit
4e2bbf1c33
@ -1,15 +1,19 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/tidwall/resp"
|
||||||
|
"github.com/tidwall/tile38/controller/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var validProperties = []string{"requirepass", "leaderauth", "protected-mode"}
|
||||||
|
|
||||||
// Config is a tile38 config
|
// Config is a tile38 config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
FollowHost string `json:"follow_host,omitempty"`
|
FollowHost string `json:"follow_host,omitempty"`
|
||||||
@ -82,6 +86,16 @@ func (c *Controller) setConfigProperty(name, value string, fromLoad bool) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) getConfigProperties(pattern string) map[string]interface{} {
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
for _, name := range validProperties {
|
||||||
|
matched, _ := globMatch(pattern, name)
|
||||||
|
if matched {
|
||||||
|
m[name] = c.getConfigProperty(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
func (c *Controller) getConfigProperty(name string) string {
|
func (c *Controller) getConfigProperty(name string) string {
|
||||||
switch name {
|
switch name {
|
||||||
default:
|
default:
|
||||||
@ -127,36 +141,63 @@ func (c *Controller) writeConfig(writeProperties bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) cmdConfig(line string) (string, error) {
|
func (c *Controller) cmdConfigGet(msg *server.Message) (res string, err error) {
|
||||||
var start = time.Now()
|
start := time.Now()
|
||||||
var cmd, name, value string
|
vs := msg.Values[1:]
|
||||||
if line, cmd = token(line); cmd == "" {
|
var ok bool
|
||||||
|
var name string
|
||||||
|
if vs, name, ok = tokenval(vs); !ok {
|
||||||
return "", errInvalidNumberOfArguments
|
return "", errInvalidNumberOfArguments
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
if len(vs) != 0 {
|
||||||
buf.WriteString(`{"ok":true`)
|
return "", errInvalidNumberOfArguments
|
||||||
switch strings.ToLower(cmd) {
|
|
||||||
default:
|
|
||||||
return "", errInvalidArgument(cmd)
|
|
||||||
case "get":
|
|
||||||
if line, name = token(line); name == "" || line != "" {
|
|
||||||
return "", errInvalidNumberOfArguments
|
|
||||||
}
|
|
||||||
value = c.getConfigProperty(name)
|
|
||||||
buf.WriteString(`,"value":` + jsonString(value))
|
|
||||||
case "set":
|
|
||||||
if line, name = token(line); name == "" {
|
|
||||||
return "", errInvalidNumberOfArguments
|
|
||||||
}
|
|
||||||
value = strings.TrimSpace(line)
|
|
||||||
if err := c.setConfigProperty(name, value, false); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
case "rewrite":
|
|
||||||
if err := c.writeConfig(true); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buf.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
m := c.getConfigProperties(name)
|
||||||
return buf.String(), nil
|
switch msg.OutputType {
|
||||||
|
case server.JSON:
|
||||||
|
data, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
res = `{"ok":true,"properties":` + string(data) + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}"
|
||||||
|
case server.RESP:
|
||||||
|
vals := respValuesSimpleMap(m)
|
||||||
|
data, err := resp.ArrayValue(vals).MarshalRESP()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
res = string(data)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (c *Controller) cmdConfigSet(msg *server.Message) (res string, err error) {
|
||||||
|
start := time.Now()
|
||||||
|
vs := msg.Values[1:]
|
||||||
|
var ok bool
|
||||||
|
var name string
|
||||||
|
if vs, name, ok = tokenval(vs); !ok {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
var value string
|
||||||
|
if vs, value, ok = tokenval(vs); !ok {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
if len(vs) != 0 {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
if err := c.setConfigProperty(name, value, false); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return server.OKMessage(msg, start), nil
|
||||||
|
}
|
||||||
|
func (c *Controller) cmdConfigRewrite(msg *server.Message) (res string, err error) {
|
||||||
|
start := time.Now()
|
||||||
|
vs := msg.Values[1:]
|
||||||
|
if len(vs) != 0 {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
if err := c.writeConfig(true); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return server.OKMessage(msg, start), nil
|
||||||
}
|
}
|
||||||
|
@ -169,13 +169,26 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message,
|
|||||||
for _, v := range msg.Values {
|
for _, v := range msg.Values {
|
||||||
words = append(words, v.String())
|
words = append(words, v.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
writeOutput := func(res string) error {
|
writeOutput := func(res string) error {
|
||||||
switch msg.ConnType {
|
switch msg.ConnType {
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unsupported conn type: %v", msg.ConnType))
|
err := fmt.Errorf("unsupported conn type: %v", msg.ConnType)
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
case server.WebSocket:
|
||||||
|
return server.WriteWebSocketMessage(w, []byte(res))
|
||||||
|
case server.HTTP:
|
||||||
|
_, err := fmt.Fprintf(w, "HTTP/1.1 200 OK\r\n"+
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Content-Length: %d\r\n"+
|
||||||
|
"Content-Type: application/json charset=utf-8\r\n"+
|
||||||
|
"\r\n", len(res)+2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.WriteString(w, res+"\r\n")
|
||||||
|
return err
|
||||||
case server.RESP:
|
case server.RESP:
|
||||||
_, err := io.WriteString(w, res)
|
_, err := io.WriteString(w, res)
|
||||||
return err
|
return err
|
||||||
@ -184,7 +197,6 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping. Just send back the response. No need to put through the pipeline.
|
// Ping. Just send back the response. No need to put through the pipeline.
|
||||||
if msg.Command == "ping" {
|
if msg.Command == "ping" {
|
||||||
switch msg.OutputType {
|
switch msg.OutputType {
|
||||||
@ -314,22 +326,9 @@ func (c *Controller) reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d commandDetailsT, err error) {
|
func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d commandDetailsT, err error) {
|
||||||
start := time.Now()
|
|
||||||
okResp := func() string {
|
|
||||||
if w != nil {
|
|
||||||
switch msg.OutputType {
|
|
||||||
case server.JSON:
|
|
||||||
return `{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}"
|
|
||||||
case server.RESP:
|
|
||||||
return "+OK\r\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
switch msg.Command {
|
switch msg.Command {
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unknown command '%s'", msg.Values[0])
|
err = fmt.Errorf("unknown command '%s'", msg.Values[0])
|
||||||
return
|
|
||||||
// lock
|
// lock
|
||||||
case "set":
|
case "set":
|
||||||
res, d, err = c.cmdSet(msg)
|
res, d, err = c.cmdSet(msg)
|
||||||
@ -359,11 +358,8 @@ func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d co
|
|||||||
// case "follow":
|
// case "follow":
|
||||||
// err = c.cmdFollow(nline)
|
// err = c.cmdFollow(nline)
|
||||||
// resp = okResp()
|
// resp = okResp()
|
||||||
// case "config":
|
case "readonly":
|
||||||
// resp, err = c.cmdConfig(nline)
|
res, err = c.cmdReadOnly(msg)
|
||||||
// case "readonly":
|
|
||||||
// err = c.cmdReadOnly(nline)
|
|
||||||
// resp = okResp()
|
|
||||||
case "stats":
|
case "stats":
|
||||||
res, err = c.cmdStats(msg)
|
res, err = c.cmdStats(msg)
|
||||||
case "server":
|
case "server":
|
||||||
@ -385,12 +381,28 @@ func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d co
|
|||||||
// case "aofmd5":
|
// case "aofmd5":
|
||||||
// resp, err = c.cmdAOFMD5(nline)
|
// resp, err = c.cmdAOFMD5(nline)
|
||||||
case "gc":
|
case "gc":
|
||||||
|
start := time.Now()
|
||||||
go runtime.GC()
|
go runtime.GC()
|
||||||
res = okResp()
|
res = server.OKMessage(msg, start)
|
||||||
// resp = okResp()
|
// case "aofshrink":
|
||||||
// case "aofshrink":
|
// go c.aofshrink()
|
||||||
// go c.aofshrink()
|
// resp = okResp()
|
||||||
// resp = okResp()
|
|
||||||
|
case "config get":
|
||||||
|
res, err = c.cmdConfigGet(msg)
|
||||||
|
case "config set":
|
||||||
|
res, err = c.cmdConfigSet(msg)
|
||||||
|
case "config rewrite":
|
||||||
|
res, err = c.cmdConfigRewrite(msg)
|
||||||
|
case "config":
|
||||||
|
err = fmt.Errorf("unknown command '%s'", msg.Values[0])
|
||||||
|
if len(msg.Values) > 1 {
|
||||||
|
command := msg.Values[0].String() + " " + msg.Values[1].String()
|
||||||
|
msg.Values[1] = resp.StringValue(command)
|
||||||
|
msg.Values = msg.Values[1:]
|
||||||
|
msg.Command = strings.ToLower(command)
|
||||||
|
return c.command(msg, w)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -2,39 +2,47 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tidwall/tile38/controller/log"
|
"github.com/tidwall/tile38/controller/log"
|
||||||
|
"github.com/tidwall/tile38/controller/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Controller) cmdReadOnly(line string) error {
|
func (c *Controller) cmdReadOnly(msg *server.Message) (res string, err error) {
|
||||||
|
start := time.Now()
|
||||||
|
vs := msg.Values[1:]
|
||||||
var arg string
|
var arg string
|
||||||
if line, arg = token(line); arg == "" {
|
var ok bool
|
||||||
return errInvalidNumberOfArguments
|
if vs, arg, ok = tokenval(vs); !ok || arg == "" {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
}
|
}
|
||||||
if line != "" {
|
if len(vs) != 0 {
|
||||||
return errInvalidNumberOfArguments
|
return "", errInvalidNumberOfArguments
|
||||||
}
|
}
|
||||||
|
update := false
|
||||||
backup := c.config
|
backup := c.config
|
||||||
switch strings.ToLower(arg) {
|
switch strings.ToLower(arg) {
|
||||||
default:
|
default:
|
||||||
return errInvalidArgument(arg)
|
return "", errInvalidArgument(arg)
|
||||||
case "yes":
|
case "yes":
|
||||||
if c.config.ReadOnly {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
c.config.ReadOnly = true
|
|
||||||
log.Info("read only")
|
|
||||||
case "no":
|
|
||||||
if !c.config.ReadOnly {
|
if !c.config.ReadOnly {
|
||||||
return nil
|
update = true
|
||||||
|
c.config.ReadOnly = true
|
||||||
|
log.Info("read only")
|
||||||
|
}
|
||||||
|
case "no":
|
||||||
|
if c.config.ReadOnly {
|
||||||
|
update = true
|
||||||
|
c.config.ReadOnly = false
|
||||||
|
log.Info("read write")
|
||||||
}
|
}
|
||||||
c.config.ReadOnly = false
|
|
||||||
log.Info("read write")
|
|
||||||
}
|
}
|
||||||
err := c.writeConfig(false)
|
if update {
|
||||||
if err != nil {
|
err := c.writeConfig(false)
|
||||||
c.config = backup
|
if err != nil {
|
||||||
return err
|
c.config = backup
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return server.OKMessage(msg, start), nil
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ func (ar *AnyReaderWriter) readHTTPMessage() (*Message, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
msg.OutputType = nmsg.OutputType
|
msg.OutputType = JSON
|
||||||
msg.Values = nmsg.Values
|
msg.Values = nmsg.Values
|
||||||
msg.Command = commandValues(nmsg.Values)
|
msg.Command = commandValues(nmsg.Values)
|
||||||
return msg, nil
|
return msg, nil
|
||||||
|
@ -2,11 +2,13 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
//"github.com/tidwall/tile38/client"
|
//"github.com/tidwall/tile38/client"
|
||||||
|
|
||||||
@ -123,10 +125,49 @@ func handleConn(
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
conn.Write([]byte("HTTP/1.1 500 Bad Request\r\nConnection: close\r\n\r\n"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if msg.ConnType == HTTP || msg.ConnType == WebSocket {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WriteWebSocketMessage(w io.Writer, data []byte) error {
|
||||||
|
var msg []byte
|
||||||
|
buf := make([]byte, 10+len(data))
|
||||||
|
buf[0] = 129 // FIN + TEXT
|
||||||
|
if len(data) <= 125 {
|
||||||
|
buf[1] = byte(len(data))
|
||||||
|
copy(buf[2:], data)
|
||||||
|
msg = buf[:2+len(data)]
|
||||||
|
} else if len(data) <= 0xFFFF {
|
||||||
|
buf[1] = 126
|
||||||
|
binary.BigEndian.PutUint16(buf[2:], uint16(len(data)))
|
||||||
|
copy(buf[4:], data)
|
||||||
|
msg = buf[:4+len(data)]
|
||||||
|
} else {
|
||||||
|
buf[1] = 127
|
||||||
|
binary.BigEndian.PutUint64(buf[2:], uint64(len(data)))
|
||||||
|
copy(buf[10:], data)
|
||||||
|
msg = buf[:10+len(data)]
|
||||||
|
}
|
||||||
|
_, err := w.Write(msg)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func OKMessage(msg *Message, start time.Time) string {
|
||||||
|
switch msg.OutputType {
|
||||||
|
case JSON:
|
||||||
|
return `{"ok":true,"elapsed":"` + time.Now().Sub(start).String() + "\"}"
|
||||||
|
case RESP:
|
||||||
|
return "+OK\r\n"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
//err := func() error {
|
//err := func() error {
|
||||||
// command, proto, auth, err := client.ReadMessage(rd, conn)
|
// command, proto, auth, err := client.ReadMessage(rd, conn)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user