|
- package zk
-
- import (
- "encoding/binary"
- "errors"
- "reflect"
- "runtime"
- "time"
- )
-
- var (
- ErrUnhandledFieldType = errors.New("zk: unhandled field type")
- ErrPtrExpected = errors.New("zk: encode/decode expect a non-nil pointer to struct")
- ErrShortBuffer = errors.New("zk: buffer too small")
- )
-
- type ACL struct {
- Perms int32
- Scheme string
- ID string
- }
-
- type zkstat struct {
- ZCzxid int64 // The zxid of the change that caused this znode to be created.
- ZMzxid int64 // The zxid of the change that last modified this znode.
- ZCtime int64 // The time in milliseconds from epoch when this znode was created.
- ZMtime int64 // The time in milliseconds from epoch when this znode was last modified.
- ZVersion int32 // The number of changes to the data of this znode.
- ZCversion int32 // The number of changes to the children of this znode.
- ZAversion int32 // The number of changes to the ACL of this znode.
- ZEphemeralOwner int64 // The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.
- ZDataLength int32 // The length of the data field of this znode.
- ZNumChildren int32 // The number of children of this znode.
- ZPzxid int64 // last modified children
- }
-
- type Stat interface {
- Czxid() int64
- Mzxid() int64
- CTime() time.Time
- MTime() time.Time
- Version() int
- CVersion() int
- AVersion() int
- EphemeralOwner() int64
- DataLength() int
- NumChildren() int
- Pzxid() int64
- }
-
- // Czxid returns the zxid of the change that caused the node to be created.
- func (s *zkstat) Czxid() int64 {
- return s.ZCzxid
- }
-
- // Mzxid returns the zxid of the change that last modified the node.
- func (s *zkstat) Mzxid() int64 {
- return s.ZMzxid
- }
-
- func millisec2time(ms int64) time.Time {
- return time.Unix(ms/1e3, ms%1e3*1e6)
- }
-
- // CTime returns the time (at millisecond resolution) when the node was
- // created.
- func (s *zkstat) CTime() time.Time {
- return millisec2time(s.ZCtime)
- }
-
- // MTime returns the time (at millisecond resolution) when the node was
- // last modified.
- func (s *zkstat) MTime() time.Time {
- return millisec2time(int64(s.ZMtime))
- }
-
- // Version returns the number of changes to the data of the node.
- func (s *zkstat) Version() int {
- return int(s.ZVersion)
- }
-
- // CVersion returns the number of changes to the children of the node.
- // This only changes when children are created or removed.
- func (s *zkstat) CVersion() int {
- return int(s.ZCversion)
- }
-
- // AVersion returns the number of changes to the ACL of the node.
- func (s *zkstat) AVersion() int {
- return int(s.ZAversion)
- }
-
- // If the node is an ephemeral node, EphemeralOwner returns the session id
- // of the owner of the node; otherwise it will return zero.
- func (s *zkstat) EphemeralOwner() int64 {
- return int64(s.ZEphemeralOwner)
- }
-
- // DataLength returns the length of the data in the node in bytes.
- func (s *zkstat) DataLength() int {
- return int(s.ZDataLength)
- }
-
- // NumChildren returns the number of children of the node.
- func (s *zkstat) NumChildren() int {
- return int(s.ZNumChildren)
- }
-
- // Pzxid returns the Pzxid of the node, whatever that is.
- func (s *zkstat) Pzxid() int64 {
- return int64(s.ZPzxid)
- }
-
- type requestHeader struct {
- Xid int32
- Opcode int32
- }
-
- type responseHeader struct {
- Xid int32
- Zxid int64
- Err ErrCode
- }
-
- type multiHeader struct {
- Type int32
- Done bool
- Err ErrCode
- }
-
- type auth struct {
- Type int32
- Scheme string
- Auth []byte
- }
-
- // Generic request structs
-
- type pathRequest struct {
- Path string
- }
-
- type PathVersionRequest struct {
- Path string
- Version int32
- }
-
- type pathWatchRequest struct {
- Path string
- Watch bool
- }
-
- type pathResponse struct {
- Path string
- }
-
- type statResponse struct {
- Stat zkstat
- }
-
- //
-
- type CheckVersionRequest PathVersionRequest
- type closeRequest struct{}
- type closeResponse struct{}
-
- type connectRequest struct {
- ProtocolVersion int32
- LastZxidSeen int64
- TimeOut int32
- SessionID int64
- Passwd []byte
- }
-
- type connectResponse struct {
- ProtocolVersion int32
- TimeOut int32
- SessionID int64
- Passwd []byte
- }
-
- type CreateRequest struct {
- Path string
- Data []byte
- Acl []ACL
- Flags int32
- }
-
- type createResponse pathResponse
- type DeleteRequest PathVersionRequest
- type deleteResponse struct{}
-
- type errorResponse struct {
- Err int32
- }
-
- type existsRequest pathWatchRequest
- type existsResponse statResponse
- type getAclRequest pathRequest
-
- type getAclResponse struct {
- Acl []ACL
- Stat zkstat
- }
-
- type getChildrenRequest pathRequest
-
- type getChildrenResponse struct {
- Children []string
- }
-
- type getChildren2Request pathWatchRequest
-
- type getChildren2Response struct {
- Children []string
- Stat zkstat
- }
-
- type getDataRequest pathWatchRequest
-
- type getDataResponse struct {
- Data []byte
- Stat zkstat
- }
-
- type getMaxChildrenRequest pathRequest
-
- type getMaxChildrenResponse struct {
- Max int32
- }
-
- type getSaslRequest struct {
- Token []byte
- }
-
- type pingRequest struct{}
- type pingResponse struct{}
-
- type setAclRequest struct {
- Path string
- Acl []ACL
- Version int32
- }
-
- type setAclResponse statResponse
-
- type SetDataRequest struct {
- Path string
- Data []byte
- Version int32
- }
-
- type setDataResponse statResponse
-
- type setMaxChildren struct {
- Path string
- Max int32
- }
-
- type setSaslRequest struct {
- Token string
- }
-
- type setSaslResponse struct {
- Token string
- }
-
- type setWatchesRequest struct {
- RelativeZxid int64
- DataWatches []string
- ExistWatches []string
- ChildWatches []string
- }
-
- type setWatchesResponse struct{}
-
- type syncRequest pathRequest
- type syncResponse pathResponse
-
- type setAuthRequest auth
- type setAuthResponse struct{}
-
- type multiRequestOp struct {
- Header multiHeader
- Op interface{}
- }
- type multiRequest struct {
- Ops []multiRequestOp
- DoneHeader multiHeader
- }
- type multiResponseOp struct {
- Header multiHeader
- String string
- Stat *zkstat
- }
- type multiResponse struct {
- Ops []multiResponseOp
- DoneHeader multiHeader
- }
-
- func (r *multiRequest) Encode(buf []byte) (int, error) {
- total := 0
- for _, op := range r.Ops {
- op.Header.Done = false
- n, err := encodePacketValue(buf[total:], reflect.ValueOf(op))
- if err != nil {
- return total, err
- }
- total += n
- }
- r.DoneHeader.Done = true
- n, err := encodePacketValue(buf[total:], reflect.ValueOf(r.DoneHeader))
- if err != nil {
- return total, err
- }
- total += n
-
- return total, nil
- }
-
- func (r *multiRequest) Decode(buf []byte) (int, error) {
- r.Ops = make([]multiRequestOp, 0)
- r.DoneHeader = multiHeader{-1, true, -1}
- total := 0
- for {
- header := &multiHeader{}
- n, err := decodePacketValue(buf[total:], reflect.ValueOf(header))
- if err != nil {
- return total, err
- }
- total += n
- if header.Done {
- r.DoneHeader = *header
- break
- }
-
- req := requestStructForOp(header.Type)
- if req == nil {
- return total, ErrAPIError
- }
- n, err = decodePacketValue(buf[total:], reflect.ValueOf(req))
- if err != nil {
- return total, err
- }
- total += n
- r.Ops = append(r.Ops, multiRequestOp{*header, req})
- }
- return total, nil
- }
-
- func (r *multiResponse) Decode(buf []byte) (int, error) {
- r.Ops = make([]multiResponseOp, 0)
- r.DoneHeader = multiHeader{-1, true, -1}
- total := 0
- for {
- header := &multiHeader{}
- n, err := decodePacketValue(buf[total:], reflect.ValueOf(header))
- if err != nil {
- return total, err
- }
- total += n
- if header.Done {
- r.DoneHeader = *header
- break
- }
-
- res := multiResponseOp{Header: *header}
- var w reflect.Value
- switch header.Type {
- default:
- return total, ErrAPIError
- case opCreate:
- w = reflect.ValueOf(&res.String)
- case opSetData:
- res.Stat = new(zkstat)
- w = reflect.ValueOf(res.Stat)
- case opCheck, opDelete:
- }
- if w.IsValid() {
- n, err := decodePacketValue(buf[total:], w)
- if err != nil {
- return total, err
- }
- total += n
- }
- r.Ops = append(r.Ops, res)
- }
- return total, nil
- }
-
- type watcherEvent struct {
- Type EventType
- State State
- Path string
- }
-
- type decoder interface {
- Decode(buf []byte) (int, error)
- }
-
- type encoder interface {
- Encode(buf []byte) (int, error)
- }
-
- func decodePacket(buf []byte, st interface{}) (n int, err error) {
- defer func() {
- if r := recover(); r != nil {
- if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: slice bounds out of range" {
- err = ErrShortBuffer
- } else {
- panic(r)
- }
- }
- }()
-
- v := reflect.ValueOf(st)
- if v.Kind() != reflect.Ptr || v.IsNil() {
- return 0, ErrPtrExpected
- }
- return decodePacketValue(buf, v)
- }
-
- func decodePacketValue(buf []byte, v reflect.Value) (int, error) {
- rv := v
- kind := v.Kind()
- if kind == reflect.Ptr {
- if v.IsNil() {
- v.Set(reflect.New(v.Type().Elem()))
- }
- v = v.Elem()
- kind = v.Kind()
- }
-
- n := 0
- switch kind {
- default:
- return n, ErrUnhandledFieldType
- case reflect.Struct:
- if de, ok := rv.Interface().(decoder); ok {
- return de.Decode(buf)
- } else if de, ok := v.Interface().(decoder); ok {
- return de.Decode(buf)
- } else {
- for i := 0; i < v.NumField(); i++ {
- field := v.Field(i)
- n2, err := decodePacketValue(buf[n:], field)
- n += n2
- if err != nil {
- return n, err
- }
- }
- }
- case reflect.Bool:
- v.SetBool(buf[n] != 0)
- n++
- case reflect.Int32:
- v.SetInt(int64(binary.BigEndian.Uint32(buf[n : n+4])))
- n += 4
- case reflect.Int64:
- v.SetInt(int64(binary.BigEndian.Uint64(buf[n : n+8])))
- n += 8
- case reflect.String:
- ln := int(binary.BigEndian.Uint32(buf[n : n+4]))
- v.SetString(string(buf[n+4 : n+4+ln]))
- n += 4 + ln
- case reflect.Slice:
- switch v.Type().Elem().Kind() {
- default:
- count := int(binary.BigEndian.Uint32(buf[n : n+4]))
- n += 4
- values := reflect.MakeSlice(v.Type(), count, count)
- v.Set(values)
- for i := 0; i < count; i++ {
- n2, err := decodePacketValue(buf[n:], values.Index(i))
- n += n2
- if err != nil {
- return n, err
- }
- }
- case reflect.Uint8:
- ln := int(int32(binary.BigEndian.Uint32(buf[n : n+4])))
- if ln < 0 {
- n += 4
- v.SetBytes(nil)
- } else {
- bytes := make([]byte, ln)
- copy(bytes, buf[n+4:n+4+ln])
- v.SetBytes(bytes)
- n += 4 + ln
- }
- }
- }
- return n, nil
- }
-
- func encodePacket(buf []byte, st interface{}) (n int, err error) {
- defer func() {
- if r := recover(); r != nil {
- if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: slice bounds out of range" {
- err = ErrShortBuffer
- } else {
- panic(r)
- }
- }
- }()
-
- v := reflect.ValueOf(st)
- if v.Kind() != reflect.Ptr || v.IsNil() {
- return 0, ErrPtrExpected
- }
- return encodePacketValue(buf, v)
- }
-
- func encodePacketValue(buf []byte, v reflect.Value) (int, error) {
- rv := v
- for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
- v = v.Elem()
- }
-
- n := 0
- switch v.Kind() {
- default:
- return n, ErrUnhandledFieldType
- case reflect.Struct:
- if en, ok := rv.Interface().(encoder); ok {
- return en.Encode(buf)
- } else if en, ok := v.Interface().(encoder); ok {
- return en.Encode(buf)
- } else {
- for i := 0; i < v.NumField(); i++ {
- field := v.Field(i)
- n2, err := encodePacketValue(buf[n:], field)
- n += n2
- if err != nil {
- return n, err
- }
- }
- }
- case reflect.Bool:
- if v.Bool() {
- buf[n] = 1
- } else {
- buf[n] = 0
- }
- n++
- case reflect.Int32:
- binary.BigEndian.PutUint32(buf[n:n+4], uint32(v.Int()))
- n += 4
- case reflect.Int64:
- binary.BigEndian.PutUint64(buf[n:n+8], uint64(v.Int()))
- n += 8
- case reflect.String:
- str := v.String()
- binary.BigEndian.PutUint32(buf[n:n+4], uint32(len(str)))
- copy(buf[n+4:n+4+len(str)], []byte(str))
- n += 4 + len(str)
- case reflect.Slice:
- switch v.Type().Elem().Kind() {
- default:
- count := v.Len()
- startN := n
- n += 4
- for i := 0; i < count; i++ {
- n2, err := encodePacketValue(buf[n:], v.Index(i))
- n += n2
- if err != nil {
- return n, err
- }
- }
- binary.BigEndian.PutUint32(buf[startN:startN+4], uint32(count))
- case reflect.Uint8:
- if v.IsNil() {
- binary.BigEndian.PutUint32(buf[n:n+4], uint32(0xffffffff))
- n += 4
- } else {
- bytes := v.Bytes()
- binary.BigEndian.PutUint32(buf[n:n+4], uint32(len(bytes)))
- copy(buf[n+4:n+4+len(bytes)], bytes)
- n += 4 + len(bytes)
- }
- }
- }
- return n, nil
- }
-
- func requestStructForOp(op int32) interface{} {
- switch op {
- case opClose:
- return &closeRequest{}
- case opCreate:
- return &CreateRequest{}
- case opDelete:
- return &DeleteRequest{}
- case opExists:
- return &existsRequest{}
- case opGetAcl:
- return &getAclRequest{}
- case opGetChildren:
- return &getChildrenRequest{}
- case opGetChildren2:
- return &getChildren2Request{}
- case opGetData:
- return &getDataRequest{}
- case opPing:
- return &pingRequest{}
- case opSetAcl:
- return &setAclRequest{}
- case opSetData:
- return &SetDataRequest{}
- case opSetWatches:
- return &setWatchesRequest{}
- case opSync:
- return &syncRequest{}
- case opSetAuth:
- return &setAuthRequest{}
- case opCheck:
- return &CheckVersionRequest{}
- case opMulti:
- return &multiRequest{}
- }
- return nil
- }
-
- func responseStructForOp(op int32) interface{} {
- switch op {
- case opClose:
- return &closeResponse{}
- case opCreate:
- return &createResponse{}
- case opDelete:
- return &deleteResponse{}
- case opExists:
- return &existsResponse{}
- case opGetAcl:
- return &getAclResponse{}
- case opGetChildren:
- return &getChildrenResponse{}
- case opGetChildren2:
- return &getChildren2Response{}
- case opGetData:
- return &getDataResponse{}
- case opPing:
- return &pingResponse{}
- case opSetAcl:
- return &setAclResponse{}
- case opSetData:
- return &setDataResponse{}
- case opSetWatches:
- return &setWatchesResponse{}
- case opSync:
- return &syncResponse{}
- case opWatcherEvent:
- return &watcherEvent{}
- case opSetAuth:
- return &setAuthResponse{}
- // case opCheck:
- // return &checkVersionResponse{}
- case opMulti:
- return &multiResponse{}
- }
- return nil
- }
|