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

Back to archive index

Susumu Yata null+****@clear*****
Fri May 12 19:17:20 JST 2017


Susumu Yata	2017-05-12 19:17:20 +0900 (Fri, 12 May 2017)

  New Revision: 09c35bc17c1a9d27caa32cc54018966d9ecee3a7
  https://github.com/groonga/grnci/commit/09c35bc17c1a9d27caa32cc54018966d9ecee3a7

  Message:
    Update v2.

  Added files:
    v2/error.go
    v2/libgrn/client.go
    v2/libgrn/libgrn.go
  Modified files:
    v2/argument.go
    v2/gqtp.go
    v2/http.go
    v2/request.go
  Renamed files:
    v2/response.go
      (from v2/respponse.go)

  Modified: v2/argument.go (+8 -4)
===================================================================
--- v2/argument.go    2017-05-11 19:51:22 +0900 (96d9742)
+++ v2/argument.go    2017-05-12 19:17:20 +0900 (0629675)
@@ -5,7 +5,11 @@ import (
 	"fmt"
 )
 
-// Argument represents a named argument of a request.
+// Argument stores a command argument.
+//
+// If Key != "", it is a named argument.
+// Otherwise, it is an unnamed argument.
+// Note that the order of unnamed arguments is important.
 type Argument struct {
 	Key   string
 	Value string
@@ -36,7 +40,7 @@ func checkArgumentKey(s string) error {
 			continue
 		}
 		switch s[i] {
-		case '#', '@', '-', '_':
+		case '#', '@', '-', '_', '.', '[', ']':
 		default:
 			return fmt.Errorf("invalid format: s = %s", s)
 		}
@@ -45,8 +49,8 @@ func checkArgumentKey(s string) error {
 }
 
 // Check checks if arg is valid.
-func (arg *Argument) Check() error {
-	if err := checkArgumentKey(arg.Key); err != nil {
+func (a *Argument) Check() error {
+	if err := checkArgumentKey(a.Key); err != nil {
 		return fmt.Errorf("checkArgumentKey failed: %v", err)
 	}
 	return nil

  Added: v2/error.go (+42 -0) 100644
===================================================================
--- /dev/null
+++ v2/error.go    2017-05-12 19:17:20 +0900 (876af5f)
@@ -0,0 +1,42 @@
+package grnci
+
+import "encoding/json"
+
+// Code is an error code.
+type Code int
+
+// List of error codes.
+const (
+	CodeSuccess = Code(0)
+)
+
+// String returns a string which briefly describes an error.
+func (c Code) String() string {
+	switch c {
+	case CodeSuccess:
+		return "Success"
+	default:
+		return "Unknown error"
+	}
+}
+
+// Error stores details of an error.
+type Error struct {
+	Code    Code
+	Message string
+	Data    interface{}
+}
+
+// NewError creates an error object.
+func NewError(code Code, data interface{}) error {
+	return &Error{
+		Code: code,
+		Data: data,
+	}
+}
+
+// Error returns a string which describes an error.
+func (e Error) Error() string {
+	b, _ := json.Marshal(e)
+	return string(b)
+}

  Modified: v2/gqtp.go (+4 -0)
===================================================================
--- v2/gqtp.go    2017-05-11 19:51:22 +0900 (3e846f9)
+++ v2/gqtp.go    2017-05-12 19:17:20 +0900 (3075594)
@@ -34,6 +34,10 @@ func (c *gqtpClient) Close() error {
 
 // Query sends a request and receives a response.
 func (c *gqtpClient) Query(req *Request) (*Response, error) {
+	if err := req.Check(); err != nil {
+		return nil, err
+	}
+
 	// TODO
 	return nil, nil
 }

  Modified: v2/http.go (+36 -2)
===================================================================
--- v2/http.go    2017-05-11 19:51:22 +0900 (e342b31)
+++ v2/http.go    2017-05-12 19:17:20 +0900 (14b732a)
@@ -2,8 +2,10 @@ package grnci
 
 import (
 	"fmt"
+	"io/ioutil"
 	"net/http"
 	"net/url"
+	"path"
 )
 
 // httpClient is an HTTP client.
@@ -34,6 +36,38 @@ func (c *httpClient) Close() error {
 
 // Query sends a request and receives a response.
 func (c *httpClient) Query(req *Request) (*Response, error) {
-	// TODO
-	return nil, nil
+	if err := req.Check(); err != nil {
+		return nil, err
+	}
+
+	u := *c.url
+	u.Path = path.Join(u.Path, req.Cmd)
+	if len(req.Args) != 0 {
+		q := u.Query()
+		for _, arg := range req.Args {
+			q.Set(arg.Key, arg.Value)
+		}
+		u.RawQuery = q.Encode()
+	}
+	addr := u.String()
+
+	var resp *http.Response
+	var err error
+	if req.Body == nil {
+		if resp, err = c.client.Get(addr); err != nil {
+			return nil, fmt.Errorf("c.client.Get failed: %v", err)
+		}
+	} else {
+		if resp, err = c.client.Post(addr, "application/json", req.Body); err != nil {
+			return nil, fmt.Errorf("c.client.Post failed: %v", err)
+		}
+	}
+	defer resp.Body.Close()
+
+	// TODO: parse the response.
+	respBytes, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, fmt.Errorf("ioutil.ReadAll failed: %v", err)
+	}
+	return &Response{Bytes: respBytes}, nil
 }

  Added: v2/libgrn/client.go (+37 -0) 100644
===================================================================
--- /dev/null
+++ v2/libgrn/client.go    2017-05-12 19:17:20 +0900 (9a85023)
@@ -0,0 +1,37 @@
+package libgrn
+
+// #cgo pkg-config: groonga
+// #include <groonga.h>
+// #include <stdlib.h>
+import "C"
+import "github.com/groonga/grnci/v2"
+
+// Client is associated with a C.grn_ctx.
+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
+}
+
+// Close closes a client.
+func (c *Client) Close() error {
+	return nil
+}
+
+// Query sends a request and receives a response.
+func (c *Client) Query(req *grnci.Request) (*grnci.Response, error) {
+	return nil, nil
+}

  Added: v2/libgrn/libgrn.go (+196 -0) 100644
===================================================================
--- /dev/null
+++ v2/libgrn/libgrn.go    2017-05-12 19:17:20 +0900 (4650603)
@@ -0,0 +1,196 @@
+// Package libgrn provides Client using libgroonga.
+package libgrn
+
+// #cgo pkg-config: groonga
+// #include <groonga.h>
+// #include <stdlib.h>
+import "C"
+import (
+	"errors"
+	"fmt"
+	"sync"
+	"unsafe"
+)
+
+var (
+	// libCount is incremented by Init and decremented by Fin.
+	libCount int
+	// libMutex is used for exclusion control in Init and Fin.
+	libMutex sync.Mutex
+)
+
+// Init initializes libgroonga.
+//
+// If an internal counter is zero, Init increments it and initializes libgroonga.
+// Otherwise, Init only increments the internal counter.
+//
+// There is no need to call Init explicitly.
+// libgrn calls Init when it creates a Client.
+func Init() error {
+	libMutex.Lock()
+	defer libMutex.Unlock()
+	if libCount == 0 {
+		if rc := C.grn_init(); rc != C.GRN_SUCCESS {
+			return fmt.Errorf("C.grn_init failed: rc = %d", rc)
+		}
+	}
+	libCount++
+	return nil
+}
+
+// Fin finalizes libgroonga.
+//
+// If an internal counter is one, Fin decrements it and finalizes libgroonga.
+// Otherwise, Fin only decrements the internal counter.
+//
+// There is no need to call Fin explicitly.
+// libgrn calls Fin when it closes a Client.
+func Fin() error {
+	libMutex.Lock()
+	defer libMutex.Unlock()
+	if libCount == 0 {
+		return fmt.Errorf("libCount = 0")
+	}
+	libCount--
+	if libCount == 0 {
+		if rc := C.grn_fin(); rc != C.GRN_SUCCESS {
+			return fmt.Errorf("C.grn_fin failed: rc = %d", rc)
+		}
+	}
+	return nil
+}
+
+// ctx is a Groonga context.
+type grnCtx struct {
+	ctx *C.grn_ctx
+}
+
+// newGrnCtx returns a new grnCtx.
+func newGrnCtx() (*grnCtx, error) {
+	if err := Init(); err != nil {
+		return nil, fmt.Errorf("Init failed: %v", err)
+	}
+	ctx := C.grn_ctx_open(C.int(0))
+	if ctx == nil {
+		Fin()
+		return nil, errors.New("C.grn_ctx_open failed")
+	}
+	return &grnCtx{ctx: ctx}, nil
+}
+
+// Close closes a grnCtx.
+func (c *grnCtx) Close() error {
+	if rc := C.grn_ctx_close(c.ctx); rc != C.GRN_SUCCESS {
+		return fmt.Errorf("C.grn_ctx_close failed: %s", rc)
+	}
+	if err := Fin(); err != nil {
+		return fmt.Errorf("Fin failed: %v", err)
+	}
+	return nil
+}
+
+func (c *grnCtx) Err() error {
+	if c.ctx.rc == C.GRN_SUCCESS {
+		return nil
+	}
+	return fmt.Errorf("rc = %s: %s", c.ctx.rc, C.GoString(&c.ctx.errbuf[0]))
+}
+
+// grnDB is a DB handle.
+type grnDB struct {
+	obj   *C.grn_obj
+	path  string
+	count int
+	mutex sync.Mutex
+}
+
+// createDB creates a new DB.
+func createDB(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)
+	if obj == nil {
+		return nil, fmt.Errorf("C.grn_db_create failed: %v", ctx.Err())
+	}
+	if cAbsPath := C.grn_obj_path(ctx.ctx, obj); cAbsPath != nil {
+		path = C.GoString(cAbsPath)
+	}
+	return &grnDB{
+		obj:   obj,
+		path:  path,
+		count: 1,
+	}, 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 = ")
+	}
+	cPath := C.CString(path)
+	defer C.free(unsafe.Pointer(cPath))
+	obj := C.grn_db_open(ctx.ctx, cPath)
+	if obj == nil {
+		return nil, fmt.Errorf("C.grn_db_create failed: %v", ctx.Err())
+	}
+	if cAbsPath := C.grn_obj_path(ctx.ctx, obj); cAbsPath != nil {
+		path = C.GoString(cAbsPath)
+	}
+	return &grnDB{
+		obj:   obj,
+		path:  path,
+		count: 1,
+	}, nil
+}
+
+// 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)
+	}
+	db.count--
+	if db.count == 0 {
+		if rc := C.grn_obj_close(ctx.ctx, db.obj); rc != C.GRN_SUCCESS {
+			return fmt.Errorf("C.grn_obj_close failed: rc = %s", rc)
+		}
+		db.obj = nil
+	}
+	return nil
+}
+
+// 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)
+	}
+	C.grn_ctx_use(ctx.ctx, db.obj)
+	if err := ctx.Err(); err != nil {
+		ctx.Close()
+		return nil, fmt.Errorf("C.grn_ctx_use failed: %v", err)
+	}
+	db.mutex.Lock()
+	db.count++
+	db.mutex.Unlock()
+	return ctx, nil
+}

  Modified: v2/request.go (+1 -1)
===================================================================
--- v2/request.go    2017-05-11 19:51:22 +0900 (dcd2fb4)
+++ v2/request.go    2017-05-12 19:17:20 +0900 (3eaa7c5)
@@ -32,7 +32,7 @@ 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)
+		return fmt.Errorf("checkCmd failed: %v", err)
 	}
 	for _, arg := range req.Args {
 		if err := arg.Check(); err != nil {

  Renamed: v2/response.go (+1 -0) 76%
===================================================================
--- v2/respponse.go    2017-05-11 19:51:22 +0900 (437d876)
+++ v2/response.go    2017-05-12 19:17:20 +0900 (b37f90a)
@@ -4,6 +4,7 @@ import (
 	"time"
 )
 
+// Response stores a response of Groonga.
 type Response struct {
 	Bytes   []byte
 	Error   error
-------------- next part --------------
HTML����������������������������...
Download 



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