document code
This commit is contained in:
parent
0208b42e2a
commit
7f4cb89dca
5 changed files with 176 additions and 69 deletions
58
sonic/control.go
Normal file
58
sonic/control.go
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package sonic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var InvalidActionName = errors.New("invalid action name")
|
||||||
|
|
||||||
|
// Controllable is used for administration purposes.
|
||||||
|
type Controllable interface {
|
||||||
|
// Trigger an action.
|
||||||
|
// Command syntax TRIGGER [<action>]?.
|
||||||
|
Trigger(action Action) (err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Quit() (err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Ping() (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ControlChannel struct {
|
||||||
|
*Driver
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControl(host string, port int, password string) (Controllable, error) {
|
||||||
|
driver := &Driver{
|
||||||
|
Host: host,
|
||||||
|
Port: port,
|
||||||
|
Password: password,
|
||||||
|
channel: Control,
|
||||||
|
}
|
||||||
|
err := driver.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ControlChannel{
|
||||||
|
Driver: driver,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ControlChannel) Trigger(action Action) (err error) {
|
||||||
|
if IsActionValid(action) {
|
||||||
|
return InvalidActionName
|
||||||
|
}
|
||||||
|
err = c.write(fmt.Sprintf("TRIGGER %s", action))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// should get OK
|
||||||
|
_, err = c.read()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
25
sonic/doc.go
Normal file
25
sonic/doc.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Package sonic implements all methods to communicate with it and execute commands.
|
||||||
|
//
|
||||||
|
// Syntax terminology (from https://github.com/valeriansaliou/sonic/blob/master/PROTOCOL.md):
|
||||||
|
//
|
||||||
|
// - collection: index collection (ie. what you search in, eg. messages, products, etc.);
|
||||||
|
//
|
||||||
|
// - bucket: index bucket name (ie. user-specific search classifier in the collection if you have any eg. user-1,
|
||||||
|
//user-2, .., otherwise use a common bucket name eg. generic, default, common, ..);
|
||||||
|
//
|
||||||
|
// - terms: text for search terms (between quotes);
|
||||||
|
//
|
||||||
|
// - count: a positive integer number; set within allowed maximum & minimum limits;
|
||||||
|
//
|
||||||
|
// - object: object identifier that refers to an entity in an external database, where the searched object is stored
|
||||||
|
// (eg. you use Sonic to index CRM contacts by name; full CRM contact data is stored in a MySQL database;
|
||||||
|
// in this case the object identifier in Sonic will be the MySQL primary key for the CRM contact);
|
||||||
|
//
|
||||||
|
// action: action to be triggered (available actions: consolidate);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Notice: the bucket terminology may confuse some Sonic users. As we are well-aware Sonic may be used in an environment
|
||||||
|
// where end-users may each hold their own search index in a given collection, we made it possible to manage per-end-user
|
||||||
|
// search indexes with bucket. If you only have a single index per collection (most Sonic users will), we advise you use
|
||||||
|
// a static generic name for your bucket, for instance: default.
|
||||||
|
package sonic
|
||||||
104
sonic/driver.go
104
sonic/driver.go
|
|
@ -13,36 +13,39 @@ import (
|
||||||
var (
|
var (
|
||||||
ClosedError = errors.New("sonic connection is closed")
|
ClosedError = errors.New("sonic connection is closed")
|
||||||
InvalidChanName = errors.New("invalid channel name")
|
InvalidChanName = errors.New("invalid channel name")
|
||||||
InvalidActionName = errors.New("invalid action name")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Base contains commons commands to all channels.
|
||||||
|
type Base interface {
|
||||||
|
// Quit stop connection, you can't execute anything after calling this method.
|
||||||
|
// Syntax command QUIT
|
||||||
|
Quit() error
|
||||||
|
|
||||||
|
// Ping ping the sonic server.
|
||||||
|
// Return an error is there is something wrong.
|
||||||
|
// If an error occur, the sonic server is maybe down.
|
||||||
|
// Syntax command PING
|
||||||
|
Ping() error
|
||||||
|
}
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
Host string
|
Host string
|
||||||
Port int
|
Port int
|
||||||
Password string
|
Password string
|
||||||
Channel Channel
|
|
||||||
|
|
||||||
|
channel Channel
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControl(host string, port int, password string) (*Driver, error) {
|
// Connect open a connection via TCP with the sonic server.
|
||||||
driver := &Driver{
|
func (c *Driver) Connect() error {
|
||||||
Host: host,
|
if !IsChannelValid(c.channel) {
|
||||||
Port: port,
|
|
||||||
Password: password,
|
|
||||||
Channel: Ingest,
|
|
||||||
}
|
|
||||||
|
|
||||||
return driver, driver.connect()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Driver) connect() error {
|
|
||||||
if !IsChannelValid(c.Channel) {
|
|
||||||
return InvalidChanName
|
return InvalidChanName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.clean()
|
||||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port))
|
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -50,7 +53,7 @@ func (c *Driver) connect() error {
|
||||||
c.conn = conn
|
c.conn = conn
|
||||||
c.reader = bufio.NewReader(c.conn)
|
c.reader = bufio.NewReader(c.conn)
|
||||||
|
|
||||||
err := c.write(fmt.Sprintf("START %s %s", c.Channel, c.Password))
|
err := c.write(fmt.Sprintf("START %s %s", c.channel, c.Password))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +67,32 @@ func (c *Driver) connect() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Driver) Quit() error {
|
||||||
|
err := c.write("QUIT")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// should get ENDED
|
||||||
|
_, err = c.read()
|
||||||
|
c.clean()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Driver) Ping() error {
|
||||||
|
err := c.write("PING")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// should get PONG
|
||||||
|
_, err = c.read()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Driver) read() (string, error) {
|
func (c *Driver) read() (string, error) {
|
||||||
if c.closed {
|
if c.closed {
|
||||||
return "", ClosedError
|
return "", ClosedError
|
||||||
|
|
@ -98,49 +127,6 @@ func (c Driver) write(str string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Driver) Quit() error {
|
|
||||||
err := c.write("QUIT")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// should get ENDED
|
|
||||||
_, err = c.read()
|
|
||||||
c.clean()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Driver) Ping() error {
|
|
||||||
err := c.write("PING")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// should get PONG
|
|
||||||
_, err = c.read()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Driver) Trigger(action Action) error {
|
|
||||||
if IsActionValid(action) {
|
|
||||||
return InvalidActionName
|
|
||||||
}
|
|
||||||
err := c.write(fmt.Sprintf("TRIGGER %s", action))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// should get OK
|
|
||||||
_, err = c.read()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Driver) clean() {
|
func (c *Driver) clean() {
|
||||||
c.closed = true
|
c.closed = true
|
||||||
_ = c.conn.Close()
|
_ = c.conn.Close()
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,38 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Ingestable is used for altering the search index (push, pop and flush).
|
||||||
type Ingestable interface {
|
type Ingestable interface {
|
||||||
|
// Push search data in the index.
|
||||||
|
// Command syntax PUSH <collection> <bucket> <object> "<text>"
|
||||||
Push(collection, bucket, object, text string) (err error)
|
Push(collection, bucket, object, text string) (err error)
|
||||||
|
|
||||||
|
// Pop search data from the index.
|
||||||
|
// Command syntax POP <collection> <bucket> <object> "<text>".
|
||||||
Pop(collection, bucket, object, text string) (err error)
|
Pop(collection, bucket, object, text string) (err error)
|
||||||
|
|
||||||
|
// Count indexed search data.
|
||||||
|
// bucket and object are optionals, empty string ignore it.
|
||||||
|
// Command syntax COUNT <collection> [<bucket> [<object>]?]?.
|
||||||
Count(collection, bucket, object string) (count int, err error)
|
Count(collection, bucket, object string) (count int, err error)
|
||||||
|
|
||||||
|
// FlushCollection Flush all indexed data from a collection.
|
||||||
|
// Command syntax FLUSHC <collection>.
|
||||||
FlushCollection(collection string) (err error)
|
FlushCollection(collection string) (err error)
|
||||||
|
|
||||||
|
// Flush all indexed data from a bucket in a collection.
|
||||||
|
// Command syntax FLUSHB <collection> <bucket>.
|
||||||
FlushBucket(collection, bucket string) (err error)
|
FlushBucket(collection, bucket string) (err error)
|
||||||
|
|
||||||
|
// Flush all indexed data from an object in a bucket in collection.
|
||||||
|
// Command syntax FLUSHO <collection> <bucket> <object>.
|
||||||
FlushObject(collection, bucket, object string) (err error)
|
FlushObject(collection, bucket, object string) (err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Quit() (err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Ping() (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ingesterCommands string
|
type ingesterCommands string
|
||||||
|
|
@ -36,9 +60,9 @@ func NewIngester(host string, port int, password string) (Ingestable, error) {
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
Password: password,
|
Password: password,
|
||||||
Channel: Ingest,
|
channel: Ingest,
|
||||||
}
|
}
|
||||||
err := driver.connect()
|
err := driver.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,23 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Searchable is used for querying the search index.
|
||||||
type Searchable interface {
|
type Searchable interface {
|
||||||
Query(collection, bucket, term string, limit, offset int) (results []string, err error)
|
|
||||||
|
// Query the database, return a list of object, represented as a string.
|
||||||
|
// Sonic default limit is 10.
|
||||||
|
// Command syntax QUERY <collection> <bucket> "<terms>" [LIMIT(<count>)]? [OFFSET(<count>)]?.
|
||||||
|
Query(collection, bucket, terms string, limit, offset int) (results []string, err error)
|
||||||
|
|
||||||
|
// Suggest auto-completes word, return a list of words as a string.
|
||||||
|
// Command syntax SUGGEST <collection> <bucket> "<word>" [LIMIT(<count>)]?.
|
||||||
Suggest(collection, bucket, word string, limit int) (results []string, err error)
|
Suggest(collection, bucket, word string, limit int) (results []string, err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Quit() (err error)
|
||||||
|
|
||||||
|
// Quit refer to the Base interface
|
||||||
|
Ping() (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchCommands string
|
type searchCommands string
|
||||||
|
|
@ -26,9 +40,9 @@ func NewSearch(host string, port int, password string) (Searchable, error) {
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
Password: password,
|
Password: password,
|
||||||
Channel: Search,
|
channel: Search,
|
||||||
}
|
}
|
||||||
err := driver.connect()
|
err := driver.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue