dependencies for mesos cloud provider
This commit is contained in:
28
Godeps/Godeps.json
generated
28
Godeps/Godeps.json
generated
@@ -187,6 +187,10 @@
|
||||
"Comment": "0-7-g939230d",
|
||||
"Rev": "939230d2086a4f1870e04c52e0a376c25bae0ec4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Rev": "ab6cea4a44ef42b748cd88d2d372047b75806e0c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/glog",
|
||||
"Rev": "44145f04b68cf362d9c4df2182967c2275eaefed"
|
||||
@@ -327,6 +331,22 @@
|
||||
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",
|
||||
"Rev": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/detector",
|
||||
"Rev": "4b1767c0dfc51020e01f35da5b38472f40ce572a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/mesosproto",
|
||||
"Rev": "4b1767c0dfc51020e01f35da5b38472f40ce572a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/mesosutil",
|
||||
"Rev": "4b1767c0dfc51020e01f35da5b38472f40ce572a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mesos/mesos-go/upid",
|
||||
"Rev": "4b1767c0dfc51020e01f35da5b38472f40ce572a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
"Rev": "3f504e8dabd5d562e997d19ce0200aa41973e1b2"
|
||||
@@ -387,6 +407,10 @@
|
||||
"Comment": "v1.2-42-g77efab5",
|
||||
"Rev": "77efab57b2f74dd3f9051c79752b2e8995c8b789"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||
"Rev": "d0e0d8e11f318e000a8cc434616d69e329edc374"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/shurcooL/sanitized_anchor_name",
|
||||
"Rev": "9a8b7d4e8f347bfa230879db9d7d4e4d9e19f962"
|
||||
@@ -420,6 +444,10 @@
|
||||
"ImportPath": "github.com/stretchr/testify/require",
|
||||
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/suite",
|
||||
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/gocapability/capability",
|
||||
"Rev": "3c85049eaeb429febe7788d9c7aac42322a377fe"
|
||||
|
||||
40
Godeps/_workspace/src/github.com/gogo/protobuf/proto/Makefile
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/gogo/protobuf/proto/Makefile
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# Go support for Protocol Buffers - Google's data interchange format
|
||||
#
|
||||
# Copyright 2010 The Go Authors. All rights reserved.
|
||||
# https://github.com/golang/protobuf
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
install:
|
||||
go install
|
||||
|
||||
test: install generate-test-pbs
|
||||
go test
|
||||
|
||||
|
||||
generate-test-pbs:
|
||||
make install && cd testdata && make
|
||||
1979
Godeps/_workspace/src/github.com/gogo/protobuf/proto/all_test.go
generated
vendored
Normal file
1979
Godeps/_workspace/src/github.com/gogo/protobuf/proto/all_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
179
Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go
generated
vendored
Normal file
179
Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone.go
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Protocol buffer deep copy.
|
||||
// TODO: MessageSet and RawMessage.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Clone returns a deep copy of a protocol buffer.
|
||||
func Clone(pb Message) Message {
|
||||
in := reflect.ValueOf(pb)
|
||||
if in.IsNil() {
|
||||
return pb
|
||||
}
|
||||
|
||||
out := reflect.New(in.Type().Elem())
|
||||
// out is empty so a merge is a deep copy.
|
||||
mergeStruct(out.Elem(), in.Elem())
|
||||
return out.Interface().(Message)
|
||||
}
|
||||
|
||||
// Merge merges src into dst.
|
||||
// Required and optional fields that are set in src will be set to that value in dst.
|
||||
// Elements of repeated fields will be appended.
|
||||
// Merge panics if src and dst are not the same type, or if dst is nil.
|
||||
func Merge(dst, src Message) {
|
||||
in := reflect.ValueOf(src)
|
||||
out := reflect.ValueOf(dst)
|
||||
if out.IsNil() {
|
||||
panic("proto: nil destination")
|
||||
}
|
||||
if in.Type() != out.Type() {
|
||||
// Explicit test prior to mergeStruct so that mistyped nils will fail
|
||||
panic("proto: type mismatch")
|
||||
}
|
||||
if in.IsNil() {
|
||||
// Merging nil into non-nil is a quiet no-op
|
||||
return
|
||||
}
|
||||
mergeStruct(out.Elem(), in.Elem())
|
||||
}
|
||||
|
||||
func mergeStruct(out, in reflect.Value) {
|
||||
for i := 0; i < in.NumField(); i++ {
|
||||
f := in.Type().Field(i)
|
||||
if strings.HasPrefix(f.Name, "XXX_") {
|
||||
continue
|
||||
}
|
||||
mergeAny(out.Field(i), in.Field(i))
|
||||
}
|
||||
|
||||
if emIn, ok := in.Addr().Interface().(extensionsMap); ok {
|
||||
emOut := out.Addr().Interface().(extensionsMap)
|
||||
mergeExtension(emOut.ExtensionMap(), emIn.ExtensionMap())
|
||||
} else if emIn, ok := in.Addr().Interface().(extensionsBytes); ok {
|
||||
emOut := out.Addr().Interface().(extensionsBytes)
|
||||
bIn := emIn.GetExtensions()
|
||||
bOut := emOut.GetExtensions()
|
||||
*bOut = append(*bOut, *bIn...)
|
||||
}
|
||||
|
||||
uf := in.FieldByName("XXX_unrecognized")
|
||||
if !uf.IsValid() {
|
||||
return
|
||||
}
|
||||
uin := uf.Bytes()
|
||||
if len(uin) > 0 {
|
||||
out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
|
||||
}
|
||||
}
|
||||
|
||||
func mergeAny(out, in reflect.Value) {
|
||||
if in.Type() == protoMessageType {
|
||||
if !in.IsNil() {
|
||||
if out.IsNil() {
|
||||
out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
|
||||
} else {
|
||||
Merge(out.Interface().(Message), in.Interface().(Message))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
switch in.Kind() {
|
||||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
|
||||
reflect.String, reflect.Uint32, reflect.Uint64:
|
||||
out.Set(in)
|
||||
case reflect.Ptr:
|
||||
if in.IsNil() {
|
||||
return
|
||||
}
|
||||
if out.IsNil() {
|
||||
out.Set(reflect.New(in.Elem().Type()))
|
||||
}
|
||||
mergeAny(out.Elem(), in.Elem())
|
||||
case reflect.Slice:
|
||||
if in.IsNil() {
|
||||
return
|
||||
}
|
||||
if in.Type().Elem().Kind() == reflect.Uint8 {
|
||||
// []byte is a scalar bytes field, not a repeated field.
|
||||
// Make a deep copy.
|
||||
// Append to []byte{} instead of []byte(nil) so that we never end up
|
||||
// with a nil result.
|
||||
out.SetBytes(append([]byte{}, in.Bytes()...))
|
||||
return
|
||||
}
|
||||
n := in.Len()
|
||||
if out.IsNil() {
|
||||
out.Set(reflect.MakeSlice(in.Type(), 0, n))
|
||||
}
|
||||
switch in.Type().Elem().Kind() {
|
||||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
|
||||
reflect.String, reflect.Uint32, reflect.Uint64:
|
||||
out.Set(reflect.AppendSlice(out, in))
|
||||
default:
|
||||
for i := 0; i < n; i++ {
|
||||
x := reflect.Indirect(reflect.New(in.Type().Elem()))
|
||||
mergeAny(x, in.Index(i))
|
||||
out.Set(reflect.Append(out, x))
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
mergeStruct(out, in)
|
||||
default:
|
||||
// unknown type, so not a protocol buffer
|
||||
log.Printf("proto: don't know how to copy %v", in)
|
||||
}
|
||||
}
|
||||
|
||||
func mergeExtension(out, in map[int32]Extension) {
|
||||
for extNum, eIn := range in {
|
||||
eOut := Extension{desc: eIn.desc}
|
||||
if eIn.value != nil {
|
||||
v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
|
||||
mergeAny(v, reflect.ValueOf(eIn.value))
|
||||
eOut.value = v.Interface()
|
||||
}
|
||||
if eIn.enc != nil {
|
||||
eOut.enc = make([]byte, len(eIn.enc))
|
||||
copy(eOut.enc, eIn.enc)
|
||||
}
|
||||
|
||||
out[extNum] = eOut
|
||||
}
|
||||
}
|
||||
202
Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone_test.go
generated
vendored
Normal file
202
Godeps/_workspace/src/github.com/gogo/protobuf/proto/clone_test.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
pb "./testdata"
|
||||
)
|
||||
|
||||
var cloneTestMessage = &pb.MyMessage{
|
||||
Count: proto.Int32(42),
|
||||
Name: proto.String("Dave"),
|
||||
Pet: []string{"bunny", "kitty", "horsey"},
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("niles"),
|
||||
Port: proto.Int32(9099),
|
||||
Connected: proto.Bool(true),
|
||||
},
|
||||
Others: []*pb.OtherMessage{
|
||||
{
|
||||
Value: []byte("some bytes"),
|
||||
},
|
||||
},
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: proto.Int32(6),
|
||||
},
|
||||
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
|
||||
}
|
||||
|
||||
func init() {
|
||||
ext := &pb.Ext{
|
||||
Data: proto.String("extension"),
|
||||
}
|
||||
if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil {
|
||||
panic("SetExtension: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
m := proto.Clone(cloneTestMessage).(*pb.MyMessage)
|
||||
if !proto.Equal(m, cloneTestMessage) {
|
||||
t.Errorf("Clone(%v) = %v", cloneTestMessage, m)
|
||||
}
|
||||
|
||||
// Verify it was a deep copy.
|
||||
*m.Inner.Port++
|
||||
if proto.Equal(m, cloneTestMessage) {
|
||||
t.Error("Mutating clone changed the original")
|
||||
}
|
||||
// Byte fields and repeated fields should be copied.
|
||||
if &m.Pet[0] == &cloneTestMessage.Pet[0] {
|
||||
t.Error("Pet: repeated field not copied")
|
||||
}
|
||||
if &m.Others[0] == &cloneTestMessage.Others[0] {
|
||||
t.Error("Others: repeated field not copied")
|
||||
}
|
||||
if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] {
|
||||
t.Error("Others[0].Value: bytes field not copied")
|
||||
}
|
||||
if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] {
|
||||
t.Error("RepBytes: repeated field not copied")
|
||||
}
|
||||
if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] {
|
||||
t.Error("RepBytes[0]: bytes field not copied")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneNil(t *testing.T) {
|
||||
var m *pb.MyMessage
|
||||
if c := proto.Clone(m); !proto.Equal(m, c) {
|
||||
t.Errorf("Clone(%v) = %v", m, c)
|
||||
}
|
||||
}
|
||||
|
||||
var mergeTests = []struct {
|
||||
src, dst, want proto.Message
|
||||
}{
|
||||
{
|
||||
src: &pb.MyMessage{
|
||||
Count: proto.Int32(42),
|
||||
},
|
||||
dst: &pb.MyMessage{
|
||||
Name: proto.String("Dave"),
|
||||
},
|
||||
want: &pb.MyMessage{
|
||||
Count: proto.Int32(42),
|
||||
Name: proto.String("Dave"),
|
||||
},
|
||||
},
|
||||
{
|
||||
src: &pb.MyMessage{
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("hey"),
|
||||
Connected: proto.Bool(true),
|
||||
},
|
||||
Pet: []string{"horsey"},
|
||||
Others: []*pb.OtherMessage{
|
||||
{
|
||||
Value: []byte("some bytes"),
|
||||
},
|
||||
},
|
||||
},
|
||||
dst: &pb.MyMessage{
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("niles"),
|
||||
Port: proto.Int32(9099),
|
||||
},
|
||||
Pet: []string{"bunny", "kitty"},
|
||||
Others: []*pb.OtherMessage{
|
||||
{
|
||||
Key: proto.Int64(31415926535),
|
||||
},
|
||||
{
|
||||
// Explicitly test a src=nil field
|
||||
Inner: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &pb.MyMessage{
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("hey"),
|
||||
Connected: proto.Bool(true),
|
||||
Port: proto.Int32(9099),
|
||||
},
|
||||
Pet: []string{"bunny", "kitty", "horsey"},
|
||||
Others: []*pb.OtherMessage{
|
||||
{
|
||||
Key: proto.Int64(31415926535),
|
||||
},
|
||||
{},
|
||||
{
|
||||
Value: []byte("some bytes"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
src: &pb.MyMessage{
|
||||
RepBytes: [][]byte{[]byte("wow")},
|
||||
},
|
||||
dst: &pb.MyMessage{
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: proto.Int32(6),
|
||||
},
|
||||
RepBytes: [][]byte{[]byte("sham")},
|
||||
},
|
||||
want: &pb.MyMessage{
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: proto.Int32(6),
|
||||
},
|
||||
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
|
||||
},
|
||||
},
|
||||
// Check that a scalar bytes field replaces rather than appends.
|
||||
{
|
||||
src: &pb.OtherMessage{Value: []byte("foo")},
|
||||
dst: &pb.OtherMessage{Value: []byte("bar")},
|
||||
want: &pb.OtherMessage{Value: []byte("foo")},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for _, m := range mergeTests {
|
||||
got := proto.Clone(m.dst)
|
||||
proto.Merge(got, m.src)
|
||||
if !proto.Equal(got, m.want) {
|
||||
t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
726
Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go
generated
vendored
Normal file
726
Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode.go
generated
vendored
Normal file
@@ -0,0 +1,726 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
/*
|
||||
* Routines for decoding protocol buffer data to construct in-memory representations.
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// errOverflow is returned when an integer is too large to be represented.
|
||||
var errOverflow = errors.New("proto: integer overflow")
|
||||
|
||||
// The fundamental decoders that interpret bytes on the wire.
|
||||
// Those that take integer types all return uint64 and are
|
||||
// therefore of type valueDecoder.
|
||||
|
||||
// DecodeVarint reads a varint-encoded integer from the slice.
|
||||
// It returns the integer and the number of bytes consumed, or
|
||||
// zero if there is not enough.
|
||||
// This is the format for the
|
||||
// int32, int64, uint32, uint64, bool, and enum
|
||||
// protocol buffer types.
|
||||
func DecodeVarint(buf []byte) (x uint64, n int) {
|
||||
// x, n already 0
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if n >= len(buf) {
|
||||
return 0, 0
|
||||
}
|
||||
b := uint64(buf[n])
|
||||
n++
|
||||
x |= (b & 0x7F) << shift
|
||||
if (b & 0x80) == 0 {
|
||||
return x, n
|
||||
}
|
||||
}
|
||||
|
||||
// The number is too large to represent in a 64-bit value.
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// DecodeVarint reads a varint-encoded integer from the Buffer.
|
||||
// This is the format for the
|
||||
// int32, int64, uint32, uint64, bool, and enum
|
||||
// protocol buffer types.
|
||||
func (p *Buffer) DecodeVarint() (x uint64, err error) {
|
||||
// x, err already 0
|
||||
|
||||
i := p.index
|
||||
l := len(p.buf)
|
||||
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if i >= l {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return
|
||||
}
|
||||
b := p.buf[i]
|
||||
i++
|
||||
x |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
p.index = i
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// The number is too large to represent in a 64-bit value.
|
||||
err = errOverflow
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeFixed64 reads a 64-bit integer from the Buffer.
|
||||
// This is the format for the
|
||||
// fixed64, sfixed64, and double protocol buffer types.
|
||||
func (p *Buffer) DecodeFixed64() (x uint64, err error) {
|
||||
// x, err already 0
|
||||
i := p.index + 8
|
||||
if i < 0 || i > len(p.buf) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return
|
||||
}
|
||||
p.index = i
|
||||
|
||||
x = uint64(p.buf[i-8])
|
||||
x |= uint64(p.buf[i-7]) << 8
|
||||
x |= uint64(p.buf[i-6]) << 16
|
||||
x |= uint64(p.buf[i-5]) << 24
|
||||
x |= uint64(p.buf[i-4]) << 32
|
||||
x |= uint64(p.buf[i-3]) << 40
|
||||
x |= uint64(p.buf[i-2]) << 48
|
||||
x |= uint64(p.buf[i-1]) << 56
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeFixed32 reads a 32-bit integer from the Buffer.
|
||||
// This is the format for the
|
||||
// fixed32, sfixed32, and float protocol buffer types.
|
||||
func (p *Buffer) DecodeFixed32() (x uint64, err error) {
|
||||
// x, err already 0
|
||||
i := p.index + 4
|
||||
if i < 0 || i > len(p.buf) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
return
|
||||
}
|
||||
p.index = i
|
||||
|
||||
x = uint64(p.buf[i-4])
|
||||
x |= uint64(p.buf[i-3]) << 8
|
||||
x |= uint64(p.buf[i-2]) << 16
|
||||
x |= uint64(p.buf[i-1]) << 24
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
|
||||
// from the Buffer.
|
||||
// This is the format used for the sint64 protocol buffer type.
|
||||
func (p *Buffer) DecodeZigzag64() (x uint64, err error) {
|
||||
x, err = p.DecodeVarint()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
|
||||
// from the Buffer.
|
||||
// This is the format used for the sint32 protocol buffer type.
|
||||
func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
|
||||
x, err = p.DecodeVarint()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
|
||||
return
|
||||
}
|
||||
|
||||
// These are not ValueDecoders: they produce an array of bytes or a string.
|
||||
// bytes, embedded messages
|
||||
|
||||
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
|
||||
// This is the format used for the bytes protocol buffer
|
||||
// type and for embedded messages.
|
||||
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
|
||||
n, err := p.DecodeVarint()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
nb := int(n)
|
||||
if nb < 0 {
|
||||
return nil, fmt.Errorf("proto: bad byte length %d", nb)
|
||||
}
|
||||
end := p.index + nb
|
||||
if end < p.index || end > len(p.buf) {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
if !alloc {
|
||||
// todo: check if can get more uses of alloc=false
|
||||
buf = p.buf[p.index:end]
|
||||
p.index += nb
|
||||
return
|
||||
}
|
||||
|
||||
buf = make([]byte, nb)
|
||||
copy(buf, p.buf[p.index:])
|
||||
p.index += nb
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeStringBytes reads an encoded string from the Buffer.
|
||||
// This is the format used for the proto2 string type.
|
||||
func (p *Buffer) DecodeStringBytes() (s string, err error) {
|
||||
buf, err := p.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||
// If the protocol buffer has extensions, and the field matches, add it as an extension.
|
||||
// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
|
||||
func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
|
||||
oi := o.index
|
||||
|
||||
err := o.skip(t, tag, wire)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !unrecField.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ptr := structPointer_Bytes(base, unrecField)
|
||||
|
||||
// Add the skipped field to struct field
|
||||
obuf := o.buf
|
||||
|
||||
o.buf = *ptr
|
||||
o.EncodeVarint(uint64(tag<<3 | wire))
|
||||
*ptr = append(o.buf, obuf[oi:o.index]...)
|
||||
|
||||
o.buf = obuf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||
func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
|
||||
|
||||
var u uint64
|
||||
var err error
|
||||
|
||||
switch wire {
|
||||
case WireVarint:
|
||||
_, err = o.DecodeVarint()
|
||||
case WireFixed64:
|
||||
_, err = o.DecodeFixed64()
|
||||
case WireBytes:
|
||||
_, err = o.DecodeRawBytes(false)
|
||||
case WireFixed32:
|
||||
_, err = o.DecodeFixed32()
|
||||
case WireStartGroup:
|
||||
for {
|
||||
u, err = o.DecodeVarint()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fwire := int(u & 0x7)
|
||||
if fwire == WireEndGroup {
|
||||
break
|
||||
}
|
||||
ftag := int(u >> 3)
|
||||
err = o.skip(t, ftag, fwire)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface representing objects that can
|
||||
// unmarshal themselves. The method should reset the receiver before
|
||||
// decoding starts. The argument points to data that may be
|
||||
// overwritten, so implementations should not keep references to the
|
||||
// buffer.
|
||||
type Unmarshaler interface {
|
||||
Unmarshal([]byte) error
|
||||
}
|
||||
|
||||
// Unmarshal parses the protocol buffer representation in buf and places the
|
||||
// decoded result in pb. If the struct underlying pb does not match
|
||||
// the data in buf, the results can be unpredictable.
|
||||
//
|
||||
// Unmarshal resets pb before starting to unmarshal, so any
|
||||
// existing data in pb is always removed. Use UnmarshalMerge
|
||||
// to preserve and append to existing data.
|
||||
func Unmarshal(buf []byte, pb Message) error {
|
||||
pb.Reset()
|
||||
return UnmarshalMerge(buf, pb)
|
||||
}
|
||||
|
||||
// UnmarshalMerge parses the protocol buffer representation in buf and
|
||||
// writes the decoded result to pb. If the struct underlying pb does not match
|
||||
// the data in buf, the results can be unpredictable.
|
||||
//
|
||||
// UnmarshalMerge merges into existing data in pb.
|
||||
// Most code should use Unmarshal instead.
|
||||
func UnmarshalMerge(buf []byte, pb Message) error {
|
||||
// If the object can unmarshal itself, let it.
|
||||
if u, ok := pb.(Unmarshaler); ok {
|
||||
return u.Unmarshal(buf)
|
||||
}
|
||||
return NewBuffer(buf).Unmarshal(pb)
|
||||
}
|
||||
|
||||
// Unmarshal parses the protocol buffer representation in the
|
||||
// Buffer and places the decoded result in pb. If the struct
|
||||
// underlying pb does not match the data in the buffer, the results can be
|
||||
// unpredictable.
|
||||
func (p *Buffer) Unmarshal(pb Message) error {
|
||||
// If the object can unmarshal itself, let it.
|
||||
if u, ok := pb.(Unmarshaler); ok {
|
||||
err := u.Unmarshal(p.buf[p.index:])
|
||||
p.index = len(p.buf)
|
||||
return err
|
||||
}
|
||||
|
||||
typ, base, err := getbase(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base)
|
||||
|
||||
if collectStats {
|
||||
stats.Decode++
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// unmarshalType does the work of unmarshaling a structure.
|
||||
func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
|
||||
var state errorState
|
||||
required, reqFields := prop.reqCount, uint64(0)
|
||||
|
||||
var err error
|
||||
for err == nil && o.index < len(o.buf) {
|
||||
oi := o.index
|
||||
var u uint64
|
||||
u, err = o.DecodeVarint()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
wire := int(u & 0x7)
|
||||
if wire == WireEndGroup {
|
||||
if is_group {
|
||||
return nil // input is satisfied
|
||||
}
|
||||
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
|
||||
}
|
||||
tag := int(u >> 3)
|
||||
if tag <= 0 {
|
||||
return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
|
||||
}
|
||||
fieldnum, ok := prop.decoderTags.get(tag)
|
||||
if !ok {
|
||||
// Maybe it's an extension?
|
||||
if prop.extendable {
|
||||
if e := structPointer_Interface(base, st).(extendableProto); isExtensionField(e, int32(tag)) {
|
||||
if err = o.skip(st, tag, wire); err == nil {
|
||||
if ee, ok := e.(extensionsMap); ok {
|
||||
ext := ee.ExtensionMap()[int32(tag)] // may be missing
|
||||
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
|
||||
ee.ExtensionMap()[int32(tag)] = ext
|
||||
} else if ee, ok := e.(extensionsBytes); ok {
|
||||
ext := ee.GetExtensions()
|
||||
*ext = append(*ext, o.buf[oi:o.index]...)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
||||
continue
|
||||
}
|
||||
p := prop.Prop[fieldnum]
|
||||
|
||||
if p.dec == nil {
|
||||
fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
|
||||
continue
|
||||
}
|
||||
dec := p.dec
|
||||
if wire != WireStartGroup && wire != p.WireType {
|
||||
if wire == WireBytes && p.packedDec != nil {
|
||||
// a packable field
|
||||
dec = p.packedDec
|
||||
} else {
|
||||
err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
|
||||
continue
|
||||
}
|
||||
}
|
||||
decErr := dec(o, p, base)
|
||||
if decErr != nil && !state.shouldContinue(decErr, p) {
|
||||
err = decErr
|
||||
}
|
||||
if err == nil && p.Required {
|
||||
// Successfully decoded a required field.
|
||||
if tag <= 64 {
|
||||
// use bitmap for fields 1-64 to catch field reuse.
|
||||
var mask uint64 = 1 << uint64(tag-1)
|
||||
if reqFields&mask == 0 {
|
||||
// new required field
|
||||
reqFields |= mask
|
||||
required--
|
||||
}
|
||||
} else {
|
||||
// This is imprecise. It can be fooled by a required field
|
||||
// with a tag > 64 that is encoded twice; that's very rare.
|
||||
// A fully correct implementation would require allocating
|
||||
// a data structure, which we would like to avoid.
|
||||
required--
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if is_group {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if state.err != nil {
|
||||
return state.err
|
||||
}
|
||||
if required > 0 {
|
||||
// Not enough information to determine the exact field. If we use extra
|
||||
// CPU, we could determine the field only if the missing required field
|
||||
// has a tag <= 64 and we check reqFields.
|
||||
return &RequiredNotSetError{"{Unknown}"}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Individual type decoders
|
||||
// For each,
|
||||
// u is the decoded value,
|
||||
// v is a pointer to the field (pointer) in the struct
|
||||
|
||||
// Sizes of the pools to allocate inside the Buffer.
|
||||
// The goal is modest amortization and allocation
|
||||
// on at least 16-byte boundaries.
|
||||
const (
|
||||
boolPoolSize = 16
|
||||
uint32PoolSize = 8
|
||||
uint64PoolSize = 4
|
||||
)
|
||||
|
||||
// Decode a bool.
|
||||
func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(o.bools) == 0 {
|
||||
o.bools = make([]bool, boolPoolSize)
|
||||
}
|
||||
o.bools[0] = u != 0
|
||||
*structPointer_Bool(base, p.field) = &o.bools[0]
|
||||
o.bools = o.bools[1:]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode an int32.
|
||||
func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode an int64.
|
||||
func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
word64_Set(structPointer_Word64(base, p.field), o, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a string.
|
||||
func (o *Buffer) dec_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sp := new(string)
|
||||
*sp = s
|
||||
*structPointer_String(base, p.field) = sp
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bytes ([]byte).
|
||||
func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_Bytes(base, p.field) = b
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bools ([]bool).
|
||||
func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_BoolSlice(base, p.field)
|
||||
*v = append(*v, u != 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bools ([]bool) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
|
||||
v := structPointer_BoolSlice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded bools
|
||||
|
||||
y := *v
|
||||
for i := 0; i < nb; i++ {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
y = append(y, u != 0)
|
||||
}
|
||||
|
||||
*v = y
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int32s ([]int32).
|
||||
func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
structPointer_Word32Slice(base, p.field).Append(uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int32s ([]int32) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
|
||||
v := structPointer_Word32Slice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded int32s
|
||||
|
||||
fin := o.index + nb
|
||||
if fin < o.index {
|
||||
return errOverflow
|
||||
}
|
||||
for o.index < fin {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Append(uint32(u))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int64s ([]int64).
|
||||
func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
structPointer_Word64Slice(base, p.field).Append(u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of int64s ([]int64) in packed format.
|
||||
func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
|
||||
v := structPointer_Word64Slice(base, p.field)
|
||||
|
||||
nn, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nb := int(nn) // number of bytes of encoded int64s
|
||||
|
||||
fin := o.index + nb
|
||||
if fin < o.index {
|
||||
return errOverflow
|
||||
}
|
||||
for o.index < fin {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Append(u)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of strings ([]string).
|
||||
func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_StringSlice(base, p.field)
|
||||
*v = append(*v, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of slice of bytes ([][]byte).
|
||||
func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := structPointer_BytesSlice(base, p.field)
|
||||
*v = append(*v, b)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a group.
|
||||
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
|
||||
bas := structPointer_GetStructPointer(base, p.field)
|
||||
if structPointer_IsNil(bas) {
|
||||
// allocate new nested message
|
||||
bas = toStructPointer(reflect.New(p.stype))
|
||||
structPointer_SetStructPointer(base, p.field, bas)
|
||||
}
|
||||
return o.unmarshalType(p.stype, p.sprop, true, bas)
|
||||
}
|
||||
|
||||
// Decode an embedded message.
|
||||
func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
|
||||
raw, e := o.DecodeRawBytes(false)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
bas := structPointer_GetStructPointer(base, p.field)
|
||||
if structPointer_IsNil(bas) {
|
||||
// allocate new nested message
|
||||
bas = toStructPointer(reflect.New(p.stype))
|
||||
structPointer_SetStructPointer(base, p.field, bas)
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
iv := structPointer_Interface(bas, p.stype)
|
||||
return iv.(Unmarshaler).Unmarshal(raw)
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, false, bas)
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode a slice of embedded messages.
|
||||
func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
|
||||
return o.dec_slice_struct(p, false, base)
|
||||
}
|
||||
|
||||
// Decode a slice of embedded groups.
|
||||
func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
|
||||
return o.dec_slice_struct(p, true, base)
|
||||
}
|
||||
|
||||
// Decode a slice of structs ([]*struct).
|
||||
func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
|
||||
v := reflect.New(p.stype)
|
||||
bas := toStructPointer(v)
|
||||
structPointer_StructPointerSlice(base, p.field).Append(bas)
|
||||
|
||||
if is_group {
|
||||
err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||
return err
|
||||
}
|
||||
|
||||
raw, err := o.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
iv := v.Interface()
|
||||
return iv.(Unmarshaler).Unmarshal(raw)
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
return err
|
||||
}
|
||||
220
Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go
generated
vendored
Normal file
220
Godeps/_workspace/src/github.com/gogo/protobuf/proto/decode_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Decode a reference to a bool pointer.
|
||||
func (o *Buffer) dec_ref_bool(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(o.bools) == 0 {
|
||||
o.bools = make([]bool, boolPoolSize)
|
||||
}
|
||||
o.bools[0] = u != 0
|
||||
*structPointer_RefBool(base, p.field) = o.bools[0]
|
||||
o.bools = o.bools[1:]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a reference to an int32 pointer.
|
||||
func (o *Buffer) dec_ref_int32(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refWord32_Set(structPointer_RefWord32(base, p.field), o, uint32(u))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a reference to an int64 pointer.
|
||||
func (o *Buffer) dec_ref_int64(p *Properties, base structPointer) error {
|
||||
u, err := p.valDec(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refWord64_Set(structPointer_RefWord64(base, p.field), o, u)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a reference to a string pointer.
|
||||
func (o *Buffer) dec_ref_string(p *Properties, base structPointer) error {
|
||||
s, err := o.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*structPointer_RefString(base, p.field) = s
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a reference to a struct pointer.
|
||||
func (o *Buffer) dec_ref_struct_message(p *Properties, base structPointer) (err error) {
|
||||
raw, e := o.DecodeRawBytes(false)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
panic("not supported, since this is a pointer receiver")
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
bas := structPointer_FieldPointer(base, p.field)
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, false, bas)
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode a slice of references to struct pointers ([]struct).
|
||||
func (o *Buffer) dec_slice_ref_struct(p *Properties, is_group bool, base structPointer) error {
|
||||
newBas := appendStructPointer(base, p.field, p.sstype)
|
||||
|
||||
if is_group {
|
||||
panic("not supported, maybe in future, if requested.")
|
||||
}
|
||||
|
||||
raw, err := o.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the object can unmarshal itself, let it.
|
||||
if p.isUnmarshaler {
|
||||
panic("not supported, since this is not a pointer receiver.")
|
||||
}
|
||||
|
||||
obuf := o.buf
|
||||
oi := o.index
|
||||
o.buf = raw
|
||||
o.index = 0
|
||||
|
||||
err = o.unmarshalType(p.stype, p.sprop, is_group, newBas)
|
||||
|
||||
o.buf = obuf
|
||||
o.index = oi
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Decode a slice of references to struct pointers.
|
||||
func (o *Buffer) dec_slice_ref_struct_message(p *Properties, base structPointer) error {
|
||||
return o.dec_slice_ref_struct(p, false, base)
|
||||
}
|
||||
|
||||
func setPtrCustomType(base structPointer, f field, v interface{}) {
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
structPointer_SetStructPointer(base, f, structPointer(reflect.ValueOf(v).Pointer()))
|
||||
}
|
||||
|
||||
func setCustomType(base structPointer, f field, value interface{}) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
v := reflect.ValueOf(value).Elem()
|
||||
t := reflect.TypeOf(value).Elem()
|
||||
kind := t.Kind()
|
||||
switch kind {
|
||||
case reflect.Slice:
|
||||
slice := reflect.MakeSlice(t, v.Len(), v.Cap())
|
||||
reflect.Copy(slice, v)
|
||||
oldHeader := structPointer_GetSliceHeader(base, f)
|
||||
oldHeader.Data = slice.Pointer()
|
||||
oldHeader.Len = v.Len()
|
||||
oldHeader.Cap = v.Cap()
|
||||
default:
|
||||
l := 1
|
||||
size := reflect.TypeOf(value).Elem().Size()
|
||||
if kind == reflect.Array {
|
||||
l = reflect.TypeOf(value).Elem().Len()
|
||||
size = reflect.TypeOf(value).Size()
|
||||
}
|
||||
total := int(size) * l
|
||||
structPointer_Copy(toStructPointer(reflect.ValueOf(value)), structPointer_Add(base, f), total)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_custom_bytes(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i := reflect.New(p.ctype.Elem()).Interface()
|
||||
custom := (i).(Unmarshaler)
|
||||
if err := custom.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
setPtrCustomType(base, p.field, custom)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Buffer) dec_custom_ref_bytes(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i := reflect.New(p.ctype).Interface()
|
||||
custom := (i).(Unmarshaler)
|
||||
if err := custom.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
if custom != nil {
|
||||
setCustomType(base, p.field, custom)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode a slice of bytes ([]byte) into a slice of custom types.
|
||||
func (o *Buffer) dec_custom_slice_bytes(p *Properties, base structPointer) error {
|
||||
b, err := o.DecodeRawBytes(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i := reflect.New(p.ctype.Elem()).Interface()
|
||||
custom := (i).(Unmarshaler)
|
||||
if err := custom.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
newBas := appendStructPointer(base, p.field, p.ctype)
|
||||
|
||||
setCustomType(newBas, 0, custom)
|
||||
|
||||
return nil
|
||||
}
|
||||
1054
Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go
generated
vendored
Normal file
1054
Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
383
Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go
generated
vendored
Normal file
383
Godeps/_workspace/src/github.com/gogo/protobuf/proto/encode_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
// Extensions for Protocol Buffers to create more go like structures.
|
||||
//
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// http://github.com/golang/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Sizer interface {
|
||||
Size() int
|
||||
}
|
||||
|
||||
func (o *Buffer) enc_ext_slice_byte(p *Properties, base structPointer) error {
|
||||
s := *structPointer_Bytes(base, p.field)
|
||||
if s == nil {
|
||||
return ErrNil
|
||||
}
|
||||
o.buf = append(o.buf, s...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ext_slice_byte(p *Properties, base structPointer) (n int) {
|
||||
s := *structPointer_Bytes(base, p.field)
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
n += len(s)
|
||||
return
|
||||
}
|
||||
|
||||
// Encode a reference to bool pointer.
|
||||
func (o *Buffer) enc_ref_bool(p *Properties, base structPointer) error {
|
||||
v := structPointer_RefBool(base, p.field)
|
||||
if v == nil {
|
||||
return ErrNil
|
||||
}
|
||||
x := 0
|
||||
if *v {
|
||||
x = 1
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
p.valEnc(o, uint64(x))
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ref_bool(p *Properties, base structPointer) int {
|
||||
v := structPointer_RefBool(base, p.field)
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
return len(p.tagcode) + 1 // each bool takes exactly one byte
|
||||
}
|
||||
|
||||
// Encode a reference to int32 pointer.
|
||||
func (o *Buffer) enc_ref_int32(p *Properties, base structPointer) error {
|
||||
v := structPointer_RefWord32(base, p.field)
|
||||
if refWord32_IsNil(v) {
|
||||
return ErrNil
|
||||
}
|
||||
x := int32(refWord32_Get(v))
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
p.valEnc(o, uint64(x))
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ref_int32(p *Properties, base structPointer) (n int) {
|
||||
v := structPointer_RefWord32(base, p.field)
|
||||
if refWord32_IsNil(v) {
|
||||
return 0
|
||||
}
|
||||
x := int32(refWord32_Get(v))
|
||||
n += len(p.tagcode)
|
||||
n += p.valSize(uint64(x))
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Buffer) enc_ref_uint32(p *Properties, base structPointer) error {
|
||||
v := structPointer_RefWord32(base, p.field)
|
||||
if refWord32_IsNil(v) {
|
||||
return ErrNil
|
||||
}
|
||||
x := refWord32_Get(v)
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
p.valEnc(o, uint64(x))
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ref_uint32(p *Properties, base structPointer) (n int) {
|
||||
v := structPointer_RefWord32(base, p.field)
|
||||
if refWord32_IsNil(v) {
|
||||
return 0
|
||||
}
|
||||
x := refWord32_Get(v)
|
||||
n += len(p.tagcode)
|
||||
n += p.valSize(uint64(x))
|
||||
return
|
||||
}
|
||||
|
||||
// Encode a reference to an int64 pointer.
|
||||
func (o *Buffer) enc_ref_int64(p *Properties, base structPointer) error {
|
||||
v := structPointer_RefWord64(base, p.field)
|
||||
if refWord64_IsNil(v) {
|
||||
return ErrNil
|
||||
}
|
||||
x := refWord64_Get(v)
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
p.valEnc(o, x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ref_int64(p *Properties, base structPointer) (n int) {
|
||||
v := structPointer_RefWord64(base, p.field)
|
||||
if refWord64_IsNil(v) {
|
||||
return 0
|
||||
}
|
||||
x := refWord64_Get(v)
|
||||
n += len(p.tagcode)
|
||||
n += p.valSize(x)
|
||||
return
|
||||
}
|
||||
|
||||
// Encode a reference to a string pointer.
|
||||
func (o *Buffer) enc_ref_string(p *Properties, base structPointer) error {
|
||||
v := structPointer_RefString(base, p.field)
|
||||
if v == nil {
|
||||
return ErrNil
|
||||
}
|
||||
x := *v
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeStringBytes(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_ref_string(p *Properties, base structPointer) (n int) {
|
||||
v := structPointer_RefString(base, p.field)
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
x := *v
|
||||
n += len(p.tagcode)
|
||||
n += sizeStringBytes(x)
|
||||
return
|
||||
}
|
||||
|
||||
// Encode a reference to a message struct.
|
||||
func (o *Buffer) enc_ref_struct_message(p *Properties, base structPointer) error {
|
||||
var state errorState
|
||||
structp := structPointer_GetRefStructPointer(base, p.field)
|
||||
if structPointer_IsNil(structp) {
|
||||
return ErrNil
|
||||
}
|
||||
|
||||
// Can the object marshal itself?
|
||||
if p.isMarshaler {
|
||||
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
||||
data, err := m.Marshal()
|
||||
if err != nil && !state.shouldContinue(err, nil) {
|
||||
return err
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeRawBytes(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
return o.enc_len_struct(p.sprop, structp, &state)
|
||||
}
|
||||
|
||||
//TODO this is only copied, please fix this
|
||||
func size_ref_struct_message(p *Properties, base structPointer) int {
|
||||
structp := structPointer_GetRefStructPointer(base, p.field)
|
||||
if structPointer_IsNil(structp) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Can the object marshal itself?
|
||||
if p.isMarshaler {
|
||||
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
||||
data, _ := m.Marshal()
|
||||
n0 := len(p.tagcode)
|
||||
n1 := sizeRawBytes(data)
|
||||
return n0 + n1
|
||||
}
|
||||
|
||||
n0 := len(p.tagcode)
|
||||
n1 := size_struct(p.sprop, structp)
|
||||
n2 := sizeVarint(uint64(n1)) // size of encoded length
|
||||
return n0 + n1 + n2
|
||||
}
|
||||
|
||||
// Encode a slice of references to message struct pointers ([]struct).
|
||||
func (o *Buffer) enc_slice_ref_struct_message(p *Properties, base structPointer) error {
|
||||
var state errorState
|
||||
ss := structPointer_GetStructPointer(base, p.field)
|
||||
ss1 := structPointer_GetRefStructPointer(ss, field(0))
|
||||
size := p.stype.Size()
|
||||
l := structPointer_Len(base, p.field)
|
||||
for i := 0; i < l; i++ {
|
||||
structp := structPointer_Add(ss1, field(uintptr(i)*size))
|
||||
if structPointer_IsNil(structp) {
|
||||
return ErrRepeatedHasNil
|
||||
}
|
||||
|
||||
// Can the object marshal itself?
|
||||
if p.isMarshaler {
|
||||
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
||||
data, err := m.Marshal()
|
||||
if err != nil && !state.shouldContinue(err, nil) {
|
||||
return err
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeRawBytes(data)
|
||||
continue
|
||||
}
|
||||
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
err := o.enc_len_struct(p.sprop, structp, &state)
|
||||
if err != nil && !state.shouldContinue(err, nil) {
|
||||
if err == ErrNil {
|
||||
return ErrRepeatedHasNil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return state.err
|
||||
}
|
||||
|
||||
//TODO this is only copied, please fix this
|
||||
func size_slice_ref_struct_message(p *Properties, base structPointer) (n int) {
|
||||
ss := structPointer_GetStructPointer(base, p.field)
|
||||
ss1 := structPointer_GetRefStructPointer(ss, field(0))
|
||||
size := p.stype.Size()
|
||||
l := structPointer_Len(base, p.field)
|
||||
n += l * len(p.tagcode)
|
||||
for i := 0; i < l; i++ {
|
||||
structp := structPointer_Add(ss1, field(uintptr(i)*size))
|
||||
if structPointer_IsNil(structp) {
|
||||
return // return the size up to this point
|
||||
}
|
||||
|
||||
// Can the object marshal itself?
|
||||
if p.isMarshaler {
|
||||
m := structPointer_Interface(structp, p.stype).(Marshaler)
|
||||
data, _ := m.Marshal()
|
||||
n += len(p.tagcode)
|
||||
n += sizeRawBytes(data)
|
||||
continue
|
||||
}
|
||||
|
||||
n0 := size_struct(p.sprop, structp)
|
||||
n1 := sizeVarint(uint64(n0)) // size of encoded length
|
||||
n += n0 + n1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Buffer) enc_custom_bytes(p *Properties, base structPointer) error {
|
||||
i := structPointer_InterfaceRef(base, p.field, p.ctype)
|
||||
if i == nil {
|
||||
return ErrNil
|
||||
}
|
||||
custom := i.(Marshaler)
|
||||
data, err := custom.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data == nil {
|
||||
return ErrNil
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeRawBytes(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_custom_bytes(p *Properties, base structPointer) (n int) {
|
||||
n += len(p.tagcode)
|
||||
i := structPointer_InterfaceRef(base, p.field, p.ctype)
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
custom := i.(Marshaler)
|
||||
data, _ := custom.Marshal()
|
||||
n += sizeRawBytes(data)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Buffer) enc_custom_ref_bytes(p *Properties, base structPointer) error {
|
||||
custom := structPointer_InterfaceAt(base, p.field, p.ctype).(Marshaler)
|
||||
data, err := custom.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data == nil {
|
||||
return ErrNil
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeRawBytes(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_custom_ref_bytes(p *Properties, base structPointer) (n int) {
|
||||
n += len(p.tagcode)
|
||||
i := structPointer_InterfaceAt(base, p.field, p.ctype)
|
||||
if i == nil {
|
||||
return 0
|
||||
}
|
||||
custom := i.(Marshaler)
|
||||
data, _ := custom.Marshal()
|
||||
n += sizeRawBytes(data)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Buffer) enc_custom_slice_bytes(p *Properties, base structPointer) error {
|
||||
inter := structPointer_InterfaceRef(base, p.field, p.ctype)
|
||||
if inter == nil {
|
||||
return ErrNil
|
||||
}
|
||||
slice := reflect.ValueOf(inter)
|
||||
l := slice.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
v := slice.Index(i)
|
||||
custom := v.Interface().(Marshaler)
|
||||
data, err := custom.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.buf = append(o.buf, p.tagcode...)
|
||||
o.EncodeRawBytes(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func size_custom_slice_bytes(p *Properties, base structPointer) (n int) {
|
||||
inter := structPointer_InterfaceRef(base, p.field, p.ctype)
|
||||
if inter == nil {
|
||||
return 0
|
||||
}
|
||||
slice := reflect.ValueOf(inter)
|
||||
l := slice.Len()
|
||||
n += l * len(p.tagcode)
|
||||
for i := 0; i < l; i++ {
|
||||
v := slice.Index(i)
|
||||
custom := v.Interface().(Marshaler)
|
||||
data, _ := custom.Marshal()
|
||||
n += sizeRawBytes(data)
|
||||
}
|
||||
return
|
||||
}
|
||||
241
Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go
generated
vendored
Normal file
241
Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal.go
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Protocol buffer comparison.
|
||||
// TODO: MessageSet.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
Equal returns true iff protocol buffers a and b are equal.
|
||||
The arguments must both be pointers to protocol buffer structs.
|
||||
|
||||
Equality is defined in this way:
|
||||
- Two messages are equal iff they are the same type,
|
||||
corresponding fields are equal, unknown field sets
|
||||
are equal, and extensions sets are equal.
|
||||
- Two set scalar fields are equal iff their values are equal.
|
||||
If the fields are of a floating-point type, remember that
|
||||
NaN != x for all x, including NaN.
|
||||
- Two repeated fields are equal iff their lengths are the same,
|
||||
and their corresponding elements are equal (a "bytes" field,
|
||||
although represented by []byte, is not a repeated field)
|
||||
- Two unset fields are equal.
|
||||
- Two unknown field sets are equal if their current
|
||||
encoded state is equal.
|
||||
- Two extension sets are equal iff they have corresponding
|
||||
elements that are pairwise equal.
|
||||
- Every other combination of things are not equal.
|
||||
|
||||
The return value is undefined if a and b are not protocol buffers.
|
||||
*/
|
||||
func Equal(a, b Message) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b)
|
||||
if v1.Type() != v2.Type() {
|
||||
return false
|
||||
}
|
||||
if v1.Kind() == reflect.Ptr {
|
||||
if v1.IsNil() {
|
||||
return v2.IsNil()
|
||||
}
|
||||
if v2.IsNil() {
|
||||
return false
|
||||
}
|
||||
v1, v2 = v1.Elem(), v2.Elem()
|
||||
}
|
||||
if v1.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
return equalStruct(v1, v2)
|
||||
}
|
||||
|
||||
// v1 and v2 are known to have the same type.
|
||||
func equalStruct(v1, v2 reflect.Value) bool {
|
||||
for i := 0; i < v1.NumField(); i++ {
|
||||
f := v1.Type().Field(i)
|
||||
if strings.HasPrefix(f.Name, "XXX_") {
|
||||
continue
|
||||
}
|
||||
f1, f2 := v1.Field(i), v2.Field(i)
|
||||
if f.Type.Kind() == reflect.Ptr {
|
||||
if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 {
|
||||
// both unset
|
||||
continue
|
||||
} else if n1 != n2 {
|
||||
// set/unset mismatch
|
||||
return false
|
||||
}
|
||||
b1, ok := f1.Interface().(raw)
|
||||
if ok {
|
||||
b2 := f2.Interface().(raw)
|
||||
// RawMessage
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
f1, f2 = f1.Elem(), f2.Elem()
|
||||
}
|
||||
if !equalAny(f1, f2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
|
||||
em2 := v2.FieldByName("XXX_extensions")
|
||||
if !equalExtensions(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
uf := v1.FieldByName("XXX_unrecognized")
|
||||
if !uf.IsValid() {
|
||||
return true
|
||||
}
|
||||
|
||||
u1 := uf.Bytes()
|
||||
u2 := v2.FieldByName("XXX_unrecognized").Bytes()
|
||||
if !bytes.Equal(u1, u2) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// v1 and v2 are known to have the same type.
|
||||
func equalAny(v1, v2 reflect.Value) bool {
|
||||
if v1.Type() == protoMessageType {
|
||||
m1, _ := v1.Interface().(Message)
|
||||
m2, _ := v2.Interface().(Message)
|
||||
return Equal(m1, m2)
|
||||
}
|
||||
switch v1.Kind() {
|
||||
case reflect.Bool:
|
||||
return v1.Bool() == v2.Bool()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v1.Float() == v2.Float()
|
||||
case reflect.Int32, reflect.Int64:
|
||||
return v1.Int() == v2.Int()
|
||||
case reflect.Ptr:
|
||||
return equalAny(v1.Elem(), v2.Elem())
|
||||
case reflect.Slice:
|
||||
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
||||
// short circuit: []byte
|
||||
if v1.IsNil() != v2.IsNil() {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte))
|
||||
}
|
||||
|
||||
if v1.Len() != v2.Len() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < v1.Len(); i++ {
|
||||
if !equalAny(v1.Index(i), v2.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.String:
|
||||
return v1.Interface().(string) == v2.Interface().(string)
|
||||
case reflect.Struct:
|
||||
return equalStruct(v1, v2)
|
||||
case reflect.Uint32, reflect.Uint64:
|
||||
return v1.Uint() == v2.Uint()
|
||||
}
|
||||
|
||||
// unknown type, so not a protocol buffer
|
||||
log.Printf("proto: don't know how to compare %v", v1)
|
||||
return false
|
||||
}
|
||||
|
||||
// base is the struct type that the extensions are based on.
|
||||
// em1 and em2 are extension maps.
|
||||
func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
||||
if len(em1) != len(em2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for extNum, e1 := range em1 {
|
||||
e2, ok := em2[extNum]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
m1, m2 := e1.value, e2.value
|
||||
|
||||
if m1 != nil && m2 != nil {
|
||||
// Both are unencoded.
|
||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// At least one is encoded. To do a semantically correct comparison
|
||||
// we need to unmarshal them first.
|
||||
var desc *ExtensionDesc
|
||||
if m := extensionMaps[base]; m != nil {
|
||||
desc = m[extNum]
|
||||
}
|
||||
if desc == nil {
|
||||
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
if m1 == nil {
|
||||
m1, err = decodeExtension(e1.enc, desc)
|
||||
}
|
||||
if m2 == nil && err == nil {
|
||||
m2, err = decodeExtension(e2.enc, desc)
|
||||
}
|
||||
if err != nil {
|
||||
// The encoded form is invalid.
|
||||
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
||||
return false
|
||||
}
|
||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
166
Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal_test.go
generated
vendored
Normal file
166
Godeps/_workspace/src/github.com/gogo/protobuf/proto/equal_test.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "./testdata"
|
||||
. "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// Four identical base messages.
|
||||
// The init function adds extensions to some of them.
|
||||
var messageWithoutExtension = &pb.MyMessage{Count: Int32(7)}
|
||||
var messageWithExtension1a = &pb.MyMessage{Count: Int32(7)}
|
||||
var messageWithExtension1b = &pb.MyMessage{Count: Int32(7)}
|
||||
var messageWithExtension2 = &pb.MyMessage{Count: Int32(7)}
|
||||
|
||||
// Two messages with non-message extensions.
|
||||
var messageWithInt32Extension1 = &pb.MyMessage{Count: Int32(8)}
|
||||
var messageWithInt32Extension2 = &pb.MyMessage{Count: Int32(8)}
|
||||
|
||||
func init() {
|
||||
ext1 := &pb.Ext{Data: String("Kirk")}
|
||||
ext2 := &pb.Ext{Data: String("Picard")}
|
||||
|
||||
// messageWithExtension1a has ext1, but never marshals it.
|
||||
if err := SetExtension(messageWithExtension1a, pb.E_Ext_More, ext1); err != nil {
|
||||
panic("SetExtension on 1a failed: " + err.Error())
|
||||
}
|
||||
|
||||
// messageWithExtension1b is the unmarshaled form of messageWithExtension1a.
|
||||
if err := SetExtension(messageWithExtension1b, pb.E_Ext_More, ext1); err != nil {
|
||||
panic("SetExtension on 1b failed: " + err.Error())
|
||||
}
|
||||
buf, err := Marshal(messageWithExtension1b)
|
||||
if err != nil {
|
||||
panic("Marshal of 1b failed: " + err.Error())
|
||||
}
|
||||
messageWithExtension1b.Reset()
|
||||
if err := Unmarshal(buf, messageWithExtension1b); err != nil {
|
||||
panic("Unmarshal of 1b failed: " + err.Error())
|
||||
}
|
||||
|
||||
// messageWithExtension2 has ext2.
|
||||
if err := SetExtension(messageWithExtension2, pb.E_Ext_More, ext2); err != nil {
|
||||
panic("SetExtension on 2 failed: " + err.Error())
|
||||
}
|
||||
|
||||
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(23)); err != nil {
|
||||
panic("SetExtension on Int32-1 failed: " + err.Error())
|
||||
}
|
||||
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(24)); err != nil {
|
||||
panic("SetExtension on Int32-2 failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
var EqualTests = []struct {
|
||||
desc string
|
||||
a, b Message
|
||||
exp bool
|
||||
}{
|
||||
{"different types", &pb.GoEnum{}, &pb.GoTestField{}, false},
|
||||
{"equal empty", &pb.GoEnum{}, &pb.GoEnum{}, true},
|
||||
{"nil vs nil", nil, nil, true},
|
||||
{"typed nil vs typed nil", (*pb.GoEnum)(nil), (*pb.GoEnum)(nil), true},
|
||||
{"typed nil vs empty", (*pb.GoEnum)(nil), &pb.GoEnum{}, false},
|
||||
{"different typed nil", (*pb.GoEnum)(nil), (*pb.GoTestField)(nil), false},
|
||||
|
||||
{"one set field, one unset field", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{}, false},
|
||||
{"one set field zero, one unset field", &pb.GoTest{Param: Int32(0)}, &pb.GoTest{}, false},
|
||||
{"different set fields", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("bar")}, false},
|
||||
{"equal set", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("foo")}, true},
|
||||
|
||||
{"repeated, one set", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{}, false},
|
||||
{"repeated, different length", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{F_Int32Repeated: []int32{2}}, false},
|
||||
{"repeated, different value", &pb.GoTest{F_Int32Repeated: []int32{2}}, &pb.GoTest{F_Int32Repeated: []int32{3}}, false},
|
||||
{"repeated, equal", &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, true},
|
||||
{"repeated, nil equal nil", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: nil}, true},
|
||||
{"repeated, nil equal empty", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: []int32{}}, true},
|
||||
{"repeated, empty equal nil", &pb.GoTest{F_Int32Repeated: []int32{}}, &pb.GoTest{F_Int32Repeated: nil}, true},
|
||||
|
||||
{
|
||||
"nested, different",
|
||||
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("foo")}},
|
||||
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("bar")}},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"nested, equal",
|
||||
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
|
||||
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
|
||||
true,
|
||||
},
|
||||
|
||||
{"bytes", &pb.OtherMessage{Value: []byte("foo")}, &pb.OtherMessage{Value: []byte("foo")}, true},
|
||||
{"bytes, empty", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: []byte{}}, true},
|
||||
{"bytes, empty vs nil", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: nil}, false},
|
||||
{
|
||||
"repeated bytes",
|
||||
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
|
||||
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
|
||||
true,
|
||||
},
|
||||
|
||||
{"extension vs. no extension", messageWithoutExtension, messageWithExtension1a, false},
|
||||
{"extension vs. same extension", messageWithExtension1a, messageWithExtension1b, true},
|
||||
{"extension vs. different extension", messageWithExtension1a, messageWithExtension2, false},
|
||||
|
||||
{"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true},
|
||||
{"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false},
|
||||
|
||||
{
|
||||
"message with group",
|
||||
&pb.MyMessage{
|
||||
Count: Int32(1),
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: Int32(5),
|
||||
},
|
||||
},
|
||||
&pb.MyMessage{
|
||||
Count: Int32(1),
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: Int32(5),
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
for _, tc := range EqualTests {
|
||||
if res := Equal(tc.a, tc.b); res != tc.exp {
|
||||
t.Errorf("%v: Equal(%v, %v) = %v, want %v", tc.desc, tc.a, tc.b, res, tc.exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
472
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go
generated
vendored
Normal file
472
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions.go
generated
vendored
Normal file
@@ -0,0 +1,472 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
/*
|
||||
* Types and routines for supporting protocol buffer extensions.
|
||||
*/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
|
||||
var ErrMissingExtension = errors.New("proto: missing extension")
|
||||
|
||||
// ExtensionRange represents a range of message extensions for a protocol buffer.
|
||||
// Used in code generated by the protocol compiler.
|
||||
type ExtensionRange struct {
|
||||
Start, End int32 // both inclusive
|
||||
}
|
||||
|
||||
// extendableProto is an interface implemented by any protocol buffer that may be extended.
|
||||
type extendableProto interface {
|
||||
Message
|
||||
ExtensionRangeArray() []ExtensionRange
|
||||
}
|
||||
|
||||
type extensionsMap interface {
|
||||
extendableProto
|
||||
ExtensionMap() map[int32]Extension
|
||||
}
|
||||
|
||||
type extensionsBytes interface {
|
||||
extendableProto
|
||||
GetExtensions() *[]byte
|
||||
}
|
||||
|
||||
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
|
||||
|
||||
// ExtensionDesc represents an extension specification.
|
||||
// Used in generated code from the protocol compiler.
|
||||
type ExtensionDesc struct {
|
||||
ExtendedType Message // nil pointer to the type that is being extended
|
||||
ExtensionType interface{} // nil pointer to the extension type
|
||||
Field int32 // field number
|
||||
Name string // fully-qualified name of extension, for text formatting
|
||||
Tag string // protobuf tag style
|
||||
}
|
||||
|
||||
func (ed *ExtensionDesc) repeated() bool {
|
||||
t := reflect.TypeOf(ed.ExtensionType)
|
||||
return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
|
||||
}
|
||||
|
||||
// Extension represents an extension in a message.
|
||||
type Extension struct {
|
||||
// When an extension is stored in a message using SetExtension
|
||||
// only desc and value are set. When the message is marshaled
|
||||
// enc will be set to the encoded form of the message.
|
||||
//
|
||||
// When a message is unmarshaled and contains extensions, each
|
||||
// extension will have only enc set. When such an extension is
|
||||
// accessed using GetExtension (or GetExtensions) desc and value
|
||||
// will be set.
|
||||
desc *ExtensionDesc
|
||||
value interface{}
|
||||
enc []byte
|
||||
}
|
||||
|
||||
// SetRawExtension is for testing only.
|
||||
func SetRawExtension(base extendableProto, id int32, b []byte) {
|
||||
if ebase, ok := base.(extensionsMap); ok {
|
||||
ebase.ExtensionMap()[id] = Extension{enc: b}
|
||||
} else if ebase, ok := base.(extensionsBytes); ok {
|
||||
clearExtension(base, id)
|
||||
ext := ebase.GetExtensions()
|
||||
*ext = append(*ext, b...)
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// isExtensionField returns true iff the given field number is in an extension range.
|
||||
func isExtensionField(pb extendableProto, field int32) bool {
|
||||
for _, er := range pb.ExtensionRangeArray() {
|
||||
if er.Start <= field && field <= er.End {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// checkExtensionTypes checks that the given extension is valid for pb.
|
||||
func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
|
||||
// Check the extended type.
|
||||
if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
|
||||
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
|
||||
}
|
||||
// Check the range.
|
||||
if !isExtensionField(pb, extension.Field) {
|
||||
return errors.New("proto: bad extension number; not in declared ranges")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// extPropKey is sufficient to uniquely identify an extension.
|
||||
type extPropKey struct {
|
||||
base reflect.Type
|
||||
field int32
|
||||
}
|
||||
|
||||
var extProp = struct {
|
||||
sync.RWMutex
|
||||
m map[extPropKey]*Properties
|
||||
}{
|
||||
m: make(map[extPropKey]*Properties),
|
||||
}
|
||||
|
||||
func extensionProperties(ed *ExtensionDesc) *Properties {
|
||||
key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field}
|
||||
|
||||
extProp.RLock()
|
||||
if prop, ok := extProp.m[key]; ok {
|
||||
extProp.RUnlock()
|
||||
return prop
|
||||
}
|
||||
extProp.RUnlock()
|
||||
|
||||
extProp.Lock()
|
||||
defer extProp.Unlock()
|
||||
// Check again.
|
||||
if prop, ok := extProp.m[key]; ok {
|
||||
return prop
|
||||
}
|
||||
|
||||
prop := new(Properties)
|
||||
prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil)
|
||||
extProp.m[key] = prop
|
||||
return prop
|
||||
}
|
||||
|
||||
// encodeExtensionMap encodes any unmarshaled (unencoded) extensions in m.
|
||||
func encodeExtensionMap(m map[int32]Extension) error {
|
||||
for k, e := range m {
|
||||
err := encodeExtension(&e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m[k] = e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeExtension(e *Extension) error {
|
||||
if e.value == nil || e.desc == nil {
|
||||
// Extension is only in its encoded form.
|
||||
return nil
|
||||
}
|
||||
// We don't skip extensions that have an encoded form set,
|
||||
// because the extension value may have been mutated after
|
||||
// the last time this function was called.
|
||||
|
||||
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||
props := extensionProperties(e.desc)
|
||||
|
||||
p := NewBuffer(nil)
|
||||
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||
// Pass a *T with a zero field and hope it all works out.
|
||||
x := reflect.New(et)
|
||||
x.Elem().Set(reflect.ValueOf(e.value))
|
||||
if err := props.enc(p, props, toStructPointer(x)); err != nil {
|
||||
return err
|
||||
}
|
||||
e.enc = p.buf
|
||||
return nil
|
||||
}
|
||||
|
||||
func sizeExtensionMap(m map[int32]Extension) (n int) {
|
||||
for _, e := range m {
|
||||
if e.value == nil || e.desc == nil {
|
||||
// Extension is only in its encoded form.
|
||||
n += len(e.enc)
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't skip extensions that have an encoded form set,
|
||||
// because the extension value may have been mutated after
|
||||
// the last time this function was called.
|
||||
|
||||
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||
props := extensionProperties(e.desc)
|
||||
|
||||
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||
// Pass a *T with a zero field and hope it all works out.
|
||||
x := reflect.New(et)
|
||||
x.Elem().Set(reflect.ValueOf(e.value))
|
||||
n += props.size(props, toStructPointer(x))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HasExtension returns whether the given extension is present in pb.
|
||||
func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
|
||||
// TODO: Check types, field numbers, etc.?
|
||||
if epb, doki := pb.(extensionsMap); doki {
|
||||
_, ok := epb.ExtensionMap()[extension.Field]
|
||||
return ok
|
||||
} else if epb, doki := pb.(extensionsBytes); doki {
|
||||
ext := epb.GetExtensions()
|
||||
buf := *ext
|
||||
o := 0
|
||||
for o < len(buf) {
|
||||
tag, n := DecodeVarint(buf[o:])
|
||||
fieldNum := int32(tag >> 3)
|
||||
if int32(fieldNum) == extension.Field {
|
||||
return true
|
||||
}
|
||||
wireType := int(tag & 0x7)
|
||||
o += n
|
||||
l, err := size(buf[o:], wireType)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
o += l
|
||||
}
|
||||
return false
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int {
|
||||
ext := pb.GetExtensions()
|
||||
for offset < len(*ext) {
|
||||
tag, n1 := DecodeVarint((*ext)[offset:])
|
||||
fieldNum := int32(tag >> 3)
|
||||
wireType := int(tag & 0x7)
|
||||
n2, err := size((*ext)[offset+n1:], wireType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newOffset := offset + n1 + n2
|
||||
if fieldNum == theFieldNum {
|
||||
*ext = append((*ext)[:offset], (*ext)[newOffset:]...)
|
||||
return offset
|
||||
}
|
||||
offset = newOffset
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func clearExtension(pb extendableProto, fieldNum int32) {
|
||||
if epb, doki := pb.(extensionsMap); doki {
|
||||
delete(epb.ExtensionMap(), fieldNum)
|
||||
} else if epb, doki := pb.(extensionsBytes); doki {
|
||||
offset := 0
|
||||
for offset != -1 {
|
||||
offset = deleteExtension(epb, fieldNum, offset)
|
||||
}
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// ClearExtension removes the given extension from pb.
|
||||
func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
|
||||
// TODO: Check types, field numbers, etc.?
|
||||
clearExtension(pb, extension.Field)
|
||||
}
|
||||
|
||||
// GetExtension parses and returns the given extension of pb.
|
||||
// If the extension is not present it returns ErrMissingExtension.
|
||||
func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
|
||||
if err := checkExtensionTypes(pb, extension); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if epb, doki := pb.(extensionsMap); doki {
|
||||
emap := epb.ExtensionMap()
|
||||
e, ok := emap[extension.Field]
|
||||
if !ok {
|
||||
return nil, ErrMissingExtension
|
||||
}
|
||||
if e.value != nil {
|
||||
// Already decoded. Check the descriptor, though.
|
||||
if e.desc != extension {
|
||||
// This shouldn't happen. If it does, it means that
|
||||
// GetExtension was called twice with two different
|
||||
// descriptors with the same field number.
|
||||
return nil, errors.New("proto: descriptor conflict")
|
||||
}
|
||||
return e.value, nil
|
||||
}
|
||||
|
||||
v, err := decodeExtension(e.enc, extension)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remember the decoded version and drop the encoded version.
|
||||
// That way it is safe to mutate what we return.
|
||||
e.value = v
|
||||
e.desc = extension
|
||||
e.enc = nil
|
||||
emap[extension.Field] = e
|
||||
return e.value, nil
|
||||
} else if epb, doki := pb.(extensionsBytes); doki {
|
||||
ext := epb.GetExtensions()
|
||||
o := 0
|
||||
for o < len(*ext) {
|
||||
tag, n := DecodeVarint((*ext)[o:])
|
||||
fieldNum := int32(tag >> 3)
|
||||
wireType := int(tag & 0x7)
|
||||
l, err := size((*ext)[o+n:], wireType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if int32(fieldNum) == extension.Field {
|
||||
v, err := decodeExtension((*ext)[o:o+n+l], extension)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
o += n + l
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// decodeExtension decodes an extension encoded in b.
|
||||
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||
o := NewBuffer(b)
|
||||
|
||||
t := reflect.TypeOf(extension.ExtensionType)
|
||||
rep := extension.repeated()
|
||||
|
||||
props := extensionProperties(extension)
|
||||
|
||||
// t is a pointer to a struct, pointer to basic type or a slice.
|
||||
// Allocate a "field" to store the pointer/slice itself; the
|
||||
// pointer/slice will be stored here. We pass
|
||||
// the address of this field to props.dec.
|
||||
// This passes a zero field and a *t and lets props.dec
|
||||
// interpret it as a *struct{ x t }.
|
||||
value := reflect.New(t).Elem()
|
||||
|
||||
for {
|
||||
// Discard wire type and field number varint. It isn't needed.
|
||||
if _, err := o.DecodeVarint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !rep || o.index >= len(o.buf) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return value.Interface(), nil
|
||||
}
|
||||
|
||||
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
|
||||
// The returned slice has the same length as es; missing extensions will appear as nil elements.
|
||||
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
|
||||
epb, ok := pb.(extendableProto)
|
||||
if !ok {
|
||||
err = errors.New("proto: not an extendable proto")
|
||||
return
|
||||
}
|
||||
extensions = make([]interface{}, len(es))
|
||||
for i, e := range es {
|
||||
extensions[i], err = GetExtension(epb, e)
|
||||
if err == ErrMissingExtension {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetExtension sets the specified extension of pb to the specified value.
|
||||
func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
|
||||
if err := checkExtensionTypes(pb, extension); err != nil {
|
||||
return err
|
||||
}
|
||||
typ := reflect.TypeOf(extension.ExtensionType)
|
||||
if typ != reflect.TypeOf(value) {
|
||||
return errors.New("proto: bad extension value type")
|
||||
}
|
||||
return setExtension(pb, extension, value)
|
||||
}
|
||||
|
||||
func setExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
|
||||
if epb, doki := pb.(extensionsMap); doki {
|
||||
epb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
|
||||
} else if epb, doki := pb.(extensionsBytes); doki {
|
||||
ClearExtension(pb, extension)
|
||||
ext := epb.GetExtensions()
|
||||
et := reflect.TypeOf(extension.ExtensionType)
|
||||
props := extensionProperties(extension)
|
||||
p := NewBuffer(nil)
|
||||
x := reflect.New(et)
|
||||
x.Elem().Set(reflect.ValueOf(value))
|
||||
if err := props.enc(p, props, toStructPointer(x)); err != nil {
|
||||
return err
|
||||
}
|
||||
*ext = append(*ext, p.buf...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A global registry of extensions.
|
||||
// The generated code will register the generated descriptors by calling RegisterExtension.
|
||||
|
||||
var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
|
||||
|
||||
// RegisterExtension is called from the generated code.
|
||||
func RegisterExtension(desc *ExtensionDesc) {
|
||||
st := reflect.TypeOf(desc.ExtendedType).Elem()
|
||||
m := extensionMaps[st]
|
||||
if m == nil {
|
||||
m = make(map[int32]*ExtensionDesc)
|
||||
extensionMaps[st] = m
|
||||
}
|
||||
if _, ok := m[desc.Field]; ok {
|
||||
panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
|
||||
}
|
||||
m[desc.Field] = desc
|
||||
}
|
||||
|
||||
// RegisteredExtensions returns a map of the registered extensions of a
|
||||
// protocol buffer struct, indexed by the extension number.
|
||||
// The argument pb should be a nil pointer to the struct type.
|
||||
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
|
||||
return extensionMaps[reflect.TypeOf(pb).Elem()]
|
||||
}
|
||||
221
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go
generated
vendored
Normal file
221
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetBoolExtension(pb extendableProto, extension *ExtensionDesc, ifnotset bool) bool {
|
||||
if reflect.ValueOf(pb).IsNil() {
|
||||
return ifnotset
|
||||
}
|
||||
value, err := GetExtension(pb, extension)
|
||||
if err != nil {
|
||||
return ifnotset
|
||||
}
|
||||
if value == nil {
|
||||
return ifnotset
|
||||
}
|
||||
if value.(*bool) == nil {
|
||||
return ifnotset
|
||||
}
|
||||
return *(value.(*bool))
|
||||
}
|
||||
|
||||
func (this *Extension) Equal(that *Extension) bool {
|
||||
return bytes.Equal(this.enc, that.enc)
|
||||
}
|
||||
|
||||
func SizeOfExtensionMap(m map[int32]Extension) (n int) {
|
||||
return sizeExtensionMap(m)
|
||||
}
|
||||
|
||||
type sortableMapElem struct {
|
||||
field int32
|
||||
ext Extension
|
||||
}
|
||||
|
||||
func newSortableExtensionsFromMap(m map[int32]Extension) sortableExtensions {
|
||||
s := make(sortableExtensions, 0, len(m))
|
||||
for k, v := range m {
|
||||
s = append(s, &sortableMapElem{field: k, ext: v})
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type sortableExtensions []*sortableMapElem
|
||||
|
||||
func (this sortableExtensions) Len() int { return len(this) }
|
||||
|
||||
func (this sortableExtensions) Swap(i, j int) { this[i], this[j] = this[j], this[i] }
|
||||
|
||||
func (this sortableExtensions) Less(i, j int) bool { return this[i].field < this[j].field }
|
||||
|
||||
func (this sortableExtensions) String() string {
|
||||
sort.Sort(this)
|
||||
ss := make([]string, len(this))
|
||||
for i := range this {
|
||||
ss[i] = fmt.Sprintf("%d: %v", this[i].field, this[i].ext)
|
||||
}
|
||||
return "map[" + strings.Join(ss, ",") + "]"
|
||||
}
|
||||
|
||||
func StringFromExtensionsMap(m map[int32]Extension) string {
|
||||
return newSortableExtensionsFromMap(m).String()
|
||||
}
|
||||
|
||||
func StringFromExtensionsBytes(ext []byte) string {
|
||||
m, err := BytesToExtensionsMap(ext)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return StringFromExtensionsMap(m)
|
||||
}
|
||||
|
||||
func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) {
|
||||
if err := encodeExtensionMap(m); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
keys := make([]int, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
for _, k := range keys {
|
||||
n += copy(data[n:], m[int32(k)].enc)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) {
|
||||
if m[id].value == nil || m[id].desc == nil {
|
||||
return m[id].enc, nil
|
||||
}
|
||||
if err := encodeExtensionMap(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m[id].enc, nil
|
||||
}
|
||||
|
||||
func size(buf []byte, wire int) (int, error) {
|
||||
switch wire {
|
||||
case WireVarint:
|
||||
_, n := DecodeVarint(buf)
|
||||
return n, nil
|
||||
case WireFixed64:
|
||||
return 8, nil
|
||||
case WireBytes:
|
||||
v, n := DecodeVarint(buf)
|
||||
return int(v) + n, nil
|
||||
case WireFixed32:
|
||||
return 4, nil
|
||||
case WireStartGroup:
|
||||
offset := 0
|
||||
for {
|
||||
u, n := DecodeVarint(buf[offset:])
|
||||
fwire := int(u & 0x7)
|
||||
offset += n
|
||||
if fwire == WireEndGroup {
|
||||
return offset, nil
|
||||
}
|
||||
s, err := size(buf[offset:], wire)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset += s
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("proto: can't get size for unknown wire type %d", wire)
|
||||
}
|
||||
|
||||
func BytesToExtensionsMap(buf []byte) (map[int32]Extension, error) {
|
||||
m := make(map[int32]Extension)
|
||||
i := 0
|
||||
for i < len(buf) {
|
||||
tag, n := DecodeVarint(buf[i:])
|
||||
if n <= 0 {
|
||||
return nil, fmt.Errorf("unable to decode varint")
|
||||
}
|
||||
fieldNum := int32(tag >> 3)
|
||||
wireType := int(tag & 0x7)
|
||||
l, err := size(buf[i+n:], wireType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
end := i + int(l) + n
|
||||
m[int32(fieldNum)] = Extension{enc: buf[i:end]}
|
||||
i = end
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func NewExtension(e []byte) Extension {
|
||||
ee := Extension{enc: make([]byte, len(e))}
|
||||
copy(ee.enc, e)
|
||||
return ee
|
||||
}
|
||||
|
||||
func (this Extension) GoString() string {
|
||||
if this.enc == nil {
|
||||
if err := encodeExtension(&this); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("proto.NewExtension(%#v)", this.enc)
|
||||
}
|
||||
|
||||
func SetUnsafeExtension(pb extendableProto, fieldNum int32, value interface{}) error {
|
||||
typ := reflect.TypeOf(pb).Elem()
|
||||
ext, ok := extensionMaps[typ]
|
||||
if !ok {
|
||||
return fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String())
|
||||
}
|
||||
desc, ok := ext[fieldNum]
|
||||
if !ok {
|
||||
return errors.New("proto: bad extension number; not in declared ranges")
|
||||
}
|
||||
return setExtension(pb, desc, value)
|
||||
}
|
||||
|
||||
func GetUnsafeExtension(pb extendableProto, fieldNum int32) (interface{}, error) {
|
||||
typ := reflect.TypeOf(pb).Elem()
|
||||
ext, ok := extensionMaps[typ]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String())
|
||||
}
|
||||
desc, ok := ext[fieldNum]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unregistered field number %d", fieldNum)
|
||||
}
|
||||
return GetExtension(pb, desc)
|
||||
}
|
||||
94
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_test.go
generated
vendored
Normal file
94
Godeps/_workspace/src/github.com/gogo/protobuf/proto/extensions_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "./testdata"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestGetExtensionsWithMissingExtensions(t *testing.T) {
|
||||
msg := &pb.MyMessage{}
|
||||
ext1 := &pb.Ext{}
|
||||
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil {
|
||||
t.Fatalf("Could not set ext1: %s", ext1)
|
||||
}
|
||||
exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{
|
||||
pb.E_Ext_More,
|
||||
pb.E_Ext_Text,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("GetExtensions() failed: %s", err)
|
||||
}
|
||||
if exts[0] != ext1 {
|
||||
t.Errorf("ext1 not in returned extensions: %T %v", exts[0], exts[0])
|
||||
}
|
||||
if exts[1] != nil {
|
||||
t.Errorf("ext2 in returned extensions: %T %v", exts[1], exts[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExtensionStability(t *testing.T) {
|
||||
check := func(m *pb.MyMessage) bool {
|
||||
ext1, err := proto.GetExtension(m, pb.E_Ext_More)
|
||||
if err != nil {
|
||||
t.Fatalf("GetExtension() failed: %s", err)
|
||||
}
|
||||
ext2, err := proto.GetExtension(m, pb.E_Ext_More)
|
||||
if err != nil {
|
||||
t.Fatalf("GetExtension() failed: %s", err)
|
||||
}
|
||||
return ext1 == ext2
|
||||
}
|
||||
msg := &pb.MyMessage{Count: proto.Int32(4)}
|
||||
ext0 := &pb.Ext{}
|
||||
if err := proto.SetExtension(msg, pb.E_Ext_More, ext0); err != nil {
|
||||
t.Fatalf("Could not set ext1: %s", ext0)
|
||||
}
|
||||
if !check(msg) {
|
||||
t.Errorf("GetExtension() not stable before marshaling")
|
||||
}
|
||||
bb, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal() failed: %s", err)
|
||||
}
|
||||
msg1 := &pb.MyMessage{}
|
||||
err = proto.Unmarshal(bb, msg1)
|
||||
if err != nil {
|
||||
t.Fatalf("Unmarshal() failed: %s", err)
|
||||
}
|
||||
if !check(msg1) {
|
||||
t.Errorf("GetExtension() not stable after unmarshaling")
|
||||
}
|
||||
}
|
||||
740
Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go
generated
vendored
Normal file
740
Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib.go
generated
vendored
Normal file
@@ -0,0 +1,740 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/*
|
||||
Package proto converts data structures to and from the wire format of
|
||||
protocol buffers. It works in concert with the Go source code generated
|
||||
for .proto files by the protocol compiler.
|
||||
|
||||
A summary of the properties of the protocol buffer interface
|
||||
for a protocol buffer variable v:
|
||||
|
||||
- Names are turned from camel_case to CamelCase for export.
|
||||
- There are no methods on v to set fields; just treat
|
||||
them as structure fields.
|
||||
- There are getters that return a field's value if set,
|
||||
and return the field's default value if unset.
|
||||
The getters work even if the receiver is a nil message.
|
||||
- The zero value for a struct is its correct initialization state.
|
||||
All desired fields must be set before marshaling.
|
||||
- A Reset() method will restore a protobuf struct to its zero state.
|
||||
- Non-repeated fields are pointers to the values; nil means unset.
|
||||
That is, optional or required field int32 f becomes F *int32.
|
||||
- Repeated fields are slices.
|
||||
- Helper functions are available to aid the setting of fields.
|
||||
Helpers for getting values are superseded by the
|
||||
GetFoo methods and their use is deprecated.
|
||||
msg.Foo = proto.String("hello") // set field
|
||||
- Constants are defined to hold the default values of all fields that
|
||||
have them. They have the form Default_StructName_FieldName.
|
||||
Because the getter methods handle defaulted values,
|
||||
direct use of these constants should be rare.
|
||||
- Enums are given type names and maps from names to values.
|
||||
Enum values are prefixed with the enum's type name. Enum types have
|
||||
a String method, and a Enum method to assist in message construction.
|
||||
- Nested groups and enums have type names prefixed with the name of
|
||||
the surrounding message type.
|
||||
- Extensions are given descriptor names that start with E_,
|
||||
followed by an underscore-delimited list of the nested messages
|
||||
that contain it (if any) followed by the CamelCased name of the
|
||||
extension field itself. HasExtension, ClearExtension, GetExtension
|
||||
and SetExtension are functions for manipulating extensions.
|
||||
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
||||
|
||||
The simplest way to describe this is to see an example.
|
||||
Given file test.proto, containing
|
||||
|
||||
package example;
|
||||
|
||||
enum FOO { X = 17; };
|
||||
|
||||
message Test {
|
||||
required string label = 1;
|
||||
optional int32 type = 2 [default=77];
|
||||
repeated int64 reps = 3;
|
||||
optional group OptionalGroup = 4 {
|
||||
required string RequiredField = 5;
|
||||
}
|
||||
}
|
||||
|
||||
The resulting file, test.pb.go, is:
|
||||
|
||||
package example
|
||||
|
||||
import "github.com/gogo/protobuf/proto"
|
||||
|
||||
type FOO int32
|
||||
const (
|
||||
FOO_X FOO = 17
|
||||
)
|
||||
var FOO_name = map[int32]string{
|
||||
17: "X",
|
||||
}
|
||||
var FOO_value = map[string]int32{
|
||||
"X": 17,
|
||||
}
|
||||
|
||||
func (x FOO) Enum() *FOO {
|
||||
p := new(FOO)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x FOO) String() string {
|
||||
return proto.EnumName(FOO_name, int32(x))
|
||||
}
|
||||
|
||||
type Test struct {
|
||||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
func (this *Test) Reset() { *this = Test{} }
|
||||
func (this *Test) String() string { return proto.CompactTextString(this) }
|
||||
const Default_Test_Type int32 = 77
|
||||
|
||||
func (this *Test) GetLabel() string {
|
||||
if this != nil && this.Label != nil {
|
||||
return *this.Label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Test) GetType() int32 {
|
||||
if this != nil && this.Type != nil {
|
||||
return *this.Type
|
||||
}
|
||||
return Default_Test_Type
|
||||
}
|
||||
|
||||
func (this *Test) GetOptionalgroup() *Test_OptionalGroup {
|
||||
if this != nil {
|
||||
return this.Optionalgroup
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Test_OptionalGroup struct {
|
||||
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
func (this *Test_OptionalGroup) Reset() { *this = Test_OptionalGroup{} }
|
||||
func (this *Test_OptionalGroup) String() string { return proto.CompactTextString(this) }
|
||||
|
||||
func (this *Test_OptionalGroup) GetRequiredField() string {
|
||||
if this != nil && this.RequiredField != nil {
|
||||
return *this.RequiredField
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
||||
}
|
||||
|
||||
To create and play with a Test object:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"./example.pb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
test := &example.Test{
|
||||
Label: proto.String("hello"),
|
||||
Type: proto.Int32(17),
|
||||
Optionalgroup: &example.Test_OptionalGroup{
|
||||
RequiredField: proto.String("good bye"),
|
||||
},
|
||||
}
|
||||
data, err := proto.Marshal(test)
|
||||
if err != nil {
|
||||
log.Fatal("marshaling error: ", err)
|
||||
}
|
||||
newTest := new(example.Test)
|
||||
err = proto.Unmarshal(data, newTest)
|
||||
if err != nil {
|
||||
log.Fatal("unmarshaling error: ", err)
|
||||
}
|
||||
// Now test and newTest contain the same data.
|
||||
if test.GetLabel() != newTest.GetLabel() {
|
||||
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
|
||||
}
|
||||
// etc.
|
||||
}
|
||||
*/
|
||||
package proto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Message is implemented by generated protocol buffer messages.
|
||||
type Message interface {
|
||||
Reset()
|
||||
String() string
|
||||
ProtoMessage()
|
||||
}
|
||||
|
||||
// Stats records allocation details about the protocol buffer encoders
|
||||
// and decoders. Useful for tuning the library itself.
|
||||
type Stats struct {
|
||||
Emalloc uint64 // mallocs in encode
|
||||
Dmalloc uint64 // mallocs in decode
|
||||
Encode uint64 // number of encodes
|
||||
Decode uint64 // number of decodes
|
||||
Chit uint64 // number of cache hits
|
||||
Cmiss uint64 // number of cache misses
|
||||
Size uint64 // number of sizes
|
||||
}
|
||||
|
||||
// Set to true to enable stats collection.
|
||||
const collectStats = false
|
||||
|
||||
var stats Stats
|
||||
|
||||
// GetStats returns a copy of the global Stats structure.
|
||||
func GetStats() Stats { return stats }
|
||||
|
||||
// A Buffer is a buffer manager for marshaling and unmarshaling
|
||||
// protocol buffers. It may be reused between invocations to
|
||||
// reduce memory usage. It is not necessary to use a Buffer;
|
||||
// the global functions Marshal and Unmarshal create a
|
||||
// temporary Buffer and are fine for most applications.
|
||||
type Buffer struct {
|
||||
buf []byte // encode/decode byte stream
|
||||
index int // write point
|
||||
|
||||
// pools of basic types to amortize allocation.
|
||||
bools []bool
|
||||
uint32s []uint32
|
||||
uint64s []uint64
|
||||
|
||||
// extra pools, only used with pointer_reflect.go
|
||||
int32s []int32
|
||||
int64s []int64
|
||||
float32s []float32
|
||||
float64s []float64
|
||||
}
|
||||
|
||||
// NewBuffer allocates a new Buffer and initializes its internal data to
|
||||
// the contents of the argument slice.
|
||||
func NewBuffer(e []byte) *Buffer {
|
||||
return &Buffer{buf: e}
|
||||
}
|
||||
|
||||
// Reset resets the Buffer, ready for marshaling a new protocol buffer.
|
||||
func (p *Buffer) Reset() {
|
||||
p.buf = p.buf[0:0] // for reading/writing
|
||||
p.index = 0 // for reading
|
||||
}
|
||||
|
||||
// SetBuf replaces the internal buffer with the slice,
|
||||
// ready for unmarshaling the contents of the slice.
|
||||
func (p *Buffer) SetBuf(s []byte) {
|
||||
p.buf = s
|
||||
p.index = 0
|
||||
}
|
||||
|
||||
// Bytes returns the contents of the Buffer.
|
||||
func (p *Buffer) Bytes() []byte { return p.buf }
|
||||
|
||||
/*
|
||||
* Helper routines for simplifying the creation of optional fields of basic type.
|
||||
*/
|
||||
|
||||
// Bool is a helper routine that allocates a new bool value
|
||||
// to store v and returns a pointer to it.
|
||||
func Bool(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int32 is a helper routine that allocates a new int32 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Int32(v int32) *int32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int is a helper routine that allocates a new int32 value
|
||||
// to store v and returns a pointer to it, but unlike Int32
|
||||
// its argument value is an int.
|
||||
func Int(v int) *int32 {
|
||||
p := new(int32)
|
||||
*p = int32(v)
|
||||
return p
|
||||
}
|
||||
|
||||
// Int64 is a helper routine that allocates a new int64 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Int64(v int64) *int64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float32 is a helper routine that allocates a new float32 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Float32(v float32) *float32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float64 is a helper routine that allocates a new float64 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Float64(v float64) *float64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint32 is a helper routine that allocates a new uint32 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Uint32(v uint32) *uint32 {
|
||||
p := new(uint32)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint64 is a helper routine that allocates a new uint64 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Uint64(v uint64) *uint64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// String is a helper routine that allocates a new string value
|
||||
// to store v and returns a pointer to it.
|
||||
func String(v string) *string {
|
||||
return &v
|
||||
}
|
||||
|
||||
// EnumName is a helper function to simplify printing protocol buffer enums
|
||||
// by name. Given an enum map and a value, it returns a useful string.
|
||||
func EnumName(m map[int32]string, v int32) string {
|
||||
s, ok := m[v]
|
||||
if ok {
|
||||
return s
|
||||
}
|
||||
return strconv.Itoa(int(v))
|
||||
}
|
||||
|
||||
// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
|
||||
// from their JSON-encoded representation. Given a map from the enum's symbolic
|
||||
// names to its int values, and a byte buffer containing the JSON-encoded
|
||||
// value, it returns an int32 that can be cast to the enum type by the caller.
|
||||
//
|
||||
// The function can deal with both JSON representations, numeric and symbolic.
|
||||
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
|
||||
if data[0] == '"' {
|
||||
// New style: enums are strings.
|
||||
var repr string
|
||||
if err := json.Unmarshal(data, &repr); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
val, ok := m[repr]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
// Old style: enums are ints.
|
||||
var val int32
|
||||
if err := json.Unmarshal(data, &val); err != nil {
|
||||
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// DebugPrint dumps the encoded data in b in a debugging format with a header
|
||||
// including the string s. Used in testing but made available for general debugging.
|
||||
func (o *Buffer) DebugPrint(s string, b []byte) {
|
||||
var u uint64
|
||||
|
||||
obuf := o.buf
|
||||
index := o.index
|
||||
o.buf = b
|
||||
o.index = 0
|
||||
depth := 0
|
||||
|
||||
fmt.Printf("\n--- %s ---\n", s)
|
||||
|
||||
out:
|
||||
for {
|
||||
for i := 0; i < depth; i++ {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
|
||||
index := o.index
|
||||
if index == len(o.buf) {
|
||||
break
|
||||
}
|
||||
|
||||
op, err := o.DecodeVarint()
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: fetching op err %v\n", index, err)
|
||||
break out
|
||||
}
|
||||
tag := op >> 3
|
||||
wire := op & 7
|
||||
|
||||
switch wire {
|
||||
default:
|
||||
fmt.Printf("%3d: t=%3d unknown wire=%d\n",
|
||||
index, tag, wire)
|
||||
break out
|
||||
|
||||
case WireBytes:
|
||||
var r []byte
|
||||
|
||||
r, err = o.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
|
||||
if len(r) <= 6 {
|
||||
for i := 0; i < len(r); i++ {
|
||||
fmt.Printf(" %.2x", r[i])
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 3; i++ {
|
||||
fmt.Printf(" %.2x", r[i])
|
||||
}
|
||||
fmt.Printf(" ..")
|
||||
for i := len(r) - 3; i < len(r); i++ {
|
||||
fmt.Printf(" %.2x", r[i])
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
case WireFixed32:
|
||||
u, err = o.DecodeFixed32()
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
|
||||
|
||||
case WireFixed64:
|
||||
u, err = o.DecodeFixed64()
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
||||
break
|
||||
|
||||
case WireVarint:
|
||||
u, err = o.DecodeVarint()
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
||||
|
||||
case WireStartGroup:
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
||||
depth++
|
||||
|
||||
case WireEndGroup:
|
||||
depth--
|
||||
if err != nil {
|
||||
fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
|
||||
break out
|
||||
}
|
||||
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
||||
}
|
||||
}
|
||||
|
||||
if depth != 0 {
|
||||
fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
o.buf = obuf
|
||||
o.index = index
|
||||
}
|
||||
|
||||
// SetDefaults sets unset protocol buffer fields to their default values.
|
||||
// It only modifies fields that are both unset and have defined defaults.
|
||||
// It recursively sets default values in any non-nil sub-messages.
|
||||
func SetDefaults(pb Message) {
|
||||
setDefaults(reflect.ValueOf(pb), true, false)
|
||||
}
|
||||
|
||||
// v is a pointer to a struct.
|
||||
func setDefaults(v reflect.Value, recur, zeros bool) {
|
||||
v = v.Elem()
|
||||
|
||||
defaultMu.RLock()
|
||||
dm, ok := defaults[v.Type()]
|
||||
defaultMu.RUnlock()
|
||||
if !ok {
|
||||
dm = buildDefaultMessage(v.Type())
|
||||
defaultMu.Lock()
|
||||
defaults[v.Type()] = dm
|
||||
defaultMu.Unlock()
|
||||
}
|
||||
|
||||
for _, sf := range dm.scalars {
|
||||
f := v.Field(sf.index)
|
||||
if !f.IsNil() {
|
||||
// field already set
|
||||
continue
|
||||
}
|
||||
dv := sf.value
|
||||
if dv == nil && !zeros {
|
||||
// no explicit default, and don't want to set zeros
|
||||
continue
|
||||
}
|
||||
fptr := f.Addr().Interface() // **T
|
||||
// TODO: Consider batching the allocations we do here.
|
||||
switch sf.kind {
|
||||
case reflect.Bool:
|
||||
b := new(bool)
|
||||
if dv != nil {
|
||||
*b = dv.(bool)
|
||||
}
|
||||
*(fptr.(**bool)) = b
|
||||
case reflect.Float32:
|
||||
f := new(float32)
|
||||
if dv != nil {
|
||||
*f = dv.(float32)
|
||||
}
|
||||
*(fptr.(**float32)) = f
|
||||
case reflect.Float64:
|
||||
f := new(float64)
|
||||
if dv != nil {
|
||||
*f = dv.(float64)
|
||||
}
|
||||
*(fptr.(**float64)) = f
|
||||
case reflect.Int32:
|
||||
// might be an enum
|
||||
if ft := f.Type(); ft != int32PtrType {
|
||||
// enum
|
||||
f.Set(reflect.New(ft.Elem()))
|
||||
if dv != nil {
|
||||
f.Elem().SetInt(int64(dv.(int32)))
|
||||
}
|
||||
} else {
|
||||
// int32 field
|
||||
i := new(int32)
|
||||
if dv != nil {
|
||||
*i = dv.(int32)
|
||||
}
|
||||
*(fptr.(**int32)) = i
|
||||
}
|
||||
case reflect.Int64:
|
||||
i := new(int64)
|
||||
if dv != nil {
|
||||
*i = dv.(int64)
|
||||
}
|
||||
*(fptr.(**int64)) = i
|
||||
case reflect.String:
|
||||
s := new(string)
|
||||
if dv != nil {
|
||||
*s = dv.(string)
|
||||
}
|
||||
*(fptr.(**string)) = s
|
||||
case reflect.Uint8:
|
||||
// exceptional case: []byte
|
||||
var b []byte
|
||||
if dv != nil {
|
||||
db := dv.([]byte)
|
||||
b = make([]byte, len(db))
|
||||
copy(b, db)
|
||||
} else {
|
||||
b = []byte{}
|
||||
}
|
||||
*(fptr.(*[]byte)) = b
|
||||
case reflect.Uint32:
|
||||
u := new(uint32)
|
||||
if dv != nil {
|
||||
*u = dv.(uint32)
|
||||
}
|
||||
*(fptr.(**uint32)) = u
|
||||
case reflect.Uint64:
|
||||
u := new(uint64)
|
||||
if dv != nil {
|
||||
*u = dv.(uint64)
|
||||
}
|
||||
*(fptr.(**uint64)) = u
|
||||
default:
|
||||
log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ni := range dm.nested {
|
||||
f := v.Field(ni)
|
||||
if f.IsNil() {
|
||||
continue
|
||||
}
|
||||
// f is *T or []*T
|
||||
if f.Kind() == reflect.Ptr {
|
||||
setDefaults(f, recur, zeros)
|
||||
} else {
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
e := f.Index(i)
|
||||
if e.IsNil() {
|
||||
continue
|
||||
}
|
||||
setDefaults(e, recur, zeros)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// defaults maps a protocol buffer struct type to a slice of the fields,
|
||||
// with its scalar fields set to their proto-declared non-zero default values.
|
||||
defaultMu sync.RWMutex
|
||||
defaults = make(map[reflect.Type]defaultMessage)
|
||||
|
||||
int32PtrType = reflect.TypeOf((*int32)(nil))
|
||||
)
|
||||
|
||||
// defaultMessage represents information about the default values of a message.
|
||||
type defaultMessage struct {
|
||||
scalars []scalarField
|
||||
nested []int // struct field index of nested messages
|
||||
}
|
||||
|
||||
type scalarField struct {
|
||||
index int // struct field index
|
||||
kind reflect.Kind // element type (the T in *T or []T)
|
||||
value interface{} // the proto-declared default value, or nil
|
||||
}
|
||||
|
||||
func ptrToStruct(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
// t is a struct type.
|
||||
func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
||||
sprop := GetProperties(t)
|
||||
for _, prop := range sprop.Prop {
|
||||
fi, ok := sprop.decoderTags.get(prop.Tag)
|
||||
if !ok {
|
||||
// XXX_unrecognized
|
||||
continue
|
||||
}
|
||||
ft := t.Field(fi).Type
|
||||
|
||||
// nested messages
|
||||
if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) {
|
||||
dm.nested = append(dm.nested, fi)
|
||||
continue
|
||||
}
|
||||
|
||||
sf := scalarField{
|
||||
index: fi,
|
||||
kind: ft.Elem().Kind(),
|
||||
}
|
||||
|
||||
// scalar fields without defaults
|
||||
if !prop.HasDefault {
|
||||
dm.scalars = append(dm.scalars, sf)
|
||||
continue
|
||||
}
|
||||
|
||||
// a scalar field: either *T or []byte
|
||||
switch ft.Elem().Kind() {
|
||||
case reflect.Bool:
|
||||
x, err := strconv.ParseBool(prop.Default)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default bool %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = x
|
||||
case reflect.Float32:
|
||||
x, err := strconv.ParseFloat(prop.Default, 32)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default float32 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = float32(x)
|
||||
case reflect.Float64:
|
||||
x, err := strconv.ParseFloat(prop.Default, 64)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default float64 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = x
|
||||
case reflect.Int32:
|
||||
x, err := strconv.ParseInt(prop.Default, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default int32 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = int32(x)
|
||||
case reflect.Int64:
|
||||
x, err := strconv.ParseInt(prop.Default, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default int64 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = x
|
||||
case reflect.String:
|
||||
sf.value = prop.Default
|
||||
case reflect.Uint8:
|
||||
// []byte (not *uint8)
|
||||
sf.value = []byte(prop.Default)
|
||||
case reflect.Uint32:
|
||||
x, err := strconv.ParseUint(prop.Default, 10, 32)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default uint32 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = uint32(x)
|
||||
case reflect.Uint64:
|
||||
x, err := strconv.ParseUint(prop.Default, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("proto: bad default uint64 %q: %v", prop.Default, err)
|
||||
continue
|
||||
}
|
||||
sf.value = x
|
||||
default:
|
||||
log.Printf("proto: unhandled def kind %v", ft.Elem().Kind())
|
||||
continue
|
||||
}
|
||||
|
||||
dm.scalars = append(dm.scalars, sf)
|
||||
}
|
||||
|
||||
return dm
|
||||
}
|
||||
40
Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/gogo/protobuf/proto/lib_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func MarshalJSONEnum(m map[int32]string, value int32) ([]byte, error) {
|
||||
s, ok := m[value]
|
||||
if !ok {
|
||||
s = strconv.Itoa(int(value))
|
||||
}
|
||||
return json.Marshal(s)
|
||||
}
|
||||
287
Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go
generated
vendored
Normal file
287
Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set.go
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
/*
|
||||
* Support for message sets.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
|
||||
// A message type ID is required for storing a protocol buffer in a message set.
|
||||
var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
|
||||
|
||||
// The first two types (_MessageSet_Item and MessageSet)
|
||||
// model what the protocol compiler produces for the following protocol message:
|
||||
// message MessageSet {
|
||||
// repeated group Item = 1 {
|
||||
// required int32 type_id = 2;
|
||||
// required string message = 3;
|
||||
// };
|
||||
// }
|
||||
// That is the MessageSet wire format. We can't use a proto to generate these
|
||||
// because that would introduce a circular dependency between it and this package.
|
||||
//
|
||||
// When a proto1 proto has a field that looks like:
|
||||
// optional message<MessageSet> info = 3;
|
||||
// the protocol compiler produces a field in the generated struct that looks like:
|
||||
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
|
||||
// The package is automatically inserted so there is no need for that proto file to
|
||||
// import this package.
|
||||
|
||||
type _MessageSet_Item struct {
|
||||
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
||||
Message []byte `protobuf:"bytes,3,req,name=message"`
|
||||
}
|
||||
|
||||
type MessageSet struct {
|
||||
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
||||
XXX_unrecognized []byte
|
||||
// TODO: caching?
|
||||
}
|
||||
|
||||
// Make sure MessageSet is a Message.
|
||||
var _ Message = (*MessageSet)(nil)
|
||||
|
||||
// messageTypeIder is an interface satisfied by a protocol buffer type
|
||||
// that may be stored in a MessageSet.
|
||||
type messageTypeIder interface {
|
||||
MessageTypeId() int32
|
||||
}
|
||||
|
||||
func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
|
||||
mti, ok := pb.(messageTypeIder)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
id := mti.MessageTypeId()
|
||||
for _, item := range ms.Item {
|
||||
if *item.TypeId == id {
|
||||
return item
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *MessageSet) Has(pb Message) bool {
|
||||
if ms.find(pb) != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ms *MessageSet) Unmarshal(pb Message) error {
|
||||
if item := ms.find(pb); item != nil {
|
||||
return Unmarshal(item.Message, pb)
|
||||
}
|
||||
if _, ok := pb.(messageTypeIder); !ok {
|
||||
return ErrNoMessageTypeId
|
||||
}
|
||||
return nil // TODO: return error instead?
|
||||
}
|
||||
|
||||
func (ms *MessageSet) Marshal(pb Message) error {
|
||||
msg, err := Marshal(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if item := ms.find(pb); item != nil {
|
||||
// reuse existing item
|
||||
item.Message = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
mti, ok := pb.(messageTypeIder)
|
||||
if !ok {
|
||||
return ErrNoMessageTypeId
|
||||
}
|
||||
|
||||
mtid := mti.MessageTypeId()
|
||||
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||
TypeId: &mtid,
|
||||
Message: msg,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *MessageSet) Reset() { *ms = MessageSet{} }
|
||||
func (ms *MessageSet) String() string { return CompactTextString(ms) }
|
||||
func (*MessageSet) ProtoMessage() {}
|
||||
|
||||
// Support for the message_set_wire_format message option.
|
||||
|
||||
func skipVarint(buf []byte) []byte {
|
||||
i := 0
|
||||
for ; buf[i]&0x80 != 0; i++ {
|
||||
}
|
||||
return buf[i+1:]
|
||||
}
|
||||
|
||||
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
|
||||
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
||||
if err := encodeExtensionMap(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sort extension IDs to provide a deterministic encoding.
|
||||
// See also enc_map in encode.go.
|
||||
ids := make([]int, 0, len(m))
|
||||
for id := range m {
|
||||
ids = append(ids, int(id))
|
||||
}
|
||||
sort.Ints(ids)
|
||||
|
||||
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||
for _, id := range ids {
|
||||
e := m[int32(id)]
|
||||
// Remove the wire type and field number varint, as well as the length varint.
|
||||
msg := skipVarint(skipVarint(e.enc))
|
||||
|
||||
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||
TypeId: Int32(int32(id)),
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
return Marshal(ms)
|
||||
}
|
||||
|
||||
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
||||
ms := new(MessageSet)
|
||||
if err := Unmarshal(buf, ms); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range ms.Item {
|
||||
id := *item.TypeId
|
||||
msg := item.Message
|
||||
|
||||
// Restore wire type and field number varint, plus length varint.
|
||||
// Be careful to preserve duplicate items.
|
||||
b := EncodeVarint(uint64(id)<<3 | WireBytes)
|
||||
if ext, ok := m[id]; ok {
|
||||
// Existing data; rip off the tag and length varint
|
||||
// so we join the new data correctly.
|
||||
// We can assume that ext.enc is set because we are unmarshaling.
|
||||
o := ext.enc[len(b):] // skip wire type and field number
|
||||
_, n := DecodeVarint(o) // calculate length of length varint
|
||||
o = o[n:] // skip length varint
|
||||
msg = append(o, msg...) // join old data and new data
|
||||
}
|
||||
b = append(b, EncodeVarint(uint64(len(msg)))...)
|
||||
b = append(b, msg...)
|
||||
|
||||
m[id] = Extension{enc: b}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
|
||||
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func MarshalMessageSetJSON(m map[int32]Extension) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteByte('{')
|
||||
|
||||
// Process the map in key order for deterministic output.
|
||||
ids := make([]int32, 0, len(m))
|
||||
for id := range m {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
|
||||
|
||||
for i, id := range ids {
|
||||
ext := m[id]
|
||||
if i > 0 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
|
||||
msd, ok := messageSetMap[id]
|
||||
if !ok {
|
||||
// Unknown type; we can't render it, so skip it.
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(&b, `"[%s]":`, msd.name)
|
||||
|
||||
x := ext.value
|
||||
if x == nil {
|
||||
x = reflect.New(msd.t.Elem()).Interface()
|
||||
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
d, err := json.Marshal(x)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Write(d)
|
||||
}
|
||||
b.WriteByte('}')
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
|
||||
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||
func UnmarshalMessageSetJSON(buf []byte, m map[int32]Extension) error {
|
||||
// Common-case fast path.
|
||||
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This is fairly tricky, and it's not clear that it is needed.
|
||||
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
|
||||
}
|
||||
|
||||
// A global registry of types that can be used in a MessageSet.
|
||||
|
||||
var messageSetMap = make(map[int32]messageSetDesc)
|
||||
|
||||
type messageSetDesc struct {
|
||||
t reflect.Type // pointer to struct
|
||||
name string
|
||||
}
|
||||
|
||||
// RegisterMessageSetType is called from the generated code.
|
||||
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
|
||||
messageSetMap[fieldNum] = messageSetDesc{
|
||||
t: reflect.TypeOf(m),
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
66
Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set_test.go
generated
vendored
Normal file
66
Godeps/_workspace/src/github.com/gogo/protobuf/proto/message_set_test.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnmarshalMessageSetWithDuplicate(t *testing.T) {
|
||||
// Check that a repeated message set entry will be concatenated.
|
||||
in := &MessageSet{
|
||||
Item: []*_MessageSet_Item{
|
||||
{TypeId: Int32(12345), Message: []byte("hoo")},
|
||||
{TypeId: Int32(12345), Message: []byte("hah")},
|
||||
},
|
||||
}
|
||||
b, err := Marshal(in)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal: %v", err)
|
||||
}
|
||||
t.Logf("Marshaled bytes: %q", b)
|
||||
|
||||
m := make(map[int32]Extension)
|
||||
if err := UnmarshalMessageSet(b, m); err != nil {
|
||||
t.Fatalf("UnmarshalMessageSet: %v", err)
|
||||
}
|
||||
ext, ok := m[12345]
|
||||
if !ok {
|
||||
t.Fatalf("Didn't retrieve extension 12345; map is %v", m)
|
||||
}
|
||||
// Skip wire type/field number and length varints.
|
||||
got := skipVarint(skipVarint(ext.enc))
|
||||
if want := []byte("hoohah"); !bytes.Equal(got, want) {
|
||||
t.Errorf("Combined extension is %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
384
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
384
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build appengine,!appenginevm
|
||||
|
||||
// This file contains an implementation of proto field accesses using package reflect.
|
||||
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
|
||||
// be used on App Engine.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// A structPointer is a pointer to a struct.
|
||||
type structPointer struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||
// The reflect value must itself be a pointer to a struct.
|
||||
func toStructPointer(v reflect.Value) structPointer {
|
||||
return structPointer{v}
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func structPointer_IsNil(p structPointer) bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
// Interface returns the struct pointer as an interface value.
|
||||
func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
|
||||
return p.v.Interface()
|
||||
}
|
||||
|
||||
// A field identifies a field in a struct, accessible from a structPointer.
|
||||
// In this implementation, a field is identified by the sequence of field indices
|
||||
// passed to reflect's FieldByIndex.
|
||||
type field []int
|
||||
|
||||
// toField returns a field equivalent to the given reflect field.
|
||||
func toField(f *reflect.StructField) field {
|
||||
return f.Index
|
||||
}
|
||||
|
||||
// invalidField is an invalid field identifier.
|
||||
var invalidField = field(nil)
|
||||
|
||||
// IsValid reports whether the field identifier is valid.
|
||||
func (f field) IsValid() bool { return f != nil }
|
||||
|
||||
// field returns the given field in the struct as a reflect value.
|
||||
func structPointer_field(p structPointer, f field) reflect.Value {
|
||||
// Special case: an extension map entry with a value of type T
|
||||
// passes a *T to the struct-handling code with a zero field,
|
||||
// expecting that it will be treated as equivalent to *struct{ X T },
|
||||
// which has the same memory layout. We have to handle that case
|
||||
// specially, because reflect will panic if we call FieldByIndex on a
|
||||
// non-struct.
|
||||
if f == nil {
|
||||
return p.v.Elem()
|
||||
}
|
||||
|
||||
return p.v.Elem().FieldByIndex(f)
|
||||
}
|
||||
|
||||
// ifield returns the given field in the struct as an interface value.
|
||||
func structPointer_ifield(p structPointer, f field) interface{} {
|
||||
return structPointer_field(p, f).Addr().Interface()
|
||||
}
|
||||
|
||||
// Bytes returns the address of a []byte field in the struct.
|
||||
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||
return structPointer_ifield(p, f).(*[]byte)
|
||||
}
|
||||
|
||||
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||
return structPointer_ifield(p, f).(*[][]byte)
|
||||
}
|
||||
|
||||
// Bool returns the address of a *bool field in the struct.
|
||||
func structPointer_Bool(p structPointer, f field) **bool {
|
||||
return structPointer_ifield(p, f).(**bool)
|
||||
}
|
||||
|
||||
// BoolSlice returns the address of a []bool field in the struct.
|
||||
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||
return structPointer_ifield(p, f).(*[]bool)
|
||||
}
|
||||
|
||||
// String returns the address of a *string field in the struct.
|
||||
func structPointer_String(p structPointer, f field) **string {
|
||||
return structPointer_ifield(p, f).(**string)
|
||||
}
|
||||
|
||||
// StringSlice returns the address of a []string field in the struct.
|
||||
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||
return structPointer_ifield(p, f).(*[]string)
|
||||
}
|
||||
|
||||
// ExtMap returns the address of an extension map field in the struct.
|
||||
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||
return structPointer_ifield(p, f).(*map[int32]Extension)
|
||||
}
|
||||
|
||||
// SetStructPointer writes a *struct field in the struct.
|
||||
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||
structPointer_field(p, f).Set(q.v)
|
||||
}
|
||||
|
||||
// GetStructPointer reads a *struct field in the struct.
|
||||
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||
return structPointer{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// StructPointerSlice the address of a []*struct field in the struct.
|
||||
func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
|
||||
return structPointerSlice{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// A structPointerSlice represents the address of a slice of pointers to structs
|
||||
// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
|
||||
type structPointerSlice struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p structPointerSlice) Len() int { return p.v.Len() }
|
||||
func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
|
||||
func (p structPointerSlice) Append(q structPointer) {
|
||||
p.v.Set(reflect.Append(p.v, q.v))
|
||||
}
|
||||
|
||||
var (
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
)
|
||||
|
||||
// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
|
||||
// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
|
||||
type word32 struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func word32_IsNil(p word32) bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
// Set sets p to point at a newly allocated word with bits set to x.
|
||||
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||
t := p.v.Type().Elem()
|
||||
switch t {
|
||||
case int32Type:
|
||||
if len(o.int32s) == 0 {
|
||||
o.int32s = make([]int32, uint32PoolSize)
|
||||
}
|
||||
o.int32s[0] = int32(x)
|
||||
p.v.Set(reflect.ValueOf(&o.int32s[0]))
|
||||
o.int32s = o.int32s[1:]
|
||||
return
|
||||
case uint32Type:
|
||||
if len(o.uint32s) == 0 {
|
||||
o.uint32s = make([]uint32, uint32PoolSize)
|
||||
}
|
||||
o.uint32s[0] = x
|
||||
p.v.Set(reflect.ValueOf(&o.uint32s[0]))
|
||||
o.uint32s = o.uint32s[1:]
|
||||
return
|
||||
case float32Type:
|
||||
if len(o.float32s) == 0 {
|
||||
o.float32s = make([]float32, uint32PoolSize)
|
||||
}
|
||||
o.float32s[0] = math.Float32frombits(x)
|
||||
p.v.Set(reflect.ValueOf(&o.float32s[0]))
|
||||
o.float32s = o.float32s[1:]
|
||||
return
|
||||
}
|
||||
|
||||
// must be enum
|
||||
p.v.Set(reflect.New(t))
|
||||
p.v.Elem().SetInt(int64(int32(x)))
|
||||
}
|
||||
|
||||
// Get gets the bits pointed at by p, as a uint32.
|
||||
func word32_Get(p word32) uint32 {
|
||||
elem := p.v.Elem()
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
return uint32(elem.Int())
|
||||
case reflect.Uint32:
|
||||
return uint32(elem.Uint())
|
||||
case reflect.Float32:
|
||||
return math.Float32bits(float32(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
|
||||
func structPointer_Word32(p structPointer, f field) word32 {
|
||||
return word32{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// A word32Slice is a slice of 32-bit values.
|
||||
// That is, v.Type() is []int32, []uint32, []float32, or []enum.
|
||||
type word32Slice struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p word32Slice) Append(x uint32) {
|
||||
n, m := p.v.Len(), p.v.Cap()
|
||||
if n < m {
|
||||
p.v.SetLen(n + 1)
|
||||
} else {
|
||||
t := p.v.Type().Elem()
|
||||
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||
}
|
||||
elem := p.v.Index(n)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
elem.SetInt(int64(int32(x)))
|
||||
case reflect.Uint32:
|
||||
elem.SetUint(uint64(x))
|
||||
case reflect.Float32:
|
||||
elem.SetFloat(float64(math.Float32frombits(x)))
|
||||
}
|
||||
}
|
||||
|
||||
func (p word32Slice) Len() int {
|
||||
return p.v.Len()
|
||||
}
|
||||
|
||||
func (p word32Slice) Index(i int) uint32 {
|
||||
elem := p.v.Index(i)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int32:
|
||||
return uint32(elem.Int())
|
||||
case reflect.Uint32:
|
||||
return uint32(elem.Uint())
|
||||
case reflect.Float32:
|
||||
return math.Float32bits(float32(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
|
||||
func structPointer_Word32Slice(p structPointer, f field) word32Slice {
|
||||
return word32Slice{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
// word64 is like word32 but for 64-bit values.
|
||||
type word64 struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||
t := p.v.Type().Elem()
|
||||
switch t {
|
||||
case int64Type:
|
||||
if len(o.int64s) == 0 {
|
||||
o.int64s = make([]int64, uint64PoolSize)
|
||||
}
|
||||
o.int64s[0] = int64(x)
|
||||
p.v.Set(reflect.ValueOf(&o.int64s[0]))
|
||||
o.int64s = o.int64s[1:]
|
||||
return
|
||||
case uint64Type:
|
||||
if len(o.uint64s) == 0 {
|
||||
o.uint64s = make([]uint64, uint64PoolSize)
|
||||
}
|
||||
o.uint64s[0] = x
|
||||
p.v.Set(reflect.ValueOf(&o.uint64s[0]))
|
||||
o.uint64s = o.uint64s[1:]
|
||||
return
|
||||
case float64Type:
|
||||
if len(o.float64s) == 0 {
|
||||
o.float64s = make([]float64, uint64PoolSize)
|
||||
}
|
||||
o.float64s[0] = math.Float64frombits(x)
|
||||
p.v.Set(reflect.ValueOf(&o.float64s[0]))
|
||||
o.float64s = o.float64s[1:]
|
||||
return
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func word64_IsNil(p word64) bool {
|
||||
return p.v.IsNil()
|
||||
}
|
||||
|
||||
func word64_Get(p word64) uint64 {
|
||||
elem := p.v.Elem()
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
return uint64(elem.Int())
|
||||
case reflect.Uint64:
|
||||
return elem.Uint()
|
||||
case reflect.Float64:
|
||||
return math.Float64bits(elem.Float())
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func structPointer_Word64(p structPointer, f field) word64 {
|
||||
return word64{structPointer_field(p, f)}
|
||||
}
|
||||
|
||||
type word64Slice struct {
|
||||
v reflect.Value
|
||||
}
|
||||
|
||||
func (p word64Slice) Append(x uint64) {
|
||||
n, m := p.v.Len(), p.v.Cap()
|
||||
if n < m {
|
||||
p.v.SetLen(n + 1)
|
||||
} else {
|
||||
t := p.v.Type().Elem()
|
||||
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||
}
|
||||
elem := p.v.Index(n)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
elem.SetInt(int64(int64(x)))
|
||||
case reflect.Uint64:
|
||||
elem.SetUint(uint64(x))
|
||||
case reflect.Float64:
|
||||
elem.SetFloat(float64(math.Float64frombits(x)))
|
||||
}
|
||||
}
|
||||
|
||||
func (p word64Slice) Len() int {
|
||||
return p.v.Len()
|
||||
}
|
||||
|
||||
func (p word64Slice) Index(i int) uint64 {
|
||||
elem := p.v.Index(i)
|
||||
switch elem.Kind() {
|
||||
case reflect.Int64:
|
||||
return uint64(elem.Int())
|
||||
case reflect.Uint64:
|
||||
return uint64(elem.Uint())
|
||||
case reflect.Float64:
|
||||
return math.Float64bits(float64(elem.Float()))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func structPointer_Word64Slice(p structPointer, f field) word64Slice {
|
||||
return word64Slice{structPointer_field(p, f)}
|
||||
}
|
||||
218
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
218
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build !appengine appenginevm
|
||||
|
||||
// This file contains the implementation of the proto field accesses using package unsafe.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NOTE: These type_Foo functions would more idiomatically be methods,
|
||||
// but Go does not allow methods on pointer types, and we must preserve
|
||||
// some pointer type for the garbage collector. We use these
|
||||
// funcs with clunky names as our poor approximation to methods.
|
||||
//
|
||||
// An alternative would be
|
||||
// type structPointer struct { p unsafe.Pointer }
|
||||
// but that does not registerize as well.
|
||||
|
||||
// A structPointer is a pointer to a struct.
|
||||
type structPointer unsafe.Pointer
|
||||
|
||||
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||
func toStructPointer(v reflect.Value) structPointer {
|
||||
return structPointer(unsafe.Pointer(v.Pointer()))
|
||||
}
|
||||
|
||||
// IsNil reports whether p is nil.
|
||||
func structPointer_IsNil(p structPointer) bool {
|
||||
return p == nil
|
||||
}
|
||||
|
||||
// Interface returns the struct pointer, assumed to have element type t,
|
||||
// as an interface value.
|
||||
func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
|
||||
return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
|
||||
}
|
||||
|
||||
// A field identifies a field in a struct, accessible from a structPointer.
|
||||
// In this implementation, a field is identified by its byte offset from the start of the struct.
|
||||
type field uintptr
|
||||
|
||||
// toField returns a field equivalent to the given reflect field.
|
||||
func toField(f *reflect.StructField) field {
|
||||
return field(f.Offset)
|
||||
}
|
||||
|
||||
// invalidField is an invalid field identifier.
|
||||
const invalidField = ^field(0)
|
||||
|
||||
// IsValid reports whether the field identifier is valid.
|
||||
func (f field) IsValid() bool {
|
||||
return f != ^field(0)
|
||||
}
|
||||
|
||||
// Bytes returns the address of a []byte field in the struct.
|
||||
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||
return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||
return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// Bool returns the address of a *bool field in the struct.
|
||||
func structPointer_Bool(p structPointer, f field) **bool {
|
||||
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// BoolSlice returns the address of a []bool field in the struct.
|
||||
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// String returns the address of a *string field in the struct.
|
||||
func structPointer_String(p structPointer, f field) **string {
|
||||
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// StringSlice returns the address of a []string field in the struct.
|
||||
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// ExtMap returns the address of an extension map field in the struct.
|
||||
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// SetStructPointer writes a *struct field in the struct.
|
||||
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
|
||||
}
|
||||
|
||||
// GetStructPointer reads a *struct field in the struct.
|
||||
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||
return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// StructPointerSlice the address of a []*struct field in the struct.
|
||||
func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
|
||||
return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
|
||||
type structPointerSlice []structPointer
|
||||
|
||||
func (v *structPointerSlice) Len() int { return len(*v) }
|
||||
func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
|
||||
func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
|
||||
|
||||
// A word32 is the address of a "pointer to 32-bit value" field.
|
||||
type word32 **uint32
|
||||
|
||||
// IsNil reports whether *v is nil.
|
||||
func word32_IsNil(p word32) bool {
|
||||
return *p == nil
|
||||
}
|
||||
|
||||
// Set sets *v to point at a newly allocated word set to x.
|
||||
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||
if len(o.uint32s) == 0 {
|
||||
o.uint32s = make([]uint32, uint32PoolSize)
|
||||
}
|
||||
o.uint32s[0] = x
|
||||
*p = &o.uint32s[0]
|
||||
o.uint32s = o.uint32s[1:]
|
||||
}
|
||||
|
||||
// Get gets the value pointed at by *v.
|
||||
func word32_Get(p word32) uint32 {
|
||||
return **p
|
||||
}
|
||||
|
||||
// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||
func structPointer_Word32(p structPointer, f field) word32 {
|
||||
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
|
||||
// A word32Slice is a slice of 32-bit values.
|
||||
type word32Slice []uint32
|
||||
|
||||
func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
|
||||
func (v *word32Slice) Len() int { return len(*v) }
|
||||
func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
|
||||
|
||||
// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
|
||||
func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
|
||||
return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// word64 is like word32 but for 64-bit values.
|
||||
type word64 **uint64
|
||||
|
||||
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||
if len(o.uint64s) == 0 {
|
||||
o.uint64s = make([]uint64, uint64PoolSize)
|
||||
}
|
||||
o.uint64s[0] = x
|
||||
*p = &o.uint64s[0]
|
||||
o.uint64s = o.uint64s[1:]
|
||||
}
|
||||
|
||||
func word64_IsNil(p word64) bool {
|
||||
return *p == nil
|
||||
}
|
||||
|
||||
func word64_Get(p word64) uint64 {
|
||||
return **p
|
||||
}
|
||||
|
||||
func structPointer_Word64(p structPointer, f field) word64 {
|
||||
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
|
||||
// word64Slice is like word32Slice but for 64-bit values.
|
||||
type word64Slice []uint64
|
||||
|
||||
func (v *word64Slice) Append(x uint64) { *v = append(*v, x) }
|
||||
func (v *word64Slice) Len() int { return len(*v) }
|
||||
func (v *word64Slice) Index(i int) uint64 { return (*v)[i] }
|
||||
|
||||
func structPointer_Word64Slice(p structPointer, f field) *word64Slice {
|
||||
return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
166
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go
generated
vendored
Normal file
166
Godeps/_workspace/src/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
// This file contains the implementation of the proto field accesses using package unsafe.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func structPointer_InterfaceAt(p structPointer, f field, t reflect.Type) interface{} {
|
||||
point := unsafe.Pointer(uintptr(p) + uintptr(f))
|
||||
r := reflect.NewAt(t, point)
|
||||
return r.Interface()
|
||||
}
|
||||
|
||||
func structPointer_InterfaceRef(p structPointer, f field, t reflect.Type) interface{} {
|
||||
point := unsafe.Pointer(uintptr(p) + uintptr(f))
|
||||
r := reflect.NewAt(t, point)
|
||||
if r.Elem().IsNil() {
|
||||
return nil
|
||||
}
|
||||
return r.Elem().Interface()
|
||||
}
|
||||
|
||||
func copyUintPtr(oldptr, newptr uintptr, size int) {
|
||||
oldbytes := make([]byte, 0)
|
||||
oldslice := (*reflect.SliceHeader)(unsafe.Pointer(&oldbytes))
|
||||
oldslice.Data = oldptr
|
||||
oldslice.Len = size
|
||||
oldslice.Cap = size
|
||||
newbytes := make([]byte, 0)
|
||||
newslice := (*reflect.SliceHeader)(unsafe.Pointer(&newbytes))
|
||||
newslice.Data = newptr
|
||||
newslice.Len = size
|
||||
newslice.Cap = size
|
||||
copy(newbytes, oldbytes)
|
||||
}
|
||||
|
||||
func structPointer_Copy(oldptr structPointer, newptr structPointer, size int) {
|
||||
copyUintPtr(uintptr(oldptr), uintptr(newptr), size)
|
||||
}
|
||||
|
||||
func appendStructPointer(base structPointer, f field, typ reflect.Type) structPointer {
|
||||
size := typ.Elem().Size()
|
||||
oldHeader := structPointer_GetSliceHeader(base, f)
|
||||
newLen := oldHeader.Len + 1
|
||||
slice := reflect.MakeSlice(typ, newLen, newLen)
|
||||
bas := toStructPointer(slice)
|
||||
for i := 0; i < oldHeader.Len; i++ {
|
||||
newElemptr := uintptr(bas) + uintptr(i)*size
|
||||
oldElemptr := oldHeader.Data + uintptr(i)*size
|
||||
copyUintPtr(oldElemptr, newElemptr, int(size))
|
||||
}
|
||||
|
||||
oldHeader.Data = uintptr(bas)
|
||||
oldHeader.Len = newLen
|
||||
oldHeader.Cap = newLen
|
||||
|
||||
return structPointer(unsafe.Pointer(uintptr(unsafe.Pointer(bas)) + uintptr(uintptr(newLen-1)*size)))
|
||||
}
|
||||
|
||||
// RefBool returns a *bool field in the struct.
|
||||
func structPointer_RefBool(p structPointer, f field) *bool {
|
||||
return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
// RefString returns the address of a string field in the struct.
|
||||
func structPointer_RefString(p structPointer, f field) *string {
|
||||
return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
func structPointer_FieldPointer(p structPointer, f field) structPointer {
|
||||
return structPointer(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
func structPointer_GetRefStructPointer(p structPointer, f field) structPointer {
|
||||
return structPointer((*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
|
||||
func structPointer_GetSliceHeader(p structPointer, f field) *reflect.SliceHeader {
|
||||
return (*reflect.SliceHeader)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||
}
|
||||
|
||||
func structPointer_Add(p structPointer, size field) structPointer {
|
||||
return structPointer(unsafe.Pointer(uintptr(p) + uintptr(size)))
|
||||
}
|
||||
|
||||
func structPointer_Len(p structPointer, f field) int {
|
||||
return len(*(*[]interface{})(unsafe.Pointer(structPointer_GetRefStructPointer(p, f))))
|
||||
}
|
||||
|
||||
// refWord32 is the address of a 32-bit value field.
|
||||
type refWord32 *uint32
|
||||
|
||||
func refWord32_IsNil(p refWord32) bool {
|
||||
return p == nil
|
||||
}
|
||||
|
||||
func refWord32_Set(p refWord32, o *Buffer, x uint32) {
|
||||
if len(o.uint32s) == 0 {
|
||||
o.uint32s = make([]uint32, uint32PoolSize)
|
||||
}
|
||||
o.uint32s[0] = x
|
||||
*p = o.uint32s[0]
|
||||
o.uint32s = o.uint32s[1:]
|
||||
}
|
||||
|
||||
func refWord32_Get(p refWord32) uint32 {
|
||||
return *p
|
||||
}
|
||||
|
||||
func structPointer_RefWord32(p structPointer, f field) refWord32 {
|
||||
return refWord32((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
|
||||
// refWord64 is like refWord32 but for 32-bit values.
|
||||
type refWord64 *uint64
|
||||
|
||||
func refWord64_Set(p refWord64, o *Buffer, x uint64) {
|
||||
if len(o.uint64s) == 0 {
|
||||
o.uint64s = make([]uint64, uint64PoolSize)
|
||||
}
|
||||
o.uint64s[0] = x
|
||||
*p = o.uint64s[0]
|
||||
o.uint64s = o.uint64s[1:]
|
||||
}
|
||||
|
||||
func refWord64_IsNil(p refWord64) bool {
|
||||
return p == nil
|
||||
}
|
||||
|
||||
func refWord64_Get(p refWord64) uint64 {
|
||||
return *p
|
||||
}
|
||||
|
||||
func structPointer_RefWord64(p structPointer, f field) refWord64 {
|
||||
return refWord64((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||
}
|
||||
683
Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go
generated
vendored
Normal file
683
Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties.go
generated
vendored
Normal file
@@ -0,0 +1,683 @@
|
||||
// Extensions for Protocol Buffers to create more go like structures.
|
||||
//
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
/*
|
||||
* Routines for encoding data into the wire format for protocol buffers.
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const debug bool = false
|
||||
|
||||
// Constants that identify the encoding of a value on the wire.
|
||||
const (
|
||||
WireVarint = 0
|
||||
WireFixed64 = 1
|
||||
WireBytes = 2
|
||||
WireStartGroup = 3
|
||||
WireEndGroup = 4
|
||||
WireFixed32 = 5
|
||||
)
|
||||
|
||||
const startSize = 10 // initial slice/string sizes
|
||||
|
||||
// Encoders are defined in encode.go
|
||||
// An encoder outputs the full representation of a field, including its
|
||||
// tag and encoder type.
|
||||
type encoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||
|
||||
// A valueEncoder encodes a single integer in a particular encoding.
|
||||
type valueEncoder func(o *Buffer, x uint64) error
|
||||
|
||||
// Sizers are defined in encode.go
|
||||
// A sizer returns the encoded size of a field, including its tag and encoder
|
||||
// type.
|
||||
type sizer func(prop *Properties, base structPointer) int
|
||||
|
||||
// A valueSizer returns the encoded size of a single integer in a particular
|
||||
// encoding.
|
||||
type valueSizer func(x uint64) int
|
||||
|
||||
// Decoders are defined in decode.go
|
||||
// A decoder creates a value from its wire representation.
|
||||
// Unrecognized subelements are saved in unrec.
|
||||
type decoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||
|
||||
// A valueDecoder decodes a single integer in a particular encoding.
|
||||
type valueDecoder func(o *Buffer) (x uint64, err error)
|
||||
|
||||
// tagMap is an optimization over map[int]int for typical protocol buffer
|
||||
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
||||
// numbers.
|
||||
type tagMap struct {
|
||||
fastTags []int
|
||||
slowTags map[int]int
|
||||
}
|
||||
|
||||
// tagMapFastLimit is the upper bound on the tag number that will be stored in
|
||||
// the tagMap slice rather than its map.
|
||||
const tagMapFastLimit = 1024
|
||||
|
||||
func (p *tagMap) get(t int) (int, bool) {
|
||||
if t > 0 && t < tagMapFastLimit {
|
||||
if t >= len(p.fastTags) {
|
||||
return 0, false
|
||||
}
|
||||
fi := p.fastTags[t]
|
||||
return fi, fi >= 0
|
||||
}
|
||||
fi, ok := p.slowTags[t]
|
||||
return fi, ok
|
||||
}
|
||||
|
||||
func (p *tagMap) put(t int, fi int) {
|
||||
if t > 0 && t < tagMapFastLimit {
|
||||
for len(p.fastTags) < t+1 {
|
||||
p.fastTags = append(p.fastTags, -1)
|
||||
}
|
||||
p.fastTags[t] = fi
|
||||
return
|
||||
}
|
||||
if p.slowTags == nil {
|
||||
p.slowTags = make(map[int]int)
|
||||
}
|
||||
p.slowTags[t] = fi
|
||||
}
|
||||
|
||||
// StructProperties represents properties for all the fields of a struct.
|
||||
// decoderTags and decoderOrigNames should only be used by the decoder.
|
||||
type StructProperties struct {
|
||||
Prop []*Properties // properties for each field
|
||||
reqCount int // required count
|
||||
decoderTags tagMap // map from proto tag to struct field number
|
||||
decoderOrigNames map[string]int // map from original name to struct field number
|
||||
order []int // list of struct field numbers in tag order
|
||||
unrecField field // field id of the XXX_unrecognized []byte field
|
||||
extendable bool // is this an extendable proto
|
||||
}
|
||||
|
||||
// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
|
||||
// See encode.go, (*Buffer).enc_struct.
|
||||
|
||||
func (sp *StructProperties) Len() int { return len(sp.order) }
|
||||
func (sp *StructProperties) Less(i, j int) bool {
|
||||
return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
|
||||
}
|
||||
func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
|
||||
|
||||
// Properties represents the protocol-specific behavior of a single struct field.
|
||||
type Properties struct {
|
||||
Name string // name of the field, for error messages
|
||||
OrigName string // original name before protocol compiler (always set)
|
||||
Wire string
|
||||
WireType int
|
||||
Tag int
|
||||
Required bool
|
||||
Optional bool
|
||||
Repeated bool
|
||||
Packed bool // relevant for repeated primitives only
|
||||
Enum string // set for enum types only
|
||||
|
||||
Default string // default value
|
||||
HasDefault bool // whether an explicit default was provided
|
||||
CustomType string
|
||||
def_uint64 uint64
|
||||
|
||||
enc encoder
|
||||
valEnc valueEncoder // set for bool and numeric types only
|
||||
field field
|
||||
tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
|
||||
tagbuf [8]byte
|
||||
stype reflect.Type // set for struct types only
|
||||
sstype reflect.Type // set for slices of structs types only
|
||||
ctype reflect.Type // set for custom types only
|
||||
sprop *StructProperties // set for struct types only
|
||||
isMarshaler bool
|
||||
isUnmarshaler bool
|
||||
|
||||
size sizer
|
||||
valSize valueSizer // set for bool and numeric types only
|
||||
|
||||
dec decoder
|
||||
valDec valueDecoder // set for bool and numeric types only
|
||||
|
||||
// If this is a packable field, this will be the decoder for the packed version of the field.
|
||||
packedDec decoder
|
||||
}
|
||||
|
||||
// String formats the properties in the protobuf struct field tag style.
|
||||
func (p *Properties) String() string {
|
||||
s := p.Wire
|
||||
s = ","
|
||||
s += strconv.Itoa(p.Tag)
|
||||
if p.Required {
|
||||
s += ",req"
|
||||
}
|
||||
if p.Optional {
|
||||
s += ",opt"
|
||||
}
|
||||
if p.Repeated {
|
||||
s += ",rep"
|
||||
}
|
||||
if p.Packed {
|
||||
s += ",packed"
|
||||
}
|
||||
if p.OrigName != p.Name {
|
||||
s += ",name=" + p.OrigName
|
||||
}
|
||||
if len(p.Enum) > 0 {
|
||||
s += ",enum=" + p.Enum
|
||||
}
|
||||
if p.HasDefault {
|
||||
s += ",def=" + p.Default
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Parse populates p by parsing a string in the protobuf struct field tag style.
|
||||
func (p *Properties) Parse(s string) {
|
||||
// "bytes,49,opt,name=foo,def=hello!"
|
||||
fields := strings.Split(s, ",") // breaks def=, but handled below.
|
||||
if len(fields) < 2 {
|
||||
fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
|
||||
return
|
||||
}
|
||||
|
||||
p.Wire = fields[0]
|
||||
switch p.Wire {
|
||||
case "varint":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeVarint
|
||||
p.valDec = (*Buffer).DecodeVarint
|
||||
p.valSize = sizeVarint
|
||||
case "fixed32":
|
||||
p.WireType = WireFixed32
|
||||
p.valEnc = (*Buffer).EncodeFixed32
|
||||
p.valDec = (*Buffer).DecodeFixed32
|
||||
p.valSize = sizeFixed32
|
||||
case "fixed64":
|
||||
p.WireType = WireFixed64
|
||||
p.valEnc = (*Buffer).EncodeFixed64
|
||||
p.valDec = (*Buffer).DecodeFixed64
|
||||
p.valSize = sizeFixed64
|
||||
case "zigzag32":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeZigzag32
|
||||
p.valDec = (*Buffer).DecodeZigzag32
|
||||
p.valSize = sizeZigzag32
|
||||
case "zigzag64":
|
||||
p.WireType = WireVarint
|
||||
p.valEnc = (*Buffer).EncodeZigzag64
|
||||
p.valDec = (*Buffer).DecodeZigzag64
|
||||
p.valSize = sizeZigzag64
|
||||
case "bytes", "group":
|
||||
p.WireType = WireBytes
|
||||
// no numeric converter for non-numeric types
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
p.Tag, err = strconv.Atoi(fields[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 2; i < len(fields); i++ {
|
||||
f := fields[i]
|
||||
switch {
|
||||
case f == "req":
|
||||
p.Required = true
|
||||
case f == "opt":
|
||||
p.Optional = true
|
||||
case f == "rep":
|
||||
p.Repeated = true
|
||||
case f == "packed":
|
||||
p.Packed = true
|
||||
case strings.HasPrefix(f, "name="):
|
||||
p.OrigName = f[5:]
|
||||
case strings.HasPrefix(f, "enum="):
|
||||
p.Enum = f[5:]
|
||||
case strings.HasPrefix(f, "def="):
|
||||
p.HasDefault = true
|
||||
p.Default = f[4:] // rest of string
|
||||
if i+1 < len(fields) {
|
||||
// Commas aren't escaped, and def is always last.
|
||||
p.Default += "," + strings.Join(fields[i+1:], ",")
|
||||
break
|
||||
}
|
||||
case strings.HasPrefix(f, "embedded="):
|
||||
p.OrigName = strings.Split(f, "=")[1]
|
||||
case strings.HasPrefix(f, "customtype="):
|
||||
p.CustomType = strings.Split(f, "=")[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func logNoSliceEnc(t1, t2 reflect.Type) {
|
||||
fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
|
||||
}
|
||||
|
||||
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
|
||||
|
||||
// Initialize the fields for encoding and decoding.
|
||||
func (p *Properties) setEncAndDec(typ reflect.Type, lockGetProp bool) {
|
||||
p.enc = nil
|
||||
p.dec = nil
|
||||
p.size = nil
|
||||
if len(p.CustomType) > 0 {
|
||||
p.setCustomEncAndDec(typ)
|
||||
p.setTag(lockGetProp)
|
||||
return
|
||||
}
|
||||
switch t1 := typ; t1.Kind() {
|
||||
default:
|
||||
if !p.setNonNullableEncAndDec(t1) {
|
||||
fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
|
||||
}
|
||||
case reflect.Ptr:
|
||||
switch t2 := t1.Elem(); t2.Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
|
||||
break
|
||||
case reflect.Bool:
|
||||
p.enc = (*Buffer).enc_bool
|
||||
p.dec = (*Buffer).dec_bool
|
||||
p.size = size_bool
|
||||
case reflect.Int32:
|
||||
p.enc = (*Buffer).enc_int32
|
||||
p.dec = (*Buffer).dec_int32
|
||||
p.size = size_int32
|
||||
case reflect.Uint32:
|
||||
p.enc = (*Buffer).enc_uint32
|
||||
p.dec = (*Buffer).dec_int32 // can reuse
|
||||
p.size = size_uint32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
p.enc = (*Buffer).enc_int64
|
||||
p.dec = (*Buffer).dec_int64
|
||||
p.size = size_int64
|
||||
case reflect.Float32:
|
||||
p.enc = (*Buffer).enc_uint32 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_int32
|
||||
p.size = size_uint32
|
||||
case reflect.Float64:
|
||||
p.enc = (*Buffer).enc_int64 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_int64
|
||||
p.size = size_int64
|
||||
case reflect.String:
|
||||
p.enc = (*Buffer).enc_string
|
||||
p.dec = (*Buffer).dec_string
|
||||
p.size = size_string
|
||||
case reflect.Struct:
|
||||
p.stype = t1.Elem()
|
||||
p.isMarshaler = isMarshaler(t1)
|
||||
p.isUnmarshaler = isUnmarshaler(t1)
|
||||
if p.Wire == "bytes" {
|
||||
p.enc = (*Buffer).enc_struct_message
|
||||
p.dec = (*Buffer).dec_struct_message
|
||||
p.size = size_struct_message
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_struct_group
|
||||
p.dec = (*Buffer).dec_struct_group
|
||||
p.size = size_struct_group
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
switch t2 := t1.Elem(); t2.Kind() {
|
||||
default:
|
||||
logNoSliceEnc(t1, t2)
|
||||
break
|
||||
case reflect.Bool:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_bool
|
||||
p.size = size_slice_packed_bool
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_bool
|
||||
p.size = size_slice_bool
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_bool
|
||||
p.packedDec = (*Buffer).dec_slice_packed_bool
|
||||
case reflect.Int32:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int32
|
||||
p.size = size_slice_packed_int32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int32
|
||||
p.size = size_slice_int32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case reflect.Uint32:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||
p.size = size_slice_packed_uint32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_uint32
|
||||
p.size = size_slice_uint32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int64
|
||||
p.size = size_slice_packed_int64
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int64
|
||||
p.size = size_slice_int64
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int64
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||
case reflect.Uint8:
|
||||
p.enc = (*Buffer).enc_slice_byte
|
||||
p.dec = (*Buffer).dec_slice_byte
|
||||
p.size = size_slice_byte
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch t2.Bits() {
|
||||
case 32:
|
||||
// can just treat them as bits
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||
p.size = size_slice_packed_uint32
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_uint32
|
||||
p.size = size_slice_uint32
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int32
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||
case 64:
|
||||
// can just treat them as bits
|
||||
if p.Packed {
|
||||
p.enc = (*Buffer).enc_slice_packed_int64
|
||||
p.size = size_slice_packed_int64
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_int64
|
||||
p.size = size_slice_int64
|
||||
}
|
||||
p.dec = (*Buffer).dec_slice_int64
|
||||
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||
default:
|
||||
logNoSliceEnc(t1, t2)
|
||||
break
|
||||
}
|
||||
case reflect.String:
|
||||
p.enc = (*Buffer).enc_slice_string
|
||||
p.dec = (*Buffer).dec_slice_string
|
||||
p.size = size_slice_string
|
||||
case reflect.Ptr:
|
||||
switch t3 := t2.Elem(); t3.Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
|
||||
break
|
||||
case reflect.Struct:
|
||||
p.stype = t2.Elem()
|
||||
p.isMarshaler = isMarshaler(t2)
|
||||
p.isUnmarshaler = isUnmarshaler(t2)
|
||||
if p.Wire == "bytes" {
|
||||
p.enc = (*Buffer).enc_slice_struct_message
|
||||
p.dec = (*Buffer).dec_slice_struct_message
|
||||
p.size = size_slice_struct_message
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_slice_struct_group
|
||||
p.dec = (*Buffer).dec_slice_struct_group
|
||||
p.size = size_slice_struct_group
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
switch t2.Elem().Kind() {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
|
||||
break
|
||||
case reflect.Uint8:
|
||||
p.enc = (*Buffer).enc_slice_slice_byte
|
||||
p.dec = (*Buffer).dec_slice_slice_byte
|
||||
p.size = size_slice_slice_byte
|
||||
}
|
||||
case reflect.Struct:
|
||||
p.setSliceOfNonPointerStructs(t1)
|
||||
}
|
||||
}
|
||||
p.setTag(lockGetProp)
|
||||
}
|
||||
|
||||
func (p *Properties) setTag(lockGetProp bool) {
|
||||
// precalculate tag code
|
||||
wire := p.WireType
|
||||
if p.Packed {
|
||||
wire = WireBytes
|
||||
}
|
||||
x := uint32(p.Tag)<<3 | uint32(wire)
|
||||
i := 0
|
||||
for i = 0; x > 127; i++ {
|
||||
p.tagbuf[i] = 0x80 | uint8(x&0x7F)
|
||||
x >>= 7
|
||||
}
|
||||
p.tagbuf[i] = uint8(x)
|
||||
p.tagcode = p.tagbuf[0 : i+1]
|
||||
|
||||
if p.stype != nil {
|
||||
if lockGetProp {
|
||||
p.sprop = GetProperties(p.stype)
|
||||
} else {
|
||||
p.sprop = getPropertiesLocked(p.stype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
// isMarshaler reports whether type t implements Marshaler.
|
||||
func isMarshaler(t reflect.Type) bool {
|
||||
return t.Implements(marshalerType)
|
||||
}
|
||||
|
||||
// isUnmarshaler reports whether type t implements Unmarshaler.
|
||||
func isUnmarshaler(t reflect.Type) bool {
|
||||
return t.Implements(unmarshalerType)
|
||||
}
|
||||
|
||||
// Init populates the properties from a protocol buffer struct tag.
|
||||
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
|
||||
p.init(typ, name, tag, f, true)
|
||||
}
|
||||
|
||||
func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
|
||||
// "bytes,49,opt,def=hello!"
|
||||
p.Name = name
|
||||
p.OrigName = name
|
||||
if f != nil {
|
||||
p.field = toField(f)
|
||||
}
|
||||
if tag == "" {
|
||||
return
|
||||
}
|
||||
p.Parse(tag)
|
||||
p.setEncAndDec(typ, lockGetProp)
|
||||
}
|
||||
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
propertiesMap = make(map[reflect.Type]*StructProperties)
|
||||
)
|
||||
|
||||
// GetProperties returns the list of properties for the type represented by t.
|
||||
// t must represent a generated struct type of a protocol message.
|
||||
func GetProperties(t reflect.Type) *StructProperties {
|
||||
if t.Kind() != reflect.Struct {
|
||||
panic("proto: type must have kind struct")
|
||||
}
|
||||
mutex.Lock()
|
||||
sprop := getPropertiesLocked(t)
|
||||
mutex.Unlock()
|
||||
return sprop
|
||||
}
|
||||
|
||||
// getPropertiesLocked requires that mutex is held.
|
||||
func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||
if prop, ok := propertiesMap[t]; ok {
|
||||
if collectStats {
|
||||
stats.Chit++
|
||||
}
|
||||
return prop
|
||||
}
|
||||
if collectStats {
|
||||
stats.Cmiss++
|
||||
}
|
||||
|
||||
prop := new(StructProperties)
|
||||
// in case of recursive protos, fill this in now.
|
||||
propertiesMap[t] = prop
|
||||
|
||||
// build properties
|
||||
prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType)
|
||||
prop.unrecField = invalidField
|
||||
prop.Prop = make([]*Properties, t.NumField())
|
||||
prop.order = make([]int, t.NumField())
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
p := new(Properties)
|
||||
name := f.Name
|
||||
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
|
||||
|
||||
if f.Name == "XXX_extensions" { // special case
|
||||
if len(f.Tag.Get("protobuf")) > 0 {
|
||||
p.enc = (*Buffer).enc_ext_slice_byte
|
||||
p.dec = nil // not needed
|
||||
p.size = size_ext_slice_byte
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_map
|
||||
p.dec = nil // not needed
|
||||
p.size = size_map
|
||||
}
|
||||
}
|
||||
if f.Name == "XXX_unrecognized" { // special case
|
||||
prop.unrecField = toField(&f)
|
||||
}
|
||||
prop.Prop[i] = p
|
||||
prop.order[i] = i
|
||||
if debug {
|
||||
print(i, " ", f.Name, " ", t.String(), " ")
|
||||
if p.Tag > 0 {
|
||||
print(p.String())
|
||||
}
|
||||
print("\n")
|
||||
}
|
||||
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
|
||||
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
||||
}
|
||||
}
|
||||
|
||||
// Re-order prop.order.
|
||||
sort.Sort(prop)
|
||||
|
||||
// build required counts
|
||||
// build tags
|
||||
reqCount := 0
|
||||
prop.decoderOrigNames = make(map[string]int)
|
||||
for i, p := range prop.Prop {
|
||||
if strings.HasPrefix(p.Name, "XXX_") {
|
||||
// Internal fields should not appear in tags/origNames maps.
|
||||
// They are handled specially when encoding and decoding.
|
||||
continue
|
||||
}
|
||||
if p.Required {
|
||||
reqCount++
|
||||
}
|
||||
prop.decoderTags.put(p.Tag, i)
|
||||
prop.decoderOrigNames[p.OrigName] = i
|
||||
}
|
||||
prop.reqCount = reqCount
|
||||
|
||||
return prop
|
||||
}
|
||||
|
||||
// Return the Properties object for the x[0]'th field of the structure.
|
||||
func propByIndex(t reflect.Type, x []int) *Properties {
|
||||
if len(x) != 1 {
|
||||
fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
|
||||
return nil
|
||||
}
|
||||
prop := GetProperties(t)
|
||||
return prop.Prop[x[0]]
|
||||
}
|
||||
|
||||
// Get the address and type of a pointer to a struct from an interface.
|
||||
func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
|
||||
if pb == nil {
|
||||
err = ErrNil
|
||||
return
|
||||
}
|
||||
// get the reflect type of the pointer to the struct.
|
||||
t = reflect.TypeOf(pb)
|
||||
// get the address of the struct.
|
||||
value := reflect.ValueOf(pb)
|
||||
b = toStructPointer(value)
|
||||
return
|
||||
}
|
||||
|
||||
// A global registry of enum types.
|
||||
// The generated code will register the generated maps by calling RegisterEnum.
|
||||
|
||||
var enumValueMaps = make(map[string]map[string]int32)
|
||||
var enumStringMaps = make(map[string]map[int32]string)
|
||||
|
||||
// RegisterEnum is called from the generated code to install the enum descriptor
|
||||
// maps into the global table to aid parsing text format protocol buffers.
|
||||
func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
|
||||
if _, ok := enumValueMaps[typeName]; ok {
|
||||
panic("proto: duplicate enum registered: " + typeName)
|
||||
}
|
||||
enumValueMaps[typeName] = valueMap
|
||||
if _, ok := enumStringMaps[typeName]; ok {
|
||||
panic("proto: duplicate enum registered: " + typeName)
|
||||
}
|
||||
enumStringMaps[typeName] = unusedNameMap
|
||||
}
|
||||
111
Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go
generated
vendored
Normal file
111
Godeps/_workspace/src/github.com/gogo/protobuf/proto/properties_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func (p *Properties) setCustomEncAndDec(typ reflect.Type) {
|
||||
p.ctype = typ
|
||||
if p.Repeated {
|
||||
p.enc = (*Buffer).enc_custom_slice_bytes
|
||||
p.dec = (*Buffer).dec_custom_slice_bytes
|
||||
p.size = size_custom_slice_bytes
|
||||
} else if typ.Kind() == reflect.Ptr {
|
||||
p.enc = (*Buffer).enc_custom_bytes
|
||||
p.dec = (*Buffer).dec_custom_bytes
|
||||
p.size = size_custom_bytes
|
||||
} else {
|
||||
p.enc = (*Buffer).enc_custom_ref_bytes
|
||||
p.dec = (*Buffer).dec_custom_ref_bytes
|
||||
p.size = size_custom_ref_bytes
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Properties) setNonNullableEncAndDec(typ reflect.Type) bool {
|
||||
switch typ.Kind() {
|
||||
case reflect.Bool:
|
||||
p.enc = (*Buffer).enc_ref_bool
|
||||
p.dec = (*Buffer).dec_ref_bool
|
||||
p.size = size_ref_bool
|
||||
case reflect.Int32:
|
||||
p.enc = (*Buffer).enc_ref_int32
|
||||
p.dec = (*Buffer).dec_ref_int32
|
||||
p.size = size_ref_int32
|
||||
case reflect.Uint32:
|
||||
p.enc = (*Buffer).enc_ref_uint32
|
||||
p.dec = (*Buffer).dec_ref_int32
|
||||
p.size = size_ref_uint32
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
p.enc = (*Buffer).enc_ref_int64
|
||||
p.dec = (*Buffer).dec_ref_int64
|
||||
p.size = size_ref_int64
|
||||
case reflect.Float32:
|
||||
p.enc = (*Buffer).enc_ref_uint32 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_ref_int32
|
||||
p.size = size_ref_uint32
|
||||
case reflect.Float64:
|
||||
p.enc = (*Buffer).enc_ref_int64 // can just treat them as bits
|
||||
p.dec = (*Buffer).dec_ref_int64
|
||||
p.size = size_ref_int64
|
||||
case reflect.String:
|
||||
p.dec = (*Buffer).dec_ref_string
|
||||
p.enc = (*Buffer).enc_ref_string
|
||||
p.size = size_ref_string
|
||||
case reflect.Struct:
|
||||
p.stype = typ
|
||||
p.isMarshaler = isMarshaler(typ)
|
||||
p.isUnmarshaler = isUnmarshaler(typ)
|
||||
if p.Wire == "bytes" {
|
||||
p.enc = (*Buffer).enc_ref_struct_message
|
||||
p.dec = (*Buffer).dec_ref_struct_message
|
||||
p.size = size_ref_struct_message
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "proto: no coders for struct %T\n", typ)
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *Properties) setSliceOfNonPointerStructs(typ reflect.Type) {
|
||||
t2 := typ.Elem()
|
||||
p.sstype = typ
|
||||
p.stype = t2
|
||||
p.isMarshaler = isMarshaler(t2)
|
||||
p.isUnmarshaler = isUnmarshaler(t2)
|
||||
p.enc = (*Buffer).enc_slice_ref_struct_message
|
||||
p.dec = (*Buffer).dec_slice_ref_struct_message
|
||||
p.size = size_slice_ref_struct_message
|
||||
if p.Wire != "bytes" {
|
||||
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T \n", typ, t2)
|
||||
}
|
||||
}
|
||||
63
Godeps/_workspace/src/github.com/gogo/protobuf/proto/size2_test.go
generated
vendored
Normal file
63
Godeps/_workspace/src/github.com/gogo/protobuf/proto/size2_test.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// This is a separate file and package from size_test.go because that one uses
|
||||
// generated messages and thus may not be in package proto without having a circular
|
||||
// dependency, whereas this file tests unexported details of size.go.
|
||||
|
||||
func TestVarintSize(t *testing.T) {
|
||||
// Check the edge cases carefully.
|
||||
testCases := []struct {
|
||||
n uint64
|
||||
size int
|
||||
}{
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{127, 1},
|
||||
{128, 2},
|
||||
{16383, 2},
|
||||
{16384, 3},
|
||||
{1<<63 - 1, 9},
|
||||
{1 << 63, 10},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
size := sizeVarint(tc.n)
|
||||
if size != tc.size {
|
||||
t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Godeps/_workspace/src/github.com/gogo/protobuf/proto/size_test.go
generated
vendored
Normal file
120
Godeps/_workspace/src/github.com/gogo/protobuf/proto/size_test.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
pb "./testdata"
|
||||
. "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)}
|
||||
|
||||
// messageWithExtension2 is in equal_test.go.
|
||||
var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)}
|
||||
|
||||
func init() {
|
||||
if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil {
|
||||
log.Panicf("SetExtension: %v", err)
|
||||
}
|
||||
if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil {
|
||||
log.Panicf("SetExtension: %v", err)
|
||||
}
|
||||
|
||||
// Force messageWithExtension3 to have the extension encoded.
|
||||
Marshal(messageWithExtension3)
|
||||
|
||||
}
|
||||
|
||||
var SizeTests = []struct {
|
||||
desc string
|
||||
pb Message
|
||||
}{
|
||||
{"empty", &pb.OtherMessage{}},
|
||||
// Basic types.
|
||||
{"bool", &pb.Defaults{F_Bool: Bool(true)}},
|
||||
{"int32", &pb.Defaults{F_Int32: Int32(12)}},
|
||||
{"negative int32", &pb.Defaults{F_Int32: Int32(-1)}},
|
||||
{"small int64", &pb.Defaults{F_Int64: Int64(1)}},
|
||||
{"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}},
|
||||
{"negative int64", &pb.Defaults{F_Int64: Int64(-1)}},
|
||||
{"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}},
|
||||
{"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}},
|
||||
{"uint32", &pb.Defaults{F_Uint32: Uint32(123)}},
|
||||
{"uint64", &pb.Defaults{F_Uint64: Uint64(124)}},
|
||||
{"float", &pb.Defaults{F_Float: Float32(12.6)}},
|
||||
{"double", &pb.Defaults{F_Double: Float64(13.9)}},
|
||||
{"string", &pb.Defaults{F_String: String("niles")}},
|
||||
{"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}},
|
||||
{"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}},
|
||||
{"sint32", &pb.Defaults{F_Sint32: Int32(65)}},
|
||||
{"sint64", &pb.Defaults{F_Sint64: Int64(67)}},
|
||||
{"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}},
|
||||
// Repeated.
|
||||
{"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}},
|
||||
{"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}},
|
||||
{"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}},
|
||||
{"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}},
|
||||
{"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}},
|
||||
{"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{
|
||||
// Need enough large numbers to verify that the header is counting the number of bytes
|
||||
// for the field, not the number of elements.
|
||||
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
|
||||
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
|
||||
}}},
|
||||
{"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}},
|
||||
{"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}},
|
||||
// Nested.
|
||||
{"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}},
|
||||
{"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}},
|
||||
// Other things.
|
||||
{"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}},
|
||||
{"extension (unencoded)", messageWithExtension1},
|
||||
{"extension (encoded)", messageWithExtension3},
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
for _, tc := range SizeTests {
|
||||
size := Size(tc.pb)
|
||||
b, err := Marshal(tc.pb)
|
||||
if err != nil {
|
||||
t.Errorf("%v: Marshal failed: %v", tc.desc, err)
|
||||
continue
|
||||
}
|
||||
if size != len(b) {
|
||||
t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b))
|
||||
t.Logf("%v: bytes: %#v", tc.desc, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go
generated
vendored
Normal file
117
Godeps/_workspace/src/github.com/gogo/protobuf/proto/skip_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func Skip(data []byte) (n int, err error) {
|
||||
l := len(data)
|
||||
index := 0
|
||||
for index < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if index >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[index]
|
||||
index++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for {
|
||||
if index >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
index++
|
||||
if data[index-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return index, nil
|
||||
case 1:
|
||||
index += 8
|
||||
return index, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if index >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[index]
|
||||
index++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
index += length
|
||||
return index, nil
|
||||
case 3:
|
||||
for {
|
||||
var wire uint64
|
||||
var start int = index
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if index >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[index]
|
||||
index++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := Skip(data[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
index = start + next
|
||||
}
|
||||
return index, nil
|
||||
case 4:
|
||||
return index, nil
|
||||
case 5:
|
||||
index += 4
|
||||
return index, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
47
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/Makefile
generated
vendored
Normal file
47
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/Makefile
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Go support for Protocol Buffers - Google's data interchange format
|
||||
#
|
||||
# Copyright 2010 The Go Authors. All rights reserved.
|
||||
# https://github.com/golang/protobuf
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
all: regenerate
|
||||
|
||||
regenerate:
|
||||
rm -f test.pb.go
|
||||
protoc --gogo_out=. test.proto
|
||||
|
||||
# The following rules are just aids to development. Not needed for typical testing.
|
||||
|
||||
diff: regenerate
|
||||
hg diff test.pb.go
|
||||
|
||||
restore:
|
||||
cp test.pb.go.golden test.pb.go
|
||||
|
||||
preserve:
|
||||
cp test.pb.go test.pb.go.golden
|
||||
86
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/golden_test.go
generated
vendored
Normal file
86
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/golden_test.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Verify that the compiler output for test.proto is unchanged.
|
||||
|
||||
package testdata
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// sum returns in string form (for easy comparison) the SHA-1 hash of the named file.
|
||||
func sum(t *testing.T, name string) string {
|
||||
data, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("sum(%q): length is %d", name, len(data))
|
||||
hash := sha1.New()
|
||||
_, err = hash.Write(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return fmt.Sprintf("% x", hash.Sum(nil))
|
||||
}
|
||||
|
||||
func run(t *testing.T, name string, args ...string) {
|
||||
cmd := exec.Command(name, args...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGolden(t *testing.T) {
|
||||
// Compute the original checksum.
|
||||
goldenSum := sum(t, "test.pb.go")
|
||||
// Run the proto compiler.
|
||||
run(t, "protoc", "--gogo_out="+os.TempDir(), "test.proto")
|
||||
newFile := filepath.Join(os.TempDir(), "test.pb.go")
|
||||
defer os.Remove(newFile)
|
||||
// Compute the new checksum.
|
||||
newSum := sum(t, newFile)
|
||||
// Verify
|
||||
if newSum != goldenSum {
|
||||
run(t, "diff", "-u", "test.pb.go", newFile)
|
||||
t.Fatal("Code generated by protoc-gen-go has changed; update test.pb.go")
|
||||
}
|
||||
}
|
||||
2356
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.pb.go
generated
vendored
Normal file
2356
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1737
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.pb.go.golden
generated
vendored
Normal file
1737
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.pb.go.golden
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
428
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.proto
generated
vendored
Normal file
428
Godeps/_workspace/src/github.com/gogo/protobuf/proto/testdata/test.proto
generated
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// A feature-rich test file for the protocol compiler and libraries.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package testdata;
|
||||
|
||||
enum FOO { FOO1 = 1; };
|
||||
|
||||
message GoEnum {
|
||||
required FOO foo = 1;
|
||||
}
|
||||
|
||||
message GoTestField {
|
||||
required string Label = 1;
|
||||
required string Type = 2;
|
||||
}
|
||||
|
||||
message GoTest {
|
||||
// An enum, for completeness.
|
||||
enum KIND {
|
||||
VOID = 0;
|
||||
|
||||
// Basic types
|
||||
BOOL = 1;
|
||||
BYTES = 2;
|
||||
FINGERPRINT = 3;
|
||||
FLOAT = 4;
|
||||
INT = 5;
|
||||
STRING = 6;
|
||||
TIME = 7;
|
||||
|
||||
// Groupings
|
||||
TUPLE = 8;
|
||||
ARRAY = 9;
|
||||
MAP = 10;
|
||||
|
||||
// Table types
|
||||
TABLE = 11;
|
||||
|
||||
// Functions
|
||||
FUNCTION = 12; // last tag
|
||||
};
|
||||
|
||||
// Some typical parameters
|
||||
required KIND Kind = 1;
|
||||
optional string Table = 2;
|
||||
optional int32 Param = 3;
|
||||
|
||||
// Required, repeated and optional foreign fields.
|
||||
required GoTestField RequiredField = 4;
|
||||
repeated GoTestField RepeatedField = 5;
|
||||
optional GoTestField OptionalField = 6;
|
||||
|
||||
// Required fields of all basic types
|
||||
required bool F_Bool_required = 10;
|
||||
required int32 F_Int32_required = 11;
|
||||
required int64 F_Int64_required = 12;
|
||||
required fixed32 F_Fixed32_required = 13;
|
||||
required fixed64 F_Fixed64_required = 14;
|
||||
required uint32 F_Uint32_required = 15;
|
||||
required uint64 F_Uint64_required = 16;
|
||||
required float F_Float_required = 17;
|
||||
required double F_Double_required = 18;
|
||||
required string F_String_required = 19;
|
||||
required bytes F_Bytes_required = 101;
|
||||
required sint32 F_Sint32_required = 102;
|
||||
required sint64 F_Sint64_required = 103;
|
||||
|
||||
// Repeated fields of all basic types
|
||||
repeated bool F_Bool_repeated = 20;
|
||||
repeated int32 F_Int32_repeated = 21;
|
||||
repeated int64 F_Int64_repeated = 22;
|
||||
repeated fixed32 F_Fixed32_repeated = 23;
|
||||
repeated fixed64 F_Fixed64_repeated = 24;
|
||||
repeated uint32 F_Uint32_repeated = 25;
|
||||
repeated uint64 F_Uint64_repeated = 26;
|
||||
repeated float F_Float_repeated = 27;
|
||||
repeated double F_Double_repeated = 28;
|
||||
repeated string F_String_repeated = 29;
|
||||
repeated bytes F_Bytes_repeated = 201;
|
||||
repeated sint32 F_Sint32_repeated = 202;
|
||||
repeated sint64 F_Sint64_repeated = 203;
|
||||
|
||||
// Optional fields of all basic types
|
||||
optional bool F_Bool_optional = 30;
|
||||
optional int32 F_Int32_optional = 31;
|
||||
optional int64 F_Int64_optional = 32;
|
||||
optional fixed32 F_Fixed32_optional = 33;
|
||||
optional fixed64 F_Fixed64_optional = 34;
|
||||
optional uint32 F_Uint32_optional = 35;
|
||||
optional uint64 F_Uint64_optional = 36;
|
||||
optional float F_Float_optional = 37;
|
||||
optional double F_Double_optional = 38;
|
||||
optional string F_String_optional = 39;
|
||||
optional bytes F_Bytes_optional = 301;
|
||||
optional sint32 F_Sint32_optional = 302;
|
||||
optional sint64 F_Sint64_optional = 303;
|
||||
|
||||
// Default-valued fields of all basic types
|
||||
optional bool F_Bool_defaulted = 40 [default=true];
|
||||
optional int32 F_Int32_defaulted = 41 [default=32];
|
||||
optional int64 F_Int64_defaulted = 42 [default=64];
|
||||
optional fixed32 F_Fixed32_defaulted = 43 [default=320];
|
||||
optional fixed64 F_Fixed64_defaulted = 44 [default=640];
|
||||
optional uint32 F_Uint32_defaulted = 45 [default=3200];
|
||||
optional uint64 F_Uint64_defaulted = 46 [default=6400];
|
||||
optional float F_Float_defaulted = 47 [default=314159.];
|
||||
optional double F_Double_defaulted = 48 [default=271828.];
|
||||
optional string F_String_defaulted = 49 [default="hello, \"world!\"\n"];
|
||||
optional bytes F_Bytes_defaulted = 401 [default="Bignose"];
|
||||
optional sint32 F_Sint32_defaulted = 402 [default = -32];
|
||||
optional sint64 F_Sint64_defaulted = 403 [default = -64];
|
||||
|
||||
// Packed repeated fields (no string or bytes).
|
||||
repeated bool F_Bool_repeated_packed = 50 [packed=true];
|
||||
repeated int32 F_Int32_repeated_packed = 51 [packed=true];
|
||||
repeated int64 F_Int64_repeated_packed = 52 [packed=true];
|
||||
repeated fixed32 F_Fixed32_repeated_packed = 53 [packed=true];
|
||||
repeated fixed64 F_Fixed64_repeated_packed = 54 [packed=true];
|
||||
repeated uint32 F_Uint32_repeated_packed = 55 [packed=true];
|
||||
repeated uint64 F_Uint64_repeated_packed = 56 [packed=true];
|
||||
repeated float F_Float_repeated_packed = 57 [packed=true];
|
||||
repeated double F_Double_repeated_packed = 58 [packed=true];
|
||||
repeated sint32 F_Sint32_repeated_packed = 502 [packed=true];
|
||||
repeated sint64 F_Sint64_repeated_packed = 503 [packed=true];
|
||||
|
||||
// Required, repeated, and optional groups.
|
||||
required group RequiredGroup = 70 {
|
||||
required string RequiredField = 71;
|
||||
};
|
||||
|
||||
repeated group RepeatedGroup = 80 {
|
||||
required string RequiredField = 81;
|
||||
};
|
||||
|
||||
optional group OptionalGroup = 90 {
|
||||
required string RequiredField = 91;
|
||||
};
|
||||
}
|
||||
|
||||
// For testing skipping of unrecognized fields.
|
||||
// Numbers are all big, larger than tag numbers in GoTestField,
|
||||
// the message used in the corresponding test.
|
||||
message GoSkipTest {
|
||||
required int32 skip_int32 = 11;
|
||||
required fixed32 skip_fixed32 = 12;
|
||||
required fixed64 skip_fixed64 = 13;
|
||||
required string skip_string = 14;
|
||||
required group SkipGroup = 15 {
|
||||
required int32 group_int32 = 16;
|
||||
required string group_string = 17;
|
||||
}
|
||||
}
|
||||
|
||||
// For testing packed/non-packed decoder switching.
|
||||
// A serialized instance of one should be deserializable as the other.
|
||||
message NonPackedTest {
|
||||
repeated int32 a = 1;
|
||||
}
|
||||
|
||||
message PackedTest {
|
||||
repeated int32 b = 1 [packed=true];
|
||||
}
|
||||
|
||||
message MaxTag {
|
||||
// Maximum possible tag number.
|
||||
optional string last_field = 536870911;
|
||||
}
|
||||
|
||||
message OldMessage {
|
||||
message Nested {
|
||||
optional string name = 1;
|
||||
}
|
||||
optional Nested nested = 1;
|
||||
|
||||
optional int32 num = 2;
|
||||
}
|
||||
|
||||
// NewMessage is wire compatible with OldMessage;
|
||||
// imagine it as a future version.
|
||||
message NewMessage {
|
||||
message Nested {
|
||||
optional string name = 1;
|
||||
optional string food_group = 2;
|
||||
}
|
||||
optional Nested nested = 1;
|
||||
|
||||
// This is an int32 in OldMessage.
|
||||
optional int64 num = 2;
|
||||
}
|
||||
|
||||
// Smaller tests for ASCII formatting.
|
||||
|
||||
message InnerMessage {
|
||||
required string host = 1;
|
||||
optional int32 port = 2 [default=4000];
|
||||
optional bool connected = 3;
|
||||
}
|
||||
|
||||
message OtherMessage {
|
||||
optional int64 key = 1;
|
||||
optional bytes value = 2;
|
||||
optional float weight = 3;
|
||||
optional InnerMessage inner = 4;
|
||||
}
|
||||
|
||||
message MyMessage {
|
||||
required int32 count = 1;
|
||||
optional string name = 2;
|
||||
optional string quote = 3;
|
||||
repeated string pet = 4;
|
||||
optional InnerMessage inner = 5;
|
||||
repeated OtherMessage others = 6;
|
||||
repeated InnerMessage rep_inner = 12;
|
||||
|
||||
enum Color {
|
||||
RED = 0;
|
||||
GREEN = 1;
|
||||
BLUE = 2;
|
||||
};
|
||||
optional Color bikeshed = 7;
|
||||
|
||||
optional group SomeGroup = 8 {
|
||||
optional int32 group_field = 9;
|
||||
}
|
||||
|
||||
// This field becomes [][]byte in the generated code.
|
||||
repeated bytes rep_bytes = 10;
|
||||
|
||||
optional double bigfloat = 11;
|
||||
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
||||
message Ext {
|
||||
extend MyMessage {
|
||||
optional Ext more = 103;
|
||||
optional string text = 104;
|
||||
optional int32 number = 105;
|
||||
}
|
||||
|
||||
optional string data = 1;
|
||||
}
|
||||
|
||||
extend MyMessage {
|
||||
repeated string greeting = 106;
|
||||
}
|
||||
|
||||
message MyMessageSet {
|
||||
option message_set_wire_format = true;
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
||||
message Empty {
|
||||
}
|
||||
|
||||
extend MyMessageSet {
|
||||
optional Empty x201 = 201;
|
||||
optional Empty x202 = 202;
|
||||
optional Empty x203 = 203;
|
||||
optional Empty x204 = 204;
|
||||
optional Empty x205 = 205;
|
||||
optional Empty x206 = 206;
|
||||
optional Empty x207 = 207;
|
||||
optional Empty x208 = 208;
|
||||
optional Empty x209 = 209;
|
||||
optional Empty x210 = 210;
|
||||
optional Empty x211 = 211;
|
||||
optional Empty x212 = 212;
|
||||
optional Empty x213 = 213;
|
||||
optional Empty x214 = 214;
|
||||
optional Empty x215 = 215;
|
||||
optional Empty x216 = 216;
|
||||
optional Empty x217 = 217;
|
||||
optional Empty x218 = 218;
|
||||
optional Empty x219 = 219;
|
||||
optional Empty x220 = 220;
|
||||
optional Empty x221 = 221;
|
||||
optional Empty x222 = 222;
|
||||
optional Empty x223 = 223;
|
||||
optional Empty x224 = 224;
|
||||
optional Empty x225 = 225;
|
||||
optional Empty x226 = 226;
|
||||
optional Empty x227 = 227;
|
||||
optional Empty x228 = 228;
|
||||
optional Empty x229 = 229;
|
||||
optional Empty x230 = 230;
|
||||
optional Empty x231 = 231;
|
||||
optional Empty x232 = 232;
|
||||
optional Empty x233 = 233;
|
||||
optional Empty x234 = 234;
|
||||
optional Empty x235 = 235;
|
||||
optional Empty x236 = 236;
|
||||
optional Empty x237 = 237;
|
||||
optional Empty x238 = 238;
|
||||
optional Empty x239 = 239;
|
||||
optional Empty x240 = 240;
|
||||
optional Empty x241 = 241;
|
||||
optional Empty x242 = 242;
|
||||
optional Empty x243 = 243;
|
||||
optional Empty x244 = 244;
|
||||
optional Empty x245 = 245;
|
||||
optional Empty x246 = 246;
|
||||
optional Empty x247 = 247;
|
||||
optional Empty x248 = 248;
|
||||
optional Empty x249 = 249;
|
||||
optional Empty x250 = 250;
|
||||
}
|
||||
|
||||
message MessageList {
|
||||
repeated group Message = 1 {
|
||||
required string name = 2;
|
||||
required int32 count = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Strings {
|
||||
optional string string_field = 1;
|
||||
optional bytes bytes_field = 2;
|
||||
}
|
||||
|
||||
message Defaults {
|
||||
enum Color {
|
||||
RED = 0;
|
||||
GREEN = 1;
|
||||
BLUE = 2;
|
||||
}
|
||||
|
||||
// Default-valued fields of all basic types.
|
||||
// Same as GoTest, but copied here to make testing easier.
|
||||
optional bool F_Bool = 1 [default=true];
|
||||
optional int32 F_Int32 = 2 [default=32];
|
||||
optional int64 F_Int64 = 3 [default=64];
|
||||
optional fixed32 F_Fixed32 = 4 [default=320];
|
||||
optional fixed64 F_Fixed64 = 5 [default=640];
|
||||
optional uint32 F_Uint32 = 6 [default=3200];
|
||||
optional uint64 F_Uint64 = 7 [default=6400];
|
||||
optional float F_Float = 8 [default=314159.];
|
||||
optional double F_Double = 9 [default=271828.];
|
||||
optional string F_String = 10 [default="hello, \"world!\"\n"];
|
||||
optional bytes F_Bytes = 11 [default="Bignose"];
|
||||
optional sint32 F_Sint32 = 12 [default=-32];
|
||||
optional sint64 F_Sint64 = 13 [default=-64];
|
||||
optional Color F_Enum = 14 [default=GREEN];
|
||||
|
||||
// More fields with crazy defaults.
|
||||
optional float F_Pinf = 15 [default=inf];
|
||||
optional float F_Ninf = 16 [default=-inf];
|
||||
optional float F_Nan = 17 [default=nan];
|
||||
|
||||
// Sub-message.
|
||||
optional SubDefaults sub = 18;
|
||||
|
||||
// Redundant but explicit defaults.
|
||||
optional string str_zero = 19 [default=""];
|
||||
}
|
||||
|
||||
message SubDefaults {
|
||||
optional int64 n = 1 [default=7];
|
||||
}
|
||||
|
||||
message RepeatedEnum {
|
||||
enum Color {
|
||||
RED = 1;
|
||||
}
|
||||
repeated Color color = 1;
|
||||
}
|
||||
|
||||
message MoreRepeated {
|
||||
repeated bool bools = 1;
|
||||
repeated bool bools_packed = 2 [packed=true];
|
||||
repeated int32 ints = 3;
|
||||
repeated int32 ints_packed = 4 [packed=true];
|
||||
repeated int64 int64s_packed = 7 [packed=true];
|
||||
repeated string strings = 5;
|
||||
repeated fixed32 fixeds = 6;
|
||||
}
|
||||
|
||||
// GroupOld and GroupNew have the same wire format.
|
||||
// GroupNew has a new field inside a group.
|
||||
|
||||
message GroupOld {
|
||||
optional group G = 101 {
|
||||
optional int32 x = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GroupNew {
|
||||
optional group G = 101 {
|
||||
optional int32 x = 2;
|
||||
optional int32 y = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message FloatingPoint {
|
||||
required double f = 1;
|
||||
}
|
||||
730
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go
generated
vendored
Normal file
730
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text.go
generated
vendored
Normal file
@@ -0,0 +1,730 @@
|
||||
// Extensions for Protocol Buffers to create more go like structures.
|
||||
//
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
// Functions for writing the text protocol buffer format.
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
newline = []byte("\n")
|
||||
spaces = []byte(" ")
|
||||
gtNewline = []byte(">\n")
|
||||
endBraceNewline = []byte("}\n")
|
||||
backslashN = []byte{'\\', 'n'}
|
||||
backslashR = []byte{'\\', 'r'}
|
||||
backslashT = []byte{'\\', 't'}
|
||||
backslashDQ = []byte{'\\', '"'}
|
||||
backslashBS = []byte{'\\', '\\'}
|
||||
posInf = []byte("inf")
|
||||
negInf = []byte("-inf")
|
||||
nan = []byte("nan")
|
||||
)
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
WriteByte(byte) error
|
||||
}
|
||||
|
||||
// textWriter is an io.Writer that tracks its indentation level.
|
||||
type textWriter struct {
|
||||
ind int
|
||||
complete bool // if the current position is a complete line
|
||||
compact bool // whether to write out as a one-liner
|
||||
w writer
|
||||
}
|
||||
|
||||
func (w *textWriter) WriteString(s string) (n int, err error) {
|
||||
if !strings.Contains(s, "\n") {
|
||||
if !w.compact && w.complete {
|
||||
w.writeIndent()
|
||||
}
|
||||
w.complete = false
|
||||
return io.WriteString(w.w, s)
|
||||
}
|
||||
// WriteString is typically called without newlines, so this
|
||||
// codepath and its copy are rare. We copy to avoid
|
||||
// duplicating all of Write's logic here.
|
||||
return w.Write([]byte(s))
|
||||
}
|
||||
|
||||
func (w *textWriter) Write(p []byte) (n int, err error) {
|
||||
newlines := bytes.Count(p, newline)
|
||||
if newlines == 0 {
|
||||
if !w.compact && w.complete {
|
||||
w.writeIndent()
|
||||
}
|
||||
n, err = w.w.Write(p)
|
||||
w.complete = false
|
||||
return n, err
|
||||
}
|
||||
|
||||
frags := bytes.SplitN(p, newline, newlines+1)
|
||||
if w.compact {
|
||||
for i, frag := range frags {
|
||||
if i > 0 {
|
||||
if err := w.w.WriteByte(' '); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
nn, err := w.w.Write(frag)
|
||||
n += nn
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
for i, frag := range frags {
|
||||
if w.complete {
|
||||
w.writeIndent()
|
||||
}
|
||||
nn, err := w.w.Write(frag)
|
||||
n += nn
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if i+1 < len(frags) {
|
||||
if err := w.w.WriteByte('\n'); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
}
|
||||
w.complete = len(frags[len(frags)-1]) == 0
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w *textWriter) WriteByte(c byte) error {
|
||||
if w.compact && c == '\n' {
|
||||
c = ' '
|
||||
}
|
||||
if !w.compact && w.complete {
|
||||
w.writeIndent()
|
||||
}
|
||||
err := w.w.WriteByte(c)
|
||||
w.complete = c == '\n'
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *textWriter) indent() { w.ind++ }
|
||||
|
||||
func (w *textWriter) unindent() {
|
||||
if w.ind == 0 {
|
||||
log.Printf("proto: textWriter unindented too far")
|
||||
return
|
||||
}
|
||||
w.ind--
|
||||
}
|
||||
|
||||
func writeName(w *textWriter, props *Properties) error {
|
||||
if _, err := w.WriteString(props.OrigName); err != nil {
|
||||
return err
|
||||
}
|
||||
if props.Wire != "group" {
|
||||
return w.WriteByte(':')
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
|
||||
)
|
||||
|
||||
// raw is the interface satisfied by RawMessage.
|
||||
type raw interface {
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
if sv.Type() == messageSetType {
|
||||
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
|
||||
}
|
||||
|
||||
st := sv.Type()
|
||||
sprops := GetProperties(st)
|
||||
for i := 0; i < sv.NumField(); i++ {
|
||||
fv := sv.Field(i)
|
||||
props := sprops.Prop[i]
|
||||
name := st.Field(i).Name
|
||||
|
||||
if strings.HasPrefix(name, "XXX_") {
|
||||
// There are two XXX_ fields:
|
||||
// XXX_unrecognized []byte
|
||||
// XXX_extensions map[int32]proto.Extension
|
||||
// The first is handled here;
|
||||
// the second is handled at the bottom of this function.
|
||||
if name == "XXX_unrecognized" && !fv.IsNil() {
|
||||
if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||
// Field not filled in. This could be an optional field or
|
||||
// a required field that wasn't filled in. Either way, there
|
||||
// isn't anything we can show for it.
|
||||
continue
|
||||
}
|
||||
if fv.Kind() == reflect.Slice && fv.IsNil() {
|
||||
// Repeated field that is empty, or a bytes field that is unused.
|
||||
continue
|
||||
}
|
||||
|
||||
if props.Repeated && fv.Kind() == reflect.Slice {
|
||||
// Repeated field.
|
||||
for j := 0; j < fv.Len(); j++ {
|
||||
if err := writeName(w, props); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
v := fv.Index(j)
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
// A nil message in a repeated field is not valid,
|
||||
// but we can handle that more gracefully than panicking.
|
||||
if _, err := w.Write([]byte("<nil>\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(props.Enum) > 0 {
|
||||
if err := writeEnum(w, v, props); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := writeAny(w, v, props); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err := writeName(w, props); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if b, ok := fv.Interface().(raw); ok {
|
||||
if err := writeRaw(w, b.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(props.Enum) > 0 {
|
||||
if err := writeEnum(w, fv, props); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := writeAny(w, fv, props); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions (the XXX_extensions field).
|
||||
pv := sv.Addr()
|
||||
if pv.Type().Implements(extendableProtoType) {
|
||||
if err := writeExtensions(w, pv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeRaw writes an uninterpreted raw message.
|
||||
func writeRaw(w *textWriter, b []byte) error {
|
||||
if err := w.WriteByte('<'); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.indent()
|
||||
if err := writeUnknownStruct(w, b); err != nil {
|
||||
return err
|
||||
}
|
||||
w.unindent()
|
||||
if err := w.WriteByte('>'); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeAny writes an arbitrary field.
|
||||
func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
v = reflect.Indirect(v)
|
||||
|
||||
if props != nil && len(props.CustomType) > 0 {
|
||||
var custom Marshaler = v.Interface().(Marshaler)
|
||||
data, err := custom.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeString(w, string(data)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Floats have special cases.
|
||||
if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
|
||||
x := v.Float()
|
||||
var b []byte
|
||||
switch {
|
||||
case math.IsInf(x, 1):
|
||||
b = posInf
|
||||
case math.IsInf(x, -1):
|
||||
b = negInf
|
||||
case math.IsNaN(x):
|
||||
b = nan
|
||||
}
|
||||
if b != nil {
|
||||
_, err := w.Write(b)
|
||||
return err
|
||||
}
|
||||
// Other values are handled below.
|
||||
}
|
||||
|
||||
// We don't attempt to serialise every possible value type; only those
|
||||
// that can occur in protocol buffers.
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
// Should only be a []byte; repeated fields are handled in writeStruct.
|
||||
if err := writeString(w, string(v.Interface().([]byte))); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.String:
|
||||
if err := writeString(w, v.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Struct:
|
||||
// Required/optional group/message.
|
||||
var bra, ket byte = '<', '>'
|
||||
if props != nil && props.Wire == "group" {
|
||||
bra, ket = '{', '}'
|
||||
}
|
||||
if err := w.WriteByte(bra); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.indent()
|
||||
if tm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||
text, err := tm.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = w.Write(text); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := writeStruct(w, v); err != nil {
|
||||
return err
|
||||
}
|
||||
w.unindent()
|
||||
if err := w.WriteByte(ket); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
_, err := fmt.Fprint(w, v.Interface())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// equivalent to C's isprint.
|
||||
func isprint(c byte) bool {
|
||||
return c >= 0x20 && c < 0x7f
|
||||
}
|
||||
|
||||
// writeString writes a string in the protocol buffer text format.
|
||||
// It is similar to strconv.Quote except we don't use Go escape sequences,
|
||||
// we treat the string as a byte sequence, and we use octal escapes.
|
||||
// These differences are to maintain interoperability with the other
|
||||
// languages' implementations of the text format.
|
||||
func writeString(w *textWriter, s string) error {
|
||||
// use WriteByte here to get any needed indent
|
||||
if err := w.WriteByte('"'); err != nil {
|
||||
return err
|
||||
}
|
||||
// Loop over the bytes, not the runes.
|
||||
for i := 0; i < len(s); i++ {
|
||||
var err error
|
||||
// Divergence from C++: we don't escape apostrophes.
|
||||
// There's no need to escape them, and the C++ parser
|
||||
// copes with a naked apostrophe.
|
||||
switch c := s[i]; c {
|
||||
case '\n':
|
||||
_, err = w.w.Write(backslashN)
|
||||
case '\r':
|
||||
_, err = w.w.Write(backslashR)
|
||||
case '\t':
|
||||
_, err = w.w.Write(backslashT)
|
||||
case '"':
|
||||
_, err = w.w.Write(backslashDQ)
|
||||
case '\\':
|
||||
_, err = w.w.Write(backslashBS)
|
||||
default:
|
||||
if isprint(c) {
|
||||
err = w.w.WriteByte(c)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(w.w, "\\%03o", c)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return w.WriteByte('"')
|
||||
}
|
||||
|
||||
func writeMessageSet(w *textWriter, ms *MessageSet) error {
|
||||
for _, item := range ms.Item {
|
||||
id := *item.TypeId
|
||||
if msd, ok := messageSetMap[id]; ok {
|
||||
// Known message set type.
|
||||
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
|
||||
return err
|
||||
}
|
||||
w.indent()
|
||||
|
||||
pb := reflect.New(msd.t.Elem())
|
||||
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
|
||||
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := writeStruct(w, pb.Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Unknown type.
|
||||
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
|
||||
return err
|
||||
}
|
||||
w.indent()
|
||||
if err := writeUnknownStruct(w, item.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.unindent()
|
||||
if _, err := w.Write(gtNewline); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
||||
if !w.compact {
|
||||
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
b := NewBuffer(data)
|
||||
for b.index < len(b.buf) {
|
||||
x, err := b.DecodeVarint()
|
||||
if err != nil {
|
||||
_, err := fmt.Fprintf(w, "/* %v */\n", err)
|
||||
return err
|
||||
}
|
||||
wire, tag := x&7, x>>3
|
||||
if wire == WireEndGroup {
|
||||
w.unindent()
|
||||
if _, err := w.Write(endBraceNewline); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err := fmt.Fprint(w, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
if wire != WireStartGroup {
|
||||
if err := w.WriteByte(':'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !w.compact || wire == WireStartGroup {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
switch wire {
|
||||
case WireBytes:
|
||||
buf, e := b.DecodeRawBytes(false)
|
||||
if e == nil {
|
||||
_, err = fmt.Fprintf(w, "%q", buf)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(w, "/* %v */", e)
|
||||
}
|
||||
case WireFixed32:
|
||||
x, err = b.DecodeFixed32()
|
||||
err = writeUnknownInt(w, x, err)
|
||||
case WireFixed64:
|
||||
x, err = b.DecodeFixed64()
|
||||
err = writeUnknownInt(w, x, err)
|
||||
case WireStartGroup:
|
||||
err = w.WriteByte('{')
|
||||
w.indent()
|
||||
case WireVarint:
|
||||
x, err = b.DecodeVarint()
|
||||
err = writeUnknownInt(w, x, err)
|
||||
default:
|
||||
_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeUnknownInt(w *textWriter, x uint64, err error) error {
|
||||
if err == nil {
|
||||
_, err = fmt.Fprint(w, x)
|
||||
} else {
|
||||
_, err = fmt.Fprintf(w, "/* %v */", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type int32Slice []int32
|
||||
|
||||
func (s int32Slice) Len() int { return len(s) }
|
||||
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
|
||||
func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// writeExtensions writes all the extensions in pv.
|
||||
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
||||
func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||
emap := extensionMaps[pv.Type().Elem()]
|
||||
ep := pv.Interface().(extendableProto)
|
||||
|
||||
// Order the extensions by ID.
|
||||
// This isn't strictly necessary, but it will give us
|
||||
// canonical output, which will also make testing easier.
|
||||
var m map[int32]Extension
|
||||
if em, ok := ep.(extensionsMap); ok {
|
||||
m = em.ExtensionMap()
|
||||
} else if em, ok := ep.(extensionsBytes); ok {
|
||||
eb := em.GetExtensions()
|
||||
var err error
|
||||
m, err = BytesToExtensionsMap(*eb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ids := make([]int32, 0, len(m))
|
||||
for id := range m {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
sort.Sort(int32Slice(ids))
|
||||
|
||||
for _, extNum := range ids {
|
||||
ext := m[extNum]
|
||||
var desc *ExtensionDesc
|
||||
if emap != nil {
|
||||
desc = emap[extNum]
|
||||
}
|
||||
if desc == nil {
|
||||
// Unknown extension.
|
||||
if err := writeUnknownStruct(w, ext.enc); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
pb, err := GetExtension(ep, desc)
|
||||
if err != nil {
|
||||
if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Repeated extensions will appear as a slice.
|
||||
if !desc.repeated() {
|
||||
if err := writeExtension(w, desc.Name, pb); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
v := reflect.ValueOf(pb)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
||||
return err
|
||||
}
|
||||
if !w.compact {
|
||||
if err := w.WriteByte(' '); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.WriteByte('\n'); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *textWriter) writeIndent() {
|
||||
if !w.complete {
|
||||
return
|
||||
}
|
||||
remain := w.ind * 2
|
||||
for remain > 0 {
|
||||
n := remain
|
||||
if n > len(spaces) {
|
||||
n = len(spaces)
|
||||
}
|
||||
w.w.Write(spaces[:n])
|
||||
remain -= n
|
||||
}
|
||||
w.complete = false
|
||||
}
|
||||
|
||||
func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||
val := reflect.ValueOf(pb)
|
||||
if pb == nil || val.IsNil() {
|
||||
w.Write([]byte("<nil>"))
|
||||
return nil
|
||||
}
|
||||
var bw *bufio.Writer
|
||||
ww, ok := w.(writer)
|
||||
if !ok {
|
||||
bw = bufio.NewWriter(w)
|
||||
ww = bw
|
||||
}
|
||||
aw := &textWriter{
|
||||
w: ww,
|
||||
complete: true,
|
||||
compact: compact,
|
||||
}
|
||||
|
||||
if tm, ok := pb.(encoding.TextMarshaler); ok {
|
||||
text, err := tm.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = aw.Write(text); err != nil {
|
||||
return err
|
||||
}
|
||||
if bw != nil {
|
||||
return bw.Flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Dereference the received pointer so we don't have outer < and >.
|
||||
v := reflect.Indirect(val)
|
||||
if err := writeStruct(aw, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if bw != nil {
|
||||
return bw.Flush()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText writes a given protocol buffer in text format.
|
||||
// The only errors returned are from w.
|
||||
func MarshalText(w io.Writer, pb Message) error {
|
||||
return marshalText(w, pb, false)
|
||||
}
|
||||
|
||||
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
||||
func MarshalTextString(pb Message) string {
|
||||
var buf bytes.Buffer
|
||||
marshalText(&buf, pb, false)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// CompactText writes a given protocol buffer in compact text format (one line).
|
||||
func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
|
||||
|
||||
// CompactTextString is the same as CompactText, but returns the string directly.
|
||||
func CompactTextString(pb Message) string {
|
||||
var buf bytes.Buffer
|
||||
marshalText(&buf, pb, true)
|
||||
return buf.String()
|
||||
}
|
||||
55
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go
generated
vendored
Normal file
55
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_gogo.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func writeEnum(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
m, ok := enumStringMaps[props.Enum]
|
||||
if !ok {
|
||||
if err := writeAny(w, v, props); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
key := int32(0)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
key = int32(v.Elem().Int())
|
||||
} else {
|
||||
key = int32(v.Int())
|
||||
}
|
||||
s, ok := m[key]
|
||||
if !ok {
|
||||
if err := writeAny(w, v, props); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err := fmt.Fprint(w, s)
|
||||
return err
|
||||
}
|
||||
730
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go
generated
vendored
Normal file
730
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser.go
generated
vendored
Normal file
@@ -0,0 +1,730 @@
|
||||
// Extensions for Protocol Buffers to create more go like structures.
|
||||
//
|
||||
// Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved.
|
||||
// http://github.com/gogo/protobuf/gogoproto
|
||||
//
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto
|
||||
|
||||
// Functions for parsing the Text protocol buffer format.
|
||||
// TODO: message sets.
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type ParseError struct {
|
||||
Message string
|
||||
Line int // 1-based line number
|
||||
Offset int // 0-based byte offset from start of input
|
||||
}
|
||||
|
||||
func (p *ParseError) Error() string {
|
||||
if p.Line == 1 {
|
||||
// show offset only for first line
|
||||
return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message)
|
||||
}
|
||||
return fmt.Sprintf("line %d: %v", p.Line, p.Message)
|
||||
}
|
||||
|
||||
type token struct {
|
||||
value string
|
||||
err *ParseError
|
||||
line int // line number
|
||||
offset int // byte number from start of input, not start of line
|
||||
unquoted string // the unquoted version of value, if it was a quoted string
|
||||
}
|
||||
|
||||
func (t *token) String() string {
|
||||
if t.err == nil {
|
||||
return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset)
|
||||
}
|
||||
return fmt.Sprintf("parse error: %v", t.err)
|
||||
}
|
||||
|
||||
type textParser struct {
|
||||
s string // remaining input
|
||||
done bool // whether the parsing is finished (success or error)
|
||||
backed bool // whether back() was called
|
||||
offset, line int
|
||||
cur token
|
||||
}
|
||||
|
||||
func newTextParser(s string) *textParser {
|
||||
p := new(textParser)
|
||||
p.s = s
|
||||
p.line = 1
|
||||
p.cur.line = 1
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
|
||||
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
|
||||
p.cur.err = pe
|
||||
p.done = true
|
||||
return pe
|
||||
}
|
||||
|
||||
// Numbers and identifiers are matched by [-+._A-Za-z0-9]
|
||||
func isIdentOrNumberChar(c byte) bool {
|
||||
switch {
|
||||
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
|
||||
return true
|
||||
case '0' <= c && c <= '9':
|
||||
return true
|
||||
}
|
||||
switch c {
|
||||
case '-', '+', '.', '_':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isWhitespace(c byte) bool {
|
||||
switch c {
|
||||
case ' ', '\t', '\n', '\r':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *textParser) skipWhitespace() {
|
||||
i := 0
|
||||
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
||||
if p.s[i] == '#' {
|
||||
// comment; skip to end of line or input
|
||||
for i < len(p.s) && p.s[i] != '\n' {
|
||||
i++
|
||||
}
|
||||
if i == len(p.s) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if p.s[i] == '\n' {
|
||||
p.line++
|
||||
}
|
||||
i++
|
||||
}
|
||||
p.offset += i
|
||||
p.s = p.s[i:len(p.s)]
|
||||
if len(p.s) == 0 {
|
||||
p.done = true
|
||||
}
|
||||
}
|
||||
|
||||
func (p *textParser) advance() {
|
||||
// Skip whitespace
|
||||
p.skipWhitespace()
|
||||
if p.done {
|
||||
return
|
||||
}
|
||||
|
||||
// Start of non-whitespace
|
||||
p.cur.err = nil
|
||||
p.cur.offset, p.cur.line = p.offset, p.line
|
||||
p.cur.unquoted = ""
|
||||
switch p.s[0] {
|
||||
case '<', '>', '{', '}', ':', '[', ']', ';', ',':
|
||||
// Single symbol
|
||||
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
||||
case '"', '\'':
|
||||
// Quoted string
|
||||
i := 1
|
||||
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
|
||||
if p.s[i] == '\\' && i+1 < len(p.s) {
|
||||
// skip escaped char
|
||||
i++
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(p.s) || p.s[i] != p.s[0] {
|
||||
p.errorf("unmatched quote")
|
||||
return
|
||||
}
|
||||
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
|
||||
if err != nil {
|
||||
p.errorf("invalid quoted string %v", p.s[0:i+1])
|
||||
return
|
||||
}
|
||||
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
|
||||
p.cur.unquoted = unq
|
||||
default:
|
||||
i := 0
|
||||
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
|
||||
i++
|
||||
}
|
||||
if i == 0 {
|
||||
p.errorf("unexpected byte %#x", p.s[0])
|
||||
return
|
||||
}
|
||||
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
|
||||
}
|
||||
p.offset += len(p.cur.value)
|
||||
}
|
||||
|
||||
var (
|
||||
errBadUTF8 = errors.New("proto: bad UTF-8")
|
||||
errBadHex = errors.New("proto: bad hexadecimal")
|
||||
)
|
||||
|
||||
func unquoteC(s string, quote rune) (string, error) {
|
||||
// This is based on C++'s tokenizer.cc.
|
||||
// Despite its name, this is *not* parsing C syntax.
|
||||
// For instance, "\0" is an invalid quoted string.
|
||||
|
||||
// Avoid allocation in trivial cases.
|
||||
simple := true
|
||||
for _, r := range s {
|
||||
if r == '\\' || r == quote {
|
||||
simple = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if simple {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, 3*len(s)/2)
|
||||
for len(s) > 0 {
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
if r == utf8.RuneError && n == 1 {
|
||||
return "", errBadUTF8
|
||||
}
|
||||
s = s[n:]
|
||||
if r != '\\' {
|
||||
if r < utf8.RuneSelf {
|
||||
buf = append(buf, byte(r))
|
||||
} else {
|
||||
buf = append(buf, string(r)...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
ch, tail, err := unescape(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf = append(buf, ch...)
|
||||
s = tail
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func unescape(s string) (ch string, tail string, err error) {
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
if r == utf8.RuneError && n == 1 {
|
||||
return "", "", errBadUTF8
|
||||
}
|
||||
s = s[n:]
|
||||
switch r {
|
||||
case 'a':
|
||||
return "\a", s, nil
|
||||
case 'b':
|
||||
return "\b", s, nil
|
||||
case 'f':
|
||||
return "\f", s, nil
|
||||
case 'n':
|
||||
return "\n", s, nil
|
||||
case 'r':
|
||||
return "\r", s, nil
|
||||
case 't':
|
||||
return "\t", s, nil
|
||||
case 'v':
|
||||
return "\v", s, nil
|
||||
case '?':
|
||||
return "?", s, nil // trigraph workaround
|
||||
case '\'', '"', '\\':
|
||||
return string(r), s, nil
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
|
||||
if len(s) < 2 {
|
||||
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
|
||||
}
|
||||
base := 8
|
||||
ss := s[:2]
|
||||
s = s[2:]
|
||||
if r == 'x' || r == 'X' {
|
||||
base = 16
|
||||
} else {
|
||||
ss = string(r) + ss
|
||||
}
|
||||
i, err := strconv.ParseUint(ss, base, 8)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return string([]byte{byte(i)}), s, nil
|
||||
case 'u', 'U':
|
||||
n := 4
|
||||
if r == 'U' {
|
||||
n = 8
|
||||
}
|
||||
if len(s) < n {
|
||||
return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
|
||||
}
|
||||
|
||||
bs := make([]byte, n/2)
|
||||
for i := 0; i < n; i += 2 {
|
||||
a, ok1 := unhex(s[i])
|
||||
b, ok2 := unhex(s[i+1])
|
||||
if !ok1 || !ok2 {
|
||||
return "", "", errBadHex
|
||||
}
|
||||
bs[i/2] = a<<4 | b
|
||||
}
|
||||
s = s[n:]
|
||||
return string(bs), s, nil
|
||||
}
|
||||
return "", "", fmt.Errorf(`unknown escape \%c`, r)
|
||||
}
|
||||
|
||||
// Adapted from src/pkg/strconv/quote.go.
|
||||
func unhex(b byte) (v byte, ok bool) {
|
||||
switch {
|
||||
case '0' <= b && b <= '9':
|
||||
return b - '0', true
|
||||
case 'a' <= b && b <= 'f':
|
||||
return b - 'a' + 10, true
|
||||
case 'A' <= b && b <= 'F':
|
||||
return b - 'A' + 10, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Back off the parser by one token. Can only be done between calls to next().
|
||||
// It makes the next advance() a no-op.
|
||||
func (p *textParser) back() { p.backed = true }
|
||||
|
||||
// Advances the parser and returns the new current token.
|
||||
func (p *textParser) next() *token {
|
||||
if p.backed || p.done {
|
||||
p.backed = false
|
||||
return &p.cur
|
||||
}
|
||||
p.advance()
|
||||
if p.done {
|
||||
p.cur.value = ""
|
||||
} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
|
||||
// Look for multiple quoted strings separated by whitespace,
|
||||
// and concatenate them.
|
||||
cat := p.cur
|
||||
for {
|
||||
p.skipWhitespace()
|
||||
if p.done || p.s[0] != '"' {
|
||||
break
|
||||
}
|
||||
p.advance()
|
||||
if p.cur.err != nil {
|
||||
return &p.cur
|
||||
}
|
||||
cat.value += " " + p.cur.value
|
||||
cat.unquoted += p.cur.unquoted
|
||||
}
|
||||
p.done = false // parser may have seen EOF, but we want to return cat
|
||||
p.cur = cat
|
||||
}
|
||||
return &p.cur
|
||||
}
|
||||
|
||||
// Return a RequiredNotSetError indicating which required field was not set.
|
||||
func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError {
|
||||
st := sv.Type()
|
||||
sprops := GetProperties(st)
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
if !isNil(sv.Field(i)) {
|
||||
continue
|
||||
}
|
||||
|
||||
props := sprops.Prop[i]
|
||||
if props.Required {
|
||||
return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)}
|
||||
}
|
||||
}
|
||||
return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen
|
||||
}
|
||||
|
||||
// Returns the index in the struct for the named field, as well as the parsed tag properties.
|
||||
func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) {
|
||||
sprops := GetProperties(st)
|
||||
i, ok := sprops.decoderOrigNames[name]
|
||||
if ok {
|
||||
return i, sprops.Prop[i], true
|
||||
}
|
||||
return -1, nil, false
|
||||
}
|
||||
|
||||
// Consume a ':' from the input stream (if the next token is a colon),
|
||||
// returning an error if a colon is needed but not present.
|
||||
func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError {
|
||||
tok := p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value != ":" {
|
||||
// Colon is optional when the field is a group or message.
|
||||
needColon := true
|
||||
switch props.Wire {
|
||||
case "group":
|
||||
needColon = false
|
||||
case "bytes":
|
||||
// A "bytes" field is either a message, a string, or a repeated field;
|
||||
// those three become *T, *string and []T respectively, so we can check for
|
||||
// this field being a pointer to a non-string.
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
// *T or *string
|
||||
if typ.Elem().Kind() == reflect.String {
|
||||
break
|
||||
}
|
||||
} else if typ.Kind() == reflect.Slice {
|
||||
// []T or []*T
|
||||
if typ.Elem().Kind() != reflect.Ptr {
|
||||
break
|
||||
}
|
||||
}
|
||||
needColon = false
|
||||
}
|
||||
if needColon {
|
||||
return p.errorf("expected ':', found %q", tok.value)
|
||||
}
|
||||
p.back()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||
st := sv.Type()
|
||||
reqCount := GetProperties(st).reqCount
|
||||
var reqFieldErr error
|
||||
fieldSet := make(map[string]bool)
|
||||
// A struct is a sequence of "name: value", terminated by one of
|
||||
// '>' or '}', or the end of the input. A name may also be
|
||||
// "[extension]".
|
||||
for {
|
||||
tok := p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value == terminator {
|
||||
break
|
||||
}
|
||||
if tok.value == "[" {
|
||||
// Looks like an extension.
|
||||
//
|
||||
// TODO: Check whether we need to handle
|
||||
// namespace rooted names (e.g. ".something.Foo").
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
var desc *ExtensionDesc
|
||||
// This could be faster, but it's functional.
|
||||
// TODO: Do something smarter than a linear scan.
|
||||
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
|
||||
if d.Name == tok.value {
|
||||
desc = d
|
||||
break
|
||||
}
|
||||
}
|
||||
if desc == nil {
|
||||
return p.errorf("unrecognized extension %q", tok.value)
|
||||
}
|
||||
// Check the extension terminator.
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value != "]" {
|
||||
return p.errorf("unrecognized extension terminator %q", tok.value)
|
||||
}
|
||||
|
||||
props := &Properties{}
|
||||
props.Parse(desc.Tag)
|
||||
|
||||
typ := reflect.TypeOf(desc.ExtensionType)
|
||||
if err := p.checkForColon(props, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rep := desc.repeated()
|
||||
|
||||
// Read the extension structure, and set it in
|
||||
// the value we're constructing.
|
||||
var ext reflect.Value
|
||||
if !rep {
|
||||
ext = reflect.New(typ).Elem()
|
||||
} else {
|
||||
ext = reflect.New(typ.Elem()).Elem()
|
||||
}
|
||||
if err := p.readAny(ext, props); err != nil {
|
||||
if _, ok := err.(*RequiredNotSetError); !ok {
|
||||
return err
|
||||
}
|
||||
reqFieldErr = err
|
||||
}
|
||||
ep := sv.Addr().Interface().(extendableProto)
|
||||
if !rep {
|
||||
SetExtension(ep, desc, ext.Interface())
|
||||
} else {
|
||||
old, err := GetExtension(ep, desc)
|
||||
var sl reflect.Value
|
||||
if err == nil {
|
||||
sl = reflect.ValueOf(old) // existing slice
|
||||
} else {
|
||||
sl = reflect.MakeSlice(typ, 0, 1)
|
||||
}
|
||||
sl = reflect.Append(sl, ext)
|
||||
SetExtension(ep, desc, sl.Interface())
|
||||
}
|
||||
} else {
|
||||
// This is a normal, non-extension field.
|
||||
name := tok.value
|
||||
fi, props, ok := structFieldByName(st, name)
|
||||
if !ok {
|
||||
return p.errorf("unknown field name %q in %v", name, st)
|
||||
}
|
||||
|
||||
dst := sv.Field(fi)
|
||||
|
||||
// Check that it's not already set if it's not a repeated field.
|
||||
if !props.Repeated && fieldSet[name] {
|
||||
return p.errorf("non-repeated field %q was repeated", name)
|
||||
}
|
||||
|
||||
if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse into the field.
|
||||
fieldSet[name] = true
|
||||
if err := p.readAny(dst, props); err != nil {
|
||||
if _, ok := err.(*RequiredNotSetError); !ok {
|
||||
return err
|
||||
}
|
||||
reqFieldErr = err
|
||||
} else if props.Required {
|
||||
reqCount--
|
||||
}
|
||||
}
|
||||
|
||||
// For backward compatibility, permit a semicolon or comma after a field.
|
||||
tok = p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value != ";" && tok.value != "," {
|
||||
p.back()
|
||||
}
|
||||
}
|
||||
|
||||
if reqCount > 0 {
|
||||
return p.missingRequiredFieldError(sv)
|
||||
}
|
||||
return reqFieldErr
|
||||
}
|
||||
|
||||
func (p *textParser) readAny(v reflect.Value, props *Properties) error {
|
||||
tok := p.next()
|
||||
if tok.err != nil {
|
||||
return tok.err
|
||||
}
|
||||
if tok.value == "" {
|
||||
return p.errorf("unexpected EOF")
|
||||
}
|
||||
if len(props.CustomType) > 0 {
|
||||
if props.Repeated {
|
||||
t := reflect.TypeOf(v.Interface())
|
||||
if t.Kind() == reflect.Slice {
|
||||
tc := reflect.TypeOf(new(Marshaler))
|
||||
ok := t.Elem().Implements(tc.Elem())
|
||||
if ok {
|
||||
fv := v
|
||||
flen := fv.Len()
|
||||
if flen == fv.Cap() {
|
||||
nav := reflect.MakeSlice(v.Type(), flen, 2*flen+1)
|
||||
reflect.Copy(nav, fv)
|
||||
fv.Set(nav)
|
||||
}
|
||||
fv.SetLen(flen + 1)
|
||||
|
||||
// Read one.
|
||||
p.back()
|
||||
return p.readAny(fv.Index(flen), props)
|
||||
}
|
||||
}
|
||||
}
|
||||
if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr {
|
||||
custom := reflect.New(props.ctype.Elem()).Interface().(Unmarshaler)
|
||||
err := custom.Unmarshal([]byte(tok.unquoted))
|
||||
if err != nil {
|
||||
return p.errorf("%v %v: %v", err, v.Type(), tok.value)
|
||||
}
|
||||
v.Set(reflect.ValueOf(custom))
|
||||
} else {
|
||||
custom := reflect.New(reflect.TypeOf(v.Interface())).Interface().(Unmarshaler)
|
||||
err := custom.Unmarshal([]byte(tok.unquoted))
|
||||
if err != nil {
|
||||
return p.errorf("%v %v: %v", err, v.Type(), tok.value)
|
||||
}
|
||||
v.Set(reflect.Indirect(reflect.ValueOf(custom)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
switch fv := v; fv.Kind() {
|
||||
case reflect.Slice:
|
||||
at := v.Type()
|
||||
if at.Elem().Kind() == reflect.Uint8 {
|
||||
// Special case for []byte
|
||||
if tok.value[0] != '"' && tok.value[0] != '\'' {
|
||||
// Deliberately written out here, as the error after
|
||||
// this switch statement would write "invalid []byte: ...",
|
||||
// which is not as user-friendly.
|
||||
return p.errorf("invalid string: %v", tok.value)
|
||||
}
|
||||
bytes := []byte(tok.unquoted)
|
||||
fv.Set(reflect.ValueOf(bytes))
|
||||
return nil
|
||||
}
|
||||
// Repeated field. May already exist.
|
||||
flen := fv.Len()
|
||||
if flen == fv.Cap() {
|
||||
nav := reflect.MakeSlice(at, flen, 2*flen+1)
|
||||
reflect.Copy(nav, fv)
|
||||
fv.Set(nav)
|
||||
}
|
||||
fv.SetLen(flen + 1)
|
||||
|
||||
// Read one.
|
||||
p.back()
|
||||
return p.readAny(fv.Index(flen), props)
|
||||
case reflect.Bool:
|
||||
// Either "true", "false", 1 or 0.
|
||||
switch tok.value {
|
||||
case "true", "1":
|
||||
fv.SetBool(true)
|
||||
return nil
|
||||
case "false", "0":
|
||||
fv.SetBool(false)
|
||||
return nil
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
v := tok.value
|
||||
// Ignore 'f' for compatibility with output generated by C++, but don't
|
||||
// remove 'f' when the value is "-inf" or "inf".
|
||||
if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" {
|
||||
v = v[:len(v)-1]
|
||||
}
|
||||
if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil {
|
||||
fv.SetFloat(f)
|
||||
return nil
|
||||
}
|
||||
case reflect.Int32:
|
||||
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
|
||||
fv.SetInt(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(props.Enum) == 0 {
|
||||
break
|
||||
}
|
||||
m, ok := enumValueMaps[props.Enum]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
x, ok := m[tok.value]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
fv.SetInt(int64(x))
|
||||
return nil
|
||||
case reflect.Int64:
|
||||
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
|
||||
fv.SetInt(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
// A basic field (indirected through pointer), or a repeated message/group
|
||||
p.back()
|
||||
fv.Set(reflect.New(fv.Type().Elem()))
|
||||
return p.readAny(fv.Elem(), props)
|
||||
case reflect.String:
|
||||
if tok.value[0] == '"' || tok.value[0] == '\'' {
|
||||
fv.SetString(tok.unquoted)
|
||||
return nil
|
||||
}
|
||||
case reflect.Struct:
|
||||
var terminator string
|
||||
switch tok.value {
|
||||
case "{":
|
||||
terminator = "}"
|
||||
case "<":
|
||||
terminator = ">"
|
||||
default:
|
||||
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||
}
|
||||
// TODO: Handle nested messages which implement encoding.TextUnmarshaler.
|
||||
return p.readStruct(fv, terminator)
|
||||
case reflect.Uint32:
|
||||
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
|
||||
fv.SetUint(uint64(x))
|
||||
return nil
|
||||
}
|
||||
case reflect.Uint64:
|
||||
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
|
||||
fv.SetUint(x)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return p.errorf("invalid %v: %v", v.Type(), tok.value)
|
||||
}
|
||||
|
||||
// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
|
||||
// before starting to unmarshal, so any existing data in pb is always removed.
|
||||
// If a required field is not set and no other error occurs,
|
||||
// UnmarshalText returns *RequiredNotSetError.
|
||||
func UnmarshalText(s string, pb Message) error {
|
||||
if um, ok := pb.(encoding.TextUnmarshaler); ok {
|
||||
err := um.UnmarshalText([]byte(s))
|
||||
return err
|
||||
}
|
||||
pb.Reset()
|
||||
v := reflect.ValueOf(pb)
|
||||
if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
|
||||
return pe
|
||||
}
|
||||
return nil
|
||||
}
|
||||
468
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser_test.go
generated
vendored
Normal file
468
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_parser_test.go
generated
vendored
Normal file
@@ -0,0 +1,468 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
. "./testdata"
|
||||
. "github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type UnmarshalTextTest struct {
|
||||
in string
|
||||
err string // if "", no error expected
|
||||
out *MyMessage
|
||||
}
|
||||
|
||||
func buildExtStructTest(text string) UnmarshalTextTest {
|
||||
msg := &MyMessage{
|
||||
Count: Int32(42),
|
||||
}
|
||||
SetExtension(msg, E_Ext_More, &Ext{
|
||||
Data: String("Hello, world!"),
|
||||
})
|
||||
return UnmarshalTextTest{in: text, out: msg}
|
||||
}
|
||||
|
||||
func buildExtDataTest(text string) UnmarshalTextTest {
|
||||
msg := &MyMessage{
|
||||
Count: Int32(42),
|
||||
}
|
||||
SetExtension(msg, E_Ext_Text, String("Hello, world!"))
|
||||
SetExtension(msg, E_Ext_Number, Int32(1729))
|
||||
return UnmarshalTextTest{in: text, out: msg}
|
||||
}
|
||||
|
||||
func buildExtRepStringTest(text string) UnmarshalTextTest {
|
||||
msg := &MyMessage{
|
||||
Count: Int32(42),
|
||||
}
|
||||
if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return UnmarshalTextTest{in: text, out: msg}
|
||||
}
|
||||
|
||||
var unMarshalTextTests = []UnmarshalTextTest{
|
||||
// Basic
|
||||
{
|
||||
in: " count:42\n name:\"Dave\" ",
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("Dave"),
|
||||
},
|
||||
},
|
||||
|
||||
// Empty quoted string
|
||||
{
|
||||
in: `count:42 name:""`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String(""),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string concatenation
|
||||
{
|
||||
in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("My name is elsewhere"),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string with escaped apostrophe
|
||||
{
|
||||
in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("HOLIDAY - New Year's Day"),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string with single quote
|
||||
{
|
||||
in: `count:42 name: 'Roger "The Ramster" Ramjet'`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String(`Roger "The Ramster" Ramjet`),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string with all the accepted special characters from the C++ test
|
||||
{
|
||||
in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"",
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string with quoted backslash
|
||||
{
|
||||
in: `count:42 name: "\\'xyz"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String(`\'xyz`),
|
||||
},
|
||||
},
|
||||
|
||||
// Quoted string with UTF-8 bytes.
|
||||
{
|
||||
in: "count:42 name: '\303\277\302\201\xAB'",
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("\303\277\302\201\xAB"),
|
||||
},
|
||||
},
|
||||
|
||||
// Bad quoted string
|
||||
{
|
||||
in: `inner: < host: "\0" >` + "\n",
|
||||
err: `line 1.15: invalid quoted string "\0"`,
|
||||
},
|
||||
|
||||
// Number too large for int64
|
||||
{
|
||||
in: "count: 1 others { key: 123456789012345678901 }",
|
||||
err: "line 1.23: invalid int64: 123456789012345678901",
|
||||
},
|
||||
|
||||
// Number too large for int32
|
||||
{
|
||||
in: "count: 1234567890123",
|
||||
err: "line 1.7: invalid int32: 1234567890123",
|
||||
},
|
||||
|
||||
// Number in hexadecimal
|
||||
{
|
||||
in: "count: 0x2beef",
|
||||
out: &MyMessage{
|
||||
Count: Int32(0x2beef),
|
||||
},
|
||||
},
|
||||
|
||||
// Number in octal
|
||||
{
|
||||
in: "count: 024601",
|
||||
out: &MyMessage{
|
||||
Count: Int32(024601),
|
||||
},
|
||||
},
|
||||
|
||||
// Floating point number with "f" suffix
|
||||
{
|
||||
in: "count: 4 others:< weight: 17.0f >",
|
||||
out: &MyMessage{
|
||||
Count: Int32(4),
|
||||
Others: []*OtherMessage{
|
||||
{
|
||||
Weight: Float32(17),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Floating point positive infinity
|
||||
{
|
||||
in: "count: 4 bigfloat: inf",
|
||||
out: &MyMessage{
|
||||
Count: Int32(4),
|
||||
Bigfloat: Float64(math.Inf(1)),
|
||||
},
|
||||
},
|
||||
|
||||
// Floating point negative infinity
|
||||
{
|
||||
in: "count: 4 bigfloat: -inf",
|
||||
out: &MyMessage{
|
||||
Count: Int32(4),
|
||||
Bigfloat: Float64(math.Inf(-1)),
|
||||
},
|
||||
},
|
||||
|
||||
// Number too large for float32
|
||||
{
|
||||
in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
|
||||
err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
|
||||
},
|
||||
|
||||
// Number posing as a quoted string
|
||||
{
|
||||
in: `inner: < host: 12 >` + "\n",
|
||||
err: `line 1.15: invalid string: 12`,
|
||||
},
|
||||
|
||||
// Quoted string posing as int32
|
||||
{
|
||||
in: `count: "12"`,
|
||||
err: `line 1.7: invalid int32: "12"`,
|
||||
},
|
||||
|
||||
// Quoted string posing a float32
|
||||
{
|
||||
in: `others:< weight: "17.4" >`,
|
||||
err: `line 1.17: invalid float32: "17.4"`,
|
||||
},
|
||||
|
||||
// Enum
|
||||
{
|
||||
in: `count:42 bikeshed: BLUE`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Bikeshed: MyMessage_BLUE.Enum(),
|
||||
},
|
||||
},
|
||||
|
||||
// Repeated field
|
||||
{
|
||||
in: `count:42 pet: "horsey" pet:"bunny"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Pet: []string{"horsey", "bunny"},
|
||||
},
|
||||
},
|
||||
|
||||
// Repeated message with/without colon and <>/{}
|
||||
{
|
||||
in: `count:42 others:{} others{} others:<> others:{}`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Others: []*OtherMessage{
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Missing colon for inner message
|
||||
{
|
||||
in: `count:42 inner < host: "cauchy.syd" >`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Inner: &InnerMessage{
|
||||
Host: String("cauchy.syd"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Missing colon for string field
|
||||
{
|
||||
in: `name "Dave"`,
|
||||
err: `line 1.5: expected ':', found "\"Dave\""`,
|
||||
},
|
||||
|
||||
// Missing colon for int32 field
|
||||
{
|
||||
in: `count 42`,
|
||||
err: `line 1.6: expected ':', found "42"`,
|
||||
},
|
||||
|
||||
// Missing required field
|
||||
{
|
||||
in: `name: "Pawel"`,
|
||||
err: `proto: required field "testdata.MyMessage.count" not set`,
|
||||
out: &MyMessage{
|
||||
Name: String("Pawel"),
|
||||
},
|
||||
},
|
||||
|
||||
// Repeated non-repeated field
|
||||
{
|
||||
in: `name: "Rob" name: "Russ"`,
|
||||
err: `line 1.12: non-repeated field "name" was repeated`,
|
||||
},
|
||||
|
||||
// Group
|
||||
{
|
||||
in: `count: 17 SomeGroup { group_field: 12 }`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(17),
|
||||
Somegroup: &MyMessage_SomeGroup{
|
||||
GroupField: Int32(12),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Semicolon between fields
|
||||
{
|
||||
in: `count:3;name:"Calvin"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(3),
|
||||
Name: String("Calvin"),
|
||||
},
|
||||
},
|
||||
// Comma between fields
|
||||
{
|
||||
in: `count:4,name:"Ezekiel"`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(4),
|
||||
Name: String("Ezekiel"),
|
||||
},
|
||||
},
|
||||
|
||||
// Extension
|
||||
buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
|
||||
buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
|
||||
buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
|
||||
buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`),
|
||||
|
||||
// Big all-in-one
|
||||
{
|
||||
in: "count:42 # Meaning\n" +
|
||||
`name:"Dave" ` +
|
||||
`quote:"\"I didn't want to go.\"" ` +
|
||||
`pet:"bunny" ` +
|
||||
`pet:"kitty" ` +
|
||||
`pet:"horsey" ` +
|
||||
`inner:<` +
|
||||
` host:"footrest.syd" ` +
|
||||
` port:7001 ` +
|
||||
` connected:true ` +
|
||||
`> ` +
|
||||
`others:<` +
|
||||
` key:3735928559 ` +
|
||||
` value:"\x01A\a\f" ` +
|
||||
`> ` +
|
||||
`others:<` +
|
||||
" weight:58.9 # Atomic weight of Co\n" +
|
||||
` inner:<` +
|
||||
` host:"lesha.mtv" ` +
|
||||
` port:8002 ` +
|
||||
` >` +
|
||||
`>`,
|
||||
out: &MyMessage{
|
||||
Count: Int32(42),
|
||||
Name: String("Dave"),
|
||||
Quote: String(`"I didn't want to go."`),
|
||||
Pet: []string{"bunny", "kitty", "horsey"},
|
||||
Inner: &InnerMessage{
|
||||
Host: String("footrest.syd"),
|
||||
Port: Int32(7001),
|
||||
Connected: Bool(true),
|
||||
},
|
||||
Others: []*OtherMessage{
|
||||
{
|
||||
Key: Int64(3735928559),
|
||||
Value: []byte{0x1, 'A', '\a', '\f'},
|
||||
},
|
||||
{
|
||||
Weight: Float32(58.9),
|
||||
Inner: &InnerMessage{
|
||||
Host: String("lesha.mtv"),
|
||||
Port: Int32(8002),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestUnmarshalText(t *testing.T) {
|
||||
for i, test := range unMarshalTextTests {
|
||||
pb := new(MyMessage)
|
||||
err := UnmarshalText(test.in, pb)
|
||||
if test.err == "" {
|
||||
// We don't expect failure.
|
||||
if err != nil {
|
||||
t.Errorf("Test %d: Unexpected error: %v", i, err)
|
||||
} else if !reflect.DeepEqual(pb, test.out) {
|
||||
t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
|
||||
i, pb, test.out)
|
||||
}
|
||||
} else {
|
||||
// We do expect failure.
|
||||
if err == nil {
|
||||
t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
|
||||
} else if err.Error() != test.err {
|
||||
t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
|
||||
i, err.Error(), test.err)
|
||||
} else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) {
|
||||
t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
|
||||
i, pb, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalTextCustomMessage(t *testing.T) {
|
||||
msg := &textMessage{}
|
||||
if err := UnmarshalText("custom", msg); err != nil {
|
||||
t.Errorf("Unexpected error from custom unmarshal: %v", err)
|
||||
}
|
||||
if UnmarshalText("not custom", msg) == nil {
|
||||
t.Errorf("Didn't get expected error from custom unmarshal")
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test; this caused a panic.
|
||||
func TestRepeatedEnum(t *testing.T) {
|
||||
pb := new(RepeatedEnum)
|
||||
if err := UnmarshalText("color: RED", pb); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp := &RepeatedEnum{
|
||||
Color: []RepeatedEnum_Color{RepeatedEnum_RED},
|
||||
}
|
||||
if !Equal(pb, exp) {
|
||||
t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
|
||||
}
|
||||
}
|
||||
|
||||
var benchInput string
|
||||
|
||||
func init() {
|
||||
benchInput = "count: 4\n"
|
||||
for i := 0; i < 1000; i++ {
|
||||
benchInput += "pet: \"fido\"\n"
|
||||
}
|
||||
|
||||
// Check it is valid input.
|
||||
pb := new(MyMessage)
|
||||
err := UnmarshalText(benchInput, pb)
|
||||
if err != nil {
|
||||
panic("Bad benchmark input: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalText(b *testing.B) {
|
||||
pb := new(MyMessage)
|
||||
for i := 0; i < b.N; i++ {
|
||||
UnmarshalText(benchInput, pb)
|
||||
}
|
||||
b.SetBytes(int64(len(benchInput)))
|
||||
}
|
||||
408
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_test.go
generated
vendored
Normal file
408
Godeps/_workspace/src/github.com/gogo/protobuf/proto/text_test.go
generated
vendored
Normal file
@@ -0,0 +1,408 @@
|
||||
// Go support for Protocol Buffers - Google's data interchange format
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// https://github.com/golang/protobuf
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
pb "./testdata"
|
||||
)
|
||||
|
||||
// textMessage implements the methods that allow it to marshal and unmarshal
|
||||
// itself as text.
|
||||
type textMessage struct {
|
||||
}
|
||||
|
||||
func (*textMessage) MarshalText() ([]byte, error) {
|
||||
return []byte("custom"), nil
|
||||
}
|
||||
|
||||
func (*textMessage) UnmarshalText(bytes []byte) error {
|
||||
if string(bytes) != "custom" {
|
||||
return errors.New("expected 'custom'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*textMessage) Reset() {}
|
||||
func (*textMessage) String() string { return "" }
|
||||
func (*textMessage) ProtoMessage() {}
|
||||
|
||||
func newTestMessage() *pb.MyMessage {
|
||||
msg := &pb.MyMessage{
|
||||
Count: proto.Int32(42),
|
||||
Name: proto.String("Dave"),
|
||||
Quote: proto.String(`"I didn't want to go."`),
|
||||
Pet: []string{"bunny", "kitty", "horsey"},
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("footrest.syd"),
|
||||
Port: proto.Int32(7001),
|
||||
Connected: proto.Bool(true),
|
||||
},
|
||||
Others: []*pb.OtherMessage{
|
||||
{
|
||||
Key: proto.Int64(0xdeadbeef),
|
||||
Value: []byte{1, 65, 7, 12},
|
||||
},
|
||||
{
|
||||
Weight: proto.Float32(6.022),
|
||||
Inner: &pb.InnerMessage{
|
||||
Host: proto.String("lesha.mtv"),
|
||||
Port: proto.Int32(8002),
|
||||
},
|
||||
},
|
||||
},
|
||||
Bikeshed: pb.MyMessage_BLUE.Enum(),
|
||||
Somegroup: &pb.MyMessage_SomeGroup{
|
||||
GroupField: proto.Int32(8),
|
||||
},
|
||||
// One normally wouldn't do this.
|
||||
// This is an undeclared tag 13, as a varint (wire type 0) with value 4.
|
||||
XXX_unrecognized: []byte{13<<3 | 0, 4},
|
||||
}
|
||||
ext := &pb.Ext{
|
||||
Data: proto.String("Big gobs for big rats"),
|
||||
}
|
||||
if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
greetings := []string{"adg", "easy", "cow"}
|
||||
if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add an unknown extension. We marshal a pb.Ext, and fake the ID.
|
||||
b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...)
|
||||
proto.SetRawExtension(msg, 201, b)
|
||||
|
||||
// Extensions can be plain fields, too, so let's test that.
|
||||
b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19)
|
||||
proto.SetRawExtension(msg, 202, b)
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
const text = `count: 42
|
||||
name: "Dave"
|
||||
quote: "\"I didn't want to go.\""
|
||||
pet: "bunny"
|
||||
pet: "kitty"
|
||||
pet: "horsey"
|
||||
inner: <
|
||||
host: "footrest.syd"
|
||||
port: 7001
|
||||
connected: true
|
||||
>
|
||||
others: <
|
||||
key: 3735928559
|
||||
value: "\001A\007\014"
|
||||
>
|
||||
others: <
|
||||
weight: 6.022
|
||||
inner: <
|
||||
host: "lesha.mtv"
|
||||
port: 8002
|
||||
>
|
||||
>
|
||||
bikeshed: BLUE
|
||||
SomeGroup {
|
||||
group_field: 8
|
||||
}
|
||||
/* 2 unknown bytes */
|
||||
13: 4
|
||||
[testdata.Ext.more]: <
|
||||
data: "Big gobs for big rats"
|
||||
>
|
||||
[testdata.greeting]: "adg"
|
||||
[testdata.greeting]: "easy"
|
||||
[testdata.greeting]: "cow"
|
||||
/* 13 unknown bytes */
|
||||
201: "\t3G skiing"
|
||||
/* 3 unknown bytes */
|
||||
202: 19
|
||||
`
|
||||
|
||||
func TestMarshalText(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := proto.MarshalText(buf, newTestMessage()); err != nil {
|
||||
t.Fatalf("proto.MarshalText: %v", err)
|
||||
}
|
||||
s := buf.String()
|
||||
if s != text {
|
||||
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalTextCustomMessage(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := proto.MarshalText(buf, &textMessage{}); err != nil {
|
||||
t.Fatalf("proto.MarshalText: %v", err)
|
||||
}
|
||||
s := buf.String()
|
||||
if s != "custom" {
|
||||
t.Errorf("Got %q, expected %q", s, "custom")
|
||||
}
|
||||
}
|
||||
func TestMarshalTextNil(t *testing.T) {
|
||||
want := "<nil>"
|
||||
tests := []proto.Message{nil, (*pb.MyMessage)(nil)}
|
||||
for i, test := range tests {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := proto.MarshalText(buf, test); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := buf.String(); got != want {
|
||||
t.Errorf("%d: got %q want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalTextUnknownEnum(t *testing.T) {
|
||||
// The Color enum only specifies values 0-2.
|
||||
m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()}
|
||||
got := m.String()
|
||||
const want = `bikeshed:3 `
|
||||
if got != want {
|
||||
t.Errorf("\n got %q\nwant %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalTextBuffered(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
m := newTestMessage()
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf.Reset()
|
||||
proto.MarshalText(buf, m)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalTextUnbuffered(b *testing.B) {
|
||||
w := ioutil.Discard
|
||||
m := newTestMessage()
|
||||
for i := 0; i < b.N; i++ {
|
||||
proto.MarshalText(w, m)
|
||||
}
|
||||
}
|
||||
|
||||
func compact(src string) string {
|
||||
// s/[ \n]+/ /g; s/ $//;
|
||||
dst := make([]byte, len(src))
|
||||
space, comment := false, false
|
||||
j := 0
|
||||
for i := 0; i < len(src); i++ {
|
||||
if strings.HasPrefix(src[i:], "/*") {
|
||||
comment = true
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if comment && strings.HasPrefix(src[i:], "*/") {
|
||||
comment = false
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if comment {
|
||||
continue
|
||||
}
|
||||
c := src[i]
|
||||
if c == ' ' || c == '\n' {
|
||||
space = true
|
||||
continue
|
||||
}
|
||||
if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') {
|
||||
space = false
|
||||
}
|
||||
if c == '{' {
|
||||
space = false
|
||||
}
|
||||
if space {
|
||||
dst[j] = ' '
|
||||
j++
|
||||
space = false
|
||||
}
|
||||
dst[j] = c
|
||||
j++
|
||||
}
|
||||
if space {
|
||||
dst[j] = ' '
|
||||
j++
|
||||
}
|
||||
return string(dst[0:j])
|
||||
}
|
||||
|
||||
var compactText = compact(text)
|
||||
|
||||
func TestCompactText(t *testing.T) {
|
||||
s := proto.CompactTextString(newTestMessage())
|
||||
if s != compactText {
|
||||
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringEscaping(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in *pb.Strings
|
||||
out string
|
||||
}{
|
||||
{
|
||||
// Test data from C++ test (TextFormatTest.StringEscape).
|
||||
// Single divergence: we don't escape apostrophes.
|
||||
&pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")},
|
||||
"string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n",
|
||||
},
|
||||
{
|
||||
// Test data from the same C++ test.
|
||||
&pb.Strings{StringField: proto.String("\350\260\267\346\255\214")},
|
||||
"string_field: \"\\350\\260\\267\\346\\255\\214\"\n",
|
||||
},
|
||||
{
|
||||
// Some UTF-8.
|
||||
&pb.Strings{StringField: proto.String("\x00\x01\xff\x81")},
|
||||
`string_field: "\000\001\377\201"` + "\n",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
var buf bytes.Buffer
|
||||
if err := proto.MarshalText(&buf, tc.in); err != nil {
|
||||
t.Errorf("proto.MarsalText: %v", err)
|
||||
continue
|
||||
}
|
||||
s := buf.String()
|
||||
if s != tc.out {
|
||||
t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check round-trip.
|
||||
pb := new(pb.Strings)
|
||||
if err := proto.UnmarshalText(s, pb); err != nil {
|
||||
t.Errorf("#%d: UnmarshalText: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !proto.Equal(pb, tc.in) {
|
||||
t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A limitedWriter accepts some output before it fails.
|
||||
// This is a proxy for something like a nearly-full or imminently-failing disk,
|
||||
// or a network connection that is about to die.
|
||||
type limitedWriter struct {
|
||||
b bytes.Buffer
|
||||
limit int
|
||||
}
|
||||
|
||||
var outOfSpace = errors.New("proto: insufficient space")
|
||||
|
||||
func (w *limitedWriter) Write(p []byte) (n int, err error) {
|
||||
var avail = w.limit - w.b.Len()
|
||||
if avail <= 0 {
|
||||
return 0, outOfSpace
|
||||
}
|
||||
if len(p) <= avail {
|
||||
return w.b.Write(p)
|
||||
}
|
||||
n, _ = w.b.Write(p[:avail])
|
||||
return n, outOfSpace
|
||||
}
|
||||
|
||||
func TestMarshalTextFailing(t *testing.T) {
|
||||
// Try lots of different sizes to exercise more error code-paths.
|
||||
for lim := 0; lim < len(text); lim++ {
|
||||
buf := new(limitedWriter)
|
||||
buf.limit = lim
|
||||
err := proto.MarshalText(buf, newTestMessage())
|
||||
// We expect a certain error, but also some partial results in the buffer.
|
||||
if err != outOfSpace {
|
||||
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace)
|
||||
}
|
||||
s := buf.b.String()
|
||||
x := text[:buf.limit]
|
||||
if s != x {
|
||||
t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloats(t *testing.T) {
|
||||
tests := []struct {
|
||||
f float64
|
||||
want string
|
||||
}{
|
||||
{0, "0"},
|
||||
{4.7, "4.7"},
|
||||
{math.Inf(1), "inf"},
|
||||
{math.Inf(-1), "-inf"},
|
||||
{math.NaN(), "nan"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
msg := &pb.FloatingPoint{F: &test.f}
|
||||
got := strings.TrimSpace(msg.String())
|
||||
want := `f:` + test.want
|
||||
if got != want {
|
||||
t.Errorf("f=%f: got %q, want %q", test.f, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepeatedNilText(t *testing.T) {
|
||||
m := &pb.MessageList{
|
||||
Message: []*pb.MessageList_Message{
|
||||
nil,
|
||||
{
|
||||
Name: proto.String("Horse"),
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
want := `Message <nil>
|
||||
Message {
|
||||
name: "Horse"
|
||||
}
|
||||
Message <nil>
|
||||
`
|
||||
if s := proto.MarshalTextString(m); s != want {
|
||||
t.Errorf(" got: %s\nwant: %s", s, want)
|
||||
}
|
||||
}
|
||||
24
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/doc.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/doc.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
The detector package houses implementation of master detectors.
|
||||
The default implementation is the zookeeper master detector.
|
||||
It uses zookeeper to detect the lead Mesos master during startup/failover.
|
||||
*/
|
||||
package detector
|
||||
155
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/factory.go
generated
vendored
Normal file
155
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/factory.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
package detector
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
util "github.com/mesos/mesos-go/mesosutil"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
)
|
||||
|
||||
var (
|
||||
pluginLock sync.Mutex
|
||||
plugins = map[string]PluginFactory{}
|
||||
EmptySpecError = errors.New("empty master specification")
|
||||
|
||||
defaultFactory = PluginFactory(func(spec string) (Master, error) {
|
||||
if len(spec) == 0 {
|
||||
return nil, EmptySpecError
|
||||
}
|
||||
if strings.Index(spec, "@") < 0 {
|
||||
spec = "master@" + spec
|
||||
}
|
||||
if pid, err := upid.Parse(spec); err == nil {
|
||||
return NewStandalone(CreateMasterInfo(pid)), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
type PluginFactory func(string) (Master, error)
|
||||
|
||||
// associates a plugin implementation with a Master specification prefix.
|
||||
// packages that provide plugins are expected to invoke this func within
|
||||
// their init() implementation. schedulers that wish to support plugins may
|
||||
// anonymously import ("_") a package the auto-registers said plugins.
|
||||
func Register(prefix string, f PluginFactory) error {
|
||||
if prefix == "" {
|
||||
return fmt.Errorf("illegal prefix: '%v'", prefix)
|
||||
}
|
||||
if f == nil {
|
||||
return fmt.Errorf("nil plugin factories are not allowed")
|
||||
}
|
||||
|
||||
pluginLock.Lock()
|
||||
defer pluginLock.Unlock()
|
||||
|
||||
if _, found := plugins[prefix]; found {
|
||||
return fmt.Errorf("detection plugin already registered for prefix '%s'", prefix)
|
||||
}
|
||||
plugins[prefix] = f
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a new detector given the provided specification. Examples are:
|
||||
//
|
||||
// - file://{path_to_local_file}
|
||||
// - {ipaddress}:{port}
|
||||
// - master@{ip_address}:{port}
|
||||
// - master({id})@{ip_address}:{port}
|
||||
//
|
||||
// Support for the file:// prefix is intentionally hardcoded so that it may
|
||||
// not be inadvertently overridden by a custom plugin implementation. Custom
|
||||
// plugins are supported via the Register and MatchingPlugin funcs.
|
||||
//
|
||||
// Furthermore it is expected that master detectors returned from this func
|
||||
// are not yet running and will only begin to spawn requisite background
|
||||
// processing upon, or some time after, the first invocation of their Detect.
|
||||
//
|
||||
func New(spec string) (m Master, err error) {
|
||||
if strings.HasPrefix(spec, "file://") {
|
||||
var body []byte
|
||||
path := spec[7:]
|
||||
body, err = ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
log.V(1).Infof("failed to read from file at '%s'", path)
|
||||
} else {
|
||||
m, err = New(string(body))
|
||||
}
|
||||
} else if f, ok := MatchingPlugin(spec); ok {
|
||||
m, err = f(spec)
|
||||
} else {
|
||||
m, err = defaultFactory(spec)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func MatchingPlugin(spec string) (PluginFactory, bool) {
|
||||
pluginLock.Lock()
|
||||
defer pluginLock.Unlock()
|
||||
|
||||
for prefix, f := range plugins {
|
||||
if strings.HasPrefix(spec, prefix) {
|
||||
return f, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Super-useful utility func that attempts to build a mesos.MasterInfo from a
|
||||
// upid.UPID specification. An attempt is made to determine the IP address of
|
||||
// the UPID's Host and any errors during such resolution will result in a nil
|
||||
// returned result. A nil result is also returned upon errors parsing the Port
|
||||
// specification of the UPID.
|
||||
//
|
||||
// TODO(jdef) make this a func of upid.UPID so that callers can invoke somePid.MasterInfo()?
|
||||
//
|
||||
func CreateMasterInfo(pid *upid.UPID) *mesos.MasterInfo {
|
||||
if pid == nil {
|
||||
return nil
|
||||
}
|
||||
port, err := strconv.Atoi(pid.Port)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse port: %v", err)
|
||||
return nil
|
||||
}
|
||||
//TODO(jdef) what about (future) ipv6 support?
|
||||
var ipv4 net.IP
|
||||
if ipv4 = net.ParseIP(pid.Host); ipv4 != nil {
|
||||
// This is needed for the people cross-compiling from macos to linux.
|
||||
// The cross-compiled version of net.LookupIP() fails to handle plain IPs.
|
||||
// See https://github.com/mesos/mesos-go/pull/117
|
||||
} else if addrs, err := net.LookupIP(pid.Host); err == nil {
|
||||
for _, ip := range addrs {
|
||||
if ip = ip.To4(); ip != nil {
|
||||
ipv4 = ip
|
||||
break
|
||||
}
|
||||
}
|
||||
if ipv4 == nil {
|
||||
log.Errorf("host does not resolve to an IPv4 address: %v", pid.Host)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
log.Errorf("failed to lookup IPs for host '%v': %v", pid.Host, err)
|
||||
return nil
|
||||
}
|
||||
packedip := binary.BigEndian.Uint32(ipv4) // network byte order is big-endian
|
||||
mi := util.NewMasterInfo(pid.ID, packedip, uint32(port))
|
||||
mi.Pid = proto.String(pid.String())
|
||||
if pid.Host != "" {
|
||||
mi.Hostname = proto.String(pid.Host)
|
||||
}
|
||||
return mi
|
||||
}
|
||||
59
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/factory_test.go
generated
vendored
Normal file
59
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/factory_test.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package detector
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type testDetector string
|
||||
|
||||
func (d testDetector) Start() error { return nil }
|
||||
func (d testDetector) Detect(f MasterChanged) error { return nil }
|
||||
|
||||
func (d testDetector) Done() <-chan struct{} { return make(<-chan struct{}) }
|
||||
func (d testDetector) Cancel() {}
|
||||
|
||||
// unregister a factory plugin according to its prefix.
|
||||
// this is part of the testing module on purpose: during normal execution there
|
||||
// should be no need to dynamically unregister plugins.
|
||||
func Unregister(prefix string) {
|
||||
pluginLock.Lock()
|
||||
defer pluginLock.Unlock()
|
||||
delete(plugins, prefix)
|
||||
}
|
||||
|
||||
func TestDetectorFactoryRegister(t *testing.T) {
|
||||
prefix := "bbm:"
|
||||
Register(prefix, func(spec string) (Master, error) {
|
||||
return testDetector("Hello!"), nil
|
||||
})
|
||||
defer Unregister(prefix)
|
||||
|
||||
f, ok := MatchingPlugin(prefix)
|
||||
|
||||
assert.True(t, ok)
|
||||
assert.NotNil(t, f)
|
||||
}
|
||||
|
||||
func TestDectorFactoryNew_EmptySpec(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m, err := New("")
|
||||
assert.NotNil(err)
|
||||
assert.Nil(m)
|
||||
}
|
||||
|
||||
func TestDectorFactoryNew_InvalidSpec(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m, err := New("localhost")
|
||||
assert.NotNil(err)
|
||||
assert.Nil(m)
|
||||
}
|
||||
|
||||
func TestDectorFactoryNew_TrivialSpec(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m, err := New("localhost:1")
|
||||
assert.NoError(err)
|
||||
assert.NotNil(m)
|
||||
assert.IsType(&Standalone{}, m)
|
||||
}
|
||||
53
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/interface.go
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/interface.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package detector
|
||||
|
||||
import (
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
)
|
||||
|
||||
type MasterChanged interface {
|
||||
// Invoked when the master changes
|
||||
OnMasterChanged(*mesos.MasterInfo)
|
||||
}
|
||||
|
||||
// func/interface adapter
|
||||
type OnMasterChanged func(*mesos.MasterInfo)
|
||||
|
||||
func (f OnMasterChanged) OnMasterChanged(mi *mesos.MasterInfo) {
|
||||
f(mi)
|
||||
}
|
||||
|
||||
// An abstraction of a Master detector which can be used to
|
||||
// detect the leading master from a group.
|
||||
type Master interface {
|
||||
// Detect new master election. Every time a new master is elected, the
|
||||
// detector will alert the observer. The first call to Detect is expected
|
||||
// to kickstart any background detection processing (and not before then).
|
||||
// If detection startup fails, or the listener cannot be added, then an
|
||||
// error is returned.
|
||||
Detect(MasterChanged) error
|
||||
|
||||
// returns a chan that, when closed, indicates the detector has terminated
|
||||
Done() <-chan struct{}
|
||||
|
||||
// cancel the detector. it's ok to call this multiple times, or even if
|
||||
// Detect() hasn't been invoked yet.
|
||||
Cancel()
|
||||
}
|
||||
244
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/standalone.go
generated
vendored
Normal file
244
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/standalone.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
package detector
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMesosHttpClientTimeout = 10 * time.Second //TODO(jdef) configurable via fiag?
|
||||
defaultMesosLeaderSyncInterval = 30 * time.Second //TODO(jdef) configurable via fiag?
|
||||
defaultMesosMasterPort = 5050
|
||||
)
|
||||
|
||||
// enables easier unit testing
|
||||
type fetcherFunc func(ctx context.Context, address string) (*upid.UPID, error)
|
||||
|
||||
type Standalone struct {
|
||||
ch chan *mesos.MasterInfo
|
||||
client *http.Client
|
||||
tr *http.Transport
|
||||
pollOnce sync.Once
|
||||
initial *mesos.MasterInfo
|
||||
done chan struct{}
|
||||
cancelOnce sync.Once
|
||||
leaderSyncInterval time.Duration
|
||||
httpClientTimeout time.Duration
|
||||
assumedMasterPort int
|
||||
poller func(pf fetcherFunc)
|
||||
fetchPid fetcherFunc
|
||||
}
|
||||
|
||||
// Create a new stand alone master detector.
|
||||
func NewStandalone(mi *mesos.MasterInfo) *Standalone {
|
||||
log.V(2).Infof("creating new standalone detector for %+v", mi)
|
||||
stand := &Standalone{
|
||||
ch: make(chan *mesos.MasterInfo),
|
||||
tr: &http.Transport{},
|
||||
initial: mi,
|
||||
done: make(chan struct{}),
|
||||
leaderSyncInterval: defaultMesosLeaderSyncInterval,
|
||||
httpClientTimeout: defaultMesosHttpClientTimeout,
|
||||
assumedMasterPort: defaultMesosMasterPort,
|
||||
}
|
||||
stand.poller = stand._poller
|
||||
stand.fetchPid = stand._fetchPid
|
||||
return stand
|
||||
}
|
||||
|
||||
func (s *Standalone) String() string {
|
||||
return fmt.Sprintf("{initial: %+v}", s.initial)
|
||||
}
|
||||
|
||||
// Detecting the new master.
|
||||
func (s *Standalone) Detect(o MasterChanged) error {
|
||||
log.V(2).Info("Detect()")
|
||||
s.pollOnce.Do(func() {
|
||||
log.V(1).Info("spinning up asyc master detector poller")
|
||||
// delayed initialization allows unit tests to modify timeouts before detection starts
|
||||
s.client = &http.Client{
|
||||
Transport: s.tr,
|
||||
Timeout: s.httpClientTimeout,
|
||||
}
|
||||
go s.poller(s.fetchPid)
|
||||
})
|
||||
if o != nil {
|
||||
log.V(1).Info("spawning asyc master detector listener")
|
||||
go func() {
|
||||
log.V(2).Infof("waiting for polled to send updates")
|
||||
pollWaiter:
|
||||
for {
|
||||
select {
|
||||
case mi, ok := <-s.ch:
|
||||
if !ok {
|
||||
break pollWaiter
|
||||
}
|
||||
log.V(1).Infof("detected master change: %+v", mi)
|
||||
o.OnMasterChanged(mi)
|
||||
case <-s.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
o.OnMasterChanged(nil)
|
||||
}()
|
||||
} else {
|
||||
log.Warningf("detect called with a nil master change listener")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Standalone) Done() <-chan struct{} {
|
||||
return s.done
|
||||
}
|
||||
|
||||
func (s *Standalone) Cancel() {
|
||||
s.cancelOnce.Do(func() { close(s.done) })
|
||||
}
|
||||
|
||||
// poll for changes to master leadership via current leader's /state.json endpoint.
|
||||
// we poll the `initial` leader, aborting if none was specified.
|
||||
//
|
||||
// TODO(jdef) follow the leader: change who we poll based on the prior leader
|
||||
// TODO(jdef) somehow determine all masters in cluster from the state.json?
|
||||
//
|
||||
func (s *Standalone) _poller(pf fetcherFunc) {
|
||||
defer func() {
|
||||
defer s.Cancel()
|
||||
log.Warning("shutting down standalone master detection")
|
||||
}()
|
||||
if s.initial == nil {
|
||||
log.Errorf("aborting master poller since initial master info is nil")
|
||||
return
|
||||
}
|
||||
addr := s.initial.GetHostname()
|
||||
if len(addr) == 0 {
|
||||
if s.initial.GetIp() == 0 {
|
||||
log.Warningf("aborted mater poller since initial master info has no host")
|
||||
return
|
||||
}
|
||||
ip := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(ip, s.initial.GetIp())
|
||||
addr = net.IP(ip).To4().String()
|
||||
}
|
||||
port := uint32(s.assumedMasterPort)
|
||||
if s.initial.Port != nil && *s.initial.Port != 0 {
|
||||
port = *s.initial.Port
|
||||
}
|
||||
addr = net.JoinHostPort(addr, strconv.Itoa(int(port)))
|
||||
log.V(1).Infof("polling for master leadership at '%v'", addr)
|
||||
var lastpid *upid.UPID
|
||||
for {
|
||||
startedAt := time.Now()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), s.leaderSyncInterval)
|
||||
if pid, err := pf(ctx, addr); err == nil {
|
||||
if !pid.Equal(lastpid) {
|
||||
log.V(2).Infof("detected leadership change from '%v' to '%v'", lastpid, pid)
|
||||
lastpid = pid
|
||||
elapsed := time.Now().Sub(startedAt)
|
||||
mi := CreateMasterInfo(pid)
|
||||
select {
|
||||
case s.ch <- mi: // noop
|
||||
case <-time.After(s.leaderSyncInterval - elapsed):
|
||||
// no one heard the master change, oh well - poll again
|
||||
goto continuePolling
|
||||
case <-s.done:
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.V(2).Infof("no change to master leadership: '%v'", lastpid)
|
||||
}
|
||||
} else if err == context.DeadlineExceeded {
|
||||
if lastpid != nil {
|
||||
lastpid = nil
|
||||
select {
|
||||
case s.ch <- nil: // lost master
|
||||
case <-s.done: // no need to cancel ctx
|
||||
return
|
||||
}
|
||||
}
|
||||
goto continuePolling
|
||||
} else {
|
||||
select {
|
||||
case <-s.done:
|
||||
cancel()
|
||||
return
|
||||
default:
|
||||
if err != context.Canceled {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if remaining := s.leaderSyncInterval - time.Now().Sub(startedAt); remaining > 0 {
|
||||
log.V(3).Infof("master leader poller sleeping for %v", remaining)
|
||||
time.Sleep(remaining)
|
||||
}
|
||||
continuePolling:
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that address is in host:port format
|
||||
func (s *Standalone) _fetchPid(ctx context.Context, address string) (*upid.UPID, error) {
|
||||
//TODO(jdef) need SSL support
|
||||
uri := fmt.Sprintf("http://%s/state.json", address)
|
||||
req, err := http.NewRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pid *upid.UPID
|
||||
err = s.httpDo(ctx, req, func(res *http.Response, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != 200 {
|
||||
return fmt.Errorf("HTTP request failed with code %d: %v", res.StatusCode, res.Status)
|
||||
}
|
||||
blob, err1 := ioutil.ReadAll(res.Body)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
log.V(3).Infof("Got mesos state, content length %v", len(blob))
|
||||
type State struct {
|
||||
Leader string `json:"leader"` // ex: master(1)@10.22.211.18:5050
|
||||
}
|
||||
state := &State{}
|
||||
err = json.Unmarshal(blob, state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pid, err = upid.Parse(state.Leader)
|
||||
return err
|
||||
})
|
||||
return pid, err
|
||||
}
|
||||
|
||||
type responseHandler func(*http.Response, error) error
|
||||
|
||||
// hacked from https://blog.golang.org/context
|
||||
func (s *Standalone) httpDo(ctx context.Context, req *http.Request, f responseHandler) error {
|
||||
// Run the HTTP request in a goroutine and pass the response to f.
|
||||
ch := make(chan error, 1)
|
||||
go func() { ch <- f(s.client.Do(req)) }()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s.tr.CancelRequest(req)
|
||||
<-ch // Wait for f to return.
|
||||
return ctx.Err()
|
||||
case err := <-ch:
|
||||
return err
|
||||
}
|
||||
}
|
||||
169
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/standalone_test.go
generated
vendored
Normal file
169
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/standalone_test.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package detector
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
"github.com/mesos/mesos-go/upid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
localhost = uint32(2130706433) // packed uint32 for 127.0.0.1 IPv4
|
||||
)
|
||||
|
||||
func TestStandalone_nil(t *testing.T) {
|
||||
d := NewStandalone(nil)
|
||||
select {
|
||||
case <-d.Done(): // expected
|
||||
t.Fatalf("expected detector to stay alive since we haven't done anything with it")
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
}
|
||||
d.Detect(nil)
|
||||
select {
|
||||
case <-d.Done(): // expected
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected detector to shutdown since it has no master")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandalone_pollerIncompleteInfo(t *testing.T) {
|
||||
d := NewStandalone(&mesos.MasterInfo{})
|
||||
f := fetcherFunc(func(context.Context, string) (*upid.UPID, error) {
|
||||
return nil, nil
|
||||
})
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
defer close(ch)
|
||||
d.poller(f)
|
||||
}()
|
||||
select {
|
||||
case <-ch: // expected
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected poller to shutdown since master info is incomplete")
|
||||
}
|
||||
select {
|
||||
case <-d.Done(): // expected
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected detector to shutdown since it has no master")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandalone_pollerFetched(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// presence of IP address allows fecher to be called
|
||||
d := NewStandalone(&mesos.MasterInfo{Ip: proto.Uint32(localhost)})
|
||||
defer d.Cancel()
|
||||
|
||||
fetched := make(chan struct{})
|
||||
pid := &upid.UPID{
|
||||
ID: "foo@127.0.0.1:5050",
|
||||
Host: "127.0.0.1",
|
||||
Port: "5050",
|
||||
}
|
||||
f := fetcherFunc(func(ctx context.Context, addr string) (*upid.UPID, error) {
|
||||
defer close(fetched)
|
||||
assert.Equal("127.0.0.1:5050", addr)
|
||||
return pid, nil
|
||||
})
|
||||
|
||||
go d.poller(f)
|
||||
|
||||
// fetch called
|
||||
select {
|
||||
case <-fetched: // expected
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected fetch")
|
||||
}
|
||||
|
||||
// read MasterInfo
|
||||
select {
|
||||
case mi := <-d.ch:
|
||||
assert.Equal(mi, CreateMasterInfo(pid))
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected poller to send master info")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandalone_pollerFetchedMulti(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
// presence of IP address allows fecher to be called
|
||||
d := NewStandalone(&mesos.MasterInfo{Ip: proto.Uint32(localhost)})
|
||||
defer d.Cancel()
|
||||
d.leaderSyncInterval = 500 * time.Millisecond
|
||||
|
||||
i := 0
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(4)
|
||||
f := fetcherFunc(func(ctx context.Context, addr string) (*upid.UPID, error) {
|
||||
defer func() { i++ }()
|
||||
switch i {
|
||||
case 0:
|
||||
wg.Done()
|
||||
assert.Equal("127.0.0.1:5050", addr)
|
||||
return &upid.UPID{ID: "foo@127.0.0.1:5050", Host: "127.0.0.1", Port: "5050"}, nil
|
||||
case 1:
|
||||
wg.Done()
|
||||
assert.Equal("127.0.0.1:5050", addr)
|
||||
return &upid.UPID{ID: "foo@127.0.0.2:5050", Host: "127.0.0.2", Port: "5050"}, nil
|
||||
case 2:
|
||||
wg.Done()
|
||||
return nil, context.DeadlineExceeded
|
||||
case 3:
|
||||
wg.Done()
|
||||
assert.Equal("127.0.0.1:5050", addr)
|
||||
return &upid.UPID{ID: "foo@127.0.0.3:5050", Host: "127.0.0.3", Port: "5050"}, nil
|
||||
default:
|
||||
d.Cancel()
|
||||
return nil, context.Canceled
|
||||
}
|
||||
})
|
||||
|
||||
go d.poller(f)
|
||||
|
||||
// fetches complete
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
defer close(ch)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
changed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(changed)
|
||||
for i := 0; i < 4; i++ {
|
||||
if mi, ok := <-d.ch; !ok {
|
||||
t.Fatalf("failed to read master info on cycle %v", i)
|
||||
break
|
||||
} else {
|
||||
switch i {
|
||||
case 0:
|
||||
assert.Equal(CreateMasterInfo(&upid.UPID{ID: "foo@127.0.0.1:5050", Host: "127.0.0.1", Port: "5050"}), mi)
|
||||
case 1:
|
||||
assert.Equal(CreateMasterInfo(&upid.UPID{ID: "foo@127.0.0.2:5050", Host: "127.0.0.2", Port: "5050"}), mi)
|
||||
case 2:
|
||||
assert.Nil(mi)
|
||||
case 3:
|
||||
assert.Equal(CreateMasterInfo(&upid.UPID{ID: "foo@127.0.0.3:5050", Host: "127.0.0.3", Port: "5050"}), mi)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
started := time.Now()
|
||||
select {
|
||||
case <-ch: // expected
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("expected fetches all complete")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-changed: // expected
|
||||
case <-time.After((3 * time.Second) - time.Now().Sub(started)):
|
||||
t.Fatalf("expected to have received all master info changes")
|
||||
}
|
||||
}
|
||||
447
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/client.go
generated
vendored
Normal file
447
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/client.go
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultSessionTimeout = 60 * time.Second
|
||||
defaultReconnectTimeout = 5 * time.Second
|
||||
currentPath = "."
|
||||
defaultRewatchDelay = 200 * time.Millisecond
|
||||
)
|
||||
|
||||
type stateType int32
|
||||
|
||||
const (
|
||||
disconnectedState stateType = iota
|
||||
connectionRequestedState
|
||||
connectionAttemptState
|
||||
connectedState
|
||||
)
|
||||
|
||||
func (s stateType) String() string {
|
||||
switch s {
|
||||
case disconnectedState:
|
||||
return "DISCONNECTED"
|
||||
case connectionRequestedState:
|
||||
return "REQUESTED"
|
||||
case connectionAttemptState:
|
||||
return "ATTEMPT"
|
||||
case connectedState:
|
||||
return "CONNECTED"
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized state: %d", int32(s)))
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
conn Connector
|
||||
defaultFactory Factory
|
||||
factory Factory // must never be nil, use setFactory to update
|
||||
state stateType
|
||||
reconnCount uint64
|
||||
reconnDelay time.Duration
|
||||
rootPath string
|
||||
errorHandler ErrorHandler // must never be nil
|
||||
connectOnce sync.Once
|
||||
stopOnce sync.Once
|
||||
shouldStop chan struct{} // signal chan
|
||||
shouldReconn chan struct{} // message chan
|
||||
connLock sync.Mutex
|
||||
hasConnected chan struct{} // message chan
|
||||
rewatchDelay time.Duration
|
||||
}
|
||||
|
||||
func newClient(hosts []string, path string) (*Client, error) {
|
||||
zkc := &Client{
|
||||
reconnDelay: defaultReconnectTimeout,
|
||||
rewatchDelay: defaultRewatchDelay,
|
||||
rootPath: path,
|
||||
shouldStop: make(chan struct{}),
|
||||
shouldReconn: make(chan struct{}, 1),
|
||||
hasConnected: make(chan struct{}, 1),
|
||||
errorHandler: ErrorHandler(func(*Client, error) {}),
|
||||
defaultFactory: asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
return zk.Connect(hosts, defaultSessionTimeout)
|
||||
}),
|
||||
}
|
||||
zkc.setFactory(zkc.defaultFactory)
|
||||
// TODO(vlad): validate URIs
|
||||
return zkc, nil
|
||||
}
|
||||
|
||||
func (zkc *Client) setFactory(f Factory) {
|
||||
if f == nil {
|
||||
f = zkc.defaultFactory
|
||||
}
|
||||
zkc.factory = asFactory(func() (c Connector, ch <-chan zk.Event, err error) {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
err = errors.New("client stopping")
|
||||
default:
|
||||
zkc.connLock.Lock()
|
||||
defer zkc.connLock.Unlock()
|
||||
if zkc.conn != nil {
|
||||
zkc.conn.Close()
|
||||
}
|
||||
c, ch, err = f.create()
|
||||
zkc.conn = c
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// return true only if the client's state was changed from `from` to `to`
|
||||
func (zkc *Client) stateChange(from, to stateType) (result bool) {
|
||||
defer func() {
|
||||
log.V(3).Infof("stateChange: from=%v to=%v result=%v", from, to, result)
|
||||
}()
|
||||
result = atomic.CompareAndSwapInt32((*int32)(&zkc.state), int32(from), int32(to))
|
||||
return
|
||||
}
|
||||
|
||||
// connect to zookeeper, blocks on the initial call to doConnect()
|
||||
func (zkc *Client) connect() {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
return
|
||||
default:
|
||||
zkc.connectOnce.Do(func() {
|
||||
if zkc.stateChange(disconnectedState, connectionRequestedState) {
|
||||
if err := zkc.doConnect(); err != nil {
|
||||
log.Error(err)
|
||||
zkc.errorHandler(zkc, err)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
zkc.connLock.Lock()
|
||||
defer zkc.connLock.Unlock()
|
||||
if zkc.conn != nil {
|
||||
zkc.conn.Close()
|
||||
}
|
||||
return
|
||||
case <-zkc.shouldReconn:
|
||||
if err := zkc.reconnect(); err != nil {
|
||||
log.Error(err)
|
||||
zkc.errorHandler(zkc, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// attempt to reconnect to zookeeper. will ignore attempts to reconnect
|
||||
// if not disconnected. if reconnection is attempted then this func will block
|
||||
// for at least reconnDelay before actually attempting to connect to zookeeper.
|
||||
func (zkc *Client) reconnect() error {
|
||||
if !zkc.stateChange(disconnectedState, connectionRequestedState) {
|
||||
log.V(4).Infoln("Ignoring reconnect, currently connected/connecting.")
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() { zkc.reconnCount++ }()
|
||||
|
||||
log.V(4).Infoln("Delaying reconnection for ", zkc.reconnDelay)
|
||||
<-time.After(zkc.reconnDelay)
|
||||
|
||||
return zkc.doConnect()
|
||||
}
|
||||
|
||||
func (zkc *Client) doConnect() error {
|
||||
if !zkc.stateChange(connectionRequestedState, connectionAttemptState) {
|
||||
log.V(4).Infoln("aborting doConnect, connection attempt already in progress or else disconnected")
|
||||
return nil
|
||||
}
|
||||
|
||||
// if we're not connected by the time we return then we failed.
|
||||
defer func() {
|
||||
zkc.stateChange(connectionAttemptState, disconnectedState)
|
||||
}()
|
||||
|
||||
// create Connector instance
|
||||
conn, sessionEvents, err := zkc.factory.create()
|
||||
if err != nil {
|
||||
// once the factory stops producing connectors, it's time to stop
|
||||
zkc.stop()
|
||||
return err
|
||||
}
|
||||
|
||||
zkc.connLock.Lock()
|
||||
zkc.conn = conn
|
||||
zkc.connLock.Unlock()
|
||||
|
||||
log.V(4).Infof("Created connection object of type %T\n", conn)
|
||||
connected := make(chan struct{})
|
||||
sessionExpired := make(chan struct{})
|
||||
go func() {
|
||||
defer close(sessionExpired)
|
||||
zkc.monitorSession(sessionEvents, connected)
|
||||
}()
|
||||
|
||||
// wait for connected confirmation
|
||||
select {
|
||||
case <-connected:
|
||||
if !zkc.stateChange(connectionAttemptState, connectedState) {
|
||||
log.V(4).Infoln("failed to transition to connected state")
|
||||
// we could be:
|
||||
// - disconnected ... reconnect() will try to connect again, otherwise;
|
||||
// - connected ... another goroutine already established a connection
|
||||
// - connectionRequested ... another goroutine is already trying to connect
|
||||
zkc.requestReconnect()
|
||||
}
|
||||
log.Infoln("zookeeper client connected")
|
||||
case <-sessionExpired:
|
||||
// connection was disconnected before it was ever really 'connected'
|
||||
if !zkc.stateChange(connectionAttemptState, disconnectedState) {
|
||||
//programming error
|
||||
panic("failed to transition from connection-attempt to disconnected state")
|
||||
}
|
||||
zkc.requestReconnect()
|
||||
case <-zkc.shouldStop:
|
||||
// noop
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// signal for reconnect unless we're shutting down
|
||||
func (zkc *Client) requestReconnect() {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
// abort reconnect request, client is shutting down
|
||||
default:
|
||||
select {
|
||||
case zkc.shouldReconn <- struct{}{}:
|
||||
// reconnect request successful
|
||||
default:
|
||||
// reconnect chan is full: reconnect has already
|
||||
// been requested. move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// monitor a zookeeper session event channel, closes the 'connected' channel once
|
||||
// a zookeeper connection has been established. errors are forwarded to the client's
|
||||
// errorHandler. the closing of the sessionEvents chan triggers a call to client.onDisconnected.
|
||||
// this func blocks until either the client's shouldStop or sessionEvents chan are closed.
|
||||
func (zkc *Client) monitorSession(sessionEvents <-chan zk.Event, connected chan struct{}) {
|
||||
firstConnected := true
|
||||
for {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
return
|
||||
case e, ok := <-sessionEvents:
|
||||
if !ok {
|
||||
// once sessionEvents is closed, the embedded ZK client will
|
||||
// no longer attempt to reconnect.
|
||||
zkc.onDisconnected()
|
||||
return
|
||||
} else if e.Err != nil {
|
||||
log.Errorf("received state error: %s", e.Err.Error())
|
||||
zkc.errorHandler(zkc, e.Err)
|
||||
}
|
||||
switch e.State {
|
||||
case zk.StateConnecting:
|
||||
log.Infoln("connecting to zookeeper..")
|
||||
|
||||
case zk.StateConnected:
|
||||
log.V(2).Infoln("received StateConnected")
|
||||
if firstConnected {
|
||||
close(connected) // signal session listener
|
||||
firstConnected = false
|
||||
}
|
||||
// let any listeners know about the change
|
||||
select {
|
||||
case <-zkc.shouldStop: // noop
|
||||
case zkc.hasConnected <- struct{}{}: // noop
|
||||
default: // message buf full, this becomes a non-blocking noop
|
||||
}
|
||||
|
||||
case zk.StateSyncConnected:
|
||||
log.Infoln("syncConnected to zookper server")
|
||||
|
||||
case zk.StateDisconnected:
|
||||
log.Infoln("zookeeper client disconnected")
|
||||
|
||||
case zk.StateExpired:
|
||||
log.Infoln("zookeeper client session expired")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// watch the child nodes for changes, at the specified path.
|
||||
// callers that specify a path of `currentPath` will watch the currently set rootPath,
|
||||
// otherwise the watchedPath is calculated as rootPath+path.
|
||||
// this func spawns a go routine to actually do the watching, and so returns immediately.
|
||||
// in the absense of errors a signalling channel is returned that will close
|
||||
// upon the termination of the watch (e.g. due to disconnection).
|
||||
func (zkc *Client) watchChildren(path string, watcher ChildWatcher) (<-chan struct{}, error) {
|
||||
watchPath := zkc.rootPath
|
||||
if path != "" && path != currentPath {
|
||||
watchPath = watchPath + path
|
||||
}
|
||||
|
||||
log.V(2).Infoln("Watching children for path", watchPath)
|
||||
watchEnded := make(chan struct{})
|
||||
go func() {
|
||||
defer close(watchEnded)
|
||||
zkc._watchChildren(watchPath, watcher)
|
||||
}()
|
||||
return watchEnded, nil
|
||||
}
|
||||
|
||||
// continuation of watchChildren. blocks until either underlying zk connector terminates, or else this
|
||||
// client is shut down. continuously renews child watches.
|
||||
func (zkc *Client) _watchChildren(watchPath string, watcher ChildWatcher) {
|
||||
watcher(zkc, watchPath) // prime the listener
|
||||
var zkevents <-chan zk.Event
|
||||
var err error
|
||||
first := true
|
||||
for {
|
||||
// we really only expect this to happen when zk session has expired,
|
||||
// give the connection a little time to re-establish itself
|
||||
for {
|
||||
//TODO(jdef) it would be better if we could listen for broadcast Connection/Disconnection events,
|
||||
//emitted whenever the embedded client cycles (read: when the connection state of this client changes).
|
||||
//As it currently stands, if the embedded client cycles fast enough, we may actually not notice it here
|
||||
//and keep on watching like nothing bad happened.
|
||||
if !zkc.isConnected() {
|
||||
log.Warningf("no longer connected to server, exiting child watch")
|
||||
return
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
return
|
||||
case <-time.After(zkc.rewatchDelay):
|
||||
}
|
||||
}
|
||||
_, _, zkevents, err = zkc.conn.ChildrenW(watchPath)
|
||||
if err == nil {
|
||||
log.V(2).Infoln("rewatching children for path", watchPath)
|
||||
break
|
||||
}
|
||||
log.V(1).Infof("unable to watch children for path %s: %s", watchPath, err.Error())
|
||||
zkc.errorHandler(zkc, err)
|
||||
}
|
||||
// zkevents is (at most) a one-trick channel
|
||||
// (a) a child event happens (no error)
|
||||
// (b) the embedded client is shutting down (zk.ErrClosing)
|
||||
// (c) the zk session expires (zk.ErrSessionExpired)
|
||||
select {
|
||||
case <-zkc.shouldStop:
|
||||
return
|
||||
case e, ok := <-zkevents:
|
||||
if !ok {
|
||||
log.Warningf("expected a single zk event before channel close")
|
||||
break // the select
|
||||
}
|
||||
switch e.Type {
|
||||
//TODO(jdef) should we not also watch for EventNode{Created,Deleted,DataChanged}?
|
||||
case zk.EventNodeChildrenChanged:
|
||||
log.V(2).Infoln("Handling: zk.EventNodeChildrenChanged")
|
||||
watcher(zkc, e.Path)
|
||||
continue
|
||||
default:
|
||||
if e.Err != nil {
|
||||
zkc.errorHandler(zkc, e.Err)
|
||||
if e.Type == zk.EventNotWatching && e.State == zk.StateDisconnected {
|
||||
if e.Err == zk.ErrClosing {
|
||||
log.V(1).Infof("watch invalidated, embedded client terminating")
|
||||
return
|
||||
}
|
||||
log.V(1).Infof("watch invalidated, attempting to watch again: %v", e.Err)
|
||||
} else {
|
||||
log.Warningf("received error while watching path %s: %s", watchPath, e.Err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (zkc *Client) onDisconnected() {
|
||||
if st := zkc.getState(); st == connectedState && zkc.stateChange(st, disconnectedState) {
|
||||
log.Infoln("disconnected from the server, reconnecting...")
|
||||
zkc.requestReconnect()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// return a channel that gets an empty struct every time a connection happens
|
||||
func (zkc *Client) connections() <-chan struct{} {
|
||||
return zkc.hasConnected
|
||||
}
|
||||
|
||||
func (zkc *Client) getState() stateType {
|
||||
return stateType(atomic.LoadInt32((*int32)(&zkc.state)))
|
||||
}
|
||||
|
||||
// convenience function
|
||||
func (zkc *Client) isConnected() bool {
|
||||
return zkc.getState() == connectedState
|
||||
}
|
||||
|
||||
// convenience function
|
||||
func (zkc *Client) isConnecting() bool {
|
||||
state := zkc.getState()
|
||||
return state == connectionRequestedState || state == connectionAttemptState
|
||||
}
|
||||
|
||||
// convenience function
|
||||
func (zkc *Client) isDisconnected() bool {
|
||||
return zkc.getState() == disconnectedState
|
||||
}
|
||||
|
||||
func (zkc *Client) list(path string) ([]string, error) {
|
||||
if !zkc.isConnected() {
|
||||
return nil, errors.New("Unable to list children, client not connected.")
|
||||
}
|
||||
|
||||
children, _, err := zkc.conn.Children(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return children, nil
|
||||
}
|
||||
|
||||
func (zkc *Client) data(path string) ([]byte, error) {
|
||||
if !zkc.isConnected() {
|
||||
return nil, errors.New("Unable to retrieve node data, client not connected.")
|
||||
}
|
||||
|
||||
data, _, err := zkc.conn.Get(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (zkc *Client) stop() {
|
||||
zkc.stopOnce.Do(func() {
|
||||
close(zkc.shouldStop)
|
||||
})
|
||||
}
|
||||
|
||||
// when this channel is closed the client is either stopping, or has stopped
|
||||
func (zkc *Client) stopped() <-chan struct{} {
|
||||
return zkc.shouldStop
|
||||
}
|
||||
339
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/client_test.go
generated
vendored
Normal file
339
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/client_test.go
generated
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
util "github.com/mesos/mesos-go/mesosutil"
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var test_zk_hosts = []string{"localhost:2181"}
|
||||
|
||||
const (
|
||||
test_zk_path = "/test"
|
||||
)
|
||||
|
||||
func TestClientNew(t *testing.T) {
|
||||
path := "/mesos"
|
||||
chEvent := make(chan zk.Event)
|
||||
connector := makeMockConnector(path, chEvent)
|
||||
|
||||
c, err := newClient(test_zk_hosts, path)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, c)
|
||||
assert.False(t, c.isConnected())
|
||||
c.conn = connector
|
||||
|
||||
}
|
||||
|
||||
// This test requires zookeeper to be running.
|
||||
// You must also set env variable ZK_HOSTS to point to zk hosts.
|
||||
// The zk package does not offer a way to mock its connection function.
|
||||
func TestClientConnectIntegration(t *testing.T) {
|
||||
if os.Getenv("ZK_HOSTS") == "" {
|
||||
t.Skip("Skipping zk-server connection test: missing env ZK_HOSTS.")
|
||||
}
|
||||
hosts := strings.Split(os.Getenv("ZK_HOSTS"), ",")
|
||||
c, err := newClient(hosts, "/mesos")
|
||||
assert.NoError(t, err)
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
err = e
|
||||
})
|
||||
c.connect()
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.connect()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, c.isConnected())
|
||||
}
|
||||
|
||||
func TestClientConnect(t *testing.T) {
|
||||
c, err := makeClient()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, c.isConnected())
|
||||
c.connect()
|
||||
assert.True(t, c.isConnected())
|
||||
assert.False(t, c.isConnecting())
|
||||
}
|
||||
|
||||
func TestClient_FlappingConnection(t *testing.T) {
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
c.reconnDelay = 10 * time.Millisecond // we don't want this test to take forever
|
||||
defer c.stop()
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
attempts := 0
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
log.V(2).Infof("**** Using zk.Conn adapter ****")
|
||||
ch0 := make(chan zk.Event, 10) // session chan
|
||||
ch1 := make(chan zk.Event) // watch chan
|
||||
go func() {
|
||||
if attempts > 1 {
|
||||
t.Fatalf("only one connector instance is expected")
|
||||
}
|
||||
attempts++
|
||||
for i := 0; i < 4; i++ {
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnecting,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateDisconnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
}
|
||||
}()
|
||||
connector := makeMockConnector(test_zk_path, ch1)
|
||||
return connector, ch0, nil
|
||||
}))
|
||||
|
||||
go c.connect()
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.True(t, c.isConnected())
|
||||
assert.Equal(t, 1, attempts)
|
||||
}
|
||||
|
||||
func TestClientWatchChildren(t *testing.T) {
|
||||
c, err := makeClient()
|
||||
assert.NoError(t, err)
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
err = e
|
||||
})
|
||||
c.connect()
|
||||
assert.NoError(t, err)
|
||||
wCh := make(chan struct{}, 1)
|
||||
childrenWatcher := ChildWatcher(func(zkc *Client, path string) {
|
||||
log.V(4).Infoln("Path", path, "changed!")
|
||||
children, err := c.list(path)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(children))
|
||||
assert.Equal(t, "info_0", children[0])
|
||||
assert.Equal(t, "info_5", children[1])
|
||||
assert.Equal(t, "info_10", children[2])
|
||||
wCh <- struct{}{}
|
||||
})
|
||||
|
||||
_, err = c.watchChildren(currentPath, childrenWatcher)
|
||||
assert.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-wCh:
|
||||
case <-time.After(time.Millisecond * 700):
|
||||
panic("Waited too long...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientWatchErrors(t *testing.T) {
|
||||
path := "/test"
|
||||
ch := make(chan zk.Event, 1)
|
||||
ch <- zk.Event{
|
||||
Type: zk.EventNotWatching,
|
||||
Err: errors.New("Event Error"),
|
||||
}
|
||||
|
||||
c, err := makeClient()
|
||||
c.state = connectedState
|
||||
|
||||
assert.NoError(t, err)
|
||||
c.conn = makeMockConnector(path, (<-chan zk.Event)(ch))
|
||||
wCh := make(chan struct{}, 1)
|
||||
c.errorHandler = ErrorHandler(func(zkc *Client, err error) {
|
||||
assert.Error(t, err)
|
||||
wCh <- struct{}{}
|
||||
})
|
||||
|
||||
c.watchChildren(currentPath, ChildWatcher(func(*Client, string) {}))
|
||||
|
||||
select {
|
||||
case <-wCh:
|
||||
case <-time.After(time.Millisecond * 700):
|
||||
t.Fatalf("timed out waiting for error message")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWatchChildren_flappy(t *testing.T) {
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
c.reconnDelay = 10 * time.Millisecond // we don't want this test to take forever
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
attempts := 0
|
||||
conn := NewMockConnector()
|
||||
defer func() {
|
||||
if !t.Failed() {
|
||||
conn.AssertExpectations(t)
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
// stop client and give it time to shut down the connector
|
||||
c.stop()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}()
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
log.V(2).Infof("**** Using zk.Conn adapter ****")
|
||||
ch0 := make(chan zk.Event, 10) // session chan
|
||||
ch1 := make(chan zk.Event) // watch chan
|
||||
go func() {
|
||||
if attempts > 1 {
|
||||
t.Fatalf("only one connector instance is expected")
|
||||
}
|
||||
attempts++
|
||||
for i := 0; i < 4; i++ {
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnecting,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateDisconnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
}
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnecting,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
ch1 <- zk.Event{
|
||||
Type: zk.EventNodeChildrenChanged,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
}()
|
||||
simulatedErr := errors.New("simulated watch error")
|
||||
conn.On("ChildrenW", test_zk_path).Return(nil, nil, nil, simulatedErr).Times(4)
|
||||
conn.On("ChildrenW", test_zk_path).Return([]string{test_zk_path}, &zk.Stat{}, (<-chan zk.Event)(ch1), nil)
|
||||
conn.On("Close").Return(nil)
|
||||
return conn, ch0, nil
|
||||
}))
|
||||
|
||||
go c.connect()
|
||||
watchChildrenCount := 0
|
||||
watcherFunc := ChildWatcher(func(zkc *Client, path string) {
|
||||
log.V(1).Infof("ChildWatcher invoked %d", watchChildrenCount)
|
||||
})
|
||||
startTime := time.Now()
|
||||
endTime := startTime.Add(2 * time.Second)
|
||||
watcherLoop:
|
||||
for time.Now().Before(endTime) {
|
||||
log.V(1).Infof("entered watcherLoop")
|
||||
select {
|
||||
case <-c.connections():
|
||||
log.V(1).Infof("invoking watchChildren")
|
||||
if _, err := c.watchChildren(currentPath, watcherFunc); err == nil {
|
||||
// watching children succeeded!!
|
||||
t.Logf("child watch success")
|
||||
watchChildrenCount++
|
||||
} else {
|
||||
// setting the watch failed
|
||||
t.Logf("setting child watch failed: %v", err)
|
||||
continue watcherLoop
|
||||
}
|
||||
case <-c.stopped():
|
||||
t.Logf("detected client termination")
|
||||
break watcherLoop
|
||||
case <-time.After(endTime.Sub(time.Now())):
|
||||
}
|
||||
}
|
||||
assert.Equal(t, 5, watchChildrenCount, "expected watchChildrenCount = 5 instead of %d, should be reinvoked upon initial ChildrenW failures", watchChildrenCount)
|
||||
}
|
||||
|
||||
func makeClient() (*Client, error) {
|
||||
ch0 := make(chan zk.Event, 2)
|
||||
ch1 := make(chan zk.Event, 1)
|
||||
|
||||
ch0 <- zk.Event{
|
||||
State: zk.StateConnected,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
ch1 <- zk.Event{
|
||||
Type: zk.EventNodeChildrenChanged,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
ch0 <- zk.Event{
|
||||
State: zk.StateDisconnected,
|
||||
}
|
||||
close(ch0)
|
||||
close(ch1)
|
||||
}()
|
||||
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// only allow a single connection
|
||||
first := true
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
if !first {
|
||||
return nil, nil, errors.New("only a single connection attempt allowed for mock connector")
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
log.V(2).Infof("**** Using zk.Conn adapter ****")
|
||||
connector := makeMockConnector(test_zk_path, ch1)
|
||||
return connector, ch0, nil
|
||||
}))
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func makeMockConnector(path string, chEvent <-chan zk.Event) *MockConnector {
|
||||
log.V(2).Infoln("Making Connector mock.")
|
||||
conn := NewMockConnector()
|
||||
conn.On("Close").Return(nil)
|
||||
conn.On("ChildrenW", path).Return([]string{path}, &zk.Stat{}, chEvent, nil)
|
||||
conn.On("Children", path).Return([]string{"info_0", "info_5", "info_10"}, &zk.Stat{}, nil)
|
||||
conn.On("Get", fmt.Sprintf("%s/info_0", path)).Return(makeTestMasterInfo(), &zk.Stat{}, nil)
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func newTestMasterInfo(id int) []byte {
|
||||
miPb := util.NewMasterInfo(fmt.Sprintf("master(%d)@localhost:5050", id), 123456789, 400)
|
||||
data, err := proto.Marshal(miPb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func makeTestMasterInfo() []byte {
|
||||
miPb := util.NewMasterInfo("master@localhost:5050", 123456789, 400)
|
||||
data, err := proto.Marshal(miPb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
231
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/detect.go
generated
vendored
Normal file
231
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/detect.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
)
|
||||
|
||||
const (
|
||||
// prefix for nodes listed at the ZK URL path
|
||||
nodePrefix = "info_"
|
||||
defaultMinDetectorCyclePeriod = 1 * time.Second
|
||||
)
|
||||
|
||||
// reasonable default for a noop change listener
|
||||
var ignoreChanged = detector.OnMasterChanged(func(*mesos.MasterInfo) {})
|
||||
|
||||
// Detector uses ZooKeeper to detect new leading master.
|
||||
type MasterDetector struct {
|
||||
client *Client
|
||||
leaderNode string
|
||||
|
||||
// for one-time zk client initiation
|
||||
bootstrap sync.Once
|
||||
|
||||
// latch: only install, at most, one ignoreChanged listener; see MasterDetector.Detect
|
||||
ignoreInstalled int32
|
||||
|
||||
// detection should not signal master change listeners more frequently than this
|
||||
minDetectorCyclePeriod time.Duration
|
||||
}
|
||||
|
||||
// Internal constructor function
|
||||
func NewMasterDetector(zkurls string) (*MasterDetector, error) {
|
||||
zkHosts, zkPath, err := parseZk(zkurls)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to parse url", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := newClient(zkHosts, zkPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
detector := &MasterDetector{
|
||||
client: client,
|
||||
minDetectorCyclePeriod: defaultMinDetectorCyclePeriod,
|
||||
}
|
||||
|
||||
log.V(2).Infoln("Created new detector, watching ", zkHosts, zkPath)
|
||||
return detector, nil
|
||||
}
|
||||
|
||||
func parseZk(zkurls string) ([]string, string, error) {
|
||||
u, err := url.Parse(zkurls)
|
||||
if err != nil {
|
||||
log.V(1).Infof("failed to parse url: %v", err)
|
||||
return nil, "", err
|
||||
}
|
||||
if u.Scheme != "zk" {
|
||||
return nil, "", fmt.Errorf("invalid url scheme for zk url: '%v'", u.Scheme)
|
||||
}
|
||||
return strings.Split(u.Host, ","), u.Path, nil
|
||||
}
|
||||
|
||||
// returns a chan that, when closed, indicates termination of the detector
|
||||
func (md *MasterDetector) Done() <-chan struct{} {
|
||||
return md.client.stopped()
|
||||
}
|
||||
|
||||
func (md *MasterDetector) Cancel() {
|
||||
md.client.stop()
|
||||
}
|
||||
|
||||
//TODO(jdef) execute async because we don't want to stall our client's event loop? if so
|
||||
//then we also probably want serial event delivery (aka. delivery via a chan) but then we
|
||||
//have to deal with chan buffer sizes .. ugh. This is probably the least painful for now.
|
||||
func (md *MasterDetector) childrenChanged(zkc *Client, path string, obs detector.MasterChanged) {
|
||||
log.V(2).Infof("fetching children at path '%v'", path)
|
||||
list, err := zkc.list(path)
|
||||
if err != nil {
|
||||
log.Warning(err)
|
||||
return
|
||||
}
|
||||
|
||||
topNode := selectTopNode(list)
|
||||
|
||||
if md.leaderNode == topNode {
|
||||
log.V(2).Infof("ignoring children-changed event, leader has not changed: %v", path)
|
||||
return
|
||||
}
|
||||
|
||||
log.V(2).Infof("changing leader node from %s -> %s", md.leaderNode, topNode)
|
||||
md.leaderNode = topNode
|
||||
|
||||
var masterInfo *mesos.MasterInfo
|
||||
if md.leaderNode != "" {
|
||||
data, err := zkc.data(fmt.Sprintf("%s/%s", path, topNode))
|
||||
if err != nil {
|
||||
log.Errorf("unable to retrieve leader data: %v", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
masterInfo = new(mesos.MasterInfo)
|
||||
err = proto.Unmarshal(data, masterInfo)
|
||||
if err != nil {
|
||||
log.Errorf("unable to unmarshall MasterInfo data from zookeeper: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.V(2).Infof("detected master info: %+v", masterInfo)
|
||||
obs.OnMasterChanged(masterInfo)
|
||||
}
|
||||
|
||||
// the first call to Detect will kickstart a connection to zookeeper. a nil change listener may
|
||||
// be spec'd, result of which is a detector that will still listen for master changes and record
|
||||
// leaderhip changes internally but no listener would be notified. Detect may be called more than
|
||||
// once, and each time the spec'd listener will be added to the list of those receiving notifications.
|
||||
func (md *MasterDetector) Detect(f detector.MasterChanged) (err error) {
|
||||
// kickstart zk client connectivity
|
||||
md.bootstrap.Do(func() { go md.client.connect() })
|
||||
|
||||
if f == nil {
|
||||
// only ever install, at most, one ignoreChanged listener. multiple instances of it
|
||||
// just consume resources and generate misleading log messages.
|
||||
if !atomic.CompareAndSwapInt32(&md.ignoreInstalled, 0, 1) {
|
||||
return
|
||||
}
|
||||
f = ignoreChanged
|
||||
}
|
||||
|
||||
go md.detect(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MasterDetector) detect(f detector.MasterChanged) {
|
||||
detectLoop:
|
||||
for {
|
||||
started := time.Now()
|
||||
select {
|
||||
case <-md.Done():
|
||||
return
|
||||
case <-md.client.connections():
|
||||
// we let the golang runtime manage our listener list for us, in form of goroutines that
|
||||
// callback to the master change notification listen func's
|
||||
if watchEnded, err := md.client.watchChildren(currentPath, ChildWatcher(func(zkc *Client, path string) {
|
||||
md.childrenChanged(zkc, path, f)
|
||||
})); err == nil {
|
||||
log.V(2).Infoln("detector listener installed")
|
||||
select {
|
||||
case <-watchEnded:
|
||||
if md.leaderNode != "" {
|
||||
log.V(1).Infof("child watch ended, signaling master lost")
|
||||
md.leaderNode = ""
|
||||
f.OnMasterChanged(nil)
|
||||
}
|
||||
case <-md.client.stopped():
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.V(1).Infof("child watch ended with error: %v", err)
|
||||
continue detectLoop
|
||||
}
|
||||
}
|
||||
// rate-limit master changes
|
||||
if elapsed := time.Now().Sub(started); elapsed > 0 {
|
||||
log.V(2).Infoln("resting before next detection cycle")
|
||||
select {
|
||||
case <-md.Done():
|
||||
return
|
||||
case <-time.After(md.minDetectorCyclePeriod - elapsed): // noop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func selectTopNode(list []string) (node string) {
|
||||
var leaderSeq uint64 = math.MaxUint64
|
||||
|
||||
for _, v := range list {
|
||||
if !strings.HasPrefix(v, nodePrefix) {
|
||||
continue // only care about participants
|
||||
}
|
||||
seqStr := strings.TrimPrefix(v, nodePrefix)
|
||||
seq, err := strconv.ParseUint(seqStr, 10, 64)
|
||||
if err != nil {
|
||||
log.Warningf("unexpected zk node format '%s': %v", seqStr, err)
|
||||
continue
|
||||
}
|
||||
if seq < leaderSeq {
|
||||
leaderSeq = seq
|
||||
node = v
|
||||
}
|
||||
}
|
||||
|
||||
if node == "" {
|
||||
log.V(3).Infoln("No top node found.")
|
||||
} else {
|
||||
log.V(3).Infof("Top node selected: '%s'", node)
|
||||
}
|
||||
return node
|
||||
}
|
||||
427
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/detect_test.go
generated
vendored
Normal file
427
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/detect_test.go
generated
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
zkurl = "zk://127.0.0.1:2181/mesos"
|
||||
zkurl_bad = "zk://127.0.0.1:2181"
|
||||
)
|
||||
|
||||
func TestParseZk_single(t *testing.T) {
|
||||
hosts, path, err := parseZk(zkurl)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(hosts))
|
||||
assert.Equal(t, "/mesos", path)
|
||||
}
|
||||
|
||||
func TestParseZk_multi(t *testing.T) {
|
||||
hosts, path, err := parseZk("zk://abc:1,def:2/foo")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"abc:1", "def:2"}, hosts)
|
||||
assert.Equal(t, "/foo", path)
|
||||
}
|
||||
|
||||
func TestParseZk_multiIP(t *testing.T) {
|
||||
hosts, path, err := parseZk("zk://10.186.175.156:2181,10.47.50.94:2181,10.0.92.171:2181/mesos")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"10.186.175.156:2181", "10.47.50.94:2181", "10.0.92.171:2181"}, hosts)
|
||||
assert.Equal(t, "/mesos", path)
|
||||
}
|
||||
|
||||
func TestMasterDetectorStart(t *testing.T) {
|
||||
c, err := makeClient()
|
||||
assert.False(t, c.isConnected())
|
||||
md, err := NewMasterDetector(zkurl)
|
||||
defer md.Cancel()
|
||||
assert.NoError(t, err)
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
err = e
|
||||
})
|
||||
md.client = c // override zk.Conn with our own.
|
||||
md.client.connect()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, c.isConnected())
|
||||
}
|
||||
|
||||
func TestMasterDetectorChildrenChanged(t *testing.T) {
|
||||
wCh := make(chan struct{}, 1)
|
||||
|
||||
c, err := makeClient()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, c.isConnected())
|
||||
|
||||
md, err := NewMasterDetector(zkurl)
|
||||
defer md.Cancel()
|
||||
assert.NoError(t, err)
|
||||
// override zk.Conn with our own.
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
err = e
|
||||
})
|
||||
md.client = c
|
||||
md.client.connect()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, c.isConnected())
|
||||
|
||||
called := 0
|
||||
md.Detect(detector.OnMasterChanged(func(master *mesos.MasterInfo) {
|
||||
//expect 2 calls in sequence: the first setting a master
|
||||
//and the second clearing it
|
||||
switch called++; called {
|
||||
case 1:
|
||||
assert.NotNil(t, master)
|
||||
assert.Equal(t, master.GetId(), "master@localhost:5050")
|
||||
wCh <- struct{}{}
|
||||
case 2:
|
||||
assert.Nil(t, master)
|
||||
wCh <- struct{}{}
|
||||
default:
|
||||
t.Fatalf("unexpected notification call attempt %d", called)
|
||||
}
|
||||
}))
|
||||
|
||||
startWait := time.Now()
|
||||
select {
|
||||
case <-wCh:
|
||||
case <-time.After(time.Second * 3):
|
||||
panic("Waited too long...")
|
||||
}
|
||||
|
||||
// wait for the disconnect event, should be triggered
|
||||
// 1s after the connected event
|
||||
waited := time.Now().Sub(startWait)
|
||||
time.Sleep((2 * time.Second) - waited)
|
||||
assert.False(t, c.isConnected())
|
||||
}
|
||||
|
||||
// single connector instance, session does not expire, but it's internal connection to zk is flappy
|
||||
func TestMasterDetectFlappingConnectionState(t *testing.T) {
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
assert.NoError(t, err)
|
||||
|
||||
initialChildren := []string{"info_005", "info_010", "info_022"}
|
||||
connector := NewMockConnector()
|
||||
connector.On("Close").Return(nil)
|
||||
connector.On("Children", test_zk_path).Return(initialChildren, &zk.Stat{}, nil)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2) // async flapping, master change detection
|
||||
|
||||
first := true
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
if !first {
|
||||
t.Fatalf("only one connector instance expected")
|
||||
return nil, nil, errors.New("ran out of connectors")
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
sessionEvents := make(chan zk.Event, 10)
|
||||
watchEvents := make(chan zk.Event, 10)
|
||||
|
||||
connector.On("Get", fmt.Sprintf("%s/info_005", test_zk_path)).Return(newTestMasterInfo(1), &zk.Stat{}, nil).Once()
|
||||
connector.On("ChildrenW", test_zk_path).Return([]string{test_zk_path}, &zk.Stat{}, (<-chan zk.Event)(watchEvents), nil)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
for attempt := 0; attempt < 5; attempt++ {
|
||||
sessionEvents <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
sessionEvents <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateDisconnected,
|
||||
}
|
||||
}
|
||||
sessionEvents <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
}
|
||||
}()
|
||||
return connector, sessionEvents, nil
|
||||
}))
|
||||
c.reconnDelay = 0 // there should be no reconnect, but just in case don't drag the test out
|
||||
|
||||
md, err := NewMasterDetector(zkurl)
|
||||
defer md.Cancel()
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
t.Logf("zk client error: %v", e)
|
||||
})
|
||||
md.client = c
|
||||
|
||||
startTime := time.Now()
|
||||
detected := false
|
||||
md.Detect(detector.OnMasterChanged(func(master *mesos.MasterInfo) {
|
||||
if detected {
|
||||
t.Fatalf("already detected master, was not expecting another change: %v", master)
|
||||
} else {
|
||||
detected = true
|
||||
assert.NotNil(t, master, fmt.Sprintf("on-master-changed %v", detected))
|
||||
t.Logf("Leader change detected at %v: '%+v'", time.Now().Sub(startTime), master)
|
||||
wg.Done()
|
||||
}
|
||||
}))
|
||||
|
||||
completed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(completed)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-completed: // expected
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("failed to detect master change")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMasterDetectFlappingConnector(t *testing.T) {
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
assert.NoError(t, err)
|
||||
|
||||
initialChildren := []string{"info_005", "info_010", "info_022"}
|
||||
connector := NewMockConnector()
|
||||
connector.On("Close").Return(nil)
|
||||
connector.On("Children", test_zk_path).Return(initialChildren, &zk.Stat{}, nil)
|
||||
|
||||
// timing
|
||||
// t=0 t=400ms t=800ms t=1200ms t=1600ms t=2000ms t=2400ms
|
||||
// |--=--=--=--|--=--=--=--|--=--=--=--|--=--=--=--|--=--=--=--|--=--=--=--|--=--=--=--|--=--=--=--
|
||||
// c1 d1 c3 d3 c5 d5 d6 ...
|
||||
// c2 d2 c4 d4 c6 c7 ...
|
||||
// M M' M M' M M'
|
||||
|
||||
attempt := 0
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
attempt++
|
||||
sessionEvents := make(chan zk.Event, 5)
|
||||
watchEvents := make(chan zk.Event, 5)
|
||||
|
||||
sessionEvents <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
}
|
||||
connector.On("Get", fmt.Sprintf("%s/info_005", test_zk_path)).Return(newTestMasterInfo(attempt), &zk.Stat{}, nil).Once()
|
||||
connector.On("ChildrenW", test_zk_path).Return([]string{test_zk_path}, &zk.Stat{}, (<-chan zk.Event)(watchEvents), nil)
|
||||
go func(attempt int) {
|
||||
defer close(sessionEvents)
|
||||
defer close(watchEvents)
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
// this is the order in which the embedded zk implementation does it
|
||||
sessionEvents <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateDisconnected,
|
||||
}
|
||||
connector.On("ChildrenW", test_zk_path).Return(nil, nil, nil, zk.ErrSessionExpired).Once()
|
||||
watchEvents <- zk.Event{
|
||||
Type: zk.EventNotWatching,
|
||||
State: zk.StateDisconnected,
|
||||
Path: test_zk_path,
|
||||
Err: zk.ErrSessionExpired,
|
||||
}
|
||||
}(attempt)
|
||||
return connector, sessionEvents, nil
|
||||
}))
|
||||
c.reconnDelay = 100 * time.Millisecond
|
||||
c.rewatchDelay = c.reconnDelay / 2
|
||||
|
||||
md, err := NewMasterDetector(zkurl)
|
||||
md.minDetectorCyclePeriod = 600 * time.Millisecond
|
||||
|
||||
defer md.Cancel()
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
t.Logf("zk client error: %v", e)
|
||||
})
|
||||
md.client = c
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(6) // 3 x (connected, disconnected)
|
||||
detected := 0
|
||||
startTime := time.Now()
|
||||
md.Detect(detector.OnMasterChanged(func(master *mesos.MasterInfo) {
|
||||
if detected > 5 {
|
||||
// ignore
|
||||
return
|
||||
}
|
||||
if (detected & 1) == 0 {
|
||||
assert.NotNil(t, master, fmt.Sprintf("on-master-changed-%d", detected))
|
||||
} else {
|
||||
assert.Nil(t, master, fmt.Sprintf("on-master-changed-%d", detected))
|
||||
}
|
||||
t.Logf("Leader change detected at %v: '%+v'", time.Now().Sub(startTime), master)
|
||||
detected++
|
||||
wg.Done()
|
||||
}))
|
||||
|
||||
completed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(completed)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-completed: // expected
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatalf("failed to detect flapping master changes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMasterDetectMultiple(t *testing.T) {
|
||||
ch0 := make(chan zk.Event, 5)
|
||||
ch1 := make(chan zk.Event, 5)
|
||||
|
||||
ch0 <- zk.Event{
|
||||
Type: zk.EventSession,
|
||||
State: zk.StateConnected,
|
||||
}
|
||||
|
||||
c, err := newClient(test_zk_hosts, test_zk_path)
|
||||
assert.NoError(t, err)
|
||||
|
||||
initialChildren := []string{"info_005", "info_010", "info_022"}
|
||||
connector := NewMockConnector()
|
||||
connector.On("Close").Return(nil)
|
||||
connector.On("Children", test_zk_path).Return(initialChildren, &zk.Stat{}, nil).Once()
|
||||
connector.On("ChildrenW", test_zk_path).Return([]string{test_zk_path}, &zk.Stat{}, (<-chan zk.Event)(ch1), nil)
|
||||
|
||||
first := true
|
||||
c.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
log.V(2).Infof("**** Using zk.Conn adapter ****")
|
||||
if !first {
|
||||
return nil, nil, errors.New("only 1 connector allowed")
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
return connector, ch0, nil
|
||||
}))
|
||||
|
||||
md, err := NewMasterDetector(zkurl)
|
||||
defer md.Cancel()
|
||||
assert.NoError(t, err)
|
||||
|
||||
c.errorHandler = ErrorHandler(func(c *Client, e error) {
|
||||
err = e
|
||||
})
|
||||
md.client = c
|
||||
|
||||
// **** Test 4 consecutive ChildrenChangedEvents ******
|
||||
// setup event changes
|
||||
sequences := [][]string{
|
||||
[]string{"info_014", "info_010", "info_005"},
|
||||
[]string{"info_005", "info_004", "info_022"},
|
||||
[]string{}, // indicates no master
|
||||
[]string{"info_017", "info_099", "info_200"},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
startTime := time.Now()
|
||||
detected := 0
|
||||
md.Detect(detector.OnMasterChanged(func(master *mesos.MasterInfo) {
|
||||
if detected == 2 {
|
||||
assert.Nil(t, master, fmt.Sprintf("on-master-changed-%d", detected))
|
||||
} else {
|
||||
assert.NotNil(t, master, fmt.Sprintf("on-master-changed-%d", detected))
|
||||
}
|
||||
t.Logf("Leader change detected at %v: '%+v'", time.Now().Sub(startTime), master)
|
||||
detected++
|
||||
wg.Done()
|
||||
}))
|
||||
|
||||
// 3 leadership changes + disconnect (leader change to '')
|
||||
wg.Add(4)
|
||||
|
||||
go func() {
|
||||
for i := range sequences {
|
||||
sorted := make([]string, len(sequences[i]))
|
||||
copy(sorted, sequences[i])
|
||||
sort.Strings(sorted)
|
||||
t.Logf("testing master change sequence %d, path '%v'", i, test_zk_path)
|
||||
connector.On("Children", test_zk_path).Return(sequences[i], &zk.Stat{}, nil).Once()
|
||||
if len(sequences[i]) > 0 {
|
||||
connector.On("Get", fmt.Sprintf("%s/%s", test_zk_path, sorted[0])).Return(newTestMasterInfo(i), &zk.Stat{}, nil).Once()
|
||||
}
|
||||
ch1 <- zk.Event{
|
||||
Type: zk.EventNodeChildrenChanged,
|
||||
Path: test_zk_path,
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond) // give async routines time to catch up
|
||||
}
|
||||
time.Sleep(1 * time.Second) // give async routines time to catch up
|
||||
t.Logf("disconnecting...")
|
||||
ch0 <- zk.Event{
|
||||
State: zk.StateDisconnected,
|
||||
}
|
||||
//TODO(jdef) does order of close matter here? probably, meaking client code is weak
|
||||
close(ch0)
|
||||
time.Sleep(500 * time.Millisecond) // give async routines time to catch up
|
||||
close(ch1)
|
||||
}()
|
||||
completed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(completed)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Fatal(r)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * time.Second):
|
||||
panic("timed out waiting for master changes to propagate")
|
||||
case <-completed:
|
||||
}
|
||||
}
|
||||
|
||||
func TestMasterDetect_selectTopNode_none(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
nodeList := []string{}
|
||||
node := selectTopNode(nodeList)
|
||||
assert.Equal("", node)
|
||||
}
|
||||
|
||||
func TestMasterDetect_selectTopNode_0000x(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
nodeList := []string{
|
||||
"info_0000000046",
|
||||
"info_0000000032",
|
||||
"info_0000000058",
|
||||
"info_0000000061",
|
||||
"info_0000000008",
|
||||
}
|
||||
node := selectTopNode(nodeList)
|
||||
assert.Equal("info_0000000008", node)
|
||||
}
|
||||
|
||||
func TestMasterDetect_selectTopNode_mixedEntries(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
nodeList := []string{
|
||||
"info_0000000046",
|
||||
"info_0000000032",
|
||||
"foo_lskdjfglsdkfsdfgdfg",
|
||||
"info_0000000061",
|
||||
"log_replicas_fdgwsdfgsdf",
|
||||
"bar",
|
||||
}
|
||||
node := selectTopNode(nodeList)
|
||||
assert.Equal("info_0000000032", node)
|
||||
}
|
||||
71
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/mocked_conn.go
generated
vendored
Normal file
71
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/mocked_conn.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// Impersontates a zk.Connection
|
||||
// It implements interface Connector
|
||||
type MockConnector struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func NewMockConnector() *MockConnector {
|
||||
return new(MockConnector)
|
||||
}
|
||||
|
||||
func (conn *MockConnector) Close() {
|
||||
conn.Called()
|
||||
}
|
||||
|
||||
func (conn *MockConnector) ChildrenW(path string) ([]string, *zk.Stat, <-chan zk.Event, error) {
|
||||
args := conn.Called(path)
|
||||
var (
|
||||
arg0 []string
|
||||
arg1 *zk.Stat
|
||||
arg2 <-chan zk.Event
|
||||
)
|
||||
if args.Get(0) != nil {
|
||||
arg0 = args.Get(0).([]string)
|
||||
}
|
||||
if args.Get(1) != nil {
|
||||
arg1 = args.Get(1).(*zk.Stat)
|
||||
}
|
||||
if args.Get(2) != nil {
|
||||
arg2 = args.Get(2).(<-chan zk.Event)
|
||||
}
|
||||
return arg0, arg1, arg2, args.Error(3)
|
||||
}
|
||||
|
||||
func (conn *MockConnector) Children(path string) ([]string, *zk.Stat, error) {
|
||||
args := conn.Called(path)
|
||||
return args.Get(0).([]string),
|
||||
args.Get(1).(*zk.Stat),
|
||||
args.Error(2)
|
||||
}
|
||||
|
||||
func (conn *MockConnector) Get(path string) ([]byte, *zk.Stat, error) {
|
||||
args := conn.Called(path)
|
||||
return args.Get(0).([]byte),
|
||||
args.Get(1).(*zk.Stat),
|
||||
args.Error(2)
|
||||
}
|
||||
88
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/mocked_detect.go
generated
vendored
Normal file
88
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/mocked_detect.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
log "github.com/golang/glog"
|
||||
util "github.com/mesos/mesos-go/mesosutil"
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
)
|
||||
|
||||
type MockMasterDetector struct {
|
||||
*MasterDetector
|
||||
zkPath string
|
||||
conCh chan zk.Event
|
||||
sesCh chan zk.Event
|
||||
}
|
||||
|
||||
func NewMockMasterDetector(zkurls string) (*MockMasterDetector, error) {
|
||||
log.V(4).Infoln("Creating mock zk master detector")
|
||||
md, err := NewMasterDetector(zkurls)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, _ := url.Parse(zkurls)
|
||||
m := &MockMasterDetector{
|
||||
MasterDetector: md,
|
||||
zkPath: u.Path,
|
||||
conCh: make(chan zk.Event, 5),
|
||||
sesCh: make(chan zk.Event, 5),
|
||||
}
|
||||
|
||||
path := m.zkPath
|
||||
connector := NewMockConnector()
|
||||
connector.On("Children", path).Return([]string{"info_0", "info_5", "info_10"}, &zk.Stat{}, nil)
|
||||
connector.On("Get", fmt.Sprintf("%s/info_0", path)).Return(m.makeMasterInfo(), &zk.Stat{}, nil)
|
||||
connector.On("Close").Return(nil)
|
||||
connector.On("ChildrenW", m.zkPath).Return([]string{m.zkPath}, &zk.Stat{}, (<-chan zk.Event)(m.sesCh), nil)
|
||||
|
||||
first := true
|
||||
m.client.setFactory(asFactory(func() (Connector, <-chan zk.Event, error) {
|
||||
if !first {
|
||||
return nil, nil, errors.New("only 1 connector allowed")
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
return connector, m.conCh, nil
|
||||
}))
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *MockMasterDetector) Start() {
|
||||
m.client.connect()
|
||||
}
|
||||
|
||||
func (m *MockMasterDetector) ScheduleConnEvent(s zk.State) {
|
||||
log.V(4).Infof("Scheduling zk connection event with state: %v\n", s)
|
||||
go func() {
|
||||
m.conCh <- zk.Event{
|
||||
State: s,
|
||||
Path: m.zkPath,
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *MockMasterDetector) ScheduleSessEvent(t zk.EventType) {
|
||||
log.V(4).Infof("Scheduling zk session event with state: %v\n", t)
|
||||
go func() {
|
||||
m.sesCh <- zk.Event{
|
||||
Type: t,
|
||||
Path: m.zkPath,
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *MockMasterDetector) makeMasterInfo() []byte {
|
||||
miPb := util.NewMasterInfo("master", 123456789, 400)
|
||||
miPb.Pid = proto.String("master@127.0.0.1:5050")
|
||||
data, err := proto.Marshal(miPb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/plugin.go
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
)
|
||||
|
||||
func init() {
|
||||
detector.Register("zk://", detector.PluginFactory(func(spec string) (detector.Master, error) {
|
||||
return NewMasterDetector(spec)
|
||||
}))
|
||||
}
|
||||
19
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/plugin_test.go
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/plugin_test.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mesos/mesos-go/detector"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// validate plugin registration for zk:// prefix is working
|
||||
func TestDectorFactoryNew_ZkPrefix(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m, err := detector.New("zk://127.0.0.1:5050/mesos")
|
||||
assert.NoError(err)
|
||||
assert.IsType(&MasterDetector{}, m)
|
||||
md := m.(*MasterDetector)
|
||||
t.Logf("canceling detector")
|
||||
md.Cancel()
|
||||
}
|
||||
33
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/types.go
generated
vendored
Normal file
33
Godeps/_workspace/src/github.com/mesos/mesos-go/detector/zoo/types.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package zoo
|
||||
|
||||
import (
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
)
|
||||
|
||||
// Connector Interface to facade zk.Conn type
|
||||
// since github.com/samuel/go-zookeeper/zk does not provide an interface
|
||||
// for the zk.Conn object, this allows for mocking and easier testing.
|
||||
type Connector interface {
|
||||
Close()
|
||||
Children(string) ([]string, *zk.Stat, error)
|
||||
ChildrenW(string) ([]string, *zk.Stat, <-chan zk.Event, error)
|
||||
Get(string) ([]byte, *zk.Stat, error)
|
||||
}
|
||||
|
||||
// interface for handling watcher event when zk.EventNodeChildrenChanged.
|
||||
type ChildWatcher func(*Client, string)
|
||||
|
||||
// interface for handling errors (session and watch related).
|
||||
type ErrorHandler func(*Client, error)
|
||||
|
||||
//Factory is an adapter to trap the creation of zk.Conn instances
|
||||
//since the official zk API does not expose an interface for zk.Conn.
|
||||
type Factory interface {
|
||||
create() (Connector, <-chan zk.Event, error)
|
||||
}
|
||||
|
||||
type asFactory func() (Connector, <-chan zk.Event, error)
|
||||
|
||||
func (f asFactory) create() (Connector, <-chan zk.Event, error) {
|
||||
return f()
|
||||
}
|
||||
2
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/Makefile
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/Makefile
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
all: *.proto
|
||||
protoc --proto_path=${GOPATH}/src:${GOPATH}/src/github.com/gogo/protobuf/protobuf:. --gogo_out=. *.proto
|
||||
255
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/containerizer.pb.go
generated
vendored
Normal file
255
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/containerizer.pb.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: containerizer.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package mesosproto is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
containerizer.proto
|
||||
internal.proto
|
||||
log.proto
|
||||
mesos.proto
|
||||
messages.proto
|
||||
registry.proto
|
||||
scheduler.proto
|
||||
state.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Launch
|
||||
Update
|
||||
Wait
|
||||
Destroy
|
||||
Usage
|
||||
Termination
|
||||
Containers
|
||||
*/
|
||||
package mesosproto
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// discarding unused import gogoproto "github.com/gogo/protobuf/gogoproto/gogo.pb"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
// *
|
||||
// Encodes the launch command sent to the external containerizer
|
||||
// program.
|
||||
type Launch struct {
|
||||
ContainerId *ContainerID `protobuf:"bytes,1,req,name=container_id" json:"container_id,omitempty"`
|
||||
TaskInfo *TaskInfo `protobuf:"bytes,2,opt,name=task_info" json:"task_info,omitempty"`
|
||||
ExecutorInfo *ExecutorInfo `protobuf:"bytes,3,opt,name=executor_info" json:"executor_info,omitempty"`
|
||||
Directory *string `protobuf:"bytes,4,opt,name=directory" json:"directory,omitempty"`
|
||||
User *string `protobuf:"bytes,5,opt,name=user" json:"user,omitempty"`
|
||||
SlaveId *SlaveID `protobuf:"bytes,6,opt,name=slave_id" json:"slave_id,omitempty"`
|
||||
SlavePid *string `protobuf:"bytes,7,opt,name=slave_pid" json:"slave_pid,omitempty"`
|
||||
Checkpoint *bool `protobuf:"varint,8,opt,name=checkpoint" json:"checkpoint,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Launch) Reset() { *m = Launch{} }
|
||||
func (m *Launch) String() string { return proto.CompactTextString(m) }
|
||||
func (*Launch) ProtoMessage() {}
|
||||
|
||||
func (m *Launch) GetContainerId() *ContainerID {
|
||||
if m != nil {
|
||||
return m.ContainerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Launch) GetTaskInfo() *TaskInfo {
|
||||
if m != nil {
|
||||
return m.TaskInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Launch) GetExecutorInfo() *ExecutorInfo {
|
||||
if m != nil {
|
||||
return m.ExecutorInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Launch) GetDirectory() string {
|
||||
if m != nil && m.Directory != nil {
|
||||
return *m.Directory
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Launch) GetUser() string {
|
||||
if m != nil && m.User != nil {
|
||||
return *m.User
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Launch) GetSlaveId() *SlaveID {
|
||||
if m != nil {
|
||||
return m.SlaveId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Launch) GetSlavePid() string {
|
||||
if m != nil && m.SlavePid != nil {
|
||||
return *m.SlavePid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Launch) GetCheckpoint() bool {
|
||||
if m != nil && m.Checkpoint != nil {
|
||||
return *m.Checkpoint
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// *
|
||||
// Encodes the update command sent to the external containerizer
|
||||
// program.
|
||||
type Update struct {
|
||||
ContainerId *ContainerID `protobuf:"bytes,1,req,name=container_id" json:"container_id,omitempty"`
|
||||
Resources []*Resource `protobuf:"bytes,2,rep,name=resources" json:"resources,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Update) Reset() { *m = Update{} }
|
||||
func (m *Update) String() string { return proto.CompactTextString(m) }
|
||||
func (*Update) ProtoMessage() {}
|
||||
|
||||
func (m *Update) GetContainerId() *ContainerID {
|
||||
if m != nil {
|
||||
return m.ContainerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Update) GetResources() []*Resource {
|
||||
if m != nil {
|
||||
return m.Resources
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// *
|
||||
// Encodes the wait command sent to the external containerizer
|
||||
// program.
|
||||
type Wait struct {
|
||||
ContainerId *ContainerID `protobuf:"bytes,1,req,name=container_id" json:"container_id,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Wait) Reset() { *m = Wait{} }
|
||||
func (m *Wait) String() string { return proto.CompactTextString(m) }
|
||||
func (*Wait) ProtoMessage() {}
|
||||
|
||||
func (m *Wait) GetContainerId() *ContainerID {
|
||||
if m != nil {
|
||||
return m.ContainerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// *
|
||||
// Encodes the destroy command sent to the external containerizer
|
||||
// program.
|
||||
type Destroy struct {
|
||||
ContainerId *ContainerID `protobuf:"bytes,1,req,name=container_id" json:"container_id,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Destroy) Reset() { *m = Destroy{} }
|
||||
func (m *Destroy) String() string { return proto.CompactTextString(m) }
|
||||
func (*Destroy) ProtoMessage() {}
|
||||
|
||||
func (m *Destroy) GetContainerId() *ContainerID {
|
||||
if m != nil {
|
||||
return m.ContainerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// *
|
||||
// Encodes the usage command sent to the external containerizer
|
||||
// program.
|
||||
type Usage struct {
|
||||
ContainerId *ContainerID `protobuf:"bytes,1,req,name=container_id" json:"container_id,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Usage) Reset() { *m = Usage{} }
|
||||
func (m *Usage) String() string { return proto.CompactTextString(m) }
|
||||
func (*Usage) ProtoMessage() {}
|
||||
|
||||
func (m *Usage) GetContainerId() *ContainerID {
|
||||
if m != nil {
|
||||
return m.ContainerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// *
|
||||
// Information about a container termination, returned by the
|
||||
// containerizer to the slave.
|
||||
type Termination struct {
|
||||
// A container may be killed if it exceeds its resources; this will
|
||||
// be indicated by killed=true and described by the message string.
|
||||
Killed *bool `protobuf:"varint,1,req,name=killed" json:"killed,omitempty"`
|
||||
Message *string `protobuf:"bytes,2,req,name=message" json:"message,omitempty"`
|
||||
// Exit status of the process.
|
||||
Status *int32 `protobuf:"varint,3,opt,name=status" json:"status,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Termination) Reset() { *m = Termination{} }
|
||||
func (m *Termination) String() string { return proto.CompactTextString(m) }
|
||||
func (*Termination) ProtoMessage() {}
|
||||
|
||||
func (m *Termination) GetKilled() bool {
|
||||
if m != nil && m.Killed != nil {
|
||||
return *m.Killed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Termination) GetMessage() string {
|
||||
if m != nil && m.Message != nil {
|
||||
return *m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Termination) GetStatus() int32 {
|
||||
if m != nil && m.Status != nil {
|
||||
return *m.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// *
|
||||
// Information on all active containers returned by the containerizer
|
||||
// to the slave.
|
||||
type Containers struct {
|
||||
Containers []*ContainerID `protobuf:"bytes,1,rep,name=containers" json:"containers,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Containers) Reset() { *m = Containers{} }
|
||||
func (m *Containers) String() string { return proto.CompactTextString(m) }
|
||||
func (*Containers) ProtoMessage() {}
|
||||
|
||||
func (m *Containers) GetContainers() []*ContainerID {
|
||||
if m != nil {
|
||||
return m.Containers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
99
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/containerizer.proto
generated
vendored
Normal file
99
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/containerizer.proto
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the launch command sent to the external containerizer
|
||||
* program.
|
||||
*/
|
||||
message Launch {
|
||||
required ContainerID container_id = 1;
|
||||
optional TaskInfo task_info = 2;
|
||||
optional ExecutorInfo executor_info = 3;
|
||||
optional string directory = 4;
|
||||
optional string user = 5;
|
||||
optional SlaveID slave_id = 6;
|
||||
optional string slave_pid = 7;
|
||||
optional bool checkpoint = 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the update command sent to the external containerizer
|
||||
* program.
|
||||
*/
|
||||
message Update {
|
||||
required ContainerID container_id = 1;
|
||||
repeated Resource resources = 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the wait command sent to the external containerizer
|
||||
* program.
|
||||
*/
|
||||
message Wait {
|
||||
required ContainerID container_id = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the destroy command sent to the external containerizer
|
||||
* program.
|
||||
*/
|
||||
message Destroy {
|
||||
required ContainerID container_id = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes the usage command sent to the external containerizer
|
||||
* program.
|
||||
*/
|
||||
message Usage {
|
||||
required ContainerID container_id = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Information about a container termination, returned by the
|
||||
* containerizer to the slave.
|
||||
*/
|
||||
message Termination {
|
||||
// A container may be killed if it exceeds its resources; this will
|
||||
// be indicated by killed=true and described by the message string.
|
||||
required bool killed = 1;
|
||||
required string message = 2;
|
||||
|
||||
// Exit status of the process.
|
||||
optional int32 status = 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Information on all active containers returned by the containerizer
|
||||
* to the slave.
|
||||
*/
|
||||
message Containers {
|
||||
repeated ContainerID containers = 1;
|
||||
}
|
||||
78
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/internal.pb.go
generated
vendored
Normal file
78
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/internal.pb.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: internal.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
package mesosproto
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// discarding unused import gogoproto "github.com/gogo/protobuf/gogoproto/gogo.pb"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
// For use with detector callbacks
|
||||
type InternalMasterChangeDetected struct {
|
||||
// will be present if there's a new master, otherwise nil
|
||||
Master *MasterInfo `protobuf:"bytes,1,opt,name=master" json:"master,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *InternalMasterChangeDetected) Reset() { *m = InternalMasterChangeDetected{} }
|
||||
func (m *InternalMasterChangeDetected) String() string { return proto.CompactTextString(m) }
|
||||
func (*InternalMasterChangeDetected) ProtoMessage() {}
|
||||
|
||||
func (m *InternalMasterChangeDetected) GetMaster() *MasterInfo {
|
||||
if m != nil {
|
||||
return m.Master
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type InternalTryAuthentication struct {
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *InternalTryAuthentication) Reset() { *m = InternalTryAuthentication{} }
|
||||
func (m *InternalTryAuthentication) String() string { return proto.CompactTextString(m) }
|
||||
func (*InternalTryAuthentication) ProtoMessage() {}
|
||||
|
||||
type InternalAuthenticationResult struct {
|
||||
// true only if the authentication process completed and login was successful
|
||||
Success *bool `protobuf:"varint,1,req,name=success" json:"success,omitempty"`
|
||||
// true if the authentication process completed, successfully or not
|
||||
Completed *bool `protobuf:"varint,2,req,name=completed" json:"completed,omitempty"`
|
||||
// master pid that this result pertains to
|
||||
Pid *string `protobuf:"bytes,3,req,name=pid" json:"pid,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *InternalAuthenticationResult) Reset() { *m = InternalAuthenticationResult{} }
|
||||
func (m *InternalAuthenticationResult) String() string { return proto.CompactTextString(m) }
|
||||
func (*InternalAuthenticationResult) ProtoMessage() {}
|
||||
|
||||
func (m *InternalAuthenticationResult) GetSuccess() bool {
|
||||
if m != nil && m.Success != nil {
|
||||
return *m.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *InternalAuthenticationResult) GetCompleted() bool {
|
||||
if m != nil && m.Completed != nil {
|
||||
return *m.Completed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *InternalAuthenticationResult) GetPid() string {
|
||||
if m != nil && m.Pid != nil {
|
||||
return *m.Pid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
23
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/internal.proto
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/internal.proto
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package mesosproto;
|
||||
|
||||
import "mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
// For use with detector callbacks
|
||||
message InternalMasterChangeDetected {
|
||||
// will be present if there's a new master, otherwise nil
|
||||
optional MasterInfo master = 1;
|
||||
}
|
||||
|
||||
message InternalTryAuthentication {
|
||||
// empty message, serves as a signal to the scheduler bindings
|
||||
}
|
||||
|
||||
message InternalAuthenticationResult {
|
||||
// true only if the authentication process completed and login was successful
|
||||
required bool success = 1;
|
||||
// true if the authentication process completed, successfully or not
|
||||
required bool completed = 2;
|
||||
// master pid that this result pertains to
|
||||
required string pid = 3;
|
||||
}
|
||||
4706
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/log.pb.go
generated
vendored
Normal file
4706
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/log.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
209
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/log.proto
generated
vendored
Normal file
209
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/log.proto
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option (gogoproto.gostring_all) = true;
|
||||
option (gogoproto.equal_all) = true;
|
||||
option (gogoproto.verbose_equal_all) = true;
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.stringer_all) = true;
|
||||
option (gogoproto.populate_all) = true;
|
||||
option (gogoproto.testgen_all) = true;
|
||||
option (gogoproto.benchgen_all) = true;
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.sizer_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
|
||||
|
||||
// Represents a "promise" that a replica has made. A promise is
|
||||
// *implicitly* valid for _all_ future actions that get performed on
|
||||
// the replicated log (provided the action comes from the same
|
||||
// proposer), until a new promise is made to a proposer with a higher
|
||||
// proposal number. Each replica writes every promise it makes as a
|
||||
// log record so that it can recover this information after a failure.
|
||||
// TODO(benh): Does the promise actually need to be written to stable
|
||||
// storage? Can we get away with looking at the last written action
|
||||
// and using it's promised value? In this case, what happens if we
|
||||
// make a promise but don't receive an action from that coordinator?
|
||||
message Promise {
|
||||
required uint64 proposal = 1;
|
||||
}
|
||||
|
||||
|
||||
// Represents an "action" performed on the log. Each action has an
|
||||
// associated position in the log. In addition, each action (i.e.,
|
||||
// position) will have been "promised" to a specific proposer
|
||||
// (implicitly or explicitly) and may have been "performed" from a
|
||||
// specific proposer. An action may also be "learned" to have reached
|
||||
// consensus. There are three types of possible actions that can be
|
||||
// performed on the log: nop (no action), append, and truncate.
|
||||
message Action {
|
||||
required uint64 position = 1;
|
||||
required uint64 promised = 2;
|
||||
optional uint64 performed = 3;
|
||||
optional bool learned = 4;
|
||||
|
||||
enum Type {
|
||||
NOP = 1;
|
||||
APPEND = 2;
|
||||
TRUNCATE = 3;
|
||||
}
|
||||
|
||||
message Nop {}
|
||||
|
||||
message Append {
|
||||
required bytes bytes = 1;
|
||||
optional bytes cksum = 2;
|
||||
}
|
||||
|
||||
message Truncate {
|
||||
required uint64 to = 1; // All positions before and exclusive of 'to'.
|
||||
}
|
||||
|
||||
optional Type type = 5; // Set iff performed is set.
|
||||
optional Nop nop = 6;
|
||||
optional Append append = 7;
|
||||
optional Truncate truncate = 8;
|
||||
}
|
||||
|
||||
|
||||
// The metadata of a replica. It has to be persisted on the disk. We
|
||||
// store the current status of the replica as well as the implicit
|
||||
// promise that a replica has made. This message is intended to
|
||||
// replace the old Promise message to support catch-up.
|
||||
message Metadata {
|
||||
enum Status {
|
||||
VOTING = 1; // Normal voting member in Paxos group.
|
||||
RECOVERING = 2; // In the process of catching up.
|
||||
STARTING = 3; // The log has been initialized.
|
||||
EMPTY = 4; // The log is empty and is not initialized.
|
||||
}
|
||||
|
||||
required Status status = 1 [default = EMPTY];
|
||||
required uint64 promised = 2 [default = 0];
|
||||
}
|
||||
|
||||
|
||||
// Represents a log record written to the local filesystem by a
|
||||
// replica. A log record may store a promise (DEPRECATED), an action
|
||||
// or metadata (defined above).
|
||||
message Record {
|
||||
enum Type {
|
||||
PROMISE = 1; // DEPRECATED!
|
||||
ACTION = 2;
|
||||
METADATA = 3;
|
||||
}
|
||||
|
||||
required Type type = 1;
|
||||
optional Promise promise = 2; // DEPRECATED!
|
||||
optional Action action = 3;
|
||||
optional Metadata metadata = 4;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Replicated log request/responses and messages. //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Represents a "promise" request from a proposer with the specified
|
||||
// 'proposal' to a replica. If the proposer is a coordinator, most
|
||||
// such requests will occur after a coordinator has failed and a new
|
||||
// coordinator is elected. In such a case, the position that the
|
||||
// coordinator is asking the replica to promise is implicitly *all*
|
||||
// positions that the replica has made no promises (thus the position
|
||||
// field is not be used). In other instances, however, a proposer
|
||||
// might be explicitly trying to request that a replica promise a
|
||||
// specific position in the log (such as when trying to fill holes
|
||||
// discovered during a client read), and then the 'position' field
|
||||
// will be present.
|
||||
message PromiseRequest {
|
||||
required uint64 proposal = 1;
|
||||
optional uint64 position = 2;
|
||||
}
|
||||
|
||||
|
||||
// Represents a "promise" response from a replica back to a proposer.
|
||||
// A replica represents a NACK (because it has promised a proposer
|
||||
// with a higher proposal number) by setting the okay field to false.
|
||||
// The 'proposal' is either the aforementioned higher proposal number
|
||||
// when the response is a NACK, or the corresponding request's
|
||||
// proposal number if it is an ACK. The replica either sends back the
|
||||
// highest position it has recorded in the log (using the 'position'
|
||||
// field) or the specific action (if any) it has at the position
|
||||
// requested in PromiseRequest (using the 'action' field).
|
||||
message PromiseResponse {
|
||||
required bool okay = 1;
|
||||
required uint64 proposal = 2;
|
||||
optional uint64 position = 4;
|
||||
optional Action action = 3;
|
||||
}
|
||||
|
||||
|
||||
// Represents a write request for a specific type of action. Note that
|
||||
// we deliberately do not include the entire Action as it contains
|
||||
// fields that are not relevant to a write request (e.g., promised,
|
||||
// performed) and rather than ignore them we exclude them for safety.
|
||||
message WriteRequest {
|
||||
required uint64 proposal = 1;
|
||||
required uint64 position = 2;
|
||||
optional bool learned = 3;
|
||||
required Action.Type type = 4;
|
||||
optional Action.Nop nop = 5;
|
||||
optional Action.Append append = 6;
|
||||
optional Action.Truncate truncate = 7;
|
||||
}
|
||||
|
||||
|
||||
// Represents a write response corresponding to a write request. A
|
||||
// replica represents a NACK (because it has promised a proposer with
|
||||
// a higher proposal number) by setting the okay field to false. If
|
||||
// the proposer is a coordinator, then it has been demoted. The
|
||||
// 'position' should always correspond to the position set in the
|
||||
// request. The 'proposal' is either the same proposal number set in
|
||||
// the request in the case of an ACK, or the higher proposal number
|
||||
// this position has been promised to in the case of a NACK.
|
||||
message WriteResponse {
|
||||
required bool okay = 1;
|
||||
required uint64 proposal = 2;
|
||||
required uint64 position = 3;
|
||||
}
|
||||
|
||||
|
||||
// Represents a "learned" event, that is, when a particular action has
|
||||
// been agreed upon (reached consensus).
|
||||
message LearnedMessage {
|
||||
required Action action = 1;
|
||||
}
|
||||
|
||||
|
||||
// Represents a recover request. A recover request is used to initiate
|
||||
// the recovery (by broadcasting it).
|
||||
message RecoverRequest {}
|
||||
|
||||
|
||||
// When a replica receives a RecoverRequest, it will reply with its
|
||||
// current status, and the begin and the end of its current log.
|
||||
message RecoverResponse {
|
||||
required Metadata.Status status = 1;
|
||||
optional uint64 begin = 2;
|
||||
optional uint64 end = 3;
|
||||
}
|
||||
3006
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/logpb_test.go
generated
vendored
Normal file
3006
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/logpb_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22907
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesos.pb.go
generated
vendored
Normal file
22907
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesos.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
942
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesos.proto
generated
vendored
Normal file
942
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesos.proto
generated
vendored
Normal file
@@ -0,0 +1,942 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option (gogoproto.gostring_all) = true;
|
||||
option (gogoproto.equal_all) = true;
|
||||
option (gogoproto.verbose_equal_all) = true;
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.stringer_all) = true;
|
||||
option (gogoproto.populate_all) = true;
|
||||
option (gogoproto.testgen_all) = true;
|
||||
option (gogoproto.benchgen_all) = true;
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.sizer_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
|
||||
|
||||
/**
|
||||
* Status is used to indicate the state of the scheduler and executor
|
||||
* driver after function calls.
|
||||
*/
|
||||
enum Status {
|
||||
DRIVER_NOT_STARTED = 1;
|
||||
DRIVER_RUNNING = 2;
|
||||
DRIVER_ABORTED = 3;
|
||||
DRIVER_STOPPED = 4;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A unique ID assigned to a framework. A framework can reuse this ID
|
||||
* in order to do failover (see MesosSchedulerDriver).
|
||||
*/
|
||||
message FrameworkID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A unique ID assigned to an offer.
|
||||
*/
|
||||
message OfferID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A unique ID assigned to a slave. Currently, a slave gets a new ID
|
||||
* whenever it (re)registers with Mesos. Framework writers shouldn't
|
||||
* assume any binding between a slave ID and and a hostname.
|
||||
*/
|
||||
message SlaveID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A framework generated ID to distinguish a task. The ID must remain
|
||||
* unique while the task is active. However, a framework can reuse an
|
||||
* ID _only_ if a previous task with the same ID has reached a
|
||||
* terminal state (e.g., TASK_FINISHED, TASK_LOST, TASK_KILLED, etc.).
|
||||
*/
|
||||
message TaskID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A framework generated ID to distinguish an executor. Only one
|
||||
* executor with the same ID can be active on the same slave at a
|
||||
* time.
|
||||
*/
|
||||
message ExecutorID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A slave generated ID to distinguish a container. The ID must be unique
|
||||
* between any active or completed containers on the slave. In particular,
|
||||
* containers for different runs of the same (framework, executor) pair must be
|
||||
* unique.
|
||||
*/
|
||||
message ContainerID {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a framework. The user field is used to determine the
|
||||
* Unix user that an executor/task should be launched as. If the user
|
||||
* field is set to an empty string Mesos will automagically set it
|
||||
* to the current user. Note that the ID is only available after a
|
||||
* framework has registered, however, it is included here in order to
|
||||
* facilitate scheduler failover (i.e., if it is set then the
|
||||
* MesosSchedulerDriver expects the scheduler is performing failover).
|
||||
* The amount of time that the master will wait for the scheduler to
|
||||
* failover before removing the framework is specified by
|
||||
* failover_timeout. If checkpoint is set, framework pid, executor
|
||||
* pids and status updates are checkpointed to disk by the slaves.
|
||||
* Checkpointing allows a restarted slave to reconnect with old
|
||||
* executors and recover status updates, at the cost of disk I/O.
|
||||
* The role field is used to group frameworks for allocation
|
||||
* decisions, depending on the allocation policy being used.
|
||||
* If the hostname field is set to an empty string Mesos will
|
||||
* automagically set it to the current hostname.
|
||||
* The principal field should match the credential the framework uses
|
||||
* in authentication. This field is used for framework API rate
|
||||
* exporting and limiting and should be set even if authentication is
|
||||
* not enabled if these features are desired.
|
||||
* The webui_url field allows a framework to advertise its web UI, so
|
||||
* that the Mesos web UI can link to it. It is expected to be a full
|
||||
* URL, for example http://my-scheduler.example.com:8080/.
|
||||
*/
|
||||
message FrameworkInfo {
|
||||
required string user = 1;
|
||||
required string name = 2;
|
||||
optional FrameworkID id = 3;
|
||||
optional double failover_timeout = 4 [default = 0.0];
|
||||
optional bool checkpoint = 5 [default = false];
|
||||
optional string role = 6 [default = "*"];
|
||||
optional string hostname = 7;
|
||||
optional string principal = 8;
|
||||
optional string webui_url = 9;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a health check for a task or executor (or any arbitrary
|
||||
* process/command). A "strategy" is picked by specifying one of the
|
||||
* optional fields, currently only 'http' and 'command' are
|
||||
* supported. Specifying more than one strategy is an error.
|
||||
*/
|
||||
message HealthCheck {
|
||||
// Describes an HTTP health check.
|
||||
message HTTP {
|
||||
// Port to send the HTTP request.
|
||||
required uint32 port = 1;
|
||||
|
||||
// HTTP request path.
|
||||
optional string path = 2 [default = "/"];
|
||||
|
||||
// TODO(benh): Implement:
|
||||
// Whether or not to use HTTPS.
|
||||
// optional bool ssl = 3 [default = false];
|
||||
|
||||
// Expected response statuses. Not specifying any statuses implies
|
||||
// that any returned status is acceptable.
|
||||
repeated uint32 statuses = 4;
|
||||
|
||||
// TODO(benh): Include an 'optional bytes data' field for checking
|
||||
// for specific data in the response.
|
||||
}
|
||||
|
||||
optional HTTP http = 1;
|
||||
|
||||
// TODO(benh): Consider adding a URL health check strategy which
|
||||
// allows doing something similar to the HTTP strategy but
|
||||
// encapsulates all the details in a single string field.
|
||||
|
||||
// TODO(benh): Other possible health check strategies could include
|
||||
// one for TCP/UDP or a "command". A "command" could be running a
|
||||
// (shell) command to check the healthiness. We'd need to determine
|
||||
// what arguments (or environment variables) we'd want to set so
|
||||
// that the command could do it's job (i.e., do we want to expose
|
||||
// the stdout/stderr and/or the pid to make checking for healthiness
|
||||
// easier).
|
||||
|
||||
// Amount of time to wait until starting the health checks.
|
||||
optional double delay_seconds = 2 [default = 15.0];
|
||||
|
||||
// Interval between health checks.
|
||||
optional double interval_seconds = 3 [default = 10.0];
|
||||
|
||||
// Amount of time to wait for the health check to complete.
|
||||
optional double timeout_seconds = 4 [default = 20.0];
|
||||
|
||||
// Number of consecutive failures until considered unhealthy.
|
||||
optional uint32 consecutive_failures = 5 [default = 3];
|
||||
|
||||
// Amount of time to allow failed health checks since launch.
|
||||
optional double grace_period_seconds = 6 [default = 10.0];
|
||||
|
||||
// Command health check.
|
||||
optional CommandInfo command = 7;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a command, executed via: '/bin/sh -c value'. Any URIs specified
|
||||
* are fetched before executing the command. If the executable field for an
|
||||
* uri is set, executable file permission is set on the downloaded file.
|
||||
* Otherwise, if the downloaded file has a recognized archive extension
|
||||
* (currently [compressed] tar and zip) it is extracted into the executor's
|
||||
* working directory. This extraction can be disabled by setting `extract` to
|
||||
* false. In addition, any environment variables are set before executing
|
||||
* the command (so they can be used to "parameterize" your command).
|
||||
*/
|
||||
message CommandInfo {
|
||||
message URI {
|
||||
required string value = 1;
|
||||
optional bool executable = 2;
|
||||
optional bool extract = 3 [default = true];
|
||||
}
|
||||
|
||||
// Describes a container.
|
||||
// Not all containerizers currently implement ContainerInfo, so it
|
||||
// is possible that a launched task will fail due to supplying this
|
||||
// attribute.
|
||||
// NOTE: The containerizer API is currently in an early beta or
|
||||
// even alpha state. Some details, like the exact semantics of an
|
||||
// "image" or "options" are not yet hardened.
|
||||
// TODO(tillt): Describe the exact scheme and semantics of "image"
|
||||
// and "options".
|
||||
message ContainerInfo {
|
||||
// URI describing the container image name.
|
||||
required string image = 1;
|
||||
|
||||
// Describes additional options passed to the containerizer.
|
||||
repeated string options = 2;
|
||||
}
|
||||
|
||||
// NOTE: MesosContainerizer does currently not support this
|
||||
// attribute and tasks supplying a 'container' will fail.
|
||||
optional ContainerInfo container = 4;
|
||||
|
||||
repeated URI uris = 1;
|
||||
|
||||
optional Environment environment = 2;
|
||||
|
||||
// There are two ways to specify the command:
|
||||
// 1) If 'shell == true', the command will be launched via shell
|
||||
// (i.e., /bin/sh -c 'value'). The 'value' specified will be
|
||||
// treated as the shell command. The 'arguments' will be ignored.
|
||||
// 2) If 'shell == false', the command will be launched by passing
|
||||
// arguments to an executable. The 'value' specified will be
|
||||
// treated as the filename of the executable. The 'arguments'
|
||||
// will be treated as the arguments to the executable. This is
|
||||
// similar to how POSIX exec families launch processes (i.e.,
|
||||
// execlp(value, arguments(0), arguments(1), ...)).
|
||||
// NOTE: The field 'value' is changed from 'required' to 'optional'
|
||||
// in 0.20.0. It will only cause issues if a new framework is
|
||||
// connecting to an old master.
|
||||
optional bool shell = 6 [default = true];
|
||||
optional string value = 3;
|
||||
repeated string arguments = 7;
|
||||
|
||||
// Enables executor and tasks to run as a specific user. If the user
|
||||
// field is present both in FrameworkInfo and here, the CommandInfo
|
||||
// user value takes precedence.
|
||||
optional string user = 5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes information about an executor. The 'data' field can be
|
||||
* used to pass arbitrary bytes to an executor.
|
||||
*/
|
||||
message ExecutorInfo {
|
||||
required ExecutorID executor_id = 1;
|
||||
optional FrameworkID framework_id = 8; // TODO(benh): Make this required.
|
||||
required CommandInfo command = 7;
|
||||
// Executor provided with a container will launch the container
|
||||
// with the executor's CommandInfo and we expect the container to
|
||||
// act as a Mesos executor.
|
||||
optional ContainerInfo container = 11;
|
||||
repeated Resource resources = 5;
|
||||
optional string name = 9;
|
||||
|
||||
// Source is an identifier style string used by frameworks to track
|
||||
// the source of an executor. This is useful when it's possible for
|
||||
// different executor ids to be related semantically.
|
||||
// NOTE: Source is exposed alongside the resource usage of the
|
||||
// executor via JSON on the slave. This allows users to import
|
||||
// usage information into a time series database for monitoring.
|
||||
optional string source = 10;
|
||||
optional bytes data = 4;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a master. This will probably have more fields in the
|
||||
* future which might be used, for example, to link a framework webui
|
||||
* to a master webui.
|
||||
*/
|
||||
message MasterInfo {
|
||||
required string id = 1;
|
||||
required uint32 ip = 2;
|
||||
required uint32 port = 3 [default = 5050];
|
||||
optional string pid = 4;
|
||||
optional string hostname = 5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a slave. Note that the 'id' field is only available after
|
||||
* a slave is registered with the master, and is made available here
|
||||
* to facilitate re-registration. If checkpoint is set, the slave is
|
||||
* checkpointing its own information and potentially frameworks'
|
||||
* information (if a framework has checkpointing enabled).
|
||||
*/
|
||||
message SlaveInfo {
|
||||
required string hostname = 1;
|
||||
optional int32 port = 8 [default = 5051];
|
||||
repeated Resource resources = 3;
|
||||
repeated Attribute attributes = 5;
|
||||
optional SlaveID id = 6;
|
||||
optional bool checkpoint = 7 [default = false];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes an Attribute or Resource "value". A value is described
|
||||
* using the standard protocol buffer "union" trick.
|
||||
*/
|
||||
message Value {
|
||||
enum Type {
|
||||
SCALAR = 0;
|
||||
RANGES = 1;
|
||||
SET = 2;
|
||||
TEXT = 3;
|
||||
}
|
||||
|
||||
message Scalar {
|
||||
required double value = 1;
|
||||
}
|
||||
|
||||
message Range {
|
||||
required uint64 begin = 1;
|
||||
required uint64 end = 2;
|
||||
}
|
||||
|
||||
message Ranges {
|
||||
repeated Range range = 1;
|
||||
}
|
||||
|
||||
message Set {
|
||||
repeated string item = 1;
|
||||
}
|
||||
|
||||
message Text {
|
||||
required string value = 1;
|
||||
}
|
||||
|
||||
required Type type = 1;
|
||||
optional Scalar scalar = 2;
|
||||
optional Ranges ranges = 3;
|
||||
optional Set set = 4;
|
||||
optional Text text = 5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes an attribute that can be set on a machine. For now,
|
||||
* attributes and resources share the same "value" type, but this may
|
||||
* change in the future and attributes may only be string based.
|
||||
*/
|
||||
message Attribute {
|
||||
required string name = 1;
|
||||
required Value.Type type = 2;
|
||||
optional Value.Scalar scalar = 3;
|
||||
optional Value.Ranges ranges = 4;
|
||||
optional Value.Set set = 6;
|
||||
optional Value.Text text = 5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a resource on a machine. A resource can take on one of
|
||||
* three types: scalar (double), a list of finite and discrete ranges
|
||||
* (e.g., [1-10, 20-30]), or a set of items. A resource is described
|
||||
* using the standard protocol buffer "union" trick.
|
||||
*
|
||||
* TODO(benh): Add better support for "expected" resources (e.g.,
|
||||
* cpus, memory, disk, network).
|
||||
*/
|
||||
message Resource {
|
||||
required string name = 1;
|
||||
required Value.Type type = 2;
|
||||
optional Value.Scalar scalar = 3;
|
||||
optional Value.Ranges ranges = 4;
|
||||
optional Value.Set set = 5;
|
||||
optional string role = 6 [default = "*"];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A snapshot of resource usage statistics.
|
||||
*/
|
||||
message ResourceStatistics {
|
||||
required double timestamp = 1; // Snapshot time, in seconds since the Epoch.
|
||||
|
||||
// CPU Usage Information:
|
||||
// Total CPU time spent in user mode, and kernel mode.
|
||||
optional double cpus_user_time_secs = 2;
|
||||
optional double cpus_system_time_secs = 3;
|
||||
|
||||
// Number of CPUs allocated.
|
||||
optional double cpus_limit = 4;
|
||||
|
||||
// cpu.stat on process throttling (for contention issues).
|
||||
optional uint32 cpus_nr_periods = 7;
|
||||
optional uint32 cpus_nr_throttled = 8;
|
||||
optional double cpus_throttled_time_secs = 9;
|
||||
|
||||
// Memory Usage Information:
|
||||
optional uint64 mem_rss_bytes = 5; // Resident Set Size.
|
||||
|
||||
// Amount of memory resources allocated.
|
||||
optional uint64 mem_limit_bytes = 6;
|
||||
|
||||
// Broken out memory usage information (files, anonymous, and mmaped files)
|
||||
optional uint64 mem_file_bytes = 10;
|
||||
optional uint64 mem_anon_bytes = 11;
|
||||
optional uint64 mem_mapped_file_bytes = 12;
|
||||
|
||||
// TODO(bmahler): Add disk usage.
|
||||
|
||||
// Perf statistics.
|
||||
optional PerfStatistics perf = 13;
|
||||
|
||||
// Network Usage Information:
|
||||
optional uint64 net_rx_packets = 14;
|
||||
optional uint64 net_rx_bytes = 15;
|
||||
optional uint64 net_rx_errors = 16;
|
||||
optional uint64 net_rx_dropped = 17;
|
||||
optional uint64 net_tx_packets = 18;
|
||||
optional uint64 net_tx_bytes = 19;
|
||||
optional uint64 net_tx_errors = 20;
|
||||
optional uint64 net_tx_dropped = 21;
|
||||
|
||||
// The kernel keeps track of RTT (round-trip time) for its TCP
|
||||
// sockets. RTT is a way to tell the latency of a container.
|
||||
optional double net_tcp_rtt_microsecs_p50 = 22;
|
||||
optional double net_tcp_rtt_microsecs_p90 = 23;
|
||||
optional double net_tcp_rtt_microsecs_p95 = 24;
|
||||
optional double net_tcp_rtt_microsecs_p99 = 25;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a snapshot of the resource usage for an executor.
|
||||
*
|
||||
* TODO(bmahler): Note that we want to be sending this information
|
||||
* to the master, and subsequently to the relevant scheduler. So
|
||||
* this proto is designed to be easy for the scheduler to use, this
|
||||
* is why we provide the slave id, executor info / task info.
|
||||
*/
|
||||
message ResourceUsage {
|
||||
required SlaveID slave_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
|
||||
// Resource usage is for an executor. For tasks launched with
|
||||
// an explicit executor, the executor id is provided. For tasks
|
||||
// launched without an executor, our internal executor will be
|
||||
// used. In this case, we provide the task id here instead, in
|
||||
// order to make this message easier for schedulers to work with.
|
||||
|
||||
optional ExecutorID executor_id = 3; // If present, this executor was
|
||||
optional string executor_name = 4; // explicitly specified.
|
||||
|
||||
optional TaskID task_id = 5; // If present, the task did not have an executor.
|
||||
|
||||
// If missing, the isolation module cannot provide resource usage.
|
||||
optional ResourceStatistics statistics = 6;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a sample of events from "perf stat". Only available on
|
||||
* Linux.
|
||||
*
|
||||
* NOTE: Each optional field matches the name of a perf event (see
|
||||
* "perf list") with the following changes:
|
||||
* 1. Names are downcased.
|
||||
* 2. Hyphens ('-') are replaced with underscores ('_').
|
||||
* 3. Events with alternate names use the name "perf stat" returns,
|
||||
* e.g., for the event "cycles OR cpu-cycles" perf always returns
|
||||
* cycles.
|
||||
*/
|
||||
message PerfStatistics {
|
||||
required double timestamp = 1; // Start of sample interval, in seconds since the Epoch.
|
||||
required double duration = 2; // Duration of sample interval, in seconds.
|
||||
|
||||
// Hardware event.
|
||||
optional uint64 cycles = 3;
|
||||
optional uint64 stalled_cycles_frontend = 4;
|
||||
optional uint64 stalled_cycles_backend = 5;
|
||||
optional uint64 instructions = 6;
|
||||
optional uint64 cache_references = 7;
|
||||
optional uint64 cache_misses = 8;
|
||||
optional uint64 branches = 9;
|
||||
optional uint64 branch_misses = 10;
|
||||
optional uint64 bus_cycles = 11;
|
||||
optional uint64 ref_cycles = 12;
|
||||
|
||||
// Software event.
|
||||
optional double cpu_clock = 13;
|
||||
optional double task_clock = 14;
|
||||
optional uint64 page_faults = 15;
|
||||
optional uint64 minor_faults = 16;
|
||||
optional uint64 major_faults = 17;
|
||||
optional uint64 context_switches = 18;
|
||||
optional uint64 cpu_migrations = 19;
|
||||
optional uint64 alignment_faults = 20;
|
||||
optional uint64 emulation_faults = 21;
|
||||
|
||||
// Hardware cache event.
|
||||
optional uint64 l1_dcache_loads = 22;
|
||||
optional uint64 l1_dcache_load_misses = 23;
|
||||
optional uint64 l1_dcache_stores = 24;
|
||||
optional uint64 l1_dcache_store_misses = 25;
|
||||
optional uint64 l1_dcache_prefetches = 26;
|
||||
optional uint64 l1_dcache_prefetch_misses = 27;
|
||||
optional uint64 l1_icache_loads = 28;
|
||||
optional uint64 l1_icache_load_misses = 29;
|
||||
optional uint64 l1_icache_prefetches = 30;
|
||||
optional uint64 l1_icache_prefetch_misses = 31;
|
||||
optional uint64 llc_loads = 32;
|
||||
optional uint64 llc_load_misses = 33;
|
||||
optional uint64 llc_stores = 34;
|
||||
optional uint64 llc_store_misses = 35;
|
||||
optional uint64 llc_prefetches = 36;
|
||||
optional uint64 llc_prefetch_misses = 37;
|
||||
optional uint64 dtlb_loads = 38;
|
||||
optional uint64 dtlb_load_misses = 39;
|
||||
optional uint64 dtlb_stores = 40;
|
||||
optional uint64 dtlb_store_misses = 41;
|
||||
optional uint64 dtlb_prefetches = 42;
|
||||
optional uint64 dtlb_prefetch_misses = 43;
|
||||
optional uint64 itlb_loads = 44;
|
||||
optional uint64 itlb_load_misses = 45;
|
||||
optional uint64 branch_loads = 46;
|
||||
optional uint64 branch_load_misses = 47;
|
||||
optional uint64 node_loads = 48;
|
||||
optional uint64 node_load_misses = 49;
|
||||
optional uint64 node_stores = 50;
|
||||
optional uint64 node_store_misses = 51;
|
||||
optional uint64 node_prefetches = 52;
|
||||
optional uint64 node_prefetch_misses = 53;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a request for resources that can be used by a framework
|
||||
* to proactively influence the allocator. If 'slave_id' is provided
|
||||
* then this request is assumed to only apply to resources on that
|
||||
* slave.
|
||||
*/
|
||||
message Request {
|
||||
optional SlaveID slave_id = 1;
|
||||
repeated Resource resources = 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes some resources available on a slave. An offer only
|
||||
* contains resources from a single slave.
|
||||
*/
|
||||
message Offer {
|
||||
required OfferID id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
required SlaveID slave_id = 3;
|
||||
required string hostname = 4;
|
||||
repeated Resource resources = 5;
|
||||
repeated Attribute attributes = 7;
|
||||
repeated ExecutorID executor_ids = 6;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a task. Passed from the scheduler all the way to an
|
||||
* executor (see SchedulerDriver::launchTasks and
|
||||
* Executor::launchTask). Either ExecutorInfo or CommandInfo should be set.
|
||||
* A different executor can be used to launch this task, and subsequent tasks
|
||||
* meant for the same executor can reuse the same ExecutorInfo struct.
|
||||
*/
|
||||
message TaskInfo {
|
||||
required string name = 1;
|
||||
required TaskID task_id = 2;
|
||||
required SlaveID slave_id = 3;
|
||||
repeated Resource resources = 4;
|
||||
optional ExecutorInfo executor = 5;
|
||||
optional CommandInfo command = 7;
|
||||
// Task provided with a container will launch the container as part
|
||||
// of this task paired with the task's CommandInfo.
|
||||
optional ContainerInfo container = 9;
|
||||
optional bytes data = 6;
|
||||
// A health check for the task (currently in *alpha* and initial
|
||||
// support will only be for TaskInfo's that have a CommandInfo).
|
||||
optional HealthCheck health_check = 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes possible task states. IMPORTANT: Mesos assumes tasks that
|
||||
* enter terminal states (see below) imply the task is no longer
|
||||
* running and thus clean up any thing associated with the task
|
||||
* (ultimately offering any resources being consumed by that task to
|
||||
* another task).
|
||||
*/
|
||||
enum TaskState {
|
||||
TASK_STAGING = 6; // Initial state. Framework status updates should not use.
|
||||
TASK_STARTING = 0;
|
||||
TASK_RUNNING = 1;
|
||||
TASK_FINISHED = 2; // TERMINAL. The task finished successfully.
|
||||
TASK_FAILED = 3; // TERMINAL. The task failed to finish successfully.
|
||||
TASK_KILLED = 4; // TERMINAL. The task was killed by the executor.
|
||||
TASK_LOST = 5; // TERMINAL. The task failed but can be rescheduled.
|
||||
// TASK_ERROR is currently unused but will be introduced in 0.22.0.
|
||||
// TODO(dhamon): Start using TASK_ERROR.
|
||||
TASK_ERROR = 7; // TERMINAL. The task description contains an error.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes the current status of a task.
|
||||
*/
|
||||
message TaskStatus {
|
||||
/** Describes the source of the task status update. */
|
||||
enum Source {
|
||||
SOURCE_MASTER = 0;
|
||||
SOURCE_SLAVE = 1;
|
||||
SOURCE_EXECUTOR = 2;
|
||||
}
|
||||
|
||||
/** Detailed reason for the task status update. */
|
||||
enum Reason {
|
||||
REASON_COMMAND_EXECUTOR_FAILED = 0;
|
||||
REASON_EXECUTOR_TERMINATED = 1;
|
||||
REASON_EXECUTOR_UNREGISTERED = 2;
|
||||
REASON_FRAMEWORK_REMOVED = 3;
|
||||
REASON_GC_ERROR = 4;
|
||||
REASON_INVALID_FRAMEWORKID = 5;
|
||||
REASON_INVALID_OFFERS = 6;
|
||||
REASON_MASTER_DISCONNECTED = 7;
|
||||
REASON_MEMORY_LIMIT = 8;
|
||||
REASON_RECONCILIATION = 9;
|
||||
REASON_SLAVE_DISCONNECTED = 10;
|
||||
REASON_SLAVE_REMOVED = 11;
|
||||
REASON_SLAVE_RESTARTED = 12;
|
||||
REASON_SLAVE_UNKNOWN = 13;
|
||||
REASON_TASK_INVALID = 14;
|
||||
REASON_TASK_UNAUTHORIZED = 15;
|
||||
REASON_TASK_UNKNOWN = 16;
|
||||
}
|
||||
|
||||
required TaskID task_id = 1;
|
||||
required TaskState state = 2;
|
||||
optional string message = 4; // Possible message explaining state.
|
||||
optional Source source = 9;
|
||||
optional Reason reason = 10;
|
||||
optional bytes data = 3;
|
||||
optional SlaveID slave_id = 5;
|
||||
optional ExecutorID executor_id = 7; // TODO(benh): Use in master/slave.
|
||||
optional double timestamp = 6;
|
||||
|
||||
// Describes whether the task has been determined to be healthy
|
||||
// (true) or unhealthy (false) according to the HealthCheck field in
|
||||
// the command info.
|
||||
optional bool healthy = 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes possible filters that can be applied to unused resources
|
||||
* (see SchedulerDriver::launchTasks) to influence the allocator.
|
||||
*/
|
||||
message Filters {
|
||||
// Time to consider unused resources refused. Note that all unused
|
||||
// resources will be considered refused and use the default value
|
||||
// (below) regardless of whether Filters was passed to
|
||||
// SchedulerDriver::launchTasks. You MUST pass Filters with this
|
||||
// field set to change this behavior (i.e., get another offer which
|
||||
// includes unused resources sooner or later than the default).
|
||||
optional double refuse_seconds = 1 [default = 5.0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a collection of environment variables. This is used with
|
||||
* CommandInfo in order to set environment variables before running a
|
||||
* command.
|
||||
*/
|
||||
message Environment {
|
||||
message Variable {
|
||||
required string name = 1;
|
||||
required string value = 2;
|
||||
}
|
||||
|
||||
repeated Variable variables = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A generic (key, value) pair used in various places for parameters.
|
||||
*/
|
||||
message Parameter {
|
||||
required string key = 1;
|
||||
required string value = 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collection of Parameter.
|
||||
*/
|
||||
message Parameters {
|
||||
repeated Parameter parameter = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Credential used in various places for authentication and
|
||||
* authorization.
|
||||
*
|
||||
* NOTE: A 'principal' is different from 'FrameworkInfo.user'. The
|
||||
* former is used for authentication and authorization while the
|
||||
* latter is used to determine the default user under which the
|
||||
* framework's executors/tasks are run.
|
||||
*/
|
||||
message Credential {
|
||||
required string principal = 1;
|
||||
optional bytes secret = 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Credentials used for framework authentication, HTTP authentication
|
||||
* (where the common 'username' and 'password' are captured as
|
||||
* 'principal' and 'secret' respectively), etc.
|
||||
*/
|
||||
message Credentials {
|
||||
repeated Credential credentials = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ACLs used for authorization.
|
||||
*/
|
||||
message ACL {
|
||||
|
||||
// Entity is used to describe a subject(s) or an object(s) of an ACL.
|
||||
// NOTE:
|
||||
// To allow everyone access to an Entity set its type to 'ANY'.
|
||||
// To deny access to an Entity set its type to 'NONE'.
|
||||
message Entity {
|
||||
enum Type {
|
||||
SOME = 0;
|
||||
ANY = 1;
|
||||
NONE = 2;
|
||||
}
|
||||
optional Type type = 1 [default = SOME];
|
||||
repeated string values = 2; // Ignored for ANY/NONE.
|
||||
}
|
||||
|
||||
// ACLs.
|
||||
message RegisterFramework {
|
||||
// Subjects.
|
||||
required Entity principals = 1; // Framework principals.
|
||||
|
||||
// Objects.
|
||||
required Entity roles = 2; // Roles for resource offers.
|
||||
}
|
||||
|
||||
message RunTask {
|
||||
// Subjects.
|
||||
required Entity principals = 1; // Framework principals.
|
||||
|
||||
// Objects.
|
||||
required Entity users = 2; // Users to run the tasks/executors as.
|
||||
}
|
||||
|
||||
// Which principals are authorized to shutdown frameworks of other
|
||||
// principals.
|
||||
message ShutdownFramework {
|
||||
// Subjects.
|
||||
required Entity principals = 1;
|
||||
|
||||
// Objects.
|
||||
required Entity framework_principals = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collection of ACL.
|
||||
*
|
||||
* Each authorization request is evaluated against the ACLs in the order
|
||||
* they are defined.
|
||||
*
|
||||
* For simplicity, the ACLs for a given action are not aggregated even
|
||||
* when they have the same subjects or objects. The first ACL that
|
||||
* matches the request determines whether that request should be
|
||||
* permitted or not. An ACL matches iff both the subjects
|
||||
* (e.g., clients, principals) and the objects (e.g., urls, users,
|
||||
* roles) of the ACL match the request.
|
||||
*
|
||||
* If none of the ACLs match the request, the 'permissive' field
|
||||
* determines whether the request should be permitted or not.
|
||||
*
|
||||
* TODO(vinod): Do aggregation of ACLs when possible.
|
||||
*
|
||||
*/
|
||||
message ACLs {
|
||||
optional bool permissive = 1 [default = true];
|
||||
repeated ACL.RegisterFramework register_frameworks = 2;
|
||||
repeated ACL.RunTask run_tasks = 3;
|
||||
repeated ACL.ShutdownFramework shutdown_frameworks = 4;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rate (queries per second, QPS) limit for messages from a framework to master.
|
||||
* Strictly speaking they are the combined rate from all frameworks of the same
|
||||
* principal.
|
||||
*/
|
||||
message RateLimit {
|
||||
// Leaving QPS unset gives it unlimited rate (i.e., not throttled),
|
||||
// which also implies unlimited capacity.
|
||||
optional double qps = 1;
|
||||
|
||||
// Principal of framework(s) to be throttled. Should match
|
||||
// FrameworkInfo.princpal and Credential.principal (if using authentication).
|
||||
required string principal = 2;
|
||||
|
||||
// Max number of outstanding messages from frameworks of this principal
|
||||
// allowed by master before the next message is dropped and an error is sent
|
||||
// back to the sender. Messages received before the capacity is reached are
|
||||
// still going to be processed after the error is sent.
|
||||
// If unspecified, this principal is assigned unlimited capacity.
|
||||
// NOTE: This value is ignored if 'qps' is not set.
|
||||
optional uint64 capacity = 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collection of RateLimit.
|
||||
* Frameworks without rate limits defined here are not throttled unless
|
||||
* 'aggregate_default_qps' is specified.
|
||||
*/
|
||||
message RateLimits {
|
||||
// Items should have unique principals.
|
||||
repeated RateLimit limits = 1;
|
||||
|
||||
// All the frameworks not specified in 'limits' get this default rate.
|
||||
// This rate is an aggregate rate for all of them, i.e., their combined
|
||||
// traffic is throttled together at this rate.
|
||||
optional double aggregate_default_qps = 2;
|
||||
|
||||
// All the frameworks not specified in 'limits' get this default capacity.
|
||||
// This is an aggregate value similar to 'aggregate_default_qps'.
|
||||
optional uint64 aggregate_default_capacity = 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a volume mapping either from host to container or vice
|
||||
* versa. Both paths can either refer to a directory or a file.
|
||||
*/
|
||||
message Volume {
|
||||
// Absolute path pointing to a directory or file in the container.
|
||||
required string container_path = 1;
|
||||
|
||||
// Absolute path pointing to a directory or file on the host or a path
|
||||
// relative to the container work directory.
|
||||
optional string host_path = 2;
|
||||
|
||||
enum Mode {
|
||||
RW = 1; // read-write.
|
||||
RO = 2; // read-only.
|
||||
}
|
||||
|
||||
required Mode mode = 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Describes a container configuration and allows extensible
|
||||
* configurations for different container implementations.
|
||||
*/
|
||||
message ContainerInfo {
|
||||
// All container implementation types.
|
||||
enum Type {
|
||||
DOCKER = 1;
|
||||
MESOS = 2;
|
||||
}
|
||||
|
||||
message DockerInfo {
|
||||
// The docker image that is going to be passed to the registry.
|
||||
required string image = 1;
|
||||
|
||||
// Network options.
|
||||
enum Network {
|
||||
HOST = 1;
|
||||
BRIDGE = 2;
|
||||
NONE = 3;
|
||||
}
|
||||
|
||||
optional Network network = 2 [default = HOST];
|
||||
|
||||
message PortMapping {
|
||||
required uint32 host_port = 1;
|
||||
required uint32 container_port = 2;
|
||||
// Protocol to expose as (ie: tcp, udp).
|
||||
optional string protocol = 3;
|
||||
}
|
||||
|
||||
repeated PortMapping port_mappings = 3;
|
||||
|
||||
optional bool privileged = 4 [default = false];
|
||||
|
||||
// Allowing arbitrary parameters to be passed to docker CLI.
|
||||
// Note that anything passed to this field is not guranteed
|
||||
// to be supported moving forward, as we might move away from
|
||||
// the docker CLI.
|
||||
repeated Parameter parameters = 5;
|
||||
}
|
||||
|
||||
required Type type = 1;
|
||||
repeated Volume volumes = 2;
|
||||
optional string hostname = 4;
|
||||
|
||||
optional DockerInfo docker = 3;
|
||||
}
|
||||
10426
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesospb_test.go
generated
vendored
Normal file
10426
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/mesospb_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1550
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/messages.pb.go
generated
vendored
Normal file
1550
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/messages.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
453
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/messages.proto
generated
vendored
Normal file
453
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/messages.proto
generated
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
// TODO(benh): Provide comments for each of these messages. Also,
|
||||
// consider splitting these messages into different "packages" which
|
||||
// represent which messages get handled by which components (e.g., the
|
||||
// "mesos.internal.executor" package includes messages that the
|
||||
// executor handles).
|
||||
|
||||
|
||||
// TODO(benh): It would be great if this could just be a
|
||||
// TaskInfo wherever it gets used! However, doing so would
|
||||
// require adding the framework_id field, the executor_id field, and
|
||||
// the state field into TaskInfo though (or send them another
|
||||
// way). Also, one performance reason why we don't do that now is
|
||||
// because storing whatever data is coupled with a TaskInfo
|
||||
// could be large and unnecessary.
|
||||
// TODO(bmahler): Add executor_uuid here, and send it to the master. This will
|
||||
// allow us to expose executor work directories for tasks in the webui when
|
||||
// looking from the master level. Currently only the slave knows which run the
|
||||
// task belongs to.
|
||||
message Task {
|
||||
required string name = 1;
|
||||
required TaskID task_id = 2;
|
||||
required FrameworkID framework_id = 3;
|
||||
optional ExecutorID executor_id = 4;
|
||||
required SlaveID slave_id = 5;
|
||||
required TaskState state = 6; // Latest state of the task.
|
||||
repeated Resource resources = 7;
|
||||
repeated TaskStatus statuses = 8;
|
||||
|
||||
// These fields correspond to the state and uuid of the latest
|
||||
// status update forwarded to the master.
|
||||
// NOTE: Either both the fields must be set or both must be unset.
|
||||
optional TaskState status_update_state = 9;
|
||||
optional bytes status_update_uuid = 10;
|
||||
}
|
||||
|
||||
|
||||
// Describes a role, which are used to group frameworks for allocation
|
||||
// decisions, depending on the allocation policy being used.
|
||||
// The weight field can be used to indicate forms of priority.
|
||||
message RoleInfo {
|
||||
required string name = 1;
|
||||
optional double weight = 2 [default = 1];
|
||||
}
|
||||
|
||||
|
||||
// TODO(vinod): Create a new UUID message type.
|
||||
message StatusUpdate {
|
||||
required FrameworkID framework_id = 1;
|
||||
optional ExecutorID executor_id = 2;
|
||||
optional SlaveID slave_id = 3;
|
||||
required TaskStatus status = 4;
|
||||
required double timestamp = 5;
|
||||
required bytes uuid = 6;
|
||||
|
||||
// This corresponds to the latest state of the task according to the
|
||||
// slave. Note that this state might be different than the state in
|
||||
// 'status' because status update manager queues updates. In other
|
||||
// words, 'status' corresponds to the update at top of the queue and
|
||||
// 'latest_state' corresponds to the update at bottom of the queue.
|
||||
optional TaskState latest_state = 7;
|
||||
}
|
||||
|
||||
|
||||
// This message encapsulates how we checkpoint a status update to disk.
|
||||
// NOTE: If type == UPDATE, the 'update' field is required.
|
||||
// NOTE: If type == ACK, the 'uuid' field is required.
|
||||
message StatusUpdateRecord {
|
||||
enum Type {
|
||||
UPDATE = 0;
|
||||
ACK = 1;
|
||||
}
|
||||
required Type type = 1;
|
||||
optional StatusUpdate update = 2;
|
||||
optional bytes uuid = 3;
|
||||
}
|
||||
|
||||
|
||||
message SubmitSchedulerRequest
|
||||
{
|
||||
required string name = 1;
|
||||
}
|
||||
|
||||
|
||||
message SubmitSchedulerResponse
|
||||
{
|
||||
required bool okay = 1;
|
||||
}
|
||||
|
||||
|
||||
message ExecutorToFrameworkMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
required ExecutorID executor_id = 3;
|
||||
required bytes data = 4;
|
||||
}
|
||||
|
||||
|
||||
message FrameworkToExecutorMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
required ExecutorID executor_id = 3;
|
||||
required bytes data = 4;
|
||||
}
|
||||
|
||||
|
||||
message RegisterFrameworkMessage {
|
||||
required FrameworkInfo framework = 1;
|
||||
}
|
||||
|
||||
|
||||
message ReregisterFrameworkMessage {
|
||||
required FrameworkInfo framework = 2;
|
||||
required bool failover = 3;
|
||||
}
|
||||
|
||||
|
||||
message FrameworkRegisteredMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
required MasterInfo master_info = 2;
|
||||
}
|
||||
|
||||
message FrameworkReregisteredMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
required MasterInfo master_info = 2;
|
||||
}
|
||||
|
||||
message UnregisterFrameworkMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message DeactivateFrameworkMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message ResourceRequestMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
repeated Request requests = 2;
|
||||
}
|
||||
|
||||
|
||||
message ResourceOffersMessage {
|
||||
repeated Offer offers = 1;
|
||||
repeated string pids = 2;
|
||||
}
|
||||
|
||||
|
||||
message LaunchTasksMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
repeated TaskInfo tasks = 3;
|
||||
required Filters filters = 5;
|
||||
repeated OfferID offer_ids = 6;
|
||||
}
|
||||
|
||||
|
||||
message RescindResourceOfferMessage {
|
||||
required OfferID offer_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message ReviveOffersMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message RunTaskMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
required FrameworkInfo framework = 2;
|
||||
required string pid = 3;
|
||||
required TaskInfo task = 4;
|
||||
}
|
||||
|
||||
|
||||
message KillTaskMessage {
|
||||
// TODO(bmahler): Include the SlaveID here to improve the Master's
|
||||
// ability to respond for non-activated slaves.
|
||||
required FrameworkID framework_id = 1;
|
||||
required TaskID task_id = 2;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: If 'pid' is present, scheduler driver sends an
|
||||
// acknowledgement to the pid.
|
||||
message StatusUpdateMessage {
|
||||
required StatusUpdate update = 1;
|
||||
optional string pid = 2;
|
||||
}
|
||||
|
||||
|
||||
message StatusUpdateAcknowledgementMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
required TaskID task_id = 3;
|
||||
required bytes uuid = 4;
|
||||
}
|
||||
|
||||
|
||||
message LostSlaveMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
}
|
||||
|
||||
|
||||
// Allows the framework to query the status for non-terminal tasks.
|
||||
// This causes the master to send back the latest task status for
|
||||
// each task in 'statuses', if possible. Tasks that are no longer
|
||||
// known will result in a TASK_LOST update. If statuses is empty,
|
||||
// then the master will send the latest status for each task
|
||||
// currently known.
|
||||
message ReconcileTasksMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
repeated TaskStatus statuses = 2; // Should be non-terminal only.
|
||||
}
|
||||
|
||||
|
||||
message FrameworkErrorMessage {
|
||||
required string message = 2;
|
||||
}
|
||||
|
||||
|
||||
message RegisterSlaveMessage {
|
||||
required SlaveInfo slave = 1;
|
||||
|
||||
// NOTE: This is a hack for the master to detect the slave's
|
||||
// version. If unset the slave is < 0.21.0.
|
||||
// TODO(bmahler): Do proper versioning: MESOS-986.
|
||||
optional string version = 2;
|
||||
}
|
||||
|
||||
|
||||
message ReregisterSlaveMessage {
|
||||
// TODO(bmahler): slave_id is deprecated.
|
||||
// 0.21.0: Now an optional field. Always written, never read.
|
||||
// 0.22.0: Remove this field.
|
||||
optional SlaveID slave_id = 1;
|
||||
required SlaveInfo slave = 2;
|
||||
repeated ExecutorInfo executor_infos = 4;
|
||||
repeated Task tasks = 3;
|
||||
repeated Archive.Framework completed_frameworks = 5;
|
||||
|
||||
// NOTE: This is a hack for the master to detect the slave's
|
||||
// version. If unset the slave is < 0.21.0.
|
||||
// TODO(bmahler): Do proper versioning: MESOS-986.
|
||||
optional string version = 6;
|
||||
}
|
||||
|
||||
|
||||
message SlaveRegisteredMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message SlaveReregisteredMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
|
||||
repeated ReconcileTasksMessage reconciliations = 2;
|
||||
}
|
||||
|
||||
|
||||
message UnregisterSlaveMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
}
|
||||
|
||||
|
||||
// This message is periodically sent by the master to the slave.
|
||||
// If the slave is connected to the master, "connected" is true.
|
||||
message PingSlaveMessage {
|
||||
required bool connected = 1;
|
||||
}
|
||||
|
||||
|
||||
// This message is sent by the slave to the master in response to the
|
||||
// PingSlaveMessage.
|
||||
message PongSlaveMessage {}
|
||||
|
||||
|
||||
// Tells a slave to shut down all executors of the given framework.
|
||||
message ShutdownFrameworkMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
}
|
||||
|
||||
|
||||
// Tells the executor to initiate a shut down by invoking
|
||||
// Executor::shutdown.
|
||||
message ShutdownExecutorMessage {}
|
||||
|
||||
|
||||
message UpdateFrameworkMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
required string pid = 2;
|
||||
}
|
||||
|
||||
|
||||
message RegisterExecutorMessage {
|
||||
required FrameworkID framework_id = 1;
|
||||
required ExecutorID executor_id = 2;
|
||||
}
|
||||
|
||||
|
||||
message ExecutorRegisteredMessage {
|
||||
required ExecutorInfo executor_info = 2;
|
||||
required FrameworkID framework_id = 3;
|
||||
required FrameworkInfo framework_info = 4;
|
||||
required SlaveID slave_id = 5;
|
||||
required SlaveInfo slave_info = 6;
|
||||
}
|
||||
|
||||
|
||||
message ExecutorReregisteredMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
required SlaveInfo slave_info = 2;
|
||||
}
|
||||
|
||||
|
||||
message ExitedExecutorMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
required ExecutorID executor_id = 3;
|
||||
required int32 status = 4;
|
||||
}
|
||||
|
||||
|
||||
message ReconnectExecutorMessage {
|
||||
required SlaveID slave_id = 1;
|
||||
}
|
||||
|
||||
|
||||
message ReregisterExecutorMessage {
|
||||
required ExecutorID executor_id = 1;
|
||||
required FrameworkID framework_id = 2;
|
||||
repeated TaskInfo tasks = 3;
|
||||
repeated StatusUpdate updates = 4;
|
||||
}
|
||||
|
||||
|
||||
message ShutdownMessage {
|
||||
optional string message = 1;
|
||||
}
|
||||
|
||||
|
||||
message AuthenticateMessage {
|
||||
required string pid = 1; // PID that needs to be authenticated.
|
||||
}
|
||||
|
||||
|
||||
message AuthenticationMechanismsMessage {
|
||||
repeated string mechanisms = 1; // List of available SASL mechanisms.
|
||||
}
|
||||
|
||||
|
||||
message AuthenticationStartMessage {
|
||||
required string mechanism = 1;
|
||||
optional string data = 2;
|
||||
}
|
||||
|
||||
|
||||
message AuthenticationStepMessage {
|
||||
required bytes data = 1;
|
||||
}
|
||||
|
||||
|
||||
message AuthenticationCompletedMessage {}
|
||||
|
||||
|
||||
message AuthenticationFailedMessage {}
|
||||
|
||||
|
||||
message AuthenticationErrorMessage {
|
||||
optional string error = 1;
|
||||
}
|
||||
|
||||
|
||||
// TODO(adam-mesos): Move this to an 'archive' package.
|
||||
/**
|
||||
* Describes Completed Frameworks, etc. for archival.
|
||||
*/
|
||||
message Archive {
|
||||
message Framework {
|
||||
required FrameworkInfo framework_info = 1;
|
||||
optional string pid = 2;
|
||||
repeated Task tasks = 3;
|
||||
}
|
||||
repeated Framework frameworks = 1;
|
||||
}
|
||||
|
||||
// Message describing task current health status that is sent by
|
||||
// the task health checker to the command executor.
|
||||
// The command executor reports the task status back to the
|
||||
// on each receive. If the health checker configured faiure
|
||||
// condition meets, then kill_task flag will be set to true which
|
||||
// the executor on message receive will kill the task.
|
||||
message TaskHealthStatus {
|
||||
required TaskID task_id = 1;
|
||||
|
||||
required bool healthy = 2;
|
||||
|
||||
// Flag to initiate task kill.
|
||||
optional bool kill_task = 3 [default = false];
|
||||
|
||||
// Number of consecutive counts in current status.
|
||||
// This will not be populated if task is healthy.
|
||||
optional int32 consecutive_failures = 4;
|
||||
}
|
||||
|
||||
|
||||
// Collection of Modules.
|
||||
message Modules {
|
||||
message Library {
|
||||
// If "file" contains a slash ("/"), then it is interpreted as a
|
||||
// (relative or absolute) pathname. Otherwise a standard library
|
||||
// search is performed.
|
||||
optional string file = 1;
|
||||
|
||||
// We will add the proper prefix ("lib") and suffix (".so" for
|
||||
// Linux and ".dylib" for OS X) to the "name".
|
||||
optional string name = 2;
|
||||
|
||||
message Module {
|
||||
// Module name.
|
||||
optional string name = 1;
|
||||
|
||||
// Module-specific parameters.
|
||||
repeated Parameter parameters = 2;
|
||||
}
|
||||
|
||||
repeated Module modules = 3;
|
||||
}
|
||||
|
||||
repeated Library libraries = 1;
|
||||
}
|
||||
91
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/registry.pb.go
generated
vendored
Normal file
91
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/registry.pb.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: registry.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
package mesosproto
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// discarding unused import gogoproto "github.com/gogo/protobuf/gogoproto/gogo.pb"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
type Registry struct {
|
||||
// Most recent leading master.
|
||||
Master *Registry_Master `protobuf:"bytes,1,opt,name=master" json:"master,omitempty"`
|
||||
// All admitted slaves.
|
||||
Slaves *Registry_Slaves `protobuf:"bytes,2,opt,name=slaves" json:"slaves,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Registry) Reset() { *m = Registry{} }
|
||||
func (m *Registry) String() string { return proto.CompactTextString(m) }
|
||||
func (*Registry) ProtoMessage() {}
|
||||
|
||||
func (m *Registry) GetMaster() *Registry_Master {
|
||||
if m != nil {
|
||||
return m.Master
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Registry) GetSlaves() *Registry_Slaves {
|
||||
if m != nil {
|
||||
return m.Slaves
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Registry_Master struct {
|
||||
Info *MasterInfo `protobuf:"bytes,1,req,name=info" json:"info,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Registry_Master) Reset() { *m = Registry_Master{} }
|
||||
func (m *Registry_Master) String() string { return proto.CompactTextString(m) }
|
||||
func (*Registry_Master) ProtoMessage() {}
|
||||
|
||||
func (m *Registry_Master) GetInfo() *MasterInfo {
|
||||
if m != nil {
|
||||
return m.Info
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Registry_Slave struct {
|
||||
Info *SlaveInfo `protobuf:"bytes,1,req,name=info" json:"info,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Registry_Slave) Reset() { *m = Registry_Slave{} }
|
||||
func (m *Registry_Slave) String() string { return proto.CompactTextString(m) }
|
||||
func (*Registry_Slave) ProtoMessage() {}
|
||||
|
||||
func (m *Registry_Slave) GetInfo() *SlaveInfo {
|
||||
if m != nil {
|
||||
return m.Info
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Registry_Slaves struct {
|
||||
Slaves []*Registry_Slave `protobuf:"bytes,1,rep,name=slaves" json:"slaves,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Registry_Slaves) Reset() { *m = Registry_Slaves{} }
|
||||
func (m *Registry_Slaves) String() string { return proto.CompactTextString(m) }
|
||||
func (*Registry_Slaves) ProtoMessage() {}
|
||||
|
||||
func (m *Registry_Slaves) GetSlaves() []*Registry_Slave {
|
||||
if m != nil {
|
||||
return m.Slaves
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
42
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/registry.proto
generated
vendored
Normal file
42
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/registry.proto
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
message Registry {
|
||||
message Master {
|
||||
required MasterInfo info = 1;
|
||||
}
|
||||
|
||||
message Slave {
|
||||
required SlaveInfo info = 1;
|
||||
}
|
||||
|
||||
message Slaves {
|
||||
repeated Slave slaves = 1;
|
||||
}
|
||||
|
||||
// Most recent leading master.
|
||||
optional Master master = 1;
|
||||
|
||||
// All admitted slaves.
|
||||
optional Slaves slaves = 2;
|
||||
}
|
||||
674
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/scheduler.pb.go
generated
vendored
Normal file
674
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/scheduler.pb.go
generated
vendored
Normal file
@@ -0,0 +1,674 @@
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: scheduler.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
package mesosproto
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// discarding unused import gogoproto "github.com/gogo/protobuf/gogoproto/gogo.pb"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
// Possible event types, followed by message definitions if
|
||||
// applicable.
|
||||
type Event_Type int32
|
||||
|
||||
const (
|
||||
Event_REGISTERED Event_Type = 1
|
||||
Event_REREGISTERED Event_Type = 2
|
||||
Event_OFFERS Event_Type = 3
|
||||
Event_RESCIND Event_Type = 4
|
||||
Event_UPDATE Event_Type = 5
|
||||
Event_MESSAGE Event_Type = 6
|
||||
Event_FAILURE Event_Type = 7
|
||||
Event_ERROR Event_Type = 8
|
||||
)
|
||||
|
||||
var Event_Type_name = map[int32]string{
|
||||
1: "REGISTERED",
|
||||
2: "REREGISTERED",
|
||||
3: "OFFERS",
|
||||
4: "RESCIND",
|
||||
5: "UPDATE",
|
||||
6: "MESSAGE",
|
||||
7: "FAILURE",
|
||||
8: "ERROR",
|
||||
}
|
||||
var Event_Type_value = map[string]int32{
|
||||
"REGISTERED": 1,
|
||||
"REREGISTERED": 2,
|
||||
"OFFERS": 3,
|
||||
"RESCIND": 4,
|
||||
"UPDATE": 5,
|
||||
"MESSAGE": 6,
|
||||
"FAILURE": 7,
|
||||
"ERROR": 8,
|
||||
}
|
||||
|
||||
func (x Event_Type) Enum() *Event_Type {
|
||||
p := new(Event_Type)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x Event_Type) String() string {
|
||||
return proto.EnumName(Event_Type_name, int32(x))
|
||||
}
|
||||
func (x *Event_Type) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(Event_Type_value, data, "Event_Type")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = Event_Type(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Possible call types, followed by message definitions if
|
||||
// applicable.
|
||||
type Call_Type int32
|
||||
|
||||
const (
|
||||
Call_REGISTER Call_Type = 1
|
||||
Call_REREGISTER Call_Type = 2
|
||||
Call_UNREGISTER Call_Type = 3
|
||||
Call_REQUEST Call_Type = 4
|
||||
Call_DECLINE Call_Type = 5
|
||||
Call_REVIVE Call_Type = 6
|
||||
Call_LAUNCH Call_Type = 7
|
||||
Call_KILL Call_Type = 8
|
||||
Call_ACKNOWLEDGE Call_Type = 9
|
||||
Call_RECONCILE Call_Type = 10
|
||||
Call_MESSAGE Call_Type = 11
|
||||
)
|
||||
|
||||
var Call_Type_name = map[int32]string{
|
||||
1: "REGISTER",
|
||||
2: "REREGISTER",
|
||||
3: "UNREGISTER",
|
||||
4: "REQUEST",
|
||||
5: "DECLINE",
|
||||
6: "REVIVE",
|
||||
7: "LAUNCH",
|
||||
8: "KILL",
|
||||
9: "ACKNOWLEDGE",
|
||||
10: "RECONCILE",
|
||||
11: "MESSAGE",
|
||||
}
|
||||
var Call_Type_value = map[string]int32{
|
||||
"REGISTER": 1,
|
||||
"REREGISTER": 2,
|
||||
"UNREGISTER": 3,
|
||||
"REQUEST": 4,
|
||||
"DECLINE": 5,
|
||||
"REVIVE": 6,
|
||||
"LAUNCH": 7,
|
||||
"KILL": 8,
|
||||
"ACKNOWLEDGE": 9,
|
||||
"RECONCILE": 10,
|
||||
"MESSAGE": 11,
|
||||
}
|
||||
|
||||
func (x Call_Type) Enum() *Call_Type {
|
||||
p := new(Call_Type)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x Call_Type) String() string {
|
||||
return proto.EnumName(Call_Type_name, int32(x))
|
||||
}
|
||||
func (x *Call_Type) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(Call_Type_value, data, "Call_Type")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = Call_Type(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// *
|
||||
// Low-level scheduler event API.
|
||||
//
|
||||
// An event is described using the standard protocol buffer "union"
|
||||
// trick, see https://developers.google.com/protocol-buffers/docs/techniques#union.
|
||||
type Event struct {
|
||||
// Type of the event, indicates which optional field below should be
|
||||
// present if that type has a nested message definition.
|
||||
Type *Event_Type `protobuf:"varint,1,req,name=type,enum=mesosproto.Event_Type" json:"type,omitempty"`
|
||||
Registered *Event_Registered `protobuf:"bytes,2,opt,name=registered" json:"registered,omitempty"`
|
||||
Reregistered *Event_Reregistered `protobuf:"bytes,3,opt,name=reregistered" json:"reregistered,omitempty"`
|
||||
Offers *Event_Offers `protobuf:"bytes,4,opt,name=offers" json:"offers,omitempty"`
|
||||
Rescind *Event_Rescind `protobuf:"bytes,5,opt,name=rescind" json:"rescind,omitempty"`
|
||||
Update *Event_Update `protobuf:"bytes,6,opt,name=update" json:"update,omitempty"`
|
||||
Message *Event_Message `protobuf:"bytes,7,opt,name=message" json:"message,omitempty"`
|
||||
Failure *Event_Failure `protobuf:"bytes,8,opt,name=failure" json:"failure,omitempty"`
|
||||
Error *Event_Error `protobuf:"bytes,9,opt,name=error" json:"error,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event) Reset() { *m = Event{} }
|
||||
func (m *Event) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event) ProtoMessage() {}
|
||||
|
||||
func (m *Event) GetType() Event_Type {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return Event_REGISTERED
|
||||
}
|
||||
|
||||
func (m *Event) GetRegistered() *Event_Registered {
|
||||
if m != nil {
|
||||
return m.Registered
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetReregistered() *Event_Reregistered {
|
||||
if m != nil {
|
||||
return m.Reregistered
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetOffers() *Event_Offers {
|
||||
if m != nil {
|
||||
return m.Offers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetRescind() *Event_Rescind {
|
||||
if m != nil {
|
||||
return m.Rescind
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetUpdate() *Event_Update {
|
||||
if m != nil {
|
||||
return m.Update
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetMessage() *Event_Message {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetFailure() *Event_Failure {
|
||||
if m != nil {
|
||||
return m.Failure
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event) GetError() *Event_Error {
|
||||
if m != nil {
|
||||
return m.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Registered struct {
|
||||
FrameworkId *FrameworkID `protobuf:"bytes,1,req,name=framework_id" json:"framework_id,omitempty"`
|
||||
MasterInfo *MasterInfo `protobuf:"bytes,2,req,name=master_info" json:"master_info,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Registered) Reset() { *m = Event_Registered{} }
|
||||
func (m *Event_Registered) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Registered) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Registered) GetFrameworkId() *FrameworkID {
|
||||
if m != nil {
|
||||
return m.FrameworkId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Registered) GetMasterInfo() *MasterInfo {
|
||||
if m != nil {
|
||||
return m.MasterInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Reregistered struct {
|
||||
FrameworkId *FrameworkID `protobuf:"bytes,1,req,name=framework_id" json:"framework_id,omitempty"`
|
||||
MasterInfo *MasterInfo `protobuf:"bytes,2,req,name=master_info" json:"master_info,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Reregistered) Reset() { *m = Event_Reregistered{} }
|
||||
func (m *Event_Reregistered) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Reregistered) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Reregistered) GetFrameworkId() *FrameworkID {
|
||||
if m != nil {
|
||||
return m.FrameworkId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Reregistered) GetMasterInfo() *MasterInfo {
|
||||
if m != nil {
|
||||
return m.MasterInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Offers struct {
|
||||
Offers []*Offer `protobuf:"bytes,1,rep,name=offers" json:"offers,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Offers) Reset() { *m = Event_Offers{} }
|
||||
func (m *Event_Offers) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Offers) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Offers) GetOffers() []*Offer {
|
||||
if m != nil {
|
||||
return m.Offers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Rescind struct {
|
||||
OfferId *OfferID `protobuf:"bytes,1,req,name=offer_id" json:"offer_id,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Rescind) Reset() { *m = Event_Rescind{} }
|
||||
func (m *Event_Rescind) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Rescind) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Rescind) GetOfferId() *OfferID {
|
||||
if m != nil {
|
||||
return m.OfferId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Update struct {
|
||||
Uuid []byte `protobuf:"bytes,1,req,name=uuid" json:"uuid,omitempty"`
|
||||
Status *TaskStatus `protobuf:"bytes,2,req,name=status" json:"status,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Update) Reset() { *m = Event_Update{} }
|
||||
func (m *Event_Update) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Update) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Update) GetUuid() []byte {
|
||||
if m != nil {
|
||||
return m.Uuid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Update) GetStatus() *TaskStatus {
|
||||
if m != nil {
|
||||
return m.Status
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Message struct {
|
||||
SlaveId *SlaveID `protobuf:"bytes,1,req,name=slave_id" json:"slave_id,omitempty"`
|
||||
ExecutorId *ExecutorID `protobuf:"bytes,2,req,name=executor_id" json:"executor_id,omitempty"`
|
||||
Data []byte `protobuf:"bytes,3,req,name=data" json:"data,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Message) Reset() { *m = Event_Message{} }
|
||||
func (m *Event_Message) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Message) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Message) GetSlaveId() *SlaveID {
|
||||
if m != nil {
|
||||
return m.SlaveId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Message) GetExecutorId() *ExecutorID {
|
||||
if m != nil {
|
||||
return m.ExecutorId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Message) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Event_Failure struct {
|
||||
SlaveId *SlaveID `protobuf:"bytes,1,opt,name=slave_id" json:"slave_id,omitempty"`
|
||||
// If this was just a failure of an executor on a slave then
|
||||
// 'executor_id' will be set and possibly 'status' (if we were
|
||||
// able to determine the exit status).
|
||||
ExecutorId *ExecutorID `protobuf:"bytes,2,opt,name=executor_id" json:"executor_id,omitempty"`
|
||||
Status *int32 `protobuf:"varint,3,opt,name=status" json:"status,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Failure) Reset() { *m = Event_Failure{} }
|
||||
func (m *Event_Failure) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Failure) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Failure) GetSlaveId() *SlaveID {
|
||||
if m != nil {
|
||||
return m.SlaveId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Failure) GetExecutorId() *ExecutorID {
|
||||
if m != nil {
|
||||
return m.ExecutorId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Event_Failure) GetStatus() int32 {
|
||||
if m != nil && m.Status != nil {
|
||||
return *m.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Event_Error struct {
|
||||
Message *string `protobuf:"bytes,1,req,name=message" json:"message,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Event_Error) Reset() { *m = Event_Error{} }
|
||||
func (m *Event_Error) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event_Error) ProtoMessage() {}
|
||||
|
||||
func (m *Event_Error) GetMessage() string {
|
||||
if m != nil && m.Message != nil {
|
||||
return *m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// *
|
||||
// Low-level scheduler call API.
|
||||
//
|
||||
// Like Event, a Call is described using the standard protocol buffer
|
||||
// "union" trick (see above).
|
||||
type Call struct {
|
||||
// Identifies who generated this call. Always necessary, but the
|
||||
// only thing that needs to be set for certain calls, e.g.,
|
||||
// REGISTER, REREGISTER, and UNREGISTER.
|
||||
FrameworkInfo *FrameworkInfo `protobuf:"bytes,1,req,name=framework_info" json:"framework_info,omitempty"`
|
||||
// Type of the call, indicates which optional field below should be
|
||||
// present if that type has a nested message definition.
|
||||
Type *Call_Type `protobuf:"varint,2,req,name=type,enum=mesosproto.Call_Type" json:"type,omitempty"`
|
||||
Request *Call_Request `protobuf:"bytes,3,opt,name=request" json:"request,omitempty"`
|
||||
Decline *Call_Decline `protobuf:"bytes,4,opt,name=decline" json:"decline,omitempty"`
|
||||
Launch *Call_Launch `protobuf:"bytes,5,opt,name=launch" json:"launch,omitempty"`
|
||||
Kill *Call_Kill `protobuf:"bytes,6,opt,name=kill" json:"kill,omitempty"`
|
||||
Acknowledge *Call_Acknowledge `protobuf:"bytes,7,opt,name=acknowledge" json:"acknowledge,omitempty"`
|
||||
Reconcile *Call_Reconcile `protobuf:"bytes,8,opt,name=reconcile" json:"reconcile,omitempty"`
|
||||
Message *Call_Message `protobuf:"bytes,9,opt,name=message" json:"message,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call) Reset() { *m = Call{} }
|
||||
func (m *Call) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call) ProtoMessage() {}
|
||||
|
||||
func (m *Call) GetFrameworkInfo() *FrameworkInfo {
|
||||
if m != nil {
|
||||
return m.FrameworkInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetType() Call_Type {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return Call_REGISTER
|
||||
}
|
||||
|
||||
func (m *Call) GetRequest() *Call_Request {
|
||||
if m != nil {
|
||||
return m.Request
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetDecline() *Call_Decline {
|
||||
if m != nil {
|
||||
return m.Decline
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetLaunch() *Call_Launch {
|
||||
if m != nil {
|
||||
return m.Launch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetKill() *Call_Kill {
|
||||
if m != nil {
|
||||
return m.Kill
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetAcknowledge() *Call_Acknowledge {
|
||||
if m != nil {
|
||||
return m.Acknowledge
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetReconcile() *Call_Reconcile {
|
||||
if m != nil {
|
||||
return m.Reconcile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call) GetMessage() *Call_Message {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Request struct {
|
||||
Requests []*Request `protobuf:"bytes,1,rep,name=requests" json:"requests,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Request) Reset() { *m = Call_Request{} }
|
||||
func (m *Call_Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Request) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Request) GetRequests() []*Request {
|
||||
if m != nil {
|
||||
return m.Requests
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Decline struct {
|
||||
OfferIds []*OfferID `protobuf:"bytes,1,rep,name=offer_ids" json:"offer_ids,omitempty"`
|
||||
Filters *Filters `protobuf:"bytes,2,opt,name=filters" json:"filters,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Decline) Reset() { *m = Call_Decline{} }
|
||||
func (m *Call_Decline) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Decline) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Decline) GetOfferIds() []*OfferID {
|
||||
if m != nil {
|
||||
return m.OfferIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Decline) GetFilters() *Filters {
|
||||
if m != nil {
|
||||
return m.Filters
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Launch struct {
|
||||
TaskInfos []*TaskInfo `protobuf:"bytes,1,rep,name=task_infos" json:"task_infos,omitempty"`
|
||||
OfferIds []*OfferID `protobuf:"bytes,2,rep,name=offer_ids" json:"offer_ids,omitempty"`
|
||||
Filters *Filters `protobuf:"bytes,3,opt,name=filters" json:"filters,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Launch) Reset() { *m = Call_Launch{} }
|
||||
func (m *Call_Launch) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Launch) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Launch) GetTaskInfos() []*TaskInfo {
|
||||
if m != nil {
|
||||
return m.TaskInfos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Launch) GetOfferIds() []*OfferID {
|
||||
if m != nil {
|
||||
return m.OfferIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Launch) GetFilters() *Filters {
|
||||
if m != nil {
|
||||
return m.Filters
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Kill struct {
|
||||
TaskId *TaskID `protobuf:"bytes,1,req,name=task_id" json:"task_id,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Kill) Reset() { *m = Call_Kill{} }
|
||||
func (m *Call_Kill) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Kill) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Kill) GetTaskId() *TaskID {
|
||||
if m != nil {
|
||||
return m.TaskId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Acknowledge struct {
|
||||
SlaveId *SlaveID `protobuf:"bytes,1,req,name=slave_id" json:"slave_id,omitempty"`
|
||||
TaskId *TaskID `protobuf:"bytes,2,req,name=task_id" json:"task_id,omitempty"`
|
||||
Uuid []byte `protobuf:"bytes,3,req,name=uuid" json:"uuid,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Acknowledge) Reset() { *m = Call_Acknowledge{} }
|
||||
func (m *Call_Acknowledge) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Acknowledge) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Acknowledge) GetSlaveId() *SlaveID {
|
||||
if m != nil {
|
||||
return m.SlaveId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Acknowledge) GetTaskId() *TaskID {
|
||||
if m != nil {
|
||||
return m.TaskId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Acknowledge) GetUuid() []byte {
|
||||
if m != nil {
|
||||
return m.Uuid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Allows the framework to query the status for non-terminal tasks.
|
||||
// This causes the master to send back the latest task status for
|
||||
// each task in 'statuses', if possible. Tasks that are no longer
|
||||
// known will result in a TASK_LOST update. If statuses is empty,
|
||||
// then the master will send the latest status for each task
|
||||
// currently known.
|
||||
// TODO(bmahler): Add a guiding document for reconciliation or
|
||||
// document reconciliation in-depth here.
|
||||
type Call_Reconcile struct {
|
||||
Statuses []*TaskStatus `protobuf:"bytes,1,rep,name=statuses" json:"statuses,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Reconcile) Reset() { *m = Call_Reconcile{} }
|
||||
func (m *Call_Reconcile) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Reconcile) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Reconcile) GetStatuses() []*TaskStatus {
|
||||
if m != nil {
|
||||
return m.Statuses
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Call_Message struct {
|
||||
SlaveId *SlaveID `protobuf:"bytes,1,req,name=slave_id" json:"slave_id,omitempty"`
|
||||
ExecutorId *ExecutorID `protobuf:"bytes,2,req,name=executor_id" json:"executor_id,omitempty"`
|
||||
Data []byte `protobuf:"bytes,3,req,name=data" json:"data,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Call_Message) Reset() { *m = Call_Message{} }
|
||||
func (m *Call_Message) String() string { return proto.CompactTextString(m) }
|
||||
func (*Call_Message) ProtoMessage() {}
|
||||
|
||||
func (m *Call_Message) GetSlaveId() *SlaveID {
|
||||
if m != nil {
|
||||
return m.SlaveId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Message) GetExecutorId() *ExecutorID {
|
||||
if m != nil {
|
||||
return m.ExecutorId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Call_Message) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("mesosproto.Event_Type", Event_Type_name, Event_Type_value)
|
||||
proto.RegisterEnum("mesosproto.Call_Type", Call_Type_name, Call_Type_value)
|
||||
}
|
||||
195
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/scheduler.proto
generated
vendored
Normal file
195
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/scheduler.proto
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "mesos.proto";
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
|
||||
/**
|
||||
* Low-level scheduler event API.
|
||||
*
|
||||
* An event is described using the standard protocol buffer "union"
|
||||
* trick, see https://developers.google.com/protocol-buffers/docs/techniques#union.
|
||||
*/
|
||||
message Event {
|
||||
// Possible event types, followed by message definitions if
|
||||
// applicable.
|
||||
enum Type {
|
||||
REGISTERED = 1;
|
||||
REREGISTERED = 2;
|
||||
OFFERS = 3;
|
||||
RESCIND = 4;
|
||||
UPDATE = 5;
|
||||
MESSAGE = 6;
|
||||
FAILURE = 7;
|
||||
ERROR = 8;
|
||||
}
|
||||
|
||||
message Registered {
|
||||
required FrameworkID framework_id = 1;
|
||||
required MasterInfo master_info = 2;
|
||||
}
|
||||
|
||||
message Reregistered {
|
||||
required FrameworkID framework_id = 1;
|
||||
required MasterInfo master_info = 2;
|
||||
}
|
||||
|
||||
message Offers {
|
||||
repeated Offer offers = 1;
|
||||
}
|
||||
|
||||
message Rescind {
|
||||
required OfferID offer_id = 1;
|
||||
}
|
||||
|
||||
message Update {
|
||||
required bytes uuid = 1; // TODO(benh): Replace with UpdateID.
|
||||
required TaskStatus status = 2;
|
||||
}
|
||||
|
||||
message Message {
|
||||
required SlaveID slave_id = 1;
|
||||
required ExecutorID executor_id = 2;
|
||||
required bytes data = 3;
|
||||
}
|
||||
|
||||
message Failure {
|
||||
optional SlaveID slave_id = 1;
|
||||
|
||||
// If this was just a failure of an executor on a slave then
|
||||
// 'executor_id' will be set and possibly 'status' (if we were
|
||||
// able to determine the exit status).
|
||||
optional ExecutorID executor_id = 2;
|
||||
optional int32 status = 3;
|
||||
}
|
||||
|
||||
message Error {
|
||||
required string message = 1;
|
||||
}
|
||||
|
||||
// TODO(benh): Add a 'from' or 'sender'.
|
||||
|
||||
// Type of the event, indicates which optional field below should be
|
||||
// present if that type has a nested message definition.
|
||||
required Type type = 1;
|
||||
|
||||
optional Registered registered = 2;
|
||||
optional Reregistered reregistered = 3;
|
||||
optional Offers offers = 4;
|
||||
optional Rescind rescind = 5;
|
||||
optional Update update = 6;
|
||||
optional Message message = 7;
|
||||
optional Failure failure = 8;
|
||||
optional Error error = 9;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Low-level scheduler call API.
|
||||
*
|
||||
* Like Event, a Call is described using the standard protocol buffer
|
||||
* "union" trick (see above).
|
||||
*/
|
||||
message Call {
|
||||
// Possible call types, followed by message definitions if
|
||||
// applicable.
|
||||
enum Type {
|
||||
REGISTER = 1;
|
||||
REREGISTER = 2;
|
||||
UNREGISTER = 3;
|
||||
REQUEST = 4;
|
||||
DECLINE = 5;
|
||||
REVIVE = 6;
|
||||
LAUNCH = 7;
|
||||
KILL = 8;
|
||||
ACKNOWLEDGE = 9;
|
||||
RECONCILE = 10;
|
||||
MESSAGE = 11;
|
||||
|
||||
// TODO(benh): Consider adding an 'ACTIVATE' and 'DEACTIVATE' for
|
||||
// already registered frameworks as a way of stopping offers from
|
||||
// being generated and other events from being sent by the master.
|
||||
// Note that this functionality existed originally to support
|
||||
// SchedulerDriver::abort which was only necessary to handle
|
||||
// exceptions getting thrown from within Scheduler callbacks,
|
||||
// something that is not an issue with the Event/Call API.
|
||||
}
|
||||
|
||||
message Request {
|
||||
repeated mesosproto.Request requests = 1;
|
||||
}
|
||||
|
||||
message Decline {
|
||||
repeated OfferID offer_ids = 1;
|
||||
optional Filters filters = 2;
|
||||
}
|
||||
|
||||
message Launch {
|
||||
repeated TaskInfo task_infos = 1;
|
||||
repeated OfferID offer_ids = 2;
|
||||
optional Filters filters = 3;
|
||||
}
|
||||
|
||||
message Kill {
|
||||
required TaskID task_id = 1;
|
||||
}
|
||||
|
||||
message Acknowledge {
|
||||
required SlaveID slave_id = 1;
|
||||
required TaskID task_id = 2;
|
||||
required bytes uuid = 3;
|
||||
}
|
||||
|
||||
// Allows the framework to query the status for non-terminal tasks.
|
||||
// This causes the master to send back the latest task status for
|
||||
// each task in 'statuses', if possible. Tasks that are no longer
|
||||
// known will result in a TASK_LOST update. If statuses is empty,
|
||||
// then the master will send the latest status for each task
|
||||
// currently known.
|
||||
// TODO(bmahler): Add a guiding document for reconciliation or
|
||||
// document reconciliation in-depth here.
|
||||
message Reconcile {
|
||||
repeated TaskStatus statuses = 1; // Should be non-terminal only.
|
||||
}
|
||||
|
||||
message Message {
|
||||
required SlaveID slave_id = 1;
|
||||
required ExecutorID executor_id = 2;
|
||||
required bytes data = 3;
|
||||
}
|
||||
|
||||
// Identifies who generated this call. Always necessary, but the
|
||||
// only thing that needs to be set for certain calls, e.g.,
|
||||
// REGISTER, REREGISTER, and UNREGISTER.
|
||||
required FrameworkInfo framework_info = 1;
|
||||
|
||||
// Type of the call, indicates which optional field below should be
|
||||
// present if that type has a nested message definition.
|
||||
required Type type = 2;
|
||||
|
||||
optional Request request = 3;
|
||||
optional Decline decline = 4;
|
||||
optional Launch launch = 5;
|
||||
optional Kill kill = 6;
|
||||
optional Acknowledge acknowledge = 7;
|
||||
optional Reconcile reconcile = 8;
|
||||
optional Message message = 9;
|
||||
}
|
||||
1580
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/state.pb.go
generated
vendored
Normal file
1580
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/state.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
73
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/state.proto
generated
vendored
Normal file
73
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/state.proto
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosproto;
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option (gogoproto.gostring_all) = true;
|
||||
option (gogoproto.equal_all) = true;
|
||||
option (gogoproto.verbose_equal_all) = true;
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.stringer_all) = true;
|
||||
option (gogoproto.populate_all) = true;
|
||||
option (gogoproto.testgen_all) = true;
|
||||
option (gogoproto.benchgen_all) = true;
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.sizer_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
|
||||
|
||||
// Describes a state entry, a versioned (via a UUID) key/value pair.
|
||||
message Entry {
|
||||
required string name = 1;
|
||||
required bytes uuid = 2;
|
||||
required bytes value = 3;
|
||||
}
|
||||
|
||||
|
||||
// Describes an operation used in the log storage implementation.
|
||||
message Operation {
|
||||
enum Type {
|
||||
SNAPSHOT = 1;
|
||||
DIFF = 3;
|
||||
EXPUNGE = 2;
|
||||
}
|
||||
|
||||
// Describes a "snapshot" operation.
|
||||
message Snapshot {
|
||||
required Entry entry = 1;
|
||||
}
|
||||
|
||||
// Describes a "diff" operation where the 'value' of the entry is
|
||||
// just the diff itself, but the 'uuid' represents the UUID of the
|
||||
// entry after applying this diff.
|
||||
message Diff {
|
||||
required Entry entry = 1;
|
||||
}
|
||||
|
||||
// Describes an "expunge" operation.
|
||||
message Expunge {
|
||||
required string name = 1;
|
||||
}
|
||||
|
||||
required Type type = 1;
|
||||
optional Snapshot snapshot = 2;
|
||||
optional Diff diff = 4;
|
||||
optional Expunge expunge = 3;
|
||||
}
|
||||
1098
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/statepb_test.go
generated
vendored
Normal file
1098
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosproto/statepb_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/constants.go
generated
vendored
Normal file
6
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/constants.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package mesosutil
|
||||
|
||||
const (
|
||||
// MesosVersion indicates the supported mesos version.
|
||||
MesosVersion = "0.20.0"
|
||||
)
|
||||
155
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/mesosprotoutil.go
generated
vendored
Normal file
155
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/mesosprotoutil.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosutil
|
||||
|
||||
import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
)
|
||||
|
||||
func NewValueRange(begin, end uint64) *mesos.Value_Range {
|
||||
return &mesos.Value_Range{Begin: proto.Uint64(begin), End: proto.Uint64(end)}
|
||||
}
|
||||
|
||||
func FilterResources(resources []*mesos.Resource, filter func(*mesos.Resource) bool) (result []*mesos.Resource) {
|
||||
for _, resource := range resources {
|
||||
if filter(resource) {
|
||||
result = append(result, resource)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func NewScalarResource(name string, val float64) *mesos.Resource {
|
||||
return &mesos.Resource{
|
||||
Name: proto.String(name),
|
||||
Type: mesos.Value_SCALAR.Enum(),
|
||||
Scalar: &mesos.Value_Scalar{Value: proto.Float64(val)},
|
||||
}
|
||||
}
|
||||
|
||||
func NewRangesResource(name string, ranges []*mesos.Value_Range) *mesos.Resource {
|
||||
return &mesos.Resource{
|
||||
Name: proto.String(name),
|
||||
Type: mesos.Value_RANGES.Enum(),
|
||||
Ranges: &mesos.Value_Ranges{Range: ranges},
|
||||
}
|
||||
}
|
||||
|
||||
func NewSetResource(name string, items []string) *mesos.Resource {
|
||||
return &mesos.Resource{
|
||||
Name: proto.String(name),
|
||||
Type: mesos.Value_SET.Enum(),
|
||||
Set: &mesos.Value_Set{Item: items},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func NewFrameworkID(id string) *mesos.FrameworkID {
|
||||
return &mesos.FrameworkID{Value: proto.String(id)}
|
||||
}
|
||||
|
||||
func NewFrameworkInfo(user, name string, frameworkId *mesos.FrameworkID) *mesos.FrameworkInfo {
|
||||
return &mesos.FrameworkInfo{
|
||||
User: proto.String(user),
|
||||
Name: proto.String(name),
|
||||
Id: frameworkId,
|
||||
}
|
||||
}
|
||||
|
||||
func NewMasterInfo(id string, ip, port uint32) *mesos.MasterInfo {
|
||||
return &mesos.MasterInfo{
|
||||
Id: proto.String(id),
|
||||
Ip: proto.Uint32(ip),
|
||||
Port: proto.Uint32(port),
|
||||
}
|
||||
}
|
||||
|
||||
func NewOfferID(id string) *mesos.OfferID {
|
||||
return &mesos.OfferID{Value: proto.String(id)}
|
||||
}
|
||||
|
||||
func NewOffer(offerId *mesos.OfferID, frameworkId *mesos.FrameworkID, slaveId *mesos.SlaveID, hostname string) *mesos.Offer {
|
||||
return &mesos.Offer{
|
||||
Id: offerId,
|
||||
FrameworkId: frameworkId,
|
||||
SlaveId: slaveId,
|
||||
Hostname: proto.String(hostname),
|
||||
}
|
||||
}
|
||||
|
||||
func FilterOffersResources(offers []*mesos.Offer, filter func(*mesos.Resource) bool) (result []*mesos.Resource) {
|
||||
for _, offer := range offers {
|
||||
result = FilterResources(offer.Resources, filter)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func NewSlaveID(id string) *mesos.SlaveID {
|
||||
return &mesos.SlaveID{Value: proto.String(id)}
|
||||
}
|
||||
|
||||
func NewTaskID(id string) *mesos.TaskID {
|
||||
return &mesos.TaskID{Value: proto.String(id)}
|
||||
}
|
||||
|
||||
func NewTaskInfo(
|
||||
name string,
|
||||
taskId *mesos.TaskID,
|
||||
slaveId *mesos.SlaveID,
|
||||
resources []*mesos.Resource,
|
||||
) *mesos.TaskInfo {
|
||||
return &mesos.TaskInfo{
|
||||
Name: proto.String(name),
|
||||
TaskId: taskId,
|
||||
SlaveId: slaveId,
|
||||
Resources: resources,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTaskStatus(taskId *mesos.TaskID, state mesos.TaskState) *mesos.TaskStatus {
|
||||
return &mesos.TaskStatus{
|
||||
TaskId: taskId,
|
||||
State: mesos.TaskState(state).Enum(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewStatusUpdate(frameworkId *mesos.FrameworkID, taskStatus *mesos.TaskStatus, timestamp float64, uuid []byte) *mesos.StatusUpdate {
|
||||
return &mesos.StatusUpdate{
|
||||
FrameworkId: frameworkId,
|
||||
Status: taskStatus,
|
||||
Timestamp: proto.Float64(timestamp),
|
||||
Uuid: uuid,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCommandInfo(command string) *mesos.CommandInfo {
|
||||
return &mesos.CommandInfo{Value: proto.String(command)}
|
||||
}
|
||||
|
||||
func NewExecutorID(id string) *mesos.ExecutorID {
|
||||
return &mesos.ExecutorID{Value: proto.String(id)}
|
||||
}
|
||||
|
||||
func NewExecutorInfo(execId *mesos.ExecutorID, command *mesos.CommandInfo) *mesos.ExecutorInfo {
|
||||
return &mesos.ExecutorInfo{
|
||||
ExecutorId: execId,
|
||||
Command: command,
|
||||
}
|
||||
}
|
||||
252
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/mesosprotoutil_test.go
generated
vendored
Normal file
252
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/mesosprotoutil_test.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package mesosutil
|
||||
|
||||
import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
mesos "github.com/mesos/mesos-go/mesosproto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFilterResources(t *testing.T) {
|
||||
resources := []*mesos.Resource{
|
||||
NewScalarResource("mem", 200),
|
||||
NewScalarResource("cpu", 4),
|
||||
NewScalarResource("mem", 500),
|
||||
}
|
||||
|
||||
memRes := FilterResources(resources, func(res *mesos.Resource) bool {
|
||||
if res.GetType() == mesos.Value_SCALAR && res.GetName() == "mem" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
assert.Equal(t, 2, len(memRes))
|
||||
}
|
||||
|
||||
func TestNewValueRange(t *testing.T) {
|
||||
val := NewValueRange(20, 40)
|
||||
if val == nil {
|
||||
t.Fatal("Not creating protobuf object Value_Range.")
|
||||
}
|
||||
|
||||
if (val.GetEnd() - val.GetBegin()) != 20 {
|
||||
t.Fatal("Protobuf object Value_Range not returning expected values.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewScalarResource(t *testing.T) {
|
||||
val := NewScalarResource("mem", 200)
|
||||
if val == nil {
|
||||
t.Fatal("Not creating protobuf object Resource properly.")
|
||||
}
|
||||
if val.GetType() != mesos.Value_SCALAR {
|
||||
t.Fatal("Expected type SCALAR for protobuf, got", val.GetType())
|
||||
}
|
||||
if val.GetName() != "mem" && val.GetScalar().GetValue() != 200 {
|
||||
t.Fatal("Protobuf object Resource has wrong name and Scalar values.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRangesResource(t *testing.T) {
|
||||
val := NewRangesResource("quotas", []*mesos.Value_Range{NewValueRange(20, 40)})
|
||||
if val == nil {
|
||||
t.Fatal("Not creating protobuf object Resource properly.")
|
||||
}
|
||||
if val.GetType() != mesos.Value_RANGES {
|
||||
t.Fatal("Expected type SCALAR for protobuf, got", val.GetType())
|
||||
}
|
||||
if len(val.GetRanges().GetRange()) != 1 {
|
||||
t.Fatal("Expected Resource of type RANGES with 1 range, but got", len(val.GetRanges().GetRange()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNewSetResource(t *testing.T) {
|
||||
val := NewSetResource("greeting", []string{"hello", "world"})
|
||||
if val == nil {
|
||||
t.Fatal("Not creating protobuf object Resource properly.")
|
||||
}
|
||||
if val.GetType() != mesos.Value_SET {
|
||||
t.Fatal("Expected type SET for protobuf, got", val.GetType())
|
||||
}
|
||||
if len(val.GetSet().GetItem()) != 2 {
|
||||
t.Fatal("Expected Resource of type SET with 2 items, but got", len(val.GetRanges().GetRange()))
|
||||
}
|
||||
if val.GetSet().GetItem()[0] != "hello" {
|
||||
t.Fatal("Protobuf Resource of type SET got wrong value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFrameworkID(t *testing.T) {
|
||||
id := NewFrameworkID("test-id")
|
||||
if id == nil {
|
||||
t.Fatal("Not creating protobuf oject FrameworkID.")
|
||||
}
|
||||
if id.GetValue() != "test-id" {
|
||||
t.Fatal("Protobuf object not returning expected value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFrameworkInfo(t *testing.T) {
|
||||
info := NewFrameworkInfo("test-user", "test-name", NewFrameworkID("test-id"))
|
||||
info.Hostname = proto.String("localhost")
|
||||
if info == nil {
|
||||
t.Fatal("Not creating protobuf object FrameworkInfo")
|
||||
}
|
||||
if info.GetUser() != "test-user" {
|
||||
t.Fatal("Protobuf object FrameworkInfo.User missing value.")
|
||||
}
|
||||
if info.GetName() != "test-name" {
|
||||
t.Fatal("Protobuf object FrameworkInfo.Name missing value.")
|
||||
}
|
||||
if info.GetId() == nil {
|
||||
t.Fatal("Protobuf object FrameowrkInfo.Id missing value.")
|
||||
}
|
||||
if info.GetHostname() != "localhost" {
|
||||
t.Fatal("Protobuf object FrameworkInfo.Hostname missing value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewMasterInfo(t *testing.T) {
|
||||
master := NewMasterInfo("master-1", 1234, 5678)
|
||||
if master == nil {
|
||||
t.Fatal("Not creating protobuf object MasterInfo")
|
||||
}
|
||||
if master.GetId() != "master-1" {
|
||||
t.Fatal("Protobuf object MasterInfo.Id missing.")
|
||||
}
|
||||
if master.GetIp() != 1234 {
|
||||
t.Fatal("Protobuf object MasterInfo.Ip missing.")
|
||||
}
|
||||
if master.GetPort() != 5678 {
|
||||
t.Fatal("Protobuf object MasterInfo.Port missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOfferID(t *testing.T) {
|
||||
id := NewOfferID("offer-1")
|
||||
if id == nil {
|
||||
t.Fatal("Not creating protobuf object OfferID")
|
||||
}
|
||||
if id.GetValue() != "offer-1" {
|
||||
t.Fatal("Protobuf object OfferID.Value missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOffer(t *testing.T) {
|
||||
offer := NewOffer(NewOfferID("offer-1"), NewFrameworkID("framework-1"), NewSlaveID("slave-1"), "localhost")
|
||||
if offer == nil {
|
||||
t.Fatal("Not creating protobuf object Offer")
|
||||
}
|
||||
if offer.GetId().GetValue() != "offer-1" {
|
||||
t.Fatal("Protobuf object Offer.Id missing")
|
||||
}
|
||||
if offer.GetFrameworkId().GetValue() != "framework-1" {
|
||||
t.Fatal("Protobuf object Offer.FrameworkId missing.")
|
||||
}
|
||||
if offer.GetSlaveId().GetValue() != "slave-1" {
|
||||
t.Fatal("Protobuf object Offer.SlaveId missing.")
|
||||
}
|
||||
if offer.GetHostname() != "localhost" {
|
||||
t.Fatal("Protobuf object offer.Hostname missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewSlaveID(t *testing.T) {
|
||||
id := NewSlaveID("slave-1")
|
||||
if id == nil {
|
||||
t.Fatal("Not creating protobuf object SlaveID")
|
||||
}
|
||||
if id.GetValue() != "slave-1" {
|
||||
t.Fatal("Protobuf object SlaveID.Value missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTaskID(t *testing.T) {
|
||||
id := NewSlaveID("task-1")
|
||||
if id == nil {
|
||||
t.Fatal("Not creating protobuf object TaskID")
|
||||
}
|
||||
if id.GetValue() != "task-1" {
|
||||
t.Fatal("Protobuf object TaskID.Value missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTaskInfo(t *testing.T) {
|
||||
info := NewTaskInfo(
|
||||
"simple-task",
|
||||
NewTaskID("simpe-task-1"),
|
||||
NewSlaveID("slave-1"),
|
||||
[]*mesos.Resource{NewScalarResource("mem", 400)},
|
||||
)
|
||||
if info == nil {
|
||||
t.Fatal("Not creating protobuf object TaskInfo")
|
||||
}
|
||||
if info.GetName() != "simple-task" {
|
||||
t.Fatal("Protobuf object TaskInfo.Name missing.")
|
||||
}
|
||||
if info.GetTaskId() == nil {
|
||||
t.Fatal("Protobuf object TaskInfo.TaskId missing.")
|
||||
}
|
||||
if info.GetSlaveId() == nil {
|
||||
t.Fatal("Protobuf object TaskInfo.SlaveId missing.")
|
||||
}
|
||||
if len(info.GetResources()) != 1 {
|
||||
t.Fatal("Protobuf object TaskInfo.Resources missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTaskStatus(t *testing.T) {
|
||||
status := NewTaskStatus(NewTaskID("task-1"), mesos.TaskState_TASK_RUNNING)
|
||||
if status == nil {
|
||||
t.Fatal("Not creating protobuf object TaskStatus")
|
||||
}
|
||||
if status.GetTaskId().GetValue() != "task-1" {
|
||||
t.Fatal("Protobuf object TaskStatus.TaskId missing.")
|
||||
}
|
||||
if status.GetState() != mesos.TaskState(mesos.TaskState_TASK_RUNNING) {
|
||||
t.Fatal("Protobuf object TaskStatus.State missing.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCommandInfo(t *testing.T) {
|
||||
cmd := NewCommandInfo("echo Hello!")
|
||||
if cmd == nil {
|
||||
t.Fatal("Not creating protobuf object CommandInfo")
|
||||
}
|
||||
if cmd.GetValue() != "echo Hello!" {
|
||||
t.Fatal("Protobuf object CommandInfo.Value missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewExecutorInfo(t *testing.T) {
|
||||
info := NewExecutorInfo(NewExecutorID("exec-1"), NewCommandInfo("ls -l"))
|
||||
if info == nil {
|
||||
t.Fatal("Not creating protobuf object ExecutorInfo")
|
||||
}
|
||||
if info.GetExecutorId().GetValue() != "exec-1" {
|
||||
t.Fatal("Protobuf object ExecutorInfo.ExecutorId missing")
|
||||
}
|
||||
if info.GetCommand().GetValue() != "ls -l" {
|
||||
t.Fatal("Protobuf object ExecutorInfo.Command missing")
|
||||
}
|
||||
}
|
||||
23
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/node.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/node.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package mesosutil
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
log "github.com/golang/glog"
|
||||
)
|
||||
|
||||
//TODO(jdef) copied from kubernetes/pkg/util/node.go
|
||||
func GetHostname(hostnameOverride string) string {
|
||||
hostname := []byte(hostnameOverride)
|
||||
if string(hostname) == "" {
|
||||
// Note: We use exec here instead of os.Hostname() because we
|
||||
// want the FQDN, and this is the easiest way to get it.
|
||||
fqdn, err := exec.Command("hostname", "-f").Output()
|
||||
if err != nil {
|
||||
log.Fatalf("Couldn't determine hostname: %v", err)
|
||||
}
|
||||
hostname = fqdn
|
||||
}
|
||||
return strings.TrimSpace(string(hostname))
|
||||
}
|
||||
34
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/process/process.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/mesos/mesos-go/mesosutil/process/process.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
pidLock sync.Mutex
|
||||
pid uint64
|
||||
)
|
||||
|
||||
func nextPid() uint64 {
|
||||
pidLock.Lock()
|
||||
defer pidLock.Unlock()
|
||||
pid++
|
||||
return pid
|
||||
}
|
||||
|
||||
//TODO(jdef) add lifecycle funcs
|
||||
//TODO(jdef) add messaging funcs
|
||||
type Process struct {
|
||||
label string
|
||||
}
|
||||
|
||||
func New(kind string) *Process {
|
||||
return &Process{
|
||||
label: fmt.Sprintf("%s(%d)", kind, nextPid()),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Process) Label() string {
|
||||
return p.label
|
||||
}
|
||||
4
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/doc.go
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
Package upid defines the UPID type and some utilities of the UPID.
|
||||
*/
|
||||
package upid
|
||||
66
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/upid.go
generated
vendored
Normal file
66
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/upid.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package upid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UPID is a equivalent of the UPID in libprocess.
|
||||
type UPID struct {
|
||||
ID string
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
// Parse parses the UPID from the input string.
|
||||
func Parse(input string) (*UPID, error) {
|
||||
upid := new(UPID)
|
||||
|
||||
splits := strings.Split(input, "@")
|
||||
if len(splits) != 2 {
|
||||
return nil, fmt.Errorf("Expect one `@' in the input")
|
||||
}
|
||||
upid.ID = splits[0]
|
||||
|
||||
if _, err := net.ResolveTCPAddr("tcp4", splits[1]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upid.Host, upid.Port, _ = net.SplitHostPort(splits[1])
|
||||
return upid, nil
|
||||
}
|
||||
|
||||
// String returns the string representation.
|
||||
func (u *UPID) String() string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s@%s:%s", u.ID, u.Host, u.Port)
|
||||
}
|
||||
|
||||
// Equal returns true if two upid is equal
|
||||
func (u *UPID) Equal(upid *UPID) bool {
|
||||
if u == nil {
|
||||
return upid == nil
|
||||
} else {
|
||||
return upid != nil && u.ID == upid.ID && u.Host == upid.Host && u.Port == upid.Port
|
||||
}
|
||||
}
|
||||
67
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/upid_test.go
generated
vendored
Normal file
67
Godeps/_workspace/src/github.com/mesos/mesos-go/upid/upid_test.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package upid
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func generateRandomString() string {
|
||||
b := make([]byte, rand.Intn(1024))
|
||||
for i := range b {
|
||||
b[i] = byte(rand.Int())
|
||||
}
|
||||
return strings.Replace(string(b), "@", "", -1)
|
||||
}
|
||||
|
||||
func TestUPIDParse(t *testing.T) {
|
||||
u, err := Parse("mesos@foo:bar")
|
||||
assert.Nil(t, u)
|
||||
assert.Error(t, err)
|
||||
|
||||
u, err = Parse("mesoslocalhost5050")
|
||||
assert.Nil(t, u)
|
||||
assert.Error(t, err)
|
||||
|
||||
u, err = Parse("mesos@localhost")
|
||||
assert.Nil(t, u)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Simple fuzzy test.
|
||||
for i := 0; i < 100000; i++ {
|
||||
ra := generateRandomString()
|
||||
u, err = Parse(ra)
|
||||
if u != nil {
|
||||
println(ra)
|
||||
}
|
||||
assert.Nil(t, u)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestUPIDString(t *testing.T) {
|
||||
u, err := Parse("mesos@localhost:5050")
|
||||
assert.NotNil(t, u)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "mesos@localhost:5050", u.String())
|
||||
}
|
||||
|
||||
func TestUPIDEqual(t *testing.T) {
|
||||
u1, err := Parse("mesos@localhost:5050")
|
||||
u2, err := Parse("mesos@localhost:5050")
|
||||
u3, err := Parse("mesos1@localhost:5050")
|
||||
u4, err := Parse("mesos@mesos.com:5050")
|
||||
u5, err := Parse("mesos@localhost:5051")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.True(t, u1.Equal(u2))
|
||||
assert.False(t, u1.Equal(u3))
|
||||
assert.False(t, u1.Equal(u4))
|
||||
assert.False(t, u1.Equal(u5))
|
||||
assert.False(t, u1.Equal(nil))
|
||||
assert.False(t, (*UPID)(nil).Equal(u5))
|
||||
assert.True(t, (*UPID)(nil).Equal(nil))
|
||||
}
|
||||
166
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/cluster_test.go
generated
vendored
Normal file
166
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/cluster_test.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type logWriter struct {
|
||||
t *testing.T
|
||||
p string
|
||||
}
|
||||
|
||||
func (lw logWriter) Write(b []byte) (int, error) {
|
||||
lw.t.Logf("%s%s", lw.p, string(b))
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func TestBasicCluster(t *testing.T) {
|
||||
ts, err := StartTestCluster(3, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk1, err := ts.Connect(0)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk1.Close()
|
||||
zk2, err := ts.Connect(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk2.Close()
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
if _, err := zk1.Create("/gozk-test", []byte("foo-cluster"), 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create failed on node 1: %+v", err)
|
||||
}
|
||||
if by, _, err := zk2.Get("/gozk-test"); err != nil {
|
||||
t.Fatalf("Get failed on node 2: %+v", err)
|
||||
} else if string(by) != "foo-cluster" {
|
||||
t.Fatal("Wrong data for node 2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientClusterFailover(t *testing.T) {
|
||||
ts, err := StartTestCluster(3, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, evCh, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
hasSession := make(chan string, 1)
|
||||
go func() {
|
||||
for ev := range evCh {
|
||||
if ev.Type == EventSession && ev.State == StateHasSession {
|
||||
select {
|
||||
case hasSession <- ev.Server:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
waitSession := func() string {
|
||||
select {
|
||||
case srv := <-hasSession:
|
||||
return srv
|
||||
case <-time.After(time.Second * 8):
|
||||
t.Fatal("Failed to connect and get a session")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
srv := waitSession()
|
||||
if _, err := zk.Create("/gozk-test", []byte("foo-cluster"), 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create failed on node 1: %+v", err)
|
||||
}
|
||||
|
||||
stopped := false
|
||||
for _, s := range ts.Servers {
|
||||
if strings.HasSuffix(srv, fmt.Sprintf(":%d", s.Port)) {
|
||||
s.Srv.Stop()
|
||||
stopped = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !stopped {
|
||||
t.Fatal("Failed to stop server")
|
||||
}
|
||||
|
||||
waitSession()
|
||||
if by, _, err := zk.Get("/gozk-test"); err != nil {
|
||||
t.Fatalf("Get failed on node 2: %+v", err)
|
||||
} else if string(by) != "foo-cluster" {
|
||||
t.Fatal("Wrong data for node 2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitForClose(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, err := ts.Connect(0)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
timeout := time.After(30 * time.Second)
|
||||
CONNECTED:
|
||||
for {
|
||||
select {
|
||||
case ev := <-zk.eventChan:
|
||||
if ev.State == StateConnected {
|
||||
break CONNECTED
|
||||
}
|
||||
case <-timeout:
|
||||
zk.Close()
|
||||
t.Fatal("Timeout")
|
||||
}
|
||||
}
|
||||
zk.Close()
|
||||
for {
|
||||
select {
|
||||
case _, ok := <-zk.eventChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatal("Timeout")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadSession(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
zk.conn.Close()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
}
|
||||
844
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/conn.go
generated
vendored
Normal file
844
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/conn.go
generated
vendored
Normal file
@@ -0,0 +1,844 @@
|
||||
package zk
|
||||
|
||||
/*
|
||||
TODO:
|
||||
* make sure a ping response comes back in a reasonable time
|
||||
|
||||
Possible watcher events:
|
||||
* Event{Type: EventNotWatching, State: StateDisconnected, Path: path, Err: err}
|
||||
*/
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrNoServer = errors.New("zk: could not connect to a server")
|
||||
|
||||
const (
|
||||
bufferSize = 1536 * 1024
|
||||
eventChanSize = 6
|
||||
sendChanSize = 16
|
||||
protectedPrefix = "_c_"
|
||||
)
|
||||
|
||||
type watchType int
|
||||
|
||||
const (
|
||||
watchTypeData = iota
|
||||
watchTypeExist = iota
|
||||
watchTypeChild = iota
|
||||
)
|
||||
|
||||
type watchPathType struct {
|
||||
path string
|
||||
wType watchType
|
||||
}
|
||||
|
||||
type Dialer func(network, address string, timeout time.Duration) (net.Conn, error)
|
||||
|
||||
type Conn struct {
|
||||
lastZxid int64
|
||||
sessionID int64
|
||||
state State // must be 32-bit aligned
|
||||
xid uint32
|
||||
timeout int32 // session timeout in milliseconds
|
||||
passwd []byte
|
||||
|
||||
dialer Dialer
|
||||
servers []string
|
||||
serverIndex int // remember last server that was tried during connect to round-robin attempts to servers
|
||||
lastServerIndex int // index of the last server that was successfully connected to and authenticated with
|
||||
conn net.Conn
|
||||
eventChan chan Event
|
||||
shouldQuit chan struct{}
|
||||
pingInterval time.Duration
|
||||
recvTimeout time.Duration
|
||||
connectTimeout time.Duration
|
||||
|
||||
sendChan chan *request
|
||||
requests map[int32]*request // Xid -> pending request
|
||||
requestsLock sync.Mutex
|
||||
watchers map[watchPathType][]chan Event
|
||||
watchersLock sync.Mutex
|
||||
|
||||
// Debug (used by unit tests)
|
||||
reconnectDelay time.Duration
|
||||
}
|
||||
|
||||
type request struct {
|
||||
xid int32
|
||||
opcode int32
|
||||
pkt interface{}
|
||||
recvStruct interface{}
|
||||
recvChan chan response
|
||||
|
||||
// Because sending and receiving happen in separate go routines, there's
|
||||
// a possible race condition when creating watches from outside the read
|
||||
// loop. We must ensure that a watcher gets added to the list synchronously
|
||||
// with the response from the server on any request that creates a watch.
|
||||
// In order to not hard code the watch logic for each opcode in the recv
|
||||
// loop the caller can use recvFunc to insert some synchronously code
|
||||
// after a response.
|
||||
recvFunc func(*request, *responseHeader, error)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
zxid int64
|
||||
err error
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Type EventType
|
||||
State State
|
||||
Path string // For non-session events, the path of the watched node.
|
||||
Err error
|
||||
Server string // For connection events
|
||||
}
|
||||
|
||||
// Connect establishes a new connection to a pool of zookeeper servers
|
||||
// using the default net.Dialer. See ConnectWithDialer for further
|
||||
// information about session timeout.
|
||||
func Connect(servers []string, sessionTimeout time.Duration) (*Conn, <-chan Event, error) {
|
||||
return ConnectWithDialer(servers, sessionTimeout, nil)
|
||||
}
|
||||
|
||||
// ConnectWithDialer establishes a new connection to a pool of zookeeper
|
||||
// servers. The provided session timeout sets the amount of time for which
|
||||
// a session is considered valid after losing connection to a server. Within
|
||||
// the session timeout it's possible to reestablish a connection to a different
|
||||
// server and keep the same session. This is means any ephemeral nodes and
|
||||
// watches are maintained.
|
||||
func ConnectWithDialer(servers []string, sessionTimeout time.Duration, dialer Dialer) (*Conn, <-chan Event, error) {
|
||||
if len(servers) == 0 {
|
||||
return nil, nil, errors.New("zk: server list must not be empty")
|
||||
}
|
||||
|
||||
recvTimeout := sessionTimeout * 2 / 3
|
||||
|
||||
srvs := make([]string, len(servers))
|
||||
|
||||
for i, addr := range servers {
|
||||
if strings.Contains(addr, ":") {
|
||||
srvs[i] = addr
|
||||
} else {
|
||||
srvs[i] = addr + ":" + strconv.Itoa(DefaultPort)
|
||||
}
|
||||
}
|
||||
|
||||
// Randomize the order of the servers to avoid creating hotspots
|
||||
stringShuffle(srvs)
|
||||
|
||||
ec := make(chan Event, eventChanSize)
|
||||
if dialer == nil {
|
||||
dialer = net.DialTimeout
|
||||
}
|
||||
conn := Conn{
|
||||
dialer: dialer,
|
||||
servers: srvs,
|
||||
serverIndex: 0,
|
||||
lastServerIndex: -1,
|
||||
conn: nil,
|
||||
state: StateDisconnected,
|
||||
eventChan: ec,
|
||||
shouldQuit: make(chan struct{}),
|
||||
recvTimeout: recvTimeout,
|
||||
pingInterval: recvTimeout / 2,
|
||||
connectTimeout: 1 * time.Second,
|
||||
sendChan: make(chan *request, sendChanSize),
|
||||
requests: make(map[int32]*request),
|
||||
watchers: make(map[watchPathType][]chan Event),
|
||||
passwd: emptyPassword,
|
||||
timeout: int32(sessionTimeout.Nanoseconds() / 1e6),
|
||||
|
||||
// Debug
|
||||
reconnectDelay: 0,
|
||||
}
|
||||
go func() {
|
||||
conn.loop()
|
||||
conn.flushRequests(ErrClosing)
|
||||
conn.invalidateWatches(ErrClosing)
|
||||
close(conn.eventChan)
|
||||
}()
|
||||
return &conn, ec, nil
|
||||
}
|
||||
|
||||
func (c *Conn) Close() {
|
||||
close(c.shouldQuit)
|
||||
|
||||
select {
|
||||
case <-c.queueRequest(opClose, &closeRequest{}, &closeResponse{}, nil):
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) State() State {
|
||||
return State(atomic.LoadInt32((*int32)(&c.state)))
|
||||
}
|
||||
|
||||
func (c *Conn) setState(state State) {
|
||||
atomic.StoreInt32((*int32)(&c.state), int32(state))
|
||||
select {
|
||||
case c.eventChan <- Event{Type: EventSession, State: state, Server: c.servers[c.serverIndex]}:
|
||||
default:
|
||||
// panic("zk: event channel full - it must be monitored and never allowed to be full")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) connect() error {
|
||||
c.setState(StateConnecting)
|
||||
for {
|
||||
c.serverIndex = (c.serverIndex + 1) % len(c.servers)
|
||||
if c.serverIndex == c.lastServerIndex {
|
||||
c.flushUnsentRequests(ErrNoServer)
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
// pass
|
||||
case <-c.shouldQuit:
|
||||
c.setState(StateDisconnected)
|
||||
c.flushUnsentRequests(ErrClosing)
|
||||
return ErrClosing
|
||||
}
|
||||
} else if c.lastServerIndex < 0 {
|
||||
// lastServerIndex defaults to -1 to avoid a delay on the initial connect
|
||||
c.lastServerIndex = 0
|
||||
}
|
||||
|
||||
zkConn, err := c.dialer("tcp", c.servers[c.serverIndex], c.connectTimeout)
|
||||
if err == nil {
|
||||
c.conn = zkConn
|
||||
c.setState(StateConnected)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Failed to connect to %s: %+v", c.servers[c.serverIndex], err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) loop() {
|
||||
for {
|
||||
if err := c.connect(); err != nil {
|
||||
// c.Close() was called
|
||||
return
|
||||
}
|
||||
|
||||
err := c.authenticate()
|
||||
switch {
|
||||
case err == ErrSessionExpired:
|
||||
c.invalidateWatches(err)
|
||||
case err != nil && c.conn != nil:
|
||||
c.conn.Close()
|
||||
case err == nil:
|
||||
c.lastServerIndex = c.serverIndex
|
||||
closeChan := make(chan struct{}) // channel to tell send loop stop
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
c.sendLoop(c.conn, closeChan)
|
||||
c.conn.Close() // causes recv loop to EOF/exit
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = c.recvLoop(c.conn)
|
||||
if err == nil {
|
||||
panic("zk: recvLoop should never return nil error")
|
||||
}
|
||||
close(closeChan) // tell send loop to exit
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
c.setState(StateDisconnected)
|
||||
|
||||
// Yeesh
|
||||
if err != io.EOF && err != ErrSessionExpired && !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.shouldQuit:
|
||||
c.flushRequests(ErrClosing)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
if err != ErrSessionExpired {
|
||||
err = ErrConnectionClosed
|
||||
}
|
||||
c.flushRequests(err)
|
||||
|
||||
if c.reconnectDelay > 0 {
|
||||
select {
|
||||
case <-c.shouldQuit:
|
||||
return
|
||||
case <-time.After(c.reconnectDelay):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) flushUnsentRequests(err error) {
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
return
|
||||
case req := <-c.sendChan:
|
||||
req.recvChan <- response{-1, err}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send error to all pending requests and clear request map
|
||||
func (c *Conn) flushRequests(err error) {
|
||||
c.requestsLock.Lock()
|
||||
for _, req := range c.requests {
|
||||
req.recvChan <- response{-1, err}
|
||||
}
|
||||
c.requests = make(map[int32]*request)
|
||||
c.requestsLock.Unlock()
|
||||
}
|
||||
|
||||
// Send error to all watchers and clear watchers map
|
||||
func (c *Conn) invalidateWatches(err error) {
|
||||
c.watchersLock.Lock()
|
||||
defer c.watchersLock.Unlock()
|
||||
|
||||
if len(c.watchers) >= 0 {
|
||||
for pathType, watchers := range c.watchers {
|
||||
ev := Event{Type: EventNotWatching, State: StateDisconnected, Path: pathType.path, Err: err}
|
||||
for _, ch := range watchers {
|
||||
ch <- ev
|
||||
close(ch)
|
||||
}
|
||||
}
|
||||
c.watchers = make(map[watchPathType][]chan Event)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) sendSetWatches() {
|
||||
c.watchersLock.Lock()
|
||||
defer c.watchersLock.Unlock()
|
||||
|
||||
if len(c.watchers) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
req := &setWatchesRequest{
|
||||
RelativeZxid: c.lastZxid,
|
||||
DataWatches: make([]string, 0),
|
||||
ExistWatches: make([]string, 0),
|
||||
ChildWatches: make([]string, 0),
|
||||
}
|
||||
n := 0
|
||||
for pathType, watchers := range c.watchers {
|
||||
if len(watchers) == 0 {
|
||||
continue
|
||||
}
|
||||
switch pathType.wType {
|
||||
case watchTypeData:
|
||||
req.DataWatches = append(req.DataWatches, pathType.path)
|
||||
case watchTypeExist:
|
||||
req.ExistWatches = append(req.ExistWatches, pathType.path)
|
||||
case watchTypeChild:
|
||||
req.ChildWatches = append(req.ChildWatches, pathType.path)
|
||||
}
|
||||
n++
|
||||
}
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
res := &setWatchesResponse{}
|
||||
_, err := c.request(opSetWatches, req, res, nil)
|
||||
if err != nil {
|
||||
log.Printf("Failed to set previous watches: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *Conn) authenticate() error {
|
||||
buf := make([]byte, 256)
|
||||
|
||||
// connect request
|
||||
|
||||
n, err := encodePacket(buf[4:], &connectRequest{
|
||||
ProtocolVersion: protocolVersion,
|
||||
LastZxidSeen: c.lastZxid,
|
||||
TimeOut: c.timeout,
|
||||
SessionID: c.sessionID,
|
||||
Passwd: c.passwd,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(buf[:4], uint32(n))
|
||||
|
||||
c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout * 10))
|
||||
_, err = c.conn.Write(buf[:n+4])
|
||||
c.conn.SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.sendSetWatches()
|
||||
|
||||
// connect response
|
||||
|
||||
// package length
|
||||
c.conn.SetReadDeadline(time.Now().Add(c.recvTimeout * 10))
|
||||
_, err = io.ReadFull(c.conn, buf[:4])
|
||||
c.conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
// Sometimes zookeeper just drops connection on invalid session data,
|
||||
// we prefer to drop session and start from scratch when that event
|
||||
// occurs instead of dropping into loop of connect/disconnect attempts
|
||||
c.sessionID = 0
|
||||
c.passwd = emptyPassword
|
||||
c.lastZxid = 0
|
||||
c.setState(StateExpired)
|
||||
return ErrSessionExpired
|
||||
}
|
||||
|
||||
blen := int(binary.BigEndian.Uint32(buf[:4]))
|
||||
if cap(buf) < blen {
|
||||
buf = make([]byte, blen)
|
||||
}
|
||||
|
||||
_, err = io.ReadFull(c.conn, buf[:blen])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := connectResponse{}
|
||||
_, err = decodePacket(buf[:blen], &r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.SessionID == 0 {
|
||||
c.sessionID = 0
|
||||
c.passwd = emptyPassword
|
||||
c.lastZxid = 0
|
||||
c.setState(StateExpired)
|
||||
return ErrSessionExpired
|
||||
}
|
||||
|
||||
if c.sessionID != r.SessionID {
|
||||
atomic.StoreUint32(&c.xid, 0)
|
||||
}
|
||||
c.timeout = r.TimeOut
|
||||
c.sessionID = r.SessionID
|
||||
c.passwd = r.Passwd
|
||||
c.setState(StateHasSession)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) sendLoop(conn net.Conn, closeChan <-chan struct{}) error {
|
||||
pingTicker := time.NewTicker(c.pingInterval)
|
||||
defer pingTicker.Stop()
|
||||
|
||||
buf := make([]byte, bufferSize)
|
||||
for {
|
||||
select {
|
||||
case req := <-c.sendChan:
|
||||
header := &requestHeader{req.xid, req.opcode}
|
||||
n, err := encodePacket(buf[4:], header)
|
||||
if err != nil {
|
||||
req.recvChan <- response{-1, err}
|
||||
continue
|
||||
}
|
||||
|
||||
n2, err := encodePacket(buf[4+n:], req.pkt)
|
||||
if err != nil {
|
||||
req.recvChan <- response{-1, err}
|
||||
continue
|
||||
}
|
||||
|
||||
n += n2
|
||||
|
||||
binary.BigEndian.PutUint32(buf[:4], uint32(n))
|
||||
|
||||
c.requestsLock.Lock()
|
||||
select {
|
||||
case <-closeChan:
|
||||
req.recvChan <- response{-1, ErrConnectionClosed}
|
||||
c.requestsLock.Unlock()
|
||||
return ErrConnectionClosed
|
||||
default:
|
||||
}
|
||||
c.requests[req.xid] = req
|
||||
c.requestsLock.Unlock()
|
||||
|
||||
conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
|
||||
_, err = conn.Write(buf[:n+4])
|
||||
conn.SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
req.recvChan <- response{-1, err}
|
||||
conn.Close()
|
||||
return err
|
||||
}
|
||||
case <-pingTicker.C:
|
||||
n, err := encodePacket(buf[4:], &requestHeader{Xid: -2, Opcode: opPing})
|
||||
if err != nil {
|
||||
panic("zk: opPing should never fail to serialize")
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(buf[:4], uint32(n))
|
||||
|
||||
conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
|
||||
_, err = conn.Write(buf[:n+4])
|
||||
conn.SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return err
|
||||
}
|
||||
case <-closeChan:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) recvLoop(conn net.Conn) error {
|
||||
buf := make([]byte, bufferSize)
|
||||
for {
|
||||
// package length
|
||||
conn.SetReadDeadline(time.Now().Add(c.recvTimeout))
|
||||
_, err := io.ReadFull(conn, buf[:4])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blen := int(binary.BigEndian.Uint32(buf[:4]))
|
||||
if cap(buf) < blen {
|
||||
buf = make([]byte, blen)
|
||||
}
|
||||
|
||||
_, err = io.ReadFull(conn, buf[:blen])
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := responseHeader{}
|
||||
_, err = decodePacket(buf[:16], &res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.Xid == -1 {
|
||||
res := &watcherEvent{}
|
||||
_, err := decodePacket(buf[16:16+blen], res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ev := Event{
|
||||
Type: res.Type,
|
||||
State: res.State,
|
||||
Path: res.Path,
|
||||
Err: nil,
|
||||
}
|
||||
select {
|
||||
case c.eventChan <- ev:
|
||||
default:
|
||||
}
|
||||
wTypes := make([]watchType, 0, 2)
|
||||
switch res.Type {
|
||||
case EventNodeCreated:
|
||||
wTypes = append(wTypes, watchTypeExist)
|
||||
case EventNodeDeleted, EventNodeDataChanged:
|
||||
wTypes = append(wTypes, watchTypeExist, watchTypeData, watchTypeChild)
|
||||
case EventNodeChildrenChanged:
|
||||
wTypes = append(wTypes, watchTypeChild)
|
||||
}
|
||||
c.watchersLock.Lock()
|
||||
for _, t := range wTypes {
|
||||
wpt := watchPathType{res.Path, t}
|
||||
if watchers := c.watchers[wpt]; watchers != nil && len(watchers) > 0 {
|
||||
for _, ch := range watchers {
|
||||
ch <- ev
|
||||
close(ch)
|
||||
}
|
||||
delete(c.watchers, wpt)
|
||||
}
|
||||
}
|
||||
c.watchersLock.Unlock()
|
||||
} else if res.Xid == -2 {
|
||||
// Ping response. Ignore.
|
||||
} else if res.Xid < 0 {
|
||||
log.Printf("Xid < 0 (%d) but not ping or watcher event", res.Xid)
|
||||
} else {
|
||||
if res.Zxid > 0 {
|
||||
c.lastZxid = res.Zxid
|
||||
}
|
||||
|
||||
c.requestsLock.Lock()
|
||||
req, ok := c.requests[res.Xid]
|
||||
if ok {
|
||||
delete(c.requests, res.Xid)
|
||||
}
|
||||
c.requestsLock.Unlock()
|
||||
|
||||
if !ok {
|
||||
log.Printf("Response for unknown request with xid %d", res.Xid)
|
||||
} else {
|
||||
if res.Err != 0 {
|
||||
err = res.Err.toError()
|
||||
} else {
|
||||
_, err = decodePacket(buf[16:16+blen], req.recvStruct)
|
||||
}
|
||||
if req.recvFunc != nil {
|
||||
req.recvFunc(req, &res, err)
|
||||
}
|
||||
req.recvChan <- response{res.Zxid, err}
|
||||
if req.opcode == opClose {
|
||||
return io.EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) nextXid() int32 {
|
||||
return int32(atomic.AddUint32(&c.xid, 1) & 0x7fffffff)
|
||||
}
|
||||
|
||||
func (c *Conn) addWatcher(path string, watchType watchType) <-chan Event {
|
||||
c.watchersLock.Lock()
|
||||
defer c.watchersLock.Unlock()
|
||||
|
||||
ch := make(chan Event, 1)
|
||||
wpt := watchPathType{path, watchType}
|
||||
c.watchers[wpt] = append(c.watchers[wpt], ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func (c *Conn) queueRequest(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) <-chan response {
|
||||
rq := &request{
|
||||
xid: c.nextXid(),
|
||||
opcode: opcode,
|
||||
pkt: req,
|
||||
recvStruct: res,
|
||||
recvChan: make(chan response, 1),
|
||||
recvFunc: recvFunc,
|
||||
}
|
||||
c.sendChan <- rq
|
||||
return rq.recvChan
|
||||
}
|
||||
|
||||
func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) (int64, error) {
|
||||
r := <-c.queueRequest(opcode, req, res, recvFunc)
|
||||
return r.zxid, r.err
|
||||
}
|
||||
|
||||
func (c *Conn) AddAuth(scheme string, auth []byte) error {
|
||||
_, err := c.request(opSetAuth, &setAuthRequest{Type: 0, Scheme: scheme, Auth: auth}, &setAuthResponse{}, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) Children(path string) ([]string, *Stat, error) {
|
||||
res := &getChildren2Response{}
|
||||
_, err := c.request(opGetChildren2, &getChildren2Request{Path: path, Watch: false}, res, nil)
|
||||
return res.Children, &res.Stat, err
|
||||
}
|
||||
|
||||
func (c *Conn) ChildrenW(path string) ([]string, *Stat, <-chan Event, error) {
|
||||
var ech <-chan Event
|
||||
res := &getChildren2Response{}
|
||||
_, err := c.request(opGetChildren2, &getChildren2Request{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
|
||||
if err == nil {
|
||||
ech = c.addWatcher(path, watchTypeChild)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return res.Children, &res.Stat, ech, err
|
||||
}
|
||||
|
||||
func (c *Conn) Get(path string) ([]byte, *Stat, error) {
|
||||
res := &getDataResponse{}
|
||||
_, err := c.request(opGetData, &getDataRequest{Path: path, Watch: false}, res, nil)
|
||||
return res.Data, &res.Stat, err
|
||||
}
|
||||
|
||||
// GetW returns the contents of a znode and sets a watch
|
||||
func (c *Conn) GetW(path string) ([]byte, *Stat, <-chan Event, error) {
|
||||
var ech <-chan Event
|
||||
res := &getDataResponse{}
|
||||
_, err := c.request(opGetData, &getDataRequest{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
|
||||
if err == nil {
|
||||
ech = c.addWatcher(path, watchTypeData)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return res.Data, &res.Stat, ech, err
|
||||
}
|
||||
|
||||
func (c *Conn) Set(path string, data []byte, version int32) (*Stat, error) {
|
||||
res := &setDataResponse{}
|
||||
_, err := c.request(opSetData, &SetDataRequest{path, data, version}, res, nil)
|
||||
return &res.Stat, err
|
||||
}
|
||||
|
||||
func (c *Conn) Create(path string, data []byte, flags int32, acl []ACL) (string, error) {
|
||||
res := &createResponse{}
|
||||
_, err := c.request(opCreate, &CreateRequest{path, data, acl, flags}, res, nil)
|
||||
return res.Path, err
|
||||
}
|
||||
|
||||
// CreateProtectedEphemeralSequential fixes a race condition if the server crashes
|
||||
// after it creates the node. On reconnect the session may still be valid so the
|
||||
// ephemeral node still exists. Therefore, on reconnect we need to check if a node
|
||||
// with a GUID generated on create exists.
|
||||
func (c *Conn) CreateProtectedEphemeralSequential(path string, data []byte, acl []ACL) (string, error) {
|
||||
var guid [16]byte
|
||||
_, err := io.ReadFull(rand.Reader, guid[:16])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
guidStr := fmt.Sprintf("%x", guid)
|
||||
|
||||
parts := strings.Split(path, "/")
|
||||
parts[len(parts)-1] = fmt.Sprintf("%s%s-%s", protectedPrefix, guidStr, parts[len(parts)-1])
|
||||
rootPath := strings.Join(parts[:len(parts)-1], "/")
|
||||
protectedPath := strings.Join(parts, "/")
|
||||
|
||||
var newPath string
|
||||
for i := 0; i < 3; i++ {
|
||||
newPath, err = c.Create(protectedPath, data, FlagEphemeral|FlagSequence, acl)
|
||||
switch err {
|
||||
case ErrSessionExpired:
|
||||
// No need to search for the node since it can't exist. Just try again.
|
||||
case ErrConnectionClosed:
|
||||
children, _, err := c.Children(rootPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, p := range children {
|
||||
parts := strings.Split(p, "/")
|
||||
if pth := parts[len(parts)-1]; strings.HasPrefix(pth, protectedPrefix) {
|
||||
if g := pth[len(protectedPrefix) : len(protectedPrefix)+32]; g == guidStr {
|
||||
return rootPath + "/" + p, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
case nil:
|
||||
return newPath, nil
|
||||
default:
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (c *Conn) Delete(path string, version int32) error {
|
||||
_, err := c.request(opDelete, &DeleteRequest{path, version}, &deleteResponse{}, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) Exists(path string) (bool, *Stat, error) {
|
||||
res := &existsResponse{}
|
||||
_, err := c.request(opExists, &existsRequest{Path: path, Watch: false}, res, nil)
|
||||
exists := true
|
||||
if err == ErrNoNode {
|
||||
exists = false
|
||||
err = nil
|
||||
}
|
||||
return exists, &res.Stat, err
|
||||
}
|
||||
|
||||
func (c *Conn) ExistsW(path string) (bool, *Stat, <-chan Event, error) {
|
||||
var ech <-chan Event
|
||||
res := &existsResponse{}
|
||||
_, err := c.request(opExists, &existsRequest{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
|
||||
if err == nil {
|
||||
ech = c.addWatcher(path, watchTypeData)
|
||||
} else if err == ErrNoNode {
|
||||
ech = c.addWatcher(path, watchTypeExist)
|
||||
}
|
||||
})
|
||||
exists := true
|
||||
if err == ErrNoNode {
|
||||
exists = false
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, nil, nil, err
|
||||
}
|
||||
return exists, &res.Stat, ech, err
|
||||
}
|
||||
|
||||
func (c *Conn) GetACL(path string) ([]ACL, *Stat, error) {
|
||||
res := &getAclResponse{}
|
||||
_, err := c.request(opGetAcl, &getAclRequest{Path: path}, res, nil)
|
||||
return res.Acl, &res.Stat, err
|
||||
}
|
||||
|
||||
func (c *Conn) SetACL(path string, acl []ACL, version int32) (*Stat, error) {
|
||||
res := &setAclResponse{}
|
||||
_, err := c.request(opSetAcl, &setAclRequest{Path: path, Acl: acl, Version: version}, res, nil)
|
||||
return &res.Stat, err
|
||||
}
|
||||
|
||||
func (c *Conn) Sync(path string) (string, error) {
|
||||
res := &syncResponse{}
|
||||
_, err := c.request(opSync, &syncRequest{Path: path}, res, nil)
|
||||
return res.Path, err
|
||||
}
|
||||
|
||||
type MultiResponse struct {
|
||||
Stat *Stat
|
||||
String string
|
||||
}
|
||||
|
||||
// Multi executes multiple ZooKeeper operations or none of them. The provided
|
||||
// ops must be one of *CreateRequest, *DeleteRequest, *SetDataRequest, or
|
||||
// *CheckVersionRequest.
|
||||
func (c *Conn) Multi(ops ...interface{}) ([]MultiResponse, error) {
|
||||
req := &multiRequest{
|
||||
Ops: make([]multiRequestOp, 0, len(ops)),
|
||||
DoneHeader: multiHeader{Type: -1, Done: true, Err: -1},
|
||||
}
|
||||
for _, op := range ops {
|
||||
var opCode int32
|
||||
switch op.(type) {
|
||||
case *CreateRequest:
|
||||
opCode = opCreate
|
||||
case *SetDataRequest:
|
||||
opCode = opSetData
|
||||
case *DeleteRequest:
|
||||
opCode = opDelete
|
||||
case *CheckVersionRequest:
|
||||
opCode = opCheck
|
||||
default:
|
||||
return nil, fmt.Errorf("uknown operation type %T", op)
|
||||
}
|
||||
req.Ops = append(req.Ops, multiRequestOp{multiHeader{opCode, false, -1}, op})
|
||||
}
|
||||
res := &multiResponse{}
|
||||
_, err := c.request(opMulti, req, res, nil)
|
||||
mr := make([]MultiResponse, len(res.Ops))
|
||||
for i, op := range res.Ops {
|
||||
mr[i] = MultiResponse{Stat: op.Stat, String: op.String}
|
||||
}
|
||||
return mr, err
|
||||
}
|
||||
242
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/constants.go
generated
vendored
Normal file
242
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/constants.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
protocolVersion = 0
|
||||
|
||||
DefaultPort = 2181
|
||||
)
|
||||
|
||||
const (
|
||||
opNotify = 0
|
||||
opCreate = 1
|
||||
opDelete = 2
|
||||
opExists = 3
|
||||
opGetData = 4
|
||||
opSetData = 5
|
||||
opGetAcl = 6
|
||||
opSetAcl = 7
|
||||
opGetChildren = 8
|
||||
opSync = 9
|
||||
opPing = 11
|
||||
opGetChildren2 = 12
|
||||
opCheck = 13
|
||||
opMulti = 14
|
||||
opClose = -11
|
||||
opSetAuth = 100
|
||||
opSetWatches = 101
|
||||
// Not in protocol, used internally
|
||||
opWatcherEvent = -2
|
||||
)
|
||||
|
||||
const (
|
||||
EventNodeCreated = EventType(1)
|
||||
EventNodeDeleted = EventType(2)
|
||||
EventNodeDataChanged = EventType(3)
|
||||
EventNodeChildrenChanged = EventType(4)
|
||||
|
||||
EventSession = EventType(-1)
|
||||
EventNotWatching = EventType(-2)
|
||||
)
|
||||
|
||||
var (
|
||||
eventNames = map[EventType]string{
|
||||
EventNodeCreated: "EventNodeCreated",
|
||||
EventNodeDeleted: "EventNodeDeleted",
|
||||
EventNodeDataChanged: "EventNodeDataChanged",
|
||||
EventNodeChildrenChanged: "EventNodeChildrenChanged",
|
||||
EventSession: "EventSession",
|
||||
EventNotWatching: "EventNotWatching",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
StateUnknown = State(-1)
|
||||
StateDisconnected = State(0)
|
||||
StateConnecting = State(1)
|
||||
StateSyncConnected = State(3)
|
||||
StateAuthFailed = State(4)
|
||||
StateConnectedReadOnly = State(5)
|
||||
StateSaslAuthenticated = State(6)
|
||||
StateExpired = State(-112)
|
||||
// StateAuthFailed = State(-113)
|
||||
|
||||
StateConnected = State(100)
|
||||
StateHasSession = State(101)
|
||||
)
|
||||
|
||||
const (
|
||||
FlagEphemeral = 1
|
||||
FlagSequence = 2
|
||||
)
|
||||
|
||||
var (
|
||||
stateNames = map[State]string{
|
||||
StateUnknown: "StateUnknown",
|
||||
StateDisconnected: "StateDisconnected",
|
||||
StateSyncConnected: "StateSyncConnected",
|
||||
StateConnectedReadOnly: "StateConnectedReadOnly",
|
||||
StateSaslAuthenticated: "StateSaslAuthenticated",
|
||||
StateExpired: "StateExpired",
|
||||
StateAuthFailed: "StateAuthFailed",
|
||||
StateConnecting: "StateConnecting",
|
||||
StateConnected: "StateConnected",
|
||||
StateHasSession: "StateHasSession",
|
||||
}
|
||||
)
|
||||
|
||||
type State int32
|
||||
|
||||
func (s State) String() string {
|
||||
if name := stateNames[s]; name != "" {
|
||||
return name
|
||||
}
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
type ErrCode int32
|
||||
|
||||
var (
|
||||
ErrConnectionClosed = errors.New("zk: connection closed")
|
||||
ErrUnknown = errors.New("zk: unknown error")
|
||||
ErrAPIError = errors.New("zk: api error")
|
||||
ErrNoNode = errors.New("zk: node does not exist")
|
||||
ErrNoAuth = errors.New("zk: not authenticated")
|
||||
ErrBadVersion = errors.New("zk: version conflict")
|
||||
ErrNoChildrenForEphemerals = errors.New("zk: ephemeral nodes may not have children")
|
||||
ErrNodeExists = errors.New("zk: node already exists")
|
||||
ErrNotEmpty = errors.New("zk: node has children")
|
||||
ErrSessionExpired = errors.New("zk: session has been expired by the server")
|
||||
ErrInvalidACL = errors.New("zk: invalid ACL specified")
|
||||
ErrAuthFailed = errors.New("zk: client authentication failed")
|
||||
ErrClosing = errors.New("zk: zookeeper is closing")
|
||||
ErrNothing = errors.New("zk: no server responsees to process")
|
||||
ErrSessionMoved = errors.New("zk: session moved to another server, so operation is ignored")
|
||||
|
||||
// ErrInvalidCallback = errors.New("zk: invalid callback specified")
|
||||
errCodeToError = map[ErrCode]error{
|
||||
0: nil,
|
||||
errAPIError: ErrAPIError,
|
||||
errNoNode: ErrNoNode,
|
||||
errNoAuth: ErrNoAuth,
|
||||
errBadVersion: ErrBadVersion,
|
||||
errNoChildrenForEphemerals: ErrNoChildrenForEphemerals,
|
||||
errNodeExists: ErrNodeExists,
|
||||
errNotEmpty: ErrNotEmpty,
|
||||
errSessionExpired: ErrSessionExpired,
|
||||
// errInvalidCallback: ErrInvalidCallback,
|
||||
errInvalidAcl: ErrInvalidACL,
|
||||
errAuthFailed: ErrAuthFailed,
|
||||
errClosing: ErrClosing,
|
||||
errNothing: ErrNothing,
|
||||
errSessionMoved: ErrSessionMoved,
|
||||
}
|
||||
)
|
||||
|
||||
func (e ErrCode) toError() error {
|
||||
if err, ok := errCodeToError[e]; ok {
|
||||
return err
|
||||
}
|
||||
return ErrUnknown
|
||||
}
|
||||
|
||||
const (
|
||||
errOk = 0
|
||||
// System and server-side errors
|
||||
errSystemError = -1
|
||||
errRuntimeInconsistency = -2
|
||||
errDataInconsistency = -3
|
||||
errConnectionLoss = -4
|
||||
errMarshallingError = -5
|
||||
errUnimplemented = -6
|
||||
errOperationTimeout = -7
|
||||
errBadArguments = -8
|
||||
errInvalidState = -9
|
||||
// API errors
|
||||
errAPIError = ErrCode(-100)
|
||||
errNoNode = ErrCode(-101) // *
|
||||
errNoAuth = ErrCode(-102)
|
||||
errBadVersion = ErrCode(-103) // *
|
||||
errNoChildrenForEphemerals = ErrCode(-108)
|
||||
errNodeExists = ErrCode(-110) // *
|
||||
errNotEmpty = ErrCode(-111)
|
||||
errSessionExpired = ErrCode(-112)
|
||||
errInvalidCallback = ErrCode(-113)
|
||||
errInvalidAcl = ErrCode(-114)
|
||||
errAuthFailed = ErrCode(-115)
|
||||
errClosing = ErrCode(-116)
|
||||
errNothing = ErrCode(-117)
|
||||
errSessionMoved = ErrCode(-118)
|
||||
)
|
||||
|
||||
// Constants for ACL permissions
|
||||
const (
|
||||
PermRead = 1 << iota
|
||||
PermWrite
|
||||
PermCreate
|
||||
PermDelete
|
||||
PermAdmin
|
||||
PermAll = 0x1f
|
||||
)
|
||||
|
||||
var (
|
||||
emptyPassword = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
opNames = map[int32]string{
|
||||
opNotify: "notify",
|
||||
opCreate: "create",
|
||||
opDelete: "delete",
|
||||
opExists: "exists",
|
||||
opGetData: "getData",
|
||||
opSetData: "setData",
|
||||
opGetAcl: "getACL",
|
||||
opSetAcl: "setACL",
|
||||
opGetChildren: "getChildren",
|
||||
opSync: "sync",
|
||||
opPing: "ping",
|
||||
opGetChildren2: "getChildren2",
|
||||
opCheck: "check",
|
||||
opMulti: "multi",
|
||||
opClose: "close",
|
||||
opSetAuth: "setAuth",
|
||||
opSetWatches: "setWatches",
|
||||
|
||||
opWatcherEvent: "watcherEvent",
|
||||
}
|
||||
)
|
||||
|
||||
type EventType int32
|
||||
|
||||
func (t EventType) String() string {
|
||||
if name := eventNames[t]; name != "" {
|
||||
return name
|
||||
}
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
// Mode is used to build custom server modes (leader|follower|standalone).
|
||||
type Mode uint8
|
||||
|
||||
func (m Mode) String() string {
|
||||
if name := modeNames[m]; name != "" {
|
||||
return name
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
ModeUnknown Mode = iota
|
||||
ModeLeader Mode = iota
|
||||
ModeFollower Mode = iota
|
||||
ModeStandalone Mode = iota
|
||||
)
|
||||
|
||||
var (
|
||||
modeNames = map[Mode]string{
|
||||
ModeLeader: "leader",
|
||||
ModeFollower: "follower",
|
||||
ModeStandalone: "standalone",
|
||||
}
|
||||
)
|
||||
24
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/constants_test.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/constants_test.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestModeString(t *testing.T) {
|
||||
if fmt.Sprintf("%v", ModeUnknown) != "unknown" {
|
||||
t.Errorf("unknown value should be 'unknown'")
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%v", ModeLeader) != "leader" {
|
||||
t.Errorf("leader value should be 'leader'")
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%v", ModeFollower) != "follower" {
|
||||
t.Errorf("follower value should be 'follower'")
|
||||
}
|
||||
|
||||
if fmt.Sprintf("%v", ModeStandalone) != "standalone" {
|
||||
t.Errorf("standlone value should be 'standalone'")
|
||||
}
|
||||
}
|
||||
288
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/flw.go
generated
vendored
Normal file
288
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/flw.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FLWSrvr is a FourLetterWord helper function. In particular, this function pulls the srvr output
|
||||
// from the zookeeper instances and parses the output. A slice of *ServerStats structs are returned
|
||||
// as well as a boolean value to indicate whether this function processed successfully.
|
||||
//
|
||||
// If the boolean value is false there was a problem. If the *ServerStats slice is empty or nil,
|
||||
// then the error happened before we started to obtain 'srvr' values. Otherwise, one of the
|
||||
// servers had an issue and the "Error" value in the struct should be inspected to determine
|
||||
// which server had the issue.
|
||||
func FLWSrvr(servers []string, timeout time.Duration) ([]*ServerStats, bool) {
|
||||
// different parts of the regular expression that are required to parse the srvr output
|
||||
var (
|
||||
zrVer = `^Zookeeper version: ([A-Za-z0-9\.\-]+), built on (\d\d/\d\d/\d\d\d\d \d\d:\d\d [A-Za-z0-9:\+\-]+)`
|
||||
zrLat = `^Latency min/avg/max: (\d+)/(\d+)/(\d+)`
|
||||
zrNet = `^Received: (\d+).*\n^Sent: (\d+).*\n^Connections: (\d+).*\n^Outstanding: (\d+)`
|
||||
zrState = `^Zxid: (0x[A-Za-z0-9]+).*\n^Mode: (\w+).*\n^Node count: (\d+)`
|
||||
)
|
||||
|
||||
// build the regex from the pieces above
|
||||
re, err := regexp.Compile(fmt.Sprintf(`(?m:\A%v.*\n%v.*\n%v.*\n%v)`, zrVer, zrLat, zrNet, zrState))
|
||||
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
imOk := true
|
||||
servers = FormatServers(servers)
|
||||
ss := make([]*ServerStats, len(servers))
|
||||
|
||||
for i := range ss {
|
||||
response, err := fourLetterWord(servers[i], "srvr", timeout)
|
||||
|
||||
if err != nil {
|
||||
ss[i] = &ServerStats{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
match := re.FindAllStringSubmatch(string(response), -1)[0][1:]
|
||||
|
||||
if match == nil {
|
||||
err := fmt.Errorf("unable to parse fields from zookeeper response (no regex matches)")
|
||||
ss[i] = &ServerStats{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
// determine current server
|
||||
var srvrMode Mode
|
||||
switch match[10] {
|
||||
case "leader":
|
||||
srvrMode = ModeLeader
|
||||
case "follower":
|
||||
srvrMode = ModeFollower
|
||||
case "standalone":
|
||||
srvrMode = ModeStandalone
|
||||
default:
|
||||
srvrMode = ModeUnknown
|
||||
}
|
||||
|
||||
buildTime, err := time.Parse("01/02/2006 15:04 MST", match[1])
|
||||
|
||||
if err != nil {
|
||||
ss[i] = &ServerStats{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
parsedInt, err := strconv.ParseInt(match[9], 0, 64)
|
||||
|
||||
if err != nil {
|
||||
ss[i] = &ServerStats{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
// the ZxID value is an int64 with two int32s packed inside
|
||||
// the high int32 is the epoch (i.e., number of leader elections)
|
||||
// the low int32 is the counter
|
||||
epoch := int32(parsedInt >> 32)
|
||||
counter := int32(parsedInt & 0xFFFFFFFF)
|
||||
|
||||
// within the regex above, these values must be numerical
|
||||
// so we can avoid useless checking of the error return value
|
||||
minLatency, _ := strconv.ParseInt(match[2], 0, 64)
|
||||
avgLatency, _ := strconv.ParseInt(match[3], 0, 64)
|
||||
maxLatency, _ := strconv.ParseInt(match[4], 0, 64)
|
||||
recv, _ := strconv.ParseInt(match[5], 0, 64)
|
||||
sent, _ := strconv.ParseInt(match[6], 0, 64)
|
||||
cons, _ := strconv.ParseInt(match[7], 0, 64)
|
||||
outs, _ := strconv.ParseInt(match[8], 0, 64)
|
||||
ncnt, _ := strconv.ParseInt(match[11], 0, 64)
|
||||
|
||||
ss[i] = &ServerStats{
|
||||
Sent: sent,
|
||||
Received: recv,
|
||||
NodeCount: ncnt,
|
||||
MinLatency: minLatency,
|
||||
AvgLatency: avgLatency,
|
||||
MaxLatency: maxLatency,
|
||||
Connections: cons,
|
||||
Outstanding: outs,
|
||||
Epoch: epoch,
|
||||
Counter: counter,
|
||||
BuildTime: buildTime,
|
||||
Mode: srvrMode,
|
||||
Version: match[0],
|
||||
}
|
||||
}
|
||||
|
||||
return ss, imOk
|
||||
}
|
||||
|
||||
// FLWRuok is a FourLetterWord helper function. In particular, this function
|
||||
// pulls the ruok output from each server.
|
||||
func FLWRuok(servers []string, timeout time.Duration) []bool {
|
||||
servers = FormatServers(servers)
|
||||
oks := make([]bool, len(servers))
|
||||
|
||||
for i := range oks {
|
||||
response, err := fourLetterWord(servers[i], "ruok", timeout)
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Equal(response[:4], []byte("imok")) {
|
||||
oks[i] = true
|
||||
}
|
||||
}
|
||||
return oks
|
||||
}
|
||||
|
||||
// FLWCons is a FourLetterWord helper function. In particular, this function
|
||||
// pulls the ruok output from each server.
|
||||
//
|
||||
// As with FLWSrvr, the boolean value indicates whether one of the requests had
|
||||
// an issue. The Clients struct has an Error value that can be checked.
|
||||
func FLWCons(servers []string, timeout time.Duration) ([]*ServerClients, bool) {
|
||||
var (
|
||||
zrAddr = `^ /((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):(?:\d+))\[\d+\]`
|
||||
zrPac = `\(queued=(\d+),recved=(\d+),sent=(\d+),sid=(0x[A-Za-z0-9]+),lop=(\w+),est=(\d+),to=(\d+),`
|
||||
zrSesh = `lcxid=(0x[A-Za-z0-9]+),lzxid=(0x[A-Za-z0-9]+),lresp=(\d+),llat=(\d+),minlat=(\d+),avglat=(\d+),maxlat=(\d+)\)`
|
||||
)
|
||||
|
||||
re, err := regexp.Compile(fmt.Sprintf("%v%v%v", zrAddr, zrPac, zrSesh))
|
||||
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
servers = FormatServers(servers)
|
||||
sc := make([]*ServerClients, len(servers))
|
||||
imOk := true
|
||||
|
||||
for i := range sc {
|
||||
response, err := fourLetterWord(servers[i], "cons", timeout)
|
||||
|
||||
if err != nil {
|
||||
sc[i] = &ServerClients{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
scan := bufio.NewScanner(bytes.NewReader(response))
|
||||
|
||||
var clients []*ServerClient
|
||||
|
||||
for scan.Scan() {
|
||||
line := scan.Bytes()
|
||||
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := re.FindAllStringSubmatch(string(line), -1)
|
||||
|
||||
if m == nil {
|
||||
err := fmt.Errorf("unable to parse fields from zookeeper response (no regex matches)")
|
||||
sc[i] = &ServerClients{Error: err}
|
||||
imOk = false
|
||||
continue
|
||||
}
|
||||
|
||||
match := m[0][1:]
|
||||
|
||||
queued, _ := strconv.ParseInt(match[1], 0, 64)
|
||||
recvd, _ := strconv.ParseInt(match[2], 0, 64)
|
||||
sent, _ := strconv.ParseInt(match[3], 0, 64)
|
||||
sid, _ := strconv.ParseInt(match[4], 0, 64)
|
||||
est, _ := strconv.ParseInt(match[6], 0, 64)
|
||||
timeout, _ := strconv.ParseInt(match[7], 0, 32)
|
||||
lresp, _ := strconv.ParseInt(match[10], 0, 64)
|
||||
llat, _ := strconv.ParseInt(match[11], 0, 32)
|
||||
minlat, _ := strconv.ParseInt(match[12], 0, 32)
|
||||
avglat, _ := strconv.ParseInt(match[13], 0, 32)
|
||||
maxlat, _ := strconv.ParseInt(match[14], 0, 32)
|
||||
|
||||
// zookeeper returns a value, '0xffffffffffffffff', as the
|
||||
// Lzxid for PING requests in the 'cons' output.
|
||||
// unfortunately, in Go that is an invalid int64 and is not represented
|
||||
// as -1.
|
||||
// However, converting the string value to a big.Int and then back to
|
||||
// and int64 properly sets the value to -1
|
||||
lzxid, ok := new(big.Int).SetString(match[9], 0)
|
||||
|
||||
var errVal error
|
||||
|
||||
if !ok {
|
||||
errVal = fmt.Errorf("failed to convert lzxid value to big.Int")
|
||||
imOk = false
|
||||
}
|
||||
|
||||
lcxid, ok := new(big.Int).SetString(match[8], 0)
|
||||
|
||||
if !ok && errVal == nil {
|
||||
errVal = fmt.Errorf("failed to convert lcxid value to big.Int")
|
||||
imOk = false
|
||||
}
|
||||
|
||||
clients = append(clients, &ServerClient{
|
||||
Queued: queued,
|
||||
Received: recvd,
|
||||
Sent: sent,
|
||||
SessionID: sid,
|
||||
Lcxid: lcxid.Int64(),
|
||||
Lzxid: lzxid.Int64(),
|
||||
Timeout: int32(timeout),
|
||||
LastLatency: int32(llat),
|
||||
MinLatency: int32(minlat),
|
||||
AvgLatency: int32(avglat),
|
||||
MaxLatency: int32(maxlat),
|
||||
Established: time.Unix(est, 0),
|
||||
LastResponse: time.Unix(lresp, 0),
|
||||
Addr: match[0],
|
||||
LastOperation: match[5],
|
||||
Error: errVal,
|
||||
})
|
||||
}
|
||||
|
||||
sc[i] = &ServerClients{Clients: clients}
|
||||
}
|
||||
|
||||
return sc, imOk
|
||||
}
|
||||
|
||||
func fourLetterWord(server, command string, timeout time.Duration) ([]byte, error) {
|
||||
conn, err := net.DialTimeout("tcp", server, timeout)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// the zookeeper server should automatically close this socket
|
||||
// once the command has been processed, but better safe than sorry
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetWriteDeadline(time.Now().Add(timeout))
|
||||
|
||||
_, err = conn.Write([]byte(command))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
|
||||
resp, err := ioutil.ReadAll(conn)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
367
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/flw_test.go
generated
vendored
Normal file
367
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/flw_test.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
zkSrvrOut = `Zookeeper version: 3.4.6-1569965, built on 02/20/2014 09:09 GMT
|
||||
Latency min/avg/max: 0/1/10
|
||||
Received: 4207
|
||||
Sent: 4220
|
||||
Connections: 81
|
||||
Outstanding: 1
|
||||
Zxid: 0x110a7a8f37
|
||||
Mode: leader
|
||||
Node count: 306
|
||||
`
|
||||
zkConsOut = ` /10.42.45.231:45361[1](queued=0,recved=9435,sent=9457,sid=0x94c2989e04716b5,lop=PING,est=1427238717217,to=20001,lcxid=0x55120915,lzxid=0xffffffffffffffff,lresp=1427259255908,llat=0,minlat=0,avglat=1,maxlat=17)
|
||||
/10.55.33.98:34342[1](queued=0,recved=9338,sent=9350,sid=0x94c2989e0471731,lop=PING,est=1427238849319,to=20001,lcxid=0x55120944,lzxid=0xffffffffffffffff,lresp=1427259252294,llat=0,minlat=0,avglat=1,maxlat=18)
|
||||
/10.44.145.114:46556[1](queued=0,recved=109253,sent=109617,sid=0x94c2989e0471709,lop=DELE,est=1427238791305,to=20001,lcxid=0x55139618,lzxid=0x110a7b187d,lresp=1427259257423,llat=2,minlat=0,avglat=1,maxlat=23)
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
func TestFLWRuok(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:2181")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
go tcpServer(l, "")
|
||||
|
||||
var oks []bool
|
||||
var ok bool
|
||||
|
||||
oks = FLWRuok([]string{"127.0.0.1"}, time.Second*10)
|
||||
|
||||
// close the connection, and pause shortly
|
||||
// to cheat around a race condition
|
||||
l.Close()
|
||||
time.Sleep(time.Millisecond * 1)
|
||||
|
||||
if len(oks) == 0 {
|
||||
t.Errorf("no values returned")
|
||||
}
|
||||
|
||||
ok = oks[0]
|
||||
|
||||
if !ok {
|
||||
t.Errorf("instance should be marked as OK")
|
||||
}
|
||||
|
||||
//
|
||||
// Confirm that it also returns false for dead instances
|
||||
//
|
||||
l, err = net.Listen("tcp", "127.0.0.1:2181")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
defer l.Close()
|
||||
|
||||
go tcpServer(l, "dead")
|
||||
|
||||
oks = FLWRuok([]string{"127.0.0.1"}, time.Second*10)
|
||||
|
||||
if len(oks) == 0 {
|
||||
t.Errorf("no values returned")
|
||||
}
|
||||
|
||||
ok = oks[0]
|
||||
|
||||
if ok {
|
||||
t.Errorf("instance should be marked as not OK")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFLWSrvr(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:2181")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
defer l.Close()
|
||||
|
||||
go tcpServer(l, "")
|
||||
|
||||
var statsSlice []*ServerStats
|
||||
var stats *ServerStats
|
||||
var ok bool
|
||||
|
||||
statsSlice, ok = FLWSrvr([]string{"127.0.0.1:2181"}, time.Second*10)
|
||||
|
||||
if !ok {
|
||||
t.Errorf("failure indicated on 'srvr' parsing")
|
||||
}
|
||||
|
||||
if len(statsSlice) == 0 {
|
||||
t.Errorf("no *ServerStats instances returned")
|
||||
}
|
||||
|
||||
stats = statsSlice[0]
|
||||
|
||||
if stats.Error != nil {
|
||||
t.Fatalf("error seen in stats: %v", err.Error())
|
||||
}
|
||||
|
||||
if stats.Sent != 4220 {
|
||||
t.Errorf("Sent != 4220")
|
||||
}
|
||||
|
||||
if stats.Received != 4207 {
|
||||
t.Errorf("Received != 4207")
|
||||
}
|
||||
|
||||
if stats.NodeCount != 306 {
|
||||
t.Errorf("NodeCount != 306")
|
||||
}
|
||||
|
||||
if stats.MinLatency != 0 {
|
||||
t.Errorf("MinLatency != 0")
|
||||
}
|
||||
|
||||
if stats.AvgLatency != 1 {
|
||||
t.Errorf("AvgLatency != 1")
|
||||
}
|
||||
|
||||
if stats.MaxLatency != 10 {
|
||||
t.Errorf("MaxLatency != 10")
|
||||
}
|
||||
|
||||
if stats.Connections != 81 {
|
||||
t.Errorf("Connection != 81")
|
||||
}
|
||||
|
||||
if stats.Outstanding != 1 {
|
||||
t.Errorf("Outstanding != 1")
|
||||
}
|
||||
|
||||
if stats.Epoch != 17 {
|
||||
t.Errorf("Epoch != 17")
|
||||
}
|
||||
|
||||
if stats.Counter != 175804215 {
|
||||
t.Errorf("Counter != 175804215")
|
||||
}
|
||||
|
||||
if stats.Mode != ModeLeader {
|
||||
t.Errorf("Mode != ModeLeader")
|
||||
}
|
||||
|
||||
if stats.Version != "3.4.6-1569965" {
|
||||
t.Errorf("Version expected: 3.4.6-1569965")
|
||||
}
|
||||
|
||||
buildTime, err := time.Parse("01/02/2006 15:04 MST", "02/20/2014 09:09 GMT")
|
||||
|
||||
if !stats.BuildTime.Equal(buildTime) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestFLWCons(t *testing.T) {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:2181")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
defer l.Close()
|
||||
|
||||
go tcpServer(l, "")
|
||||
|
||||
var clients []*ServerClients
|
||||
var ok bool
|
||||
|
||||
clients, ok = FLWCons([]string{"127.0.0.1"}, time.Second*10)
|
||||
|
||||
if !ok {
|
||||
t.Errorf("failure indicated on 'cons' parsing")
|
||||
}
|
||||
|
||||
if len(clients) == 0 {
|
||||
t.Errorf("no *ServerClients instances returned")
|
||||
}
|
||||
|
||||
results := []*ServerClient{
|
||||
&ServerClient{
|
||||
Queued: 0,
|
||||
Received: 9435,
|
||||
Sent: 9457,
|
||||
SessionID: 669956116721374901,
|
||||
LastOperation: "PING",
|
||||
Established: time.Unix(1427238717217, 0),
|
||||
Timeout: 20001,
|
||||
Lcxid: 1427245333,
|
||||
Lzxid: -1,
|
||||
LastResponse: time.Unix(1427259255908, 0),
|
||||
LastLatency: 0,
|
||||
MinLatency: 0,
|
||||
AvgLatency: 1,
|
||||
MaxLatency: 17,
|
||||
Addr: "10.42.45.231:45361",
|
||||
},
|
||||
&ServerClient{
|
||||
Queued: 0,
|
||||
Received: 9338,
|
||||
Sent: 9350,
|
||||
SessionID: 669956116721375025,
|
||||
LastOperation: "PING",
|
||||
Established: time.Unix(1427238849319, 0),
|
||||
Timeout: 20001,
|
||||
Lcxid: 1427245380,
|
||||
Lzxid: -1,
|
||||
LastResponse: time.Unix(1427259252294, 0),
|
||||
LastLatency: 0,
|
||||
MinLatency: 0,
|
||||
AvgLatency: 1,
|
||||
MaxLatency: 18,
|
||||
Addr: "10.55.33.98:34342",
|
||||
},
|
||||
&ServerClient{
|
||||
Queued: 0,
|
||||
Received: 109253,
|
||||
Sent: 109617,
|
||||
SessionID: 669956116721374985,
|
||||
LastOperation: "DELE",
|
||||
Established: time.Unix(1427238791305, 0),
|
||||
Timeout: 20001,
|
||||
Lcxid: 1427346968,
|
||||
Lzxid: 73190283389,
|
||||
LastResponse: time.Unix(1427259257423, 0),
|
||||
LastLatency: 2,
|
||||
MinLatency: 0,
|
||||
AvgLatency: 1,
|
||||
MaxLatency: 23,
|
||||
Addr: "10.44.145.114:46556",
|
||||
},
|
||||
}
|
||||
|
||||
for _, z := range clients {
|
||||
if z.Error != nil {
|
||||
t.Errorf("error seen: %v", err.Error())
|
||||
}
|
||||
|
||||
for i, v := range z.Clients {
|
||||
c := results[i]
|
||||
|
||||
if v.Error != nil {
|
||||
t.Errorf("client error seen: %v", err.Error())
|
||||
}
|
||||
|
||||
if v.Queued != c.Queued {
|
||||
t.Errorf("Queued value mismatch (%d/%d)", v.Queued, c.Queued)
|
||||
}
|
||||
|
||||
if v.Received != c.Received {
|
||||
t.Errorf("Received value mismatch (%d/%d)", v.Received, c.Received)
|
||||
}
|
||||
|
||||
if v.Sent != c.Sent {
|
||||
t.Errorf("Sent value mismatch (%d/%d)", v.Sent, c.Sent)
|
||||
}
|
||||
|
||||
if v.SessionID != c.SessionID {
|
||||
t.Errorf("SessionID value mismatch (%d/%d)", v.SessionID, c.SessionID)
|
||||
}
|
||||
|
||||
if v.LastOperation != c.LastOperation {
|
||||
t.Errorf("LastOperation value mismatch ('%v'/'%v')", v.LastOperation, c.LastOperation)
|
||||
}
|
||||
|
||||
if v.Timeout != c.Timeout {
|
||||
t.Errorf("Timeout value mismatch (%d/%d)", v.Timeout, c.Timeout)
|
||||
}
|
||||
|
||||
if v.Lcxid != c.Lcxid {
|
||||
t.Errorf("Lcxid value mismatch (%d/%d)", v.Lcxid, c.Lcxid)
|
||||
}
|
||||
|
||||
if v.Lzxid != c.Lzxid {
|
||||
t.Errorf("Lzxid value mismatch (%d/%d)", v.Lzxid, c.Lzxid)
|
||||
}
|
||||
|
||||
if v.LastLatency != c.LastLatency {
|
||||
t.Errorf("LastLatency value mismatch (%d/%d)", v.LastLatency, c.LastLatency)
|
||||
}
|
||||
|
||||
if v.MinLatency != c.MinLatency {
|
||||
t.Errorf("MinLatency value mismatch (%d/%d)", v.MinLatency, c.MinLatency)
|
||||
}
|
||||
|
||||
if v.AvgLatency != c.AvgLatency {
|
||||
t.Errorf("AvgLatency value mismatch (%d/%d)", v.AvgLatency, c.AvgLatency)
|
||||
}
|
||||
|
||||
if v.MaxLatency != c.MaxLatency {
|
||||
t.Errorf("MaxLatency value mismatch (%d/%d)", v.MaxLatency, c.MaxLatency)
|
||||
}
|
||||
|
||||
if v.Addr != c.Addr {
|
||||
t.Errorf("Addr value mismatch ('%v'/'%v')", v.Addr, c.Addr)
|
||||
}
|
||||
|
||||
if !c.Established.Equal(v.Established) {
|
||||
t.Errorf("Established value mismatch (%v/%v)", c.Established, v.Established)
|
||||
}
|
||||
|
||||
if !c.LastResponse.Equal(v.LastResponse) {
|
||||
t.Errorf("Established value mismatch (%v/%v)", c.LastResponse, v.LastResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tcpServer(listener net.Listener, thing string) {
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go connHandler(conn, thing)
|
||||
}
|
||||
}
|
||||
|
||||
func connHandler(conn net.Conn, thing string) {
|
||||
defer conn.Close()
|
||||
|
||||
data := make([]byte, 4)
|
||||
|
||||
_, err := conn.Read(data)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch string(data) {
|
||||
case "ruok":
|
||||
switch thing {
|
||||
case "dead":
|
||||
return
|
||||
default:
|
||||
conn.Write([]byte("imok"))
|
||||
}
|
||||
case "srvr":
|
||||
switch thing {
|
||||
case "dead":
|
||||
return
|
||||
default:
|
||||
conn.Write([]byte(zkSrvrOut))
|
||||
}
|
||||
case "cons":
|
||||
switch thing {
|
||||
case "dead":
|
||||
return
|
||||
default:
|
||||
conn.Write([]byte(zkConsOut))
|
||||
}
|
||||
default:
|
||||
conn.Write([]byte("This ZooKeeper instance is not currently serving requests."))
|
||||
}
|
||||
}
|
||||
131
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/lock.go
generated
vendored
Normal file
131
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/lock.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDeadlock = errors.New("zk: trying to acquire a lock twice")
|
||||
ErrNotLocked = errors.New("zk: not locked")
|
||||
)
|
||||
|
||||
type Lock struct {
|
||||
c *Conn
|
||||
path string
|
||||
acl []ACL
|
||||
lockPath string
|
||||
seq int
|
||||
}
|
||||
|
||||
func NewLock(c *Conn, path string, acl []ACL) *Lock {
|
||||
return &Lock{
|
||||
c: c,
|
||||
path: path,
|
||||
acl: acl,
|
||||
}
|
||||
}
|
||||
|
||||
func parseSeq(path string) (int, error) {
|
||||
parts := strings.Split(path, "-")
|
||||
return strconv.Atoi(parts[len(parts)-1])
|
||||
}
|
||||
|
||||
func (l *Lock) Lock() error {
|
||||
if l.lockPath != "" {
|
||||
return ErrDeadlock
|
||||
}
|
||||
|
||||
prefix := fmt.Sprintf("%s/lock-", l.path)
|
||||
|
||||
path := ""
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
path, err = l.c.CreateProtectedEphemeralSequential(prefix, []byte{}, l.acl)
|
||||
if err == ErrNoNode {
|
||||
// Create parent node.
|
||||
parts := strings.Split(l.path, "/")
|
||||
pth := ""
|
||||
for _, p := range parts[1:] {
|
||||
pth += "/" + p
|
||||
_, err := l.c.Create(pth, []byte{}, 0, l.acl)
|
||||
if err != nil && err != ErrNodeExists {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if err == nil {
|
||||
break
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
seq, err := parseSeq(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
children, _, err := l.c.Children(l.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lowestSeq := seq
|
||||
prevSeq := 0
|
||||
prevSeqPath := ""
|
||||
for _, p := range children {
|
||||
s, err := parseSeq(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s < lowestSeq {
|
||||
lowestSeq = s
|
||||
}
|
||||
if s < seq && s > prevSeq {
|
||||
prevSeq = s
|
||||
prevSeqPath = p
|
||||
}
|
||||
}
|
||||
|
||||
if seq == lowestSeq {
|
||||
// Acquired the lock
|
||||
break
|
||||
}
|
||||
|
||||
// Wait on the node next in line for the lock
|
||||
_, _, ch, err := l.c.GetW(l.path + "/" + prevSeqPath)
|
||||
if err != nil && err != ErrNoNode {
|
||||
return err
|
||||
} else if err != nil && err == ErrNoNode {
|
||||
// try again
|
||||
continue
|
||||
}
|
||||
|
||||
ev := <-ch
|
||||
if ev.Err != nil {
|
||||
return ev.Err
|
||||
}
|
||||
}
|
||||
|
||||
l.seq = seq
|
||||
l.lockPath = path
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lock) Unlock() error {
|
||||
if l.lockPath == "" {
|
||||
return ErrNotLocked
|
||||
}
|
||||
if err := l.c.Delete(l.lockPath, -1); err != nil {
|
||||
return err
|
||||
}
|
||||
l.lockPath = ""
|
||||
l.seq = 0
|
||||
return nil
|
||||
}
|
||||
94
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/lock_test.go
generated
vendored
Normal file
94
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/lock_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLock(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
acls := WorldACL(PermAll)
|
||||
|
||||
l := NewLock(zk, "/test", acls)
|
||||
if err := l.Lock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := l.Unlock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
val := make(chan int, 3)
|
||||
|
||||
if err := l.Lock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l2 := NewLock(zk, "/test", acls)
|
||||
go func() {
|
||||
if err := l2.Lock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
val <- 2
|
||||
if err := l2.Unlock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
val <- 3
|
||||
}()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
val <- 1
|
||||
if err := l.Unlock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if x := <-val; x != 1 {
|
||||
t.Fatalf("Expected 1 instead of %d", x)
|
||||
}
|
||||
if x := <-val; x != 2 {
|
||||
t.Fatalf("Expected 2 instead of %d", x)
|
||||
}
|
||||
if x := <-val; x != 3 {
|
||||
t.Fatalf("Expected 3 instead of %d", x)
|
||||
}
|
||||
}
|
||||
|
||||
// This tests creating a lock with a path that's more than 1 node deep (e.g. "/test-multi-level/lock"),
|
||||
// when a part of that path already exists (i.e. "/test-multi-level" node already exists).
|
||||
func TestMultiLevelLock(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
acls := WorldACL(PermAll)
|
||||
path := "/test-multi-level"
|
||||
if p, err := zk.Create(path, []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if p != path {
|
||||
t.Fatalf("Create returned different path '%s' != '%s'", p, path)
|
||||
}
|
||||
l := NewLock(zk, "/test-multi-level/lock", acls)
|
||||
defer zk.Delete("/test-multi-level", -1) // Clean up what we've created for this test
|
||||
defer zk.Delete("/test-multi-level/lock", -1)
|
||||
if err := l.Lock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := l.Unlock(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
119
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/server_help.go
generated
vendored
Normal file
119
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/server_help.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TestServer struct {
|
||||
Port int
|
||||
Path string
|
||||
Srv *Server
|
||||
}
|
||||
|
||||
type TestCluster struct {
|
||||
Path string
|
||||
Servers []TestServer
|
||||
}
|
||||
|
||||
func StartTestCluster(size int, stdout, stderr io.Writer) (*TestCluster, error) {
|
||||
tmpPath, err := ioutil.TempDir("", "gozk")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
success := false
|
||||
startPort := int(rand.Int31n(6000) + 10000)
|
||||
cluster := &TestCluster{Path: tmpPath}
|
||||
defer func() {
|
||||
if !success {
|
||||
cluster.Stop()
|
||||
}
|
||||
}()
|
||||
for serverN := 0; serverN < size; serverN++ {
|
||||
srvPath := filepath.Join(tmpPath, fmt.Sprintf("srv%d", serverN))
|
||||
if err := os.Mkdir(srvPath, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
port := startPort + serverN*3
|
||||
cfg := ServerConfig{
|
||||
ClientPort: port,
|
||||
DataDir: srvPath,
|
||||
}
|
||||
for i := 0; i < size; i++ {
|
||||
cfg.Servers = append(cfg.Servers, ServerConfigServer{
|
||||
ID: i + 1,
|
||||
Host: "127.0.0.1",
|
||||
PeerPort: startPort + i*3 + 1,
|
||||
LeaderElectionPort: startPort + i*3 + 2,
|
||||
})
|
||||
}
|
||||
cfgPath := filepath.Join(srvPath, "zoo.cfg")
|
||||
fi, err := os.Create(cfgPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = cfg.Marshall(fi)
|
||||
fi.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fi, err = os.Create(filepath.Join(srvPath, "myid"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = fmt.Fprintf(fi, "%d\n", serverN+1)
|
||||
fi.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srv := &Server{
|
||||
ConfigPath: cfgPath,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
}
|
||||
if err := srv.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cluster.Servers = append(cluster.Servers, TestServer{
|
||||
Path: srvPath,
|
||||
Port: cfg.ClientPort,
|
||||
Srv: srv,
|
||||
})
|
||||
}
|
||||
success = true
|
||||
time.Sleep(time.Second) // Give the server time to become active. Should probably actually attempt to connect to verify.
|
||||
return cluster, nil
|
||||
}
|
||||
|
||||
func (ts *TestCluster) Connect(idx int) (*Conn, error) {
|
||||
zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15)
|
||||
return zk, err
|
||||
}
|
||||
|
||||
func (ts *TestCluster) ConnectAll() (*Conn, <-chan Event, error) {
|
||||
return ts.ConnectAllTimeout(time.Second * 15)
|
||||
}
|
||||
|
||||
func (ts *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) {
|
||||
hosts := make([]string, len(ts.Servers))
|
||||
for i, srv := range ts.Servers {
|
||||
hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port)
|
||||
}
|
||||
zk, ch, err := Connect(hosts, sessionTimeout)
|
||||
return zk, ch, err
|
||||
}
|
||||
|
||||
func (ts *TestCluster) Stop() error {
|
||||
for _, srv := range ts.Servers {
|
||||
srv.Srv.Stop()
|
||||
}
|
||||
defer os.RemoveAll(ts.Path)
|
||||
return nil
|
||||
}
|
||||
136
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/server_java.go
generated
vendored
Normal file
136
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/server_java.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type ErrMissingServerConfigField string
|
||||
|
||||
func (e ErrMissingServerConfigField) Error() string {
|
||||
return fmt.Sprintf("zk: missing server config field '%s'", string(e))
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultServerTickTime = 2000
|
||||
DefaultServerInitLimit = 10
|
||||
DefaultServerSyncLimit = 5
|
||||
DefaultServerAutoPurgeSnapRetainCount = 3
|
||||
DefaultPeerPort = 2888
|
||||
DefaultLeaderElectionPort = 3888
|
||||
)
|
||||
|
||||
type ServerConfigServer struct {
|
||||
ID int
|
||||
Host string
|
||||
PeerPort int
|
||||
LeaderElectionPort int
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
TickTime int // Number of milliseconds of each tick
|
||||
InitLimit int // Number of ticks that the initial synchronization phase can take
|
||||
SyncLimit int // Number of ticks that can pass between sending a request and getting an acknowledgement
|
||||
DataDir string // Direcrory where the snapshot is stored
|
||||
ClientPort int // Port at which clients will connect
|
||||
AutoPurgeSnapRetainCount int // Number of snapshots to retain in dataDir
|
||||
AutoPurgePurgeInterval int // Purge task internal in hours (0 to disable auto purge)
|
||||
Servers []ServerConfigServer
|
||||
}
|
||||
|
||||
func (sc ServerConfig) Marshall(w io.Writer) error {
|
||||
if sc.DataDir == "" {
|
||||
return ErrMissingServerConfigField("dataDir")
|
||||
}
|
||||
fmt.Fprintf(w, "dataDir=%s\n", sc.DataDir)
|
||||
if sc.TickTime <= 0 {
|
||||
sc.TickTime = DefaultServerTickTime
|
||||
}
|
||||
fmt.Fprintf(w, "tickTime=%d\n", sc.TickTime)
|
||||
if sc.InitLimit <= 0 {
|
||||
sc.InitLimit = DefaultServerInitLimit
|
||||
}
|
||||
fmt.Fprintf(w, "initLimit=%d\n", sc.InitLimit)
|
||||
if sc.SyncLimit <= 0 {
|
||||
sc.SyncLimit = DefaultServerSyncLimit
|
||||
}
|
||||
fmt.Fprintf(w, "syncLimit=%d\n", sc.SyncLimit)
|
||||
if sc.ClientPort <= 0 {
|
||||
sc.ClientPort = DefaultPort
|
||||
}
|
||||
fmt.Fprintf(w, "clientPort=%d\n", sc.ClientPort)
|
||||
if sc.AutoPurgePurgeInterval > 0 {
|
||||
if sc.AutoPurgeSnapRetainCount <= 0 {
|
||||
sc.AutoPurgeSnapRetainCount = DefaultServerAutoPurgeSnapRetainCount
|
||||
}
|
||||
fmt.Fprintf(w, "autopurge.snapRetainCount=%d\n", sc.AutoPurgeSnapRetainCount)
|
||||
fmt.Fprintf(w, "autopurge.purgeInterval=%d\n", sc.AutoPurgePurgeInterval)
|
||||
}
|
||||
if len(sc.Servers) > 0 {
|
||||
for _, srv := range sc.Servers {
|
||||
if srv.PeerPort <= 0 {
|
||||
srv.PeerPort = DefaultPeerPort
|
||||
}
|
||||
if srv.LeaderElectionPort <= 0 {
|
||||
srv.LeaderElectionPort = DefaultLeaderElectionPort
|
||||
}
|
||||
fmt.Fprintf(w, "server.%d=%s:%d:%d\n", srv.ID, srv.Host, srv.PeerPort, srv.LeaderElectionPort)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var jarSearchPaths = []string{
|
||||
"zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
|
||||
"../zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
|
||||
"/usr/share/java/zookeeper-*.jar",
|
||||
"/usr/local/zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
|
||||
"/usr/local/Cellar/zookeeper/*/libexec/contrib/fatjar/zookeeper-*-fatjar.jar",
|
||||
}
|
||||
|
||||
func findZookeeperFatJar() string {
|
||||
var paths []string
|
||||
zkPath := os.Getenv("ZOOKEEPER_PATH")
|
||||
if zkPath == "" {
|
||||
paths = jarSearchPaths
|
||||
} else {
|
||||
paths = []string{filepath.Join(zkPath, "contrib/fatjar/zookeeper-*-fatjar.jar")}
|
||||
}
|
||||
for _, path := range paths {
|
||||
matches, _ := filepath.Glob(path)
|
||||
// TODO: could sort by version and pick latest
|
||||
if len(matches) > 0 {
|
||||
return matches[0]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
JarPath string
|
||||
ConfigPath string
|
||||
Stdout, Stderr io.Writer
|
||||
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
func (srv *Server) Start() error {
|
||||
if srv.JarPath == "" {
|
||||
srv.JarPath = findZookeeperFatJar()
|
||||
if srv.JarPath == "" {
|
||||
return fmt.Errorf("zk: unable to find server jar")
|
||||
}
|
||||
}
|
||||
srv.cmd = exec.Command("java", "-jar", srv.JarPath, "server", srv.ConfigPath)
|
||||
srv.cmd.Stdout = srv.Stdout
|
||||
srv.cmd.Stderr = srv.Stderr
|
||||
return srv.cmd.Start()
|
||||
}
|
||||
|
||||
func (srv *Server) Stop() error {
|
||||
srv.cmd.Process.Signal(os.Kill)
|
||||
return srv.cmd.Wait()
|
||||
}
|
||||
633
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/structs.go
generated
vendored
Normal file
633
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/structs.go
generated
vendored
Normal file
@@ -0,0 +1,633 @@
|
||||
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 Stat struct {
|
||||
Czxid int64 // The zxid of the change that caused this znode to be created.
|
||||
Mzxid int64 // The zxid of the change that last modified this znode.
|
||||
Ctime int64 // The time in milliseconds from epoch when this znode was created.
|
||||
Mtime int64 // The time in milliseconds from epoch when this znode was last modified.
|
||||
Version int32 // The number of changes to the data of this znode.
|
||||
Cversion int32 // The number of changes to the children of this znode.
|
||||
Aversion int32 // The number of changes to the ACL of this znode.
|
||||
EphemeralOwner 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.
|
||||
DataLength int32 // The length of the data field of this znode.
|
||||
NumChildren int32 // The number of children of this znode.
|
||||
Pzxid int64 // last modified children
|
||||
}
|
||||
|
||||
// ServerClient is the information for a single Zookeeper client and its session.
|
||||
// This is used to parse/extract the output fo the `cons` command.
|
||||
type ServerClient struct {
|
||||
Queued int64
|
||||
Received int64
|
||||
Sent int64
|
||||
SessionID int64
|
||||
Lcxid int64
|
||||
Lzxid int64
|
||||
Timeout int32
|
||||
LastLatency int32
|
||||
MinLatency int32
|
||||
AvgLatency int32
|
||||
MaxLatency int32
|
||||
Established time.Time
|
||||
LastResponse time.Time
|
||||
Addr string
|
||||
LastOperation string // maybe?
|
||||
Error error
|
||||
}
|
||||
|
||||
// ServerClients is a struct for the FLWCons() function. It's used to provide
|
||||
// the list of Clients.
|
||||
//
|
||||
// This is needed because FLWCons() takes multiple servers.
|
||||
type ServerClients struct {
|
||||
Clients []*ServerClient
|
||||
Error error
|
||||
}
|
||||
|
||||
// ServerStats is the information pulled from the Zookeeper `stat` command.
|
||||
type ServerStats struct {
|
||||
Sent int64
|
||||
Received int64
|
||||
NodeCount int64
|
||||
MinLatency int64
|
||||
AvgLatency int64
|
||||
MaxLatency int64
|
||||
Connections int64
|
||||
Outstanding int64
|
||||
Epoch int32
|
||||
Counter int32
|
||||
BuildTime time.Time
|
||||
Mode Mode
|
||||
Version string
|
||||
Error error
|
||||
}
|
||||
|
||||
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 Stat
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
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 Stat
|
||||
}
|
||||
|
||||
type getChildrenRequest pathRequest
|
||||
|
||||
type getChildrenResponse struct {
|
||||
Children []string
|
||||
}
|
||||
|
||||
type getChildren2Request pathWatchRequest
|
||||
|
||||
type getChildren2Response struct {
|
||||
Children []string
|
||||
Stat Stat
|
||||
}
|
||||
|
||||
type getDataRequest pathWatchRequest
|
||||
|
||||
type getDataResponse struct {
|
||||
Data []byte
|
||||
Stat Stat
|
||||
}
|
||||
|
||||
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 *Stat
|
||||
}
|
||||
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(Stat)
|
||||
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
|
||||
}
|
||||
60
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/structs_test.go
generated
vendored
Normal file
60
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/structs_test.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncodeDecodePacket(t *testing.T) {
|
||||
encodeDecodeTest(t, &requestHeader{-2, 5})
|
||||
encodeDecodeTest(t, &connectResponse{1, 2, 3, nil})
|
||||
encodeDecodeTest(t, &connectResponse{1, 2, 3, []byte{4, 5, 6}})
|
||||
encodeDecodeTest(t, &getAclResponse{[]ACL{{12, "s", "anyone"}}, Stat{}})
|
||||
encodeDecodeTest(t, &getChildrenResponse{[]string{"foo", "bar"}})
|
||||
encodeDecodeTest(t, &pathWatchRequest{"path", true})
|
||||
encodeDecodeTest(t, &pathWatchRequest{"path", false})
|
||||
encodeDecodeTest(t, &CheckVersionRequest{"/", -1})
|
||||
encodeDecodeTest(t, &multiRequest{Ops: []multiRequestOp{{multiHeader{opCheck, false, -1}, &CheckVersionRequest{"/", -1}}}})
|
||||
}
|
||||
|
||||
func encodeDecodeTest(t *testing.T, r interface{}) {
|
||||
buf := make([]byte, 1024)
|
||||
n, err := encodePacket(buf, r)
|
||||
if err != nil {
|
||||
t.Errorf("encodePacket returned non-nil error %+v\n", err)
|
||||
return
|
||||
}
|
||||
t.Logf("%+v %x", r, buf[:n])
|
||||
r2 := reflect.New(reflect.ValueOf(r).Elem().Type()).Interface()
|
||||
n2, err := decodePacket(buf[:n], r2)
|
||||
if err != nil {
|
||||
t.Errorf("decodePacket returned non-nil error %+v\n", err)
|
||||
return
|
||||
}
|
||||
if n != n2 {
|
||||
t.Errorf("sizes don't match: %d != %d", n, n2)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(r, r2) {
|
||||
t.Errorf("results don't match: %+v != %+v", r, r2)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeShortBuffer(t *testing.T) {
|
||||
buf := make([]byte, 0)
|
||||
_, err := encodePacket(buf, &requestHeader{1, 2})
|
||||
if err != ErrShortBuffer {
|
||||
t.Errorf("encodePacket should return ErrShortBuffer on a short buffer instead of '%+v'", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeShortBuffer(t *testing.T) {
|
||||
buf := make([]byte, 0)
|
||||
_, err := decodePacket(buf, &responseHeader{})
|
||||
if err != ErrShortBuffer {
|
||||
t.Errorf("decodePacket should return ErrShortBuffer on a short buffer instead of '%+v'", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
148
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/tracer.go
generated
vendored
Normal file
148
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/tracer.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
requests = make(map[int32]int32) // Map of Xid -> Opcode
|
||||
requestsLock = &sync.Mutex{}
|
||||
)
|
||||
|
||||
func trace(conn1, conn2 net.Conn, client bool) {
|
||||
defer conn1.Close()
|
||||
defer conn2.Close()
|
||||
buf := make([]byte, 10*1024)
|
||||
init := true
|
||||
for {
|
||||
_, err := io.ReadFull(conn1, buf[:4])
|
||||
if err != nil {
|
||||
fmt.Println("1>", client, err)
|
||||
return
|
||||
}
|
||||
|
||||
blen := int(binary.BigEndian.Uint32(buf[:4]))
|
||||
|
||||
_, err = io.ReadFull(conn1, buf[4:4+blen])
|
||||
if err != nil {
|
||||
fmt.Println("2>", client, err)
|
||||
return
|
||||
}
|
||||
|
||||
var cr interface{}
|
||||
opcode := int32(-1)
|
||||
readHeader := true
|
||||
if client {
|
||||
if init {
|
||||
cr = &connectRequest{}
|
||||
readHeader = false
|
||||
} else {
|
||||
xid := int32(binary.BigEndian.Uint32(buf[4:8]))
|
||||
opcode = int32(binary.BigEndian.Uint32(buf[8:12]))
|
||||
requestsLock.Lock()
|
||||
requests[xid] = opcode
|
||||
requestsLock.Unlock()
|
||||
cr = requestStructForOp(opcode)
|
||||
if cr == nil {
|
||||
fmt.Printf("Unknown opcode %d\n", opcode)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if init {
|
||||
cr = &connectResponse{}
|
||||
readHeader = false
|
||||
} else {
|
||||
xid := int32(binary.BigEndian.Uint32(buf[4:8]))
|
||||
zxid := int64(binary.BigEndian.Uint64(buf[8:16]))
|
||||
errnum := int32(binary.BigEndian.Uint32(buf[16:20]))
|
||||
if xid != -1 || zxid != -1 {
|
||||
requestsLock.Lock()
|
||||
found := false
|
||||
opcode, found = requests[xid]
|
||||
if !found {
|
||||
opcode = 0
|
||||
}
|
||||
delete(requests, xid)
|
||||
requestsLock.Unlock()
|
||||
} else {
|
||||
opcode = opWatcherEvent
|
||||
}
|
||||
cr = responseStructForOp(opcode)
|
||||
if cr == nil {
|
||||
fmt.Printf("Unknown opcode %d\n", opcode)
|
||||
}
|
||||
if errnum != 0 {
|
||||
cr = &struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
opname := "."
|
||||
if opcode != -1 {
|
||||
opname = opNames[opcode]
|
||||
}
|
||||
if cr == nil {
|
||||
fmt.Printf("%+v %s %+v\n", client, opname, buf[4:4+blen])
|
||||
} else {
|
||||
n := 4
|
||||
hdrStr := ""
|
||||
if readHeader {
|
||||
var hdr interface{}
|
||||
if client {
|
||||
hdr = &requestHeader{}
|
||||
} else {
|
||||
hdr = &responseHeader{}
|
||||
}
|
||||
if n2, err := decodePacket(buf[n:n+blen], hdr); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
n += n2
|
||||
}
|
||||
hdrStr = fmt.Sprintf(" %+v", hdr)
|
||||
}
|
||||
if _, err := decodePacket(buf[n:n+blen], cr); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Printf("%+v %s%s %+v\n", client, opname, hdrStr, cr)
|
||||
}
|
||||
|
||||
init = false
|
||||
|
||||
written, err := conn2.Write(buf[:4+blen])
|
||||
if err != nil {
|
||||
fmt.Println("3>", client, err)
|
||||
return
|
||||
} else if written != 4+blen {
|
||||
fmt.Printf("Written != read: %d != %d\n", written, blen)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleConnection(addr string, conn net.Conn) {
|
||||
zkConn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
go trace(conn, zkConn, true)
|
||||
trace(zkConn, conn, false)
|
||||
}
|
||||
|
||||
func StartTracer(listenAddr, serverAddr string) {
|
||||
ln, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
go handleConnection(serverAddr, conn)
|
||||
}
|
||||
}
|
||||
54
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/util.go
generated
vendored
Normal file
54
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/util.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AuthACL produces an ACL list containing a single ACL which uses the
|
||||
// provided permissions, with the scheme "auth", and ID "", which is used
|
||||
// by ZooKeeper to represent any authenticated user.
|
||||
func AuthACL(perms int32) []ACL {
|
||||
return []ACL{{perms, "auth", ""}}
|
||||
}
|
||||
|
||||
// WorldACL produces an ACL list containing a single ACL which uses the
|
||||
// provided permissions, with the scheme "world", and ID "anyone", which
|
||||
// is used by ZooKeeper to represent any user at all.
|
||||
func WorldACL(perms int32) []ACL {
|
||||
return []ACL{{perms, "world", "anyone"}}
|
||||
}
|
||||
|
||||
func DigestACL(perms int32, user, password string) []ACL {
|
||||
userPass := []byte(fmt.Sprintf("%s:%s", user, password))
|
||||
h := sha1.New()
|
||||
if n, err := h.Write(userPass); err != nil || n != len(userPass) {
|
||||
panic("SHA1 failed")
|
||||
}
|
||||
digest := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
return []ACL{{perms, "digest", fmt.Sprintf("%s:%s", user, digest)}}
|
||||
}
|
||||
|
||||
// FormatServers takes a slice of addresses, and makes sure they are in a format
|
||||
// that resembles <addr>:<port>. If the server has no port provided, the
|
||||
// DefaultPort constant is added to the end.
|
||||
func FormatServers(servers []string) []string {
|
||||
for i := range servers {
|
||||
if !strings.Contains(servers[i], ":") {
|
||||
servers[i] = servers[i] + ":" + strconv.Itoa(DefaultPort)
|
||||
}
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
// stringShuffle performs a Fisher-Yates shuffle on a slice of strings
|
||||
func stringShuffle(s []string) {
|
||||
for i := len(s) - 1; i > 0; i-- {
|
||||
j := rand.Intn(i + 1)
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
}
|
||||
17
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/util_test.go
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/util_test.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package zk
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFormatServers(t *testing.T) {
|
||||
servers := []string{"127.0.0.1:2181", "127.0.0.42", "127.0.42.1:8811"}
|
||||
r := []string{"127.0.0.1:2181", "127.0.0.42:2181", "127.0.42.1:8811"}
|
||||
|
||||
var s []string
|
||||
s = FormatServers(servers)
|
||||
|
||||
for i := range s {
|
||||
if s[i] != r[i] {
|
||||
t.Errorf("%v should equal %v", s[i], r[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
518
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/zk_test.go
generated
vendored
Normal file
518
Godeps/_workspace/src/github.com/samuel/go-zookeeper/zk/zk_test.go
generated
vendored
Normal file
@@ -0,0 +1,518 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"camlistore.org/pkg/throttle"
|
||||
)
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
path := "/gozk-test"
|
||||
|
||||
if err := zk.Delete(path, -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
if p, err := zk.Create(path, []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if p != path {
|
||||
t.Fatalf("Create returned different path '%s' != '%s'", p, path)
|
||||
}
|
||||
if data, stat, err := zk.Get(path); err != nil {
|
||||
t.Fatalf("Get returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Get returned nil stat")
|
||||
} else if len(data) < 4 {
|
||||
t.Fatal("Get returned wrong size data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulti(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
path := "/gozk-test"
|
||||
|
||||
if err := zk.Delete(path, -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
ops := []interface{}{
|
||||
&CreateRequest{Path: path, Data: []byte{1, 2, 3, 4}, Acl: WorldACL(PermAll)},
|
||||
&SetDataRequest{Path: path, Data: []byte{1, 2, 3, 4}, Version: -1},
|
||||
}
|
||||
if res, err := zk.Multi(ops...); err != nil {
|
||||
t.Fatalf("Multi returned error: %+v", err)
|
||||
} else if len(res) != 2 {
|
||||
t.Fatalf("Expected 2 responses got %d", len(res))
|
||||
} else {
|
||||
t.Logf("%+v", res)
|
||||
}
|
||||
if data, stat, err := zk.Get(path); err != nil {
|
||||
t.Fatalf("Get returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Get returned nil stat")
|
||||
} else if len(data) < 4 {
|
||||
t.Fatal("Get returned wrong size data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSetACL(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
if err := zk.AddAuth("digest", []byte("blah")); err != nil {
|
||||
t.Fatalf("AddAuth returned error %+v", err)
|
||||
}
|
||||
|
||||
path := "/gozk-test"
|
||||
|
||||
if err := zk.Delete(path, -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
if path, err := zk.Create(path, []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if path != "/gozk-test" {
|
||||
t.Fatalf("Create returned different path '%s' != '/gozk-test'", path)
|
||||
}
|
||||
|
||||
expected := WorldACL(PermAll)
|
||||
|
||||
if acl, stat, err := zk.GetACL(path); err != nil {
|
||||
t.Fatalf("GetACL returned error %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatalf("GetACL returned nil Stat")
|
||||
} else if len(acl) != 1 || expected[0] != acl[0] {
|
||||
t.Fatalf("GetACL mismatch expected %+v instead of %+v", expected, acl)
|
||||
}
|
||||
|
||||
expected = []ACL{{PermAll, "ip", "127.0.0.1"}}
|
||||
|
||||
if stat, err := zk.SetACL(path, expected, -1); err != nil {
|
||||
t.Fatalf("SetACL returned error %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatalf("SetACL returned nil Stat")
|
||||
}
|
||||
|
||||
if acl, stat, err := zk.GetACL(path); err != nil {
|
||||
t.Fatalf("GetACL returned error %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatalf("GetACL returned nil Stat")
|
||||
} else if len(acl) != 1 || expected[0] != acl[0] {
|
||||
t.Fatalf("GetACL mismatch expected %+v instead of %+v", expected, acl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
path := "/gozk-digest-test"
|
||||
if err := zk.Delete(path, -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
acl := DigestACL(PermAll, "user", "password")
|
||||
|
||||
if p, err := zk.Create(path, []byte{1, 2, 3, 4}, 0, acl); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if p != path {
|
||||
t.Fatalf("Create returned different path '%s' != '%s'", p, path)
|
||||
}
|
||||
|
||||
if a, stat, err := zk.GetACL(path); err != nil {
|
||||
t.Fatalf("GetACL returned error %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatalf("GetACL returned nil Stat")
|
||||
} else if len(a) != 1 || acl[0] != a[0] {
|
||||
t.Fatalf("GetACL mismatch expected %+v instead of %+v", acl, a)
|
||||
}
|
||||
|
||||
if _, _, err := zk.Get(path); err != ErrNoAuth {
|
||||
t.Fatalf("Get returned error %+v instead of ErrNoAuth", err)
|
||||
}
|
||||
|
||||
if err := zk.AddAuth("digest", []byte("user:password")); err != nil {
|
||||
t.Fatalf("AddAuth returned error %+v", err)
|
||||
}
|
||||
|
||||
if data, stat, err := zk.Get(path); err != nil {
|
||||
t.Fatalf("Get returned error %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatalf("Get returned nil Stat")
|
||||
} else if len(data) != 4 {
|
||||
t.Fatalf("Get returned wrong data length")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChildWatch(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
children, stat, childCh, err := zk.ChildrenW("/")
|
||||
if err != nil {
|
||||
t.Fatalf("Children returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Children returned nil stat")
|
||||
} else if len(children) < 1 {
|
||||
t.Fatal("Children should return at least 1 child")
|
||||
}
|
||||
|
||||
if path, err := zk.Create("/gozk-test", []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if path != "/gozk-test" {
|
||||
t.Fatalf("Create returned different path '%s' != '/gozk-test'", path)
|
||||
}
|
||||
|
||||
select {
|
||||
case ev := <-childCh:
|
||||
if ev.Err != nil {
|
||||
t.Fatalf("Child watcher error %+v", ev.Err)
|
||||
}
|
||||
if ev.Path != "/" {
|
||||
t.Fatalf("Child watcher wrong path %s instead of %s", ev.Path, "/")
|
||||
}
|
||||
case _ = <-time.After(time.Second * 2):
|
||||
t.Fatal("Child watcher timed out")
|
||||
}
|
||||
|
||||
// Delete of the watched node should trigger the watch
|
||||
|
||||
children, stat, childCh, err = zk.ChildrenW("/gozk-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Children returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Children returned nil stat")
|
||||
} else if len(children) != 0 {
|
||||
t.Fatal("Children should return 0 children")
|
||||
}
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case ev := <-childCh:
|
||||
if ev.Err != nil {
|
||||
t.Fatalf("Child watcher error %+v", ev.Err)
|
||||
}
|
||||
if ev.Path != "/gozk-test" {
|
||||
t.Fatalf("Child watcher wrong path %s instead of %s", ev.Path, "/")
|
||||
}
|
||||
case _ = <-time.After(time.Second * 2):
|
||||
t.Fatal("Child watcher timed out")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetWatchers(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
zk.reconnectDelay = time.Second
|
||||
|
||||
zk2, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk2.Close()
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
testPath, err := zk.Create("/gozk-test-2", []byte{}, 0, WorldACL(PermAll))
|
||||
if err != nil {
|
||||
t.Fatalf("Create returned: %+v", err)
|
||||
}
|
||||
|
||||
_, _, testEvCh, err := zk.GetW(testPath)
|
||||
if err != nil {
|
||||
t.Fatalf("GetW returned: %+v", err)
|
||||
}
|
||||
|
||||
children, stat, childCh, err := zk.ChildrenW("/")
|
||||
if err != nil {
|
||||
t.Fatalf("Children returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Children returned nil stat")
|
||||
} else if len(children) < 1 {
|
||||
t.Fatal("Children should return at least 1 child")
|
||||
}
|
||||
|
||||
zk.conn.Close()
|
||||
if err := zk2.Delete(testPath, -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
if path, err := zk2.Create("/gozk-test", []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatalf("Create returned error: %+v", err)
|
||||
} else if path != "/gozk-test" {
|
||||
t.Fatalf("Create returned different path '%s' != '/gozk-test'", path)
|
||||
}
|
||||
|
||||
select {
|
||||
case ev := <-testEvCh:
|
||||
if ev.Err != nil {
|
||||
t.Fatalf("GetW watcher error %+v", ev.Err)
|
||||
}
|
||||
if ev.Path != testPath {
|
||||
t.Fatalf("GetW watcher wrong path %s instead of %s", ev.Path, testPath)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("GetW watcher timed out")
|
||||
}
|
||||
|
||||
select {
|
||||
case ev := <-childCh:
|
||||
if ev.Err != nil {
|
||||
t.Fatalf("Child watcher error %+v", ev.Err)
|
||||
}
|
||||
if ev.Path != "/" {
|
||||
t.Fatalf("Child watcher wrong path %s instead of %s", ev.Path, "/")
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("Child watcher timed out")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpiringWatch(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
zk, _, err := ts.ConnectAll()
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %+v", err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err != nil && err != ErrNoNode {
|
||||
t.Fatalf("Delete returned error: %+v", err)
|
||||
}
|
||||
|
||||
children, stat, childCh, err := zk.ChildrenW("/")
|
||||
if err != nil {
|
||||
t.Fatalf("Children returned error: %+v", err)
|
||||
} else if stat == nil {
|
||||
t.Fatal("Children returned nil stat")
|
||||
} else if len(children) < 1 {
|
||||
t.Fatal("Children should return at least 1 child")
|
||||
}
|
||||
|
||||
zk.sessionID = 99999
|
||||
zk.conn.Close()
|
||||
|
||||
select {
|
||||
case ev := <-childCh:
|
||||
if ev.Err != ErrSessionExpired {
|
||||
t.Fatalf("Child watcher error %+v instead of expected ErrSessionExpired", ev.Err)
|
||||
}
|
||||
if ev.Path != "/" {
|
||||
t.Fatalf("Child watcher wrong path %s instead of %s", ev.Path, "/")
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("Child watcher timed out")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestFail(t *testing.T) {
|
||||
// If connecting fails to all servers in the list then pending requests
|
||||
// should be errored out so they don't hang forever.
|
||||
|
||||
zk, _, err := Connect([]string{"127.0.0.1:32444"}, time.Second*15)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
_, _, err := zk.Get("/blah")
|
||||
ch <- err
|
||||
}()
|
||||
select {
|
||||
case err := <-ch:
|
||||
if err == nil {
|
||||
t.Fatal("Expected non-nil error on failed request due to connection failure")
|
||||
}
|
||||
case <-time.After(time.Second * 2):
|
||||
t.Fatal("Get hung when connection could not be made")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlowServer(t *testing.T) {
|
||||
ts, err := StartTestCluster(1, nil, logWriter{t: t, p: "[ZKERR] "})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ts.Stop()
|
||||
|
||||
realAddr := fmt.Sprintf("127.0.0.1:%d", ts.Servers[0].Port)
|
||||
proxyAddr, stopCh, err := startSlowProxy(t,
|
||||
throttle.Rate{}, throttle.Rate{},
|
||||
realAddr, func(ln *throttle.Listener) {
|
||||
if ln.Up.Latency == 0 {
|
||||
ln.Up.Latency = time.Millisecond * 2000
|
||||
ln.Down.Latency = time.Millisecond * 2000
|
||||
} else {
|
||||
ln.Up.Latency = 0
|
||||
ln.Down.Latency = 0
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
zk, _, err := Connect([]string{proxyAddr}, time.Millisecond*500)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer zk.Close()
|
||||
|
||||
_, _, wch, err := zk.ChildrenW("/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Force a reconnect to get a throttled connection
|
||||
zk.conn.Close()
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
if err := zk.Delete("/gozk-test", -1); err == nil {
|
||||
t.Fatal("Delete should have failed")
|
||||
}
|
||||
|
||||
// The previous request should have timed out causing the server to be disconnected and reconnected
|
||||
|
||||
if _, err := zk.Create("/gozk-test", []byte{1, 2, 3, 4}, 0, WorldACL(PermAll)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Make sure event is still returned because the session should not have been affected
|
||||
select {
|
||||
case ev := <-wch:
|
||||
t.Logf("Received event: %+v", ev)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("Expected to receive a watch event")
|
||||
}
|
||||
}
|
||||
|
||||
func startSlowProxy(t *testing.T, up, down throttle.Rate, upstream string, adj func(ln *throttle.Listener)) (string, chan bool, error) {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
tln := &throttle.Listener{
|
||||
Listener: ln,
|
||||
Up: up,
|
||||
Down: down,
|
||||
}
|
||||
stopCh := make(chan bool)
|
||||
go func() {
|
||||
<-stopCh
|
||||
tln.Close()
|
||||
}()
|
||||
go func() {
|
||||
for {
|
||||
cn, err := tln.Accept()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
t.Fatalf("Accept failed: %s", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if adj != nil {
|
||||
adj(tln)
|
||||
}
|
||||
go func(cn net.Conn) {
|
||||
defer cn.Close()
|
||||
upcn, err := net.Dial("tcp", upstream)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
// This will leave hanging goroutines util stopCh is closed
|
||||
// but it doesn't matter in the context of running tests.
|
||||
go func() {
|
||||
<-stopCh
|
||||
upcn.Close()
|
||||
}()
|
||||
go func() {
|
||||
if _, err := io.Copy(upcn, cn); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
// log.Printf("Upstream write failed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
if _, err := io.Copy(cn, upcn); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
// log.Printf("Upstream read failed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}(cn)
|
||||
}
|
||||
}()
|
||||
return ln.Addr().String(), stopCh, nil
|
||||
}
|
||||
65
Godeps/_workspace/src/github.com/stretchr/testify/suite/doc.go
generated
vendored
Normal file
65
Godeps/_workspace/src/github.com/stretchr/testify/suite/doc.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// The suite package contains logic for creating testing suite structs
|
||||
// and running the methods on those structs as tests. The most useful
|
||||
// piece of this package is that you can create setup/teardown methods
|
||||
// on your testing suites, which will run before/after the whole suite
|
||||
// or individual tests (depending on which interface(s) you
|
||||
// implement).
|
||||
//
|
||||
// A testing suite is usually built by first extending the built-in
|
||||
// suite functionality from suite.Suite in testify. Alternatively,
|
||||
// you could reproduce that logic on your own if you wanted (you
|
||||
// just need to implement the TestingSuite interface from
|
||||
// suite/interfaces.go).
|
||||
//
|
||||
// After that, you can implement any of the interfaces in
|
||||
// suite/interfaces.go to add setup/teardown functionality to your
|
||||
// suite, and add any methods that start with "Test" to add tests.
|
||||
// Methods that do not match any suite interfaces and do not begin
|
||||
// with "Test" will not be run by testify, and can safely be used as
|
||||
// helper methods.
|
||||
//
|
||||
// Once you've built your testing suite, you need to run the suite
|
||||
// (using suite.Run from testify) inside any function that matches the
|
||||
// identity that "go test" is already looking for (i.e.
|
||||
// func(*testing.T)).
|
||||
//
|
||||
// Regular expression to select test suites specified command-line
|
||||
// argument "-run". Regular expression to select the methods
|
||||
// of test suites specified command-line argument "-m".
|
||||
// Suite object has assertion methods.
|
||||
//
|
||||
// A crude example:
|
||||
// // Basic imports
|
||||
// import (
|
||||
// "testing"
|
||||
// "github.com/stretchr/testify/assert"
|
||||
// "github.com/stretchr/testify/suite"
|
||||
// )
|
||||
//
|
||||
// // Define the suite, and absorb the built-in basic suite
|
||||
// // functionality from testify - including a T() method which
|
||||
// // returns the current testing context
|
||||
// type ExampleTestSuite struct {
|
||||
// suite.Suite
|
||||
// VariableThatShouldStartAtFive int
|
||||
// }
|
||||
//
|
||||
// // Make sure that VariableThatShouldStartAtFive is set to five
|
||||
// // before each test
|
||||
// func (suite *ExampleTestSuite) SetupTest() {
|
||||
// suite.VariableThatShouldStartAtFive = 5
|
||||
// }
|
||||
//
|
||||
// // All methods that begin with "Test" are run as tests within a
|
||||
// // suite.
|
||||
// func (suite *ExampleTestSuite) TestExample() {
|
||||
// assert.Equal(suite.T(), suite.VariableThatShouldStartAtFive, 5)
|
||||
// suite.Equal(suite.VariableThatShouldStartAtFive, 5)
|
||||
// }
|
||||
//
|
||||
// // In order for 'go test' to run this suite, we need to create
|
||||
// // a normal test function and pass our suite to suite.Run
|
||||
// func TestExampleTestSuite(t *testing.T) {
|
||||
// suite.Run(t, new(ExampleTestSuite))
|
||||
// }
|
||||
package suite
|
||||
34
Godeps/_workspace/src/github.com/stretchr/testify/suite/interfaces.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/stretchr/testify/suite/interfaces.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package suite
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestingSuite can store and return the current *testing.T context
|
||||
// generated by 'go test'.
|
||||
type TestingSuite interface {
|
||||
T() *testing.T
|
||||
SetT(*testing.T)
|
||||
}
|
||||
|
||||
// SetupAllSuite has a SetupSuite method, which will run before the
|
||||
// tests in the suite are run.
|
||||
type SetupAllSuite interface {
|
||||
SetupSuite()
|
||||
}
|
||||
|
||||
// SetupTestSuite has a SetupTest method, which will run before each
|
||||
// test in the suite.
|
||||
type SetupTestSuite interface {
|
||||
SetupTest()
|
||||
}
|
||||
|
||||
// TearDownAllSuite has a TearDownSuite method, which will run after
|
||||
// all the tests in the suite have been run.
|
||||
type TearDownAllSuite interface {
|
||||
TearDownSuite()
|
||||
}
|
||||
|
||||
// TearDownTestSuite has a TearDownTest method, which will run after
|
||||
// each test in the suite.
|
||||
type TearDownTestSuite interface {
|
||||
TearDownTest()
|
||||
}
|
||||
114
Godeps/_workspace/src/github.com/stretchr/testify/suite/suite.go
generated
vendored
Normal file
114
Godeps/_workspace/src/github.com/stretchr/testify/suite/suite.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package suite
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var matchMethod = flag.String("m", "", "regular expression to select tests of the suite to run")
|
||||
|
||||
// Suite is a basic testing suite with methods for storing and
|
||||
// retrieving the current *testing.T context.
|
||||
type Suite struct {
|
||||
*assert.Assertions
|
||||
require *require.Assertions
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
// T retrieves the current *testing.T context.
|
||||
func (suite *Suite) T() *testing.T {
|
||||
return suite.t
|
||||
}
|
||||
|
||||
// SetT sets the current *testing.T context.
|
||||
func (suite *Suite) SetT(t *testing.T) {
|
||||
suite.t = t
|
||||
suite.Assertions = assert.New(t)
|
||||
}
|
||||
|
||||
// Require returns a require context for suite.
|
||||
func (suite *Suite) Require() *require.Assertions {
|
||||
if suite.require == nil {
|
||||
suite.require = require.New(suite.T())
|
||||
}
|
||||
return suite.require
|
||||
}
|
||||
|
||||
// Assert returns an assert context for suite. Normally, you can call
|
||||
// `suite.NoError(expected, actual)`, but for situations where the embedded
|
||||
// methods are overridden (for example, you might want to override
|
||||
// assert.Assertions with require.Assertions), this method is provided so you
|
||||
// can call `suite.Assert().NoError()`.
|
||||
func (suite *Suite) Assert() *assert.Assertions {
|
||||
if suite.Assertions == nil {
|
||||
suite.Assertions = assert.New(suite.T())
|
||||
}
|
||||
return suite.Assertions
|
||||
}
|
||||
|
||||
// Run takes a testing suite and runs all of the tests attached
|
||||
// to it.
|
||||
func Run(t *testing.T, suite TestingSuite) {
|
||||
suite.SetT(t)
|
||||
|
||||
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
||||
setupAllSuite.SetupSuite()
|
||||
}
|
||||
defer func() {
|
||||
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
|
||||
tearDownAllSuite.TearDownSuite()
|
||||
}
|
||||
}()
|
||||
|
||||
methodFinder := reflect.TypeOf(suite)
|
||||
tests := []testing.InternalTest{}
|
||||
for index := 0; index < methodFinder.NumMethod(); index++ {
|
||||
method := methodFinder.Method(index)
|
||||
ok, err := methodFilter(method.Name)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if ok {
|
||||
test := testing.InternalTest{
|
||||
Name: method.Name,
|
||||
F: func(t *testing.T) {
|
||||
parentT := suite.T()
|
||||
suite.SetT(t)
|
||||
if setupTestSuite, ok := suite.(SetupTestSuite); ok {
|
||||
setupTestSuite.SetupTest()
|
||||
}
|
||||
defer func() {
|
||||
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
|
||||
tearDownTestSuite.TearDownTest()
|
||||
}
|
||||
suite.SetT(parentT)
|
||||
}()
|
||||
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
|
||||
},
|
||||
}
|
||||
tests = append(tests, test)
|
||||
}
|
||||
}
|
||||
|
||||
if !testing.RunTests(func(_, _ string) (bool, error) { return true, nil },
|
||||
tests) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// Filtering method according to set regular expression
|
||||
// specified command-line argument -m
|
||||
func methodFilter(name string) (bool, error) {
|
||||
if ok, _ := regexp.MatchString("^Test", name); !ok {
|
||||
return false, nil
|
||||
}
|
||||
return regexp.MatchString(*matchMethod, name)
|
||||
}
|
||||
208
Godeps/_workspace/src/github.com/stretchr/testify/suite/suite_test.go
generated
vendored
Normal file
208
Godeps/_workspace/src/github.com/stretchr/testify/suite/suite_test.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package suite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// This suite is intended to store values to make sure that only
|
||||
// testing-suite-related methods are run. It's also a fully
|
||||
// functional example of a testing suite, using setup/teardown methods
|
||||
// and a helper method that is ignored by testify. To make this look
|
||||
// more like a real world example, all tests in the suite perform some
|
||||
// type of assertion.
|
||||
type SuiteTester struct {
|
||||
// Include our basic suite logic.
|
||||
Suite
|
||||
|
||||
// Keep counts of how many times each method is run.
|
||||
SetupSuiteRunCount int
|
||||
TearDownSuiteRunCount int
|
||||
SetupTestRunCount int
|
||||
TearDownTestRunCount int
|
||||
TestOneRunCount int
|
||||
TestTwoRunCount int
|
||||
NonTestMethodRunCount int
|
||||
}
|
||||
|
||||
type SuiteSkipTester struct {
|
||||
// Include our basic suite logic.
|
||||
Suite
|
||||
|
||||
// Keep counts of how many times each method is run.
|
||||
SetupSuiteRunCount int
|
||||
TearDownSuiteRunCount int
|
||||
}
|
||||
|
||||
// The SetupSuite method will be run by testify once, at the very
|
||||
// start of the testing suite, before any tests are run.
|
||||
func (suite *SuiteTester) SetupSuite() {
|
||||
suite.SetupSuiteRunCount++
|
||||
}
|
||||
|
||||
func (suite *SuiteSkipTester) SetupSuite() {
|
||||
suite.SetupSuiteRunCount++
|
||||
suite.T().Skip()
|
||||
}
|
||||
|
||||
// The TearDownSuite method will be run by testify once, at the very
|
||||
// end of the testing suite, after all tests have been run.
|
||||
func (suite *SuiteTester) TearDownSuite() {
|
||||
suite.TearDownSuiteRunCount++
|
||||
}
|
||||
|
||||
func (suite *SuiteSkipTester) TearDownSuite() {
|
||||
suite.TearDownSuiteRunCount++
|
||||
}
|
||||
|
||||
// The SetupTest method will be run before every test in the suite.
|
||||
func (suite *SuiteTester) SetupTest() {
|
||||
suite.SetupTestRunCount++
|
||||
}
|
||||
|
||||
// The TearDownTest method will be run after every test in the suite.
|
||||
func (suite *SuiteTester) TearDownTest() {
|
||||
suite.TearDownTestRunCount++
|
||||
}
|
||||
|
||||
// Every method in a testing suite that begins with "Test" will be run
|
||||
// as a test. TestOne is an example of a test. For the purposes of
|
||||
// this example, we've included assertions in the tests, since most
|
||||
// tests will issue assertions.
|
||||
func (suite *SuiteTester) TestOne() {
|
||||
beforeCount := suite.TestOneRunCount
|
||||
suite.TestOneRunCount++
|
||||
assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1)
|
||||
suite.Equal(suite.TestOneRunCount, beforeCount+1)
|
||||
}
|
||||
|
||||
// TestTwo is another example of a test.
|
||||
func (suite *SuiteTester) TestTwo() {
|
||||
beforeCount := suite.TestTwoRunCount
|
||||
suite.TestTwoRunCount++
|
||||
assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount)
|
||||
suite.NotEqual(suite.TestTwoRunCount, beforeCount)
|
||||
}
|
||||
|
||||
func (suite *SuiteTester) TestSkip() {
|
||||
suite.T().Skip()
|
||||
}
|
||||
|
||||
// NonTestMethod does not begin with "Test", so it will not be run by
|
||||
// testify as a test in the suite. This is useful for creating helper
|
||||
// methods for your tests.
|
||||
func (suite *SuiteTester) NonTestMethod() {
|
||||
suite.NonTestMethodRunCount++
|
||||
}
|
||||
|
||||
// TestRunSuite will be run by the 'go test' command, so within it, we
|
||||
// can run our suite using the Run(*testing.T, TestingSuite) function.
|
||||
func TestRunSuite(t *testing.T) {
|
||||
suiteTester := new(SuiteTester)
|
||||
Run(t, suiteTester)
|
||||
|
||||
// Normally, the test would end here. The following are simply
|
||||
// some assertions to ensure that the Run function is working as
|
||||
// intended - they are not part of the example.
|
||||
|
||||
// The suite was only run once, so the SetupSuite and TearDownSuite
|
||||
// methods should have each been run only once.
|
||||
assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
|
||||
assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
|
||||
|
||||
// There are three test methods (TestOne, TestTwo, and TestSkip), so
|
||||
// the SetupTest and TearDownTest methods (which should be run once for
|
||||
// each test) should have been run three times.
|
||||
assert.Equal(t, suiteTester.SetupTestRunCount, 3)
|
||||
assert.Equal(t, suiteTester.TearDownTestRunCount, 3)
|
||||
|
||||
// Each test should have been run once.
|
||||
assert.Equal(t, suiteTester.TestOneRunCount, 1)
|
||||
assert.Equal(t, suiteTester.TestTwoRunCount, 1)
|
||||
|
||||
// Methods that don't match the test method identifier shouldn't
|
||||
// have been run at all.
|
||||
assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)
|
||||
|
||||
suiteSkipTester := new(SuiteSkipTester)
|
||||
Run(t, suiteSkipTester)
|
||||
|
||||
// The suite was only run once, so the SetupSuite and TearDownSuite
|
||||
// methods should have each been run only once, even though SetupSuite
|
||||
// called Skip()
|
||||
assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1)
|
||||
assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1)
|
||||
|
||||
}
|
||||
|
||||
func TestSuiteGetters(t *testing.T) {
|
||||
suite := new(SuiteTester)
|
||||
suite.SetT(t)
|
||||
assert.NotNil(t, suite.Assert())
|
||||
assert.Equal(t, suite.Assertions, suite.Assert())
|
||||
assert.NotNil(t, suite.Require())
|
||||
assert.Equal(t, suite.require, suite.Require())
|
||||
}
|
||||
|
||||
type SuiteLoggingTester struct {
|
||||
Suite
|
||||
}
|
||||
|
||||
func (s *SuiteLoggingTester) TestLoggingPass() {
|
||||
s.T().Log("TESTLOGPASS")
|
||||
}
|
||||
|
||||
func (s *SuiteLoggingTester) TestLoggingFail() {
|
||||
s.T().Log("TESTLOGFAIL")
|
||||
assert.NotNil(s.T(), nil) // expected to fail
|
||||
}
|
||||
|
||||
type StdoutCapture struct {
|
||||
oldStdout *os.File
|
||||
readPipe *os.File
|
||||
}
|
||||
|
||||
func (sc *StdoutCapture) StartCapture() {
|
||||
sc.oldStdout = os.Stdout
|
||||
sc.readPipe, os.Stdout, _ = os.Pipe()
|
||||
}
|
||||
|
||||
func (sc *StdoutCapture) StopCapture() (string, error) {
|
||||
if sc.oldStdout == nil || sc.readPipe == nil {
|
||||
return "", errors.New("StartCapture not called before StopCapture")
|
||||
}
|
||||
os.Stdout.Close()
|
||||
os.Stdout = sc.oldStdout
|
||||
bytes, err := ioutil.ReadAll(sc.readPipe)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
func TestSuiteLogging(t *testing.T) {
|
||||
testT := testing.T{}
|
||||
|
||||
suiteLoggingTester := new(SuiteLoggingTester)
|
||||
|
||||
capture := StdoutCapture{}
|
||||
capture.StartCapture()
|
||||
Run(&testT, suiteLoggingTester)
|
||||
output, err := capture.StopCapture()
|
||||
|
||||
assert.Nil(t, err, "Got an error trying to capture stdout!")
|
||||
|
||||
// Failed tests' output is always printed
|
||||
assert.Contains(t, output, "TESTLOGFAIL")
|
||||
|
||||
if testing.Verbose() {
|
||||
// In verbose mode, output from successful tests is also printed
|
||||
assert.Contains(t, output, "TESTLOGPASS")
|
||||
} else {
|
||||
assert.NotContains(t, output, "TESTLOGPASS")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user