goserver_sync/core/zk/zk.go

125 lines
3.3 KiB
Go

package zk
import (
"errors"
"path"
"strings"
"time"
"github.com/samuel/go-zookeeper/zk"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module"
)
var (
// error
ErrNoChild = errors.New("zk: children is nil")
ErrNodeNotExist = errors.New("zk: node not exist")
)
// Connect connect to zookeeper, and start a goroutine log the event.
func Connect(addr []string, timeout time.Duration) (*zk.Conn, error) {
conn, session, err := zk.Connect(addr, timeout)
if err != nil {
logger.Logger.Errorf("zk.Connect(\"%v\", %d) error(%v)", addr, timeout, err)
return nil, err
}
go func() {
for {
event := <-session
logger.Logger.Tracef("zookeeper get a event: %s", event.State.String())
}
}()
return conn, nil
}
// Create create zookeeper path, if path exists ignore error
func Create(conn *zk.Conn, fpath string) error {
// create zk root path
tpath := ""
for _, str := range strings.Split(fpath, "/")[1:] {
tpath = path.Join(tpath, "/", str)
logger.Logger.Tracef("create zookeeper path: \"%s\"", tpath)
_, err := conn.Create(tpath, []byte(""), 0, zk.WorldACL(zk.PermAll))
if err != nil {
if err == zk.ErrNodeExists {
logger.Logger.Warnf("zk.create(\"%s\") exists", tpath)
} else {
logger.Logger.Errorf("zk.create(\"%s\") error(%v)", tpath, err)
return err
}
}
}
return nil
}
// RegisterTmp create a ephemeral node, and watch it, if node droped then shutdown.
func RegisterTemp(conn *zk.Conn, fpath string, data []byte) error {
tpath, err := conn.Create(path.Join(fpath)+"/", data, zk.FlagEphemeral|zk.FlagSequence, zk.WorldACL(zk.PermAll))
if err != nil {
logger.Logger.Errorf("conn.Create(\"%s\", \"%s\", zk.FlagEphemeral|zk.FlagSequence) error(%v)", fpath, string(data), err)
return err
}
logger.Logger.Tracef("create a zookeeper node:%s", tpath)
// watch self
go func() {
for {
logger.Logger.Infof("zk path: \"%s\" set a watch", tpath)
exist, _, watch, err := conn.ExistsW(tpath)
if err != nil {
logger.Logger.Errorf("zk.ExistsW(\"%s\") error(%v)", tpath, err)
logger.Logger.Warnf("zk path: \"%s\" set watch failed, shutdown", tpath)
module.Stop()
return
}
if !exist {
logger.Logger.Warnf("zk path: \"%s\" not exist, shutdown", tpath)
module.Stop()
return
}
event := <-watch
logger.Logger.Infof("zk path: \"%s\" receive a event %v", tpath, event)
}
}()
return nil
}
// GetNodesW get all child from zk path with a watch.
func GetNodesW(conn *zk.Conn, path string) ([]string, <-chan zk.Event, error) {
nodes, stat, watch, err := conn.ChildrenW(path)
if err != nil {
if err == zk.ErrNoNode {
return nil, nil, ErrNodeNotExist
}
logger.Logger.Errorf("zk.ChildrenW(\"%s\") error(%v)", path, err)
return nil, nil, err
}
if stat == nil {
return nil, nil, ErrNodeNotExist
}
if len(nodes) == 0 {
return nil, nil, ErrNoChild
}
return nodes, watch, nil
}
// GetNodes get all child from zk path.
func GetNodes(conn *zk.Conn, path string) ([]string, error) {
nodes, stat, err := conn.Children(path)
if err != nil {
if err == zk.ErrNoNode {
return nil, ErrNodeNotExist
}
logger.Logger.Errorf("zk.Children(\"%s\") error(%v)", path, err)
return nil, err
}
if stat == nil {
return nil, ErrNodeNotExist
}
if len(nodes) == 0 {
return nil, ErrNoChild
}
return nodes, nil
}