You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
2.8 KiB
137 lines
2.8 KiB
package livezk |
|
|
|
import ( |
|
"context" |
|
"encoding/json" |
|
"errors" |
|
"net/url" |
|
"path" |
|
"strings" |
|
"time" |
|
|
|
"go-common/library/log" |
|
"go-common/library/naming" |
|
xtime "go-common/library/time" |
|
|
|
"github.com/samuel/go-zookeeper/zk" |
|
) |
|
|
|
const ( |
|
basePath = "/live/service" |
|
scheme = "grpc" |
|
) |
|
|
|
// Zookeeper Server&Client settings. |
|
type Zookeeper struct { |
|
Root string |
|
Addrs []string |
|
Timeout xtime.Duration |
|
} |
|
|
|
// New new live zookeeper registry |
|
func New(config *Zookeeper) (naming.Registry, error) { |
|
lz := &livezk{ |
|
zkConfig: config, |
|
} |
|
var err error |
|
lz.zkConn, lz.zkEvent, err = zk.Connect(config.Addrs, time.Duration(config.Timeout)) |
|
if err != nil { |
|
go lz.eventproc() |
|
} |
|
return lz, err |
|
} |
|
|
|
type zkIns struct { |
|
Group string `json:"group"` |
|
LibVersion string `json:"lib_version"` |
|
StartupTime string `json:"startup_time"` |
|
} |
|
|
|
func newZkInsData(ins *naming.Instance) ([]byte, error) { |
|
zi := &zkIns{ |
|
// TODO group support |
|
Group: "default", |
|
LibVersion: ins.Version, |
|
StartupTime: time.Now().Format("2006-01-02 15:04:05"), |
|
} |
|
return json.Marshal(zi) |
|
} |
|
|
|
// livezk live service zookeeper registry |
|
type livezk struct { |
|
zkConfig *Zookeeper |
|
zkConn *zk.Conn |
|
zkEvent <-chan zk.Event |
|
} |
|
|
|
var _ naming.Registry = &livezk{} |
|
|
|
func (l *livezk) Register(ctx context.Context, ins *naming.Instance) (cancel context.CancelFunc, err error) { |
|
nodePath := path.Join(l.zkConfig.Root, basePath, ins.AppID) |
|
if err = l.createAll(nodePath); err != nil { |
|
return |
|
} |
|
var rpc string |
|
for _, addr := range ins.Addrs { |
|
u, ue := url.Parse(addr) |
|
if ue == nil && u.Scheme == scheme { |
|
rpc = u.Host |
|
break |
|
} |
|
} |
|
if rpc == "" { |
|
err = errors.New("no GRPC addr") |
|
return |
|
} |
|
|
|
dataPath := path.Join(nodePath, rpc) |
|
data, err := newZkInsData(ins) |
|
if err != nil { |
|
return nil, err |
|
} |
|
_, err = l.zkConn.Create(dataPath, data, zk.FlagEphemeral, zk.WorldACL(zk.PermAll)) |
|
if err != nil { |
|
return nil, err |
|
} |
|
return func() { |
|
l.unregister(dataPath) |
|
}, nil |
|
} |
|
|
|
func (l *livezk) Close() error { |
|
l.zkConn.Close() |
|
return nil |
|
} |
|
|
|
func (l *livezk) createAll(nodePath string) (err error) { |
|
seps := strings.Split(nodePath, "/") |
|
lastPath := "/" |
|
ok := false |
|
for _, part := range seps { |
|
if part == "" { |
|
continue |
|
} |
|
lastPath = path.Join(lastPath, part) |
|
if ok, _, err = l.zkConn.Exists(lastPath); err != nil { |
|
return err |
|
} else if ok { |
|
continue |
|
} |
|
if _, err = l.zkConn.Create(lastPath, nil, 0, zk.WorldACL(zk.PermAll)); err != nil { |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (l *livezk) eventproc() { |
|
for event := range l.zkEvent { |
|
// TODO handle zookeeper event |
|
log.Info("zk event: err: %s, path: %s, server: %s, state: %s, type: %s", |
|
event.Err, event.Path, event.Server, event.State, event.Type) |
|
} |
|
} |
|
|
|
func (l *livezk) unregister(dataPath string) error { |
|
return l.zkConn.Delete(dataPath, -1) |
|
}
|
|
|