[Groonga-commit] groonga/grnci at e6ff6ab [master] Update v2.

Back to archive index

Susumu Yata null+****@clear*****
Mon May 15 19:04:47 JST 2017


Susumu Yata	2017-05-15 19:04:47 +0900 (Mon, 15 May 2017)

  New Revision: e6ff6ab6b1ac3306d287e1cf57a01abc244133d2
  https://github.com/groonga/grnci/commit/e6ff6ab6b1ac3306d287e1cf57a01abc244133d2

  Message:
    Update v2.

  Added files:
    v2/libgrn/handle.go
  Modified files:
    v2/address.go
    v2/argument.go
    v2/client.go
    v2/http.go
    v2/libgrn/client.go
    v2/libgrn/libgrn.go
    v2/request.go
    v2/response.go

  Modified: v2/address.go (+1 -1)
===================================================================
--- v2/address.go    2017-05-12 19:17:20 +0900 (6ff2d8d)
+++ v2/address.go    2017-05-15 19:04:47 +0900 (cfa5634)
@@ -22,7 +22,7 @@ type Address struct {
 	Fragment string
 }
 
-// String reassembles the address fields except Raw into an address string.
+// String assembles the address fields except Raw into an address string.
 func (a *Address) String() string {
 	var url string
 	if a.Scheme != "" {

  Modified: v2/argument.go (+4 -1)
===================================================================
--- v2/argument.go    2017-05-12 19:17:20 +0900 (0629675)
+++ v2/argument.go    2017-05-15 19:04:47 +0900 (8862bcd)
@@ -35,7 +35,10 @@ func checkArgumentKey(s string) error {
 	if s == "" {
 		return errors.New("invalid format: s = ")
 	}
-	for i := 0; i < len(s); i++ {
+	if !isAlpha(s[0]) {
+		return fmt.Errorf("invalid format: s = %s", s)
+	}
+	for i := 1; i < len(s); i++ {
 		if isAlnum(s[i]) {
 			continue
 		}

  Modified: v2/client.go (+12 -2)
===================================================================
--- v2/client.go    2017-05-12 19:17:20 +0900 (254bcb5)
+++ v2/client.go    2017-05-15 19:04:47 +0900 (9f46eaa)
@@ -14,12 +14,12 @@ type iClient interface {
 
 // Client is a Groonga client.
 type Client struct {
-	iClient
+	impl iClient
 }
 
 // NewClient returns a new Client using an existing client.
 func NewClient(c iClient) *Client {
-	return &Client{iClient: c}
+	return &Client{impl: c}
 }
 
 // NewClientByAddress returns a new Client to access a Groonga server.
@@ -76,3 +76,13 @@ func NewHTTPClient(addr string, client *http.Client) (*Client, error) {
 	}
 	return NewClient(c), nil
 }
+
+// Close closes a client.
+func (c *Client) Close() error {
+	return c.impl.Close()
+}
+
+// Query sends a request and receives a response.
+func (c *Client) Query(req *Request) (*Response, error) {
+	return c.impl.Query(req)
+}

  Modified: v2/http.go (+3 -3)
===================================================================
--- v2/http.go    2017-05-12 19:17:20 +0900 (14b732a)
+++ v2/http.go    2017-05-15 19:04:47 +0900 (14e2fbf)
@@ -41,10 +41,10 @@ func (c *httpClient) Query(req *Request) (*Response, error) {
 	}
 
 	u := *c.url
-	u.Path = path.Join(u.Path, req.Cmd)
-	if len(req.Args) != 0 {
+	u.Path = path.Join(u.Path, req.Command)
+	if len(req.Arguments) != 0 {
 		q := u.Query()
-		for _, arg := range req.Args {
+		for _, arg := range req.Arguments {
 			q.Set(arg.Key, arg.Value)
 		}
 		u.RawQuery = q.Encode()

  Modified: v2/libgrn/client.go (+0 -10)
===================================================================
--- v2/libgrn/client.go    2017-05-12 19:17:20 +0900 (9a85023)
+++ v2/libgrn/client.go    2017-05-15 19:04:47 +0900 (a8075b4)
@@ -11,16 +11,6 @@ type Client struct {
 	ctx *grnCtx
 }
 
-// Open opens a local Groonga DB.
-func Open(path string) (*grnci.Client, error) {
-	return nil, nil
-}
-
-// Create creates a local Groonga DB.
-func Create(path string) (*grnci.Client, error) {
-	return nil, nil
-}
-
 // Connect establishes a connection with a GQTP server.
 func Connect(addr string) (*grnci.Client, error) {
 	return nil, nil

  Added: v2/libgrn/handle.go (+134 -0) 100644
===================================================================
--- /dev/null
+++ v2/libgrn/handle.go    2017-05-15 19:04:47 +0900 (0af4fa1)
@@ -0,0 +1,134 @@
+package libgrn
+
+// #cgo pkg-config: groonga
+// #include <groonga.h>
+// #include <stdlib.h>
+import "C"
+import (
+	"fmt"
+	"io/ioutil"
+	"unsafe"
+
+	"github.com/groonga/grnci/v2"
+)
+
+// Handle is associated with a C.grn_ctx.
+type Handle struct {
+	ctx *grnCtx
+	db  *grnDB
+}
+
+// Open opens a local DB and returns a handle.
+func Open(path string) (*Handle, error) {
+	ctx, err := newGrnCtx()
+	if err != nil {
+		return nil, err
+	}
+	db, err := openGrnDB(ctx, path)
+	if err != nil {
+		ctx.Close()
+		return nil, err
+	}
+	return &Handle{
+		ctx: ctx,
+		db:  db,
+	}, nil
+}
+
+// Create creates a local DB and returns a hendle.
+func Create(path string) (*Handle, error) {
+	ctx, err := newGrnCtx()
+	if err != nil {
+		return nil, err
+	}
+	db, err := createGrnDB(ctx, path)
+	if err != nil {
+		ctx.Close()
+		return nil, err
+	}
+	return &Handle{
+		ctx: ctx,
+		db:  db,
+	}, nil
+}
+
+// Close closes a handle.
+func (h *Handle) Close() error {
+	if err := h.db.Close(h.ctx); err != nil {
+		return err
+	}
+	if err := h.ctx.Close(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// Dup duplicates a handle.
+func (h *Handle) Dup() (*Handle, error) {
+	ctx, err := h.db.Dup()
+	if err != nil {
+		return nil, err
+	}
+	return &Handle{
+		ctx: ctx,
+		db:  h.db,
+	}, nil
+}
+
+// send sends data.
+func (h *Handle) send(data []byte) error {
+	var p *C.char
+	if len(data) != 0 {
+		p = (*C.char)(unsafe.Pointer(&data[0]))
+	}
+	rc := C.grn_rc(C.grn_ctx_send(h.ctx.ctx, p, C.uint(len(data)), C.int(0)))
+	if (rc != C.GRN_SUCCESS) || (h.ctx.ctx.rc != C.GRN_SUCCESS) {
+		return fmt.Errorf("C.grn_ctx_send failed: rc = %d", rc)
+	}
+	return nil
+}
+
+// recv receives the response to sent data.
+func (h *Handle) recv() ([]byte, error) {
+	var resp *C.char
+	var respLen C.uint
+	var respFlags C.int
+	rc := C.grn_rc(C.grn_ctx_recv(h.ctx.ctx, &resp, &respLen, &respFlags))
+	if (rc != C.GRN_SUCCESS) || (h.ctx.ctx.rc != C.GRN_SUCCESS) {
+		return nil, fmt.Errorf("C.grn_ctx_recv failed: rc = %d", rc)
+	}
+	return C.GoBytes(unsafe.Pointer(resp), C.int(respLen)), nil
+}
+
+// Query sends a request and receives a response.
+//
+// TODO: error handling
+func (h *Handle) Query(req *grnci.Request) (*grnci.Response, error) {
+	cmd, err := req.Assemble()
+	if err != nil {
+		return nil, err
+	}
+	if err := h.send([]byte(cmd)); err != nil {
+		respBytes, _ := h.recv()
+		resp, _ := grnci.NewResponse(respBytes)
+		return resp, err
+	}
+	respBytes, err := h.recv()
+	if (req.Body == nil) || (err != nil) {
+		resp, _ := grnci.NewResponse(respBytes)
+		return resp, err
+	}
+	if len(respBytes) != 0 {
+		resp, _ := grnci.NewResponse(respBytes)
+		return resp, fmt.Errorf("unexpected response")
+	}
+	body, _ := ioutil.ReadAll(req.Body)
+	if err := h.send(body); err != nil {
+		respBytes, _ := h.recv()
+		resp, _ := grnci.NewResponse(respBytes)
+		return resp, err
+	}
+	respBytes, _ = h.recv()
+	resp, _ := grnci.NewResponse(respBytes)
+	return resp, nil
+}

  Modified: v2/libgrn/libgrn.go (+5 -26)
===================================================================
--- v2/libgrn/libgrn.go    2017-05-12 19:17:20 +0900 (4650603)
+++ v2/libgrn/libgrn.go    2017-05-15 19:04:47 +0900 (b77537f)
@@ -104,8 +104,8 @@ type grnDB struct {
 	mutex sync.Mutex
 }
 
-// createDB creates a new DB.
-func createDB(ctx *grnCtx, path string) (*grnDB, error) {
+// createGrnDB creates a new DB.
+func createGrnDB(ctx *grnCtx, path string) (*grnDB, error) {
 	cPath := C.CString(path)
 	defer C.free(unsafe.Pointer(cPath))
 	obj := C.grn_db_create(ctx.ctx, cPath, nil)
@@ -122,14 +122,8 @@ func createDB(ctx *grnCtx, path string) (*grnDB, error) {
 	}, nil
 }
 
-// openDB opens an existing DB.
-func openDB(ctx *grnCtx, path string) (*grnDB, error) {
-	if ctx == nil {
-		return nil, errors.New("invalid argument: ctx = nil")
-	}
-	if path == "" {
-		return nil, errors.New("invalid argument: path = ")
-	}
+// openGrnDB opens an existing DB.
+func openGrnDB(ctx *grnCtx, path string) (*grnDB, error) {
 	cPath := C.CString(path)
 	defer C.free(unsafe.Pointer(cPath))
 	obj := C.grn_db_open(ctx.ctx, cPath)
@@ -148,19 +142,10 @@ func openDB(ctx *grnCtx, path string) (*grnDB, error) {
 
 // Close closes a DB.
 func (db *grnDB) Close(ctx *grnCtx) error {
-	if db == nil {
-		return errors.New("invalid self: db = nil")
-	}
-	if db.obj == nil {
-		return errors.New("invalid self: obj = nil")
-	}
-	if ctx == nil {
-		return errors.New("invalid argument: ctx = nil")
-	}
 	db.mutex.Lock()
 	defer db.mutex.Unlock()
 	if db.count <= 0 {
-		return fmt.Errorf("underflow: cnt = %d", db.count)
+		return fmt.Errorf("underflow: count = %d", db.count)
 	}
 	db.count--
 	if db.count == 0 {
@@ -174,12 +159,6 @@ func (db *grnDB) Close(ctx *grnCtx) error {
 
 // Dup duplicates a DB handle.
 func (db *grnDB) Dup() (*grnCtx, error) {
-	if db == nil {
-		return nil, errors.New("invalid self: db = nil")
-	}
-	if db.obj == nil {
-		return nil, errors.New("invalid self: obj = nil")
-	}
 	ctx, err := newGrnCtx()
 	if err != nil {
 		return nil, fmt.Errorf("newGrnCtx failed: %v", err)

  Modified: v2/request.go (+48 -9)
===================================================================
--- v2/request.go    2017-05-12 19:17:20 +0900 (3eaa7c5)
+++ v2/request.go    2017-05-15 19:04:47 +0900 (f3bc332)
@@ -8,13 +8,13 @@ import (
 
 // Request stores a Groonga command with arguments.
 type Request struct {
-	Cmd  string
-	Args []Argument
-	Body io.Reader
+	Command   string
+	Arguments []Argument
+	Body      io.Reader
 }
 
-// checkCmd checks if s is valid as a command name.
-func checkCmd(s string) error {
+// checkCommand checks if s is valid as a command name.
+func checkCommand(s string) error {
 	if s == "" {
 		return errors.New("invalid name: s = ")
 	}
@@ -30,14 +30,53 @@ func checkCmd(s string) error {
 }
 
 // Check checks if req is valid.
-func (req *Request) Check() error {
-	if err := checkCmd(req.Cmd); err != nil {
-		return fmt.Errorf("checkCmd failed: %v", err)
+func (r *Request) Check() error {
+	if err := checkCommand(r.Command); err != nil {
+		return fmt.Errorf("checkCommand failed: %v", err)
 	}
-	for _, arg := range req.Args {
+	for _, arg := range r.Arguments {
 		if err := arg.Check(); err != nil {
 			return fmt.Errorf("arg.Check failed: %v", err)
 		}
 	}
 	return nil
 }
+
+// Assemble assembles Command and Arguments into a command string.
+//
+// The command string format is
+// Command --Arguments[i].Key 'Arguments[i].Value' ...
+func (r *Request) Assemble() (string, error) {
+	if err := r.Check(); err != nil {
+		return "", err
+	}
+	size := len(r.Command)
+	for _, arg := range r.Arguments {
+		if len(arg.Key) != 0 {
+			size += len(arg.Key) + 3
+		}
+		size += len(arg.Value)*2 + 3
+	}
+	buf := make([]byte, 0, size)
+	buf = append(buf, r.Command...)
+	for _, arg := range r.Arguments {
+		buf = append(buf, ' ')
+		if len(arg.Key) != 0 {
+			buf = append(buf, "--"...)
+			buf = append(buf, arg.Key...)
+		}
+		buf = append(buf, '\'')
+		for i := 0; i < len(arg.Value); i++ {
+			switch arg.Value[i] {
+			case '\'':
+				buf = append(buf, '\'')
+			case '\\':
+				buf = append(buf, '\'')
+			}
+			buf = append(buf, arg.Value[i])
+		}
+		buf = append(buf, '\'')
+
+	}
+	return string(buf), nil
+}

  Modified: v2/response.go (+4 -0)
===================================================================
--- v2/response.go    2017-05-12 19:17:20 +0900 (b37f90a)
+++ v2/response.go    2017-05-15 19:04:47 +0900 (c5323e6)
@@ -11,3 +11,7 @@ type Response struct {
 	Time    time.Time
 	Elapsed time.Duration
 }
+
+func NewResponse([]byte) (*Response, error) {
+	return nil, nil
+}
-------------- next part --------------
HTML����������������������������...
다운로드 



More information about the Groonga-commit mailing list
Back to archive index