<commit_before>package token

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"github.com/mitchellh/go-homedir"
)

// InternalTokenHelper fulfills the TokenHelper interface when no external
// token-helper is configured, and avoids shelling out
type InternalTokenHelper struct {
	tokenPath string
}

// populateTokenPath figures out the token path using homedir to get the user's
// home directory
func (i *InternalTokenHelper) populateTokenPath() {
	homePath, err := homedir.Dir()
	if err != nil {
		panic(fmt.Errorf("error getting user's home directory: %v", err))
	}
	i.tokenPath = homePath + "/.vault-token"
}

func (i *InternalTokenHelper) Path() string {
	return i.tokenPath
}

// Get gets the value of the stored token, if any
func (i *InternalTokenHelper) Get() (string, error) {
	i.populateTokenPath()
	f, err := os.Open(i.tokenPath)
	if os.IsNotExist(err) {
		return "", nil
	}
	if err != nil {
		return "", err
	}
	defer f.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, f); err != nil {
		return "", err
	}

	return buf.String(), nil
}

// Store stores the value of the token to the file
func (i *InternalTokenHelper) Store(input string) error {
	i.populateTokenPath()
	f, err := os.OpenFile(i.tokenPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if err != nil {
		return err
	}
	defer f.Close()

	buf := bytes.NewBufferString(input)
	if _, err := io.Copy(f, buf); err != nil {
		return err
	}

	return nil
}

// Erase erases the value of the token
func (i *InternalTokenHelper) Erase() error {
	i.populateTokenPath()
	if err := os.Remove(i.tokenPath); err != nil && !os.IsNotExist(err) {
		return err
	}

	return nil
}
<commit_msg>Strip trailing whitespace in token from file.<commit_after>package token

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/mitchellh/go-homedir"
)

// InternalTokenHelper fulfills the TokenHelper interface when no external
// token-helper is configured, and avoids shelling out
type InternalTokenHelper struct {
	tokenPath string
}

// populateTokenPath figures out the token path using homedir to get the user's
// home directory
func (i *InternalTokenHelper) populateTokenPath() {
	homePath, err := homedir.Dir()
	if err != nil {
		panic(fmt.Errorf("error getting user's home directory: %v", err))
	}
	i.tokenPath = homePath + "/.vault-token"
}

func (i *InternalTokenHelper) Path() string {
	return i.tokenPath
}

// Get gets the value of the stored token, if any
func (i *InternalTokenHelper) Get() (string, error) {
	i.populateTokenPath()
	f, err := os.Open(i.tokenPath)
	if os.IsNotExist(err) {
		return "", nil
	}
	if err != nil {
		return "", err
	}
	defer f.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, f); err != nil {
		return "", err
	}

	return strings.TrimSpace(buf.String()), nil
}

// Store stores the value of the token to the file
func (i *InternalTokenHelper) Store(input string) error {
	i.populateTokenPath()
	f, err := os.OpenFile(i.tokenPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if err != nil {
		return err
	}
	defer f.Close()

	buf := bytes.NewBufferString(input)
	if _, err := io.Copy(f, buf); err != nil {
		return err
	}

	return nil
}

// Erase erases the value of the token
func (i *InternalTokenHelper) Erase() error {
	i.populateTokenPath()
	if err := os.Remove(i.tokenPath); err != nil && !os.IsNotExist(err) {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package test

import (
	"bytes"
	"net"
	"testing"
	"crypto/rsa"
	"crypto/tls"
	"math/big"
	"encoding/hex"
)

var testConfig *tls.Config

func init() {
	testConfig = new(tls.Config)
	testConfig.Certificates = make([]tls.Certificate, 1)
	testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
	testConfig.Certificates[0].PrivateKey = testPrivateKey
	testConfig.BuildNameToCertificate()
}

type TestServer struct {
	net.Conn
	t *testing.T
}

func NewTestServer(t *testing.T, n net.Conn) *TestServer {
	var s = new(TestServer)

	s.t = t
	s.Conn = n

	return s
}

func (s *TestServer) AssertRead(v string) bool {
	var buf []byte
	var n int
	var e error

	buf = make([]byte, len(v))
	if n, e = s.Conn.Read(buf); e != nil {
		s.t.Errorf("Error: %#v", e)
		return false
	}

	var a []byte = []byte(v)
	var b []byte = buf[0:n]

	if !bytes.Equal(a, b) {
		s.t.Errorf("Expected: %#v, got: %#v", string(a), string(b))
		return false
	}

	return true
}

func (s *TestServer) AssertWrite(v string) bool {
	var e error

	if _, e = s.Conn.Write([]byte(v)); e != nil {
		s.t.Errorf("Error: %#v", e)
		return false
	}

	return true
}

func (s *TestServer) Close() {
	var e error

	if e = s.Conn.Close(); e != nil {
		panic(e)
	}
}

func (s *TestServer) StartTLS() {
	s.Conn = tls.Server(s.Conn, testConfig)
}

// Following code copied from go/src/pkg/crypto/tls/handshake_server_test.go

func bigFromString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 10)
	return ret
}

func fromHex(s string) []byte {
	b, _ := hex.DecodeString(s)
	return b
}

var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")

var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")

var testPrivateKey = &rsa.PrivateKey{
	PublicKey: rsa.PublicKey{
		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
		E: 65537,
	},
	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
	Primes: []*big.Int{
		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
	},
}
<commit_msg>Switch order<commit_after>package test

import (
	"bytes"
	"net"
	"testing"
	"crypto/rsa"
	"crypto/tls"
	"math/big"
	"encoding/hex"
)

var testConfig *tls.Config

func init() {
	testConfig = new(tls.Config)
	testConfig.Certificates = make([]tls.Certificate, 1)
	testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
	testConfig.Certificates[0].PrivateKey = testPrivateKey
	testConfig.BuildNameToCertificate()
}

type TestServer struct {
	t *testing.T
	net.Conn
}

func NewTestServer(t *testing.T, n net.Conn) *TestServer {
	var s = new(TestServer)

	s.t = t
	s.Conn = n

	return s
}

func (s *TestServer) AssertRead(v string) bool {
	var buf []byte
	var n int
	var e error

	buf = make([]byte, len(v))
	if n, e = s.Conn.Read(buf); e != nil {
		s.t.Errorf("Error: %#v", e)
		return false
	}

	var a []byte = []byte(v)
	var b []byte = buf[0:n]

	if !bytes.Equal(a, b) {
		s.t.Errorf("Expected: %#v, got: %#v", string(a), string(b))
		return false
	}

	return true
}

func (s *TestServer) AssertWrite(v string) bool {
	var e error

	if _, e = s.Conn.Write([]byte(v)); e != nil {
		s.t.Errorf("Error: %#v", e)
		return false
	}

	return true
}

func (s *TestServer) Close() {
	var e error

	if e = s.Conn.Close(); e != nil {
		panic(e)
	}
}

func (s *TestServer) StartTLS() {
	s.Conn = tls.Server(s.Conn, testConfig)
}

// Following code copied from go/src/pkg/crypto/tls/handshake_server_test.go

func bigFromString(s string) *big.Int {
	ret := new(big.Int)
	ret.SetString(s, 10)
	return ret
}

func fromHex(s string) []byte {
	b, _ := hex.DecodeString(s)
	return b
}

var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")

var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a3323030300e0603551d0f0101ff0404030200a0300d0603551d0e0406040401020304300f0603551d2304083006800401020304300b06092a864886f70d0101050381810089c6455f1c1f5ef8eb1ab174ee2439059f5c4259bb1a8d86cdb1d056f56a717da40e95ab90f59e8deaf627c157995094db0802266eb34fc6842dea8a4b68d9c1389103ab84fb9e1f85d9b5d23ff2312c8670fbb540148245a4ebafe264d90c8a4cf4f85b0fac12ac2fc4a3154bad52462868af96c62c6525d652b6e31845bdcc")

var testPrivateKey = &rsa.PrivateKey{
	PublicKey: rsa.PublicKey{
		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
		E: 65537,
	},
	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
	Primes: []*big.Int{
		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
	},
}
<|endoftext|>


<commit_before>/*
This package reads and writes pickled data. The format is the same
as the Python "pickle" module.

Protocols 0,1,2 are implemented. These are the versions written by the Python
2.x series. Python 3 defines newer protocol versions, but can write the older
protocol versions so they are readable by this package.

To read data, see stalecucumber.Unpickle.

To write data, see stalecucumber.NewPickler.

TLDR

Read a pickled string or unicode object
	pickle.dumps("foobar")
	---
	var somePickledData io.Reader
	mystring, err := stalecucumber.String(stalecucumber.Unpickle(somePickledData))

Read a pickled integer
	pickle.dumps(42)
	---
	var somePickledData io.Reader
	myint64, err := stalecucumber.Int(stalecucumber.Unpickle(somePickledData))

Read a pickled list of numbers into a structure
	pickle.dumps([8,8,2005])
	---
	var somePickledData io.Reader
	numbers := make([]int64,0)

	err := stalecucumber.UnpackInto(&numbers).From(stalecucumber.Unpickle(somePickledData))

Read a pickled dictionary into a structure
	pickle.dumps({"apple":1,"banana":2,"cat":"hello","Dog":42.0})
	---
	var somePickledData io.Reader
	mystruct := struct{
		Apple int
		Banana uint
		Cat string
		Dog float32}{}

	err := stalecucumber.UnpackInto(&mystruct).From(stalecucumber.Unpickle(somePickledData))

Pickle a structure

	buf := new(bytes.Buffer)
	mystruct := struct{
			Apple int
			Banana uint
			Cat string
			Dog float32}{}

	err := stalecucumber.NewPickler(buf).Pickle(mystruct)

Recursive objects

You can pickle recursive objects like so

	a = {}
	a["self"] = a
	pickle.dumps(a)

Python's pickler is intelligent enough not to emit an infinite data structure
when a recursive object is pickled.

I recommend against pickling recursive objects in the first place, but this
library handles unpickling them without a problem. The result of unpickling
the above is map[interface{}]interface{} with a key "a" that contains
a reference to itself.

Attempting to unpack the result of the above python code into a structure
with UnpackInto would either fail or recurse forever.

Protocol Performance

If the version of Python you are using supports protocol version 1 or 2,
you should always specify that protocol version. By default the "pickle"
and "cPickle" modules in Python write using protocol 0. Protocol 0
requires much more space to represent the same values and is much
slower to parse.

Unsupported Opcodes

The pickle format is incredibly flexible and as a result has some
features that are impractical or unimportant when implementing a reader in
another language.

Each set of opcodes is listed below by protocol version with the impact.

Protocol 0

	GLOBAL

This opcode is equivalent to calling "import foo; foo.bar" in python. It is
generated whenever an object instance, class definition, or method definition
is serialized. As long as the pickled data does not contain an instance
of a python class or a reference to a python callable this opcode is not
emitted by the "pickle" module.

A few examples of what will definitely cause this opcode to be emitted

	pickle.dumps(range) #Pickling the range function
	pickle.dumps(Exception()) #Pickling an instance of a python class

This opcode will be partially supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	REDUCE
	BUILD
	INST

These opcodes are used in recreating pickled python objects. That is currently
not supported by this package.

These opcodes will be supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	PERSID

This opcode is used to reference concrete definitions of objects between
a pickler and an unpickler by an ID number. The pickle protocol doesn't define
what a persistent ID means.

This opcode is unlikely to ever be supported by this package.

Protocol 1

	OBJ

This opcodes is used in recreating pickled python objects. That is currently
not supported by this package.

This opcode will supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	BINPERSID

This opcode is equivalent to PERSID in protocol 0 and won't be supported
for the same reason.

Protocol 2

	NEWOBJ

This opcodes is used in recreating pickled python objects. That is currently
not supported by this package.

This opcode will supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	EXT1
	EXT2
	EXT4

These opcodes allow using a registry
of popular objects that are pickled by name, typically classes.
It is envisioned that through a global negotiation and
registration process, third parties can set up a mapping between
ints and object names.

These opcodes are unlikely to ever be supported by this package.

*/
package stalecucumber

import "errors"
import "io"
import "bytes"
import "encoding/binary"
import "fmt"

var ErrOpcodeStopped = errors.New("STOP opcode found")
var ErrStackTooSmall = errors.New("Stack is too small to perform requested operation")
var ErrInputTruncated = errors.New("Input to the pickle machine was truncated")
var ErrOpcodeNotImplemented = errors.New("Input encountered opcode that is not implemented")
var ErrNoResult = errors.New("Input did not place a value onto the stack")
var ErrMarkNotFound = errors.New("Mark could not be found on the stack")

/*
Unpickle a value from a reader. This function takes a reader and
attempts to read a complete pickle program from it. This is normally
the output of the function "pickle.dump" from Python.

The returned type is interface{} because unpickling can generate any type. Use
a helper function to convert to another type without an additional type check.

This function returns an error if
the reader fails, the pickled data is invalid, or if the pickled data contains
an unsupported opcode. See unsupported opcodes in the documentation of
this package for more information.

Type Conversions

Types conversion Python types to Go types is performed as followed
	int -> int64
	string -> string
	unicode -> string
	float -> float64
	long -> big.Int from the "math/big" package
	lists -> []interface{}
	tuples -> []interface{}
	dict -> map[interface{}]interface{}

The following values are converted from Python to the Go types
	True & False -> bool
	None -> stalecucumber.PickleNone, sets pointers to nil

Helper Functions

The following helper functions were inspired by the github.com/garyburd/redigo
package. Each function takes the result of Unpickle as its arguments. If unpickle
fails it does nothing and returns that error. Otherwise it attempts to
convert to the appropriate type. If type conversion fails it returns an error

	String - string from Python string or unicode
	Int - int64 from Python int or long
	Bool - bool from Python True or False
	Big - *big.Int from Python long
	ListOrTuple - []interface{} from Python Tuple or List
	Float - float64 from Python float
	Dict - map[interface{}]interface{} from Python dictionary
	DictString -
		map[string]interface{} from Python dictionary.
		Keys must all be of type unicode or string.

Unpacking into structures

If the pickled object is a python dictionary that has only unicode and string
objects for keys, that object can be unpickled into a struct in Go by using
the "UnpackInto" function. The "From" receiver on the return value accepts
the result of "Unpickle" as its actual parameters.

The keys of the python dictionary are assigned to fields in a structure.
Structures may specify the tag "pickle" on fields. The value of this tag is taken
as the key name of the Python dictionary value to place in this field. If no
field has a matching "pickle" tag the fields are looked up by name. If
the first character of the key is not uppercase, it is uppercased. If a field
matching that name is found, the value in the python dictionary is unpacked
into the value of the field within the structure.

A list of python dictionaries can be unpickled into a slice of structures in
Go.

A homogeneous list of python values can be unpickled into a slice in
Go with the appropriate element type.

A nested python dictionary is unpickled into nested structures in Go. If a
field is of type map[interface{}]interface{} it is of course unpacked into that
as well.

By default UnpackInto skips any missing fields and fails if a field's
type is not compatible with the object's type.

This behavior can be changed by setting "AllowMissingFields" and
"AllowMismatchedFields" on the return value of UnpackInto before calling
From.

*/
func Unpickle(reader io.Reader) (interface{}, error) {
	var pm PickleMachine
	pm.buf = &bytes.Buffer{}
	pm.Reader = reader

	err := (&pm).execute()
	if err != nil {
		return nil, err
	}

	if len(pm.Stack) == 0 {
		return nil, ErrNoResult
	}

	return pm.Stack[0], nil

}

var jumpList = buildEmptyJumpList()

func init() {
	populateJumpList(&jumpList)
}

/*
This type is returned whenever Unpickle encounters an error in pickled data.
*/
type PickleMachineError struct {
	Err       error
	StackSize int
	MemoSize  int
	Opcode    uint8
}

/*
This struct is current exposed but not useful. It is likely to be hidden
in the near future.
*/
type PickleMachine struct {
	Stack  []interface{}
	Memo   []interface{}
	Reader io.Reader

	currentOpcode uint8
	buf           *bytes.Buffer
}

func (pme PickleMachineError) Error() string {
	return fmt.Sprintf("Pickle Machine failed on opcode:0x%x. Stack size:%d. Memo size:%d. Cause:%v", pme.Opcode, pme.StackSize, pme.MemoSize, pme.Err)
}

func (pm *PickleMachine) error(src error) error {
	return PickleMachineError{
		StackSize: len(pm.Stack),
		MemoSize:  len(pm.Memo),
		Err:       src,
		Opcode:    pm.currentOpcode,
	}
}

func (pm *PickleMachine) execute() error {
	for {
		var opcode uint8
		err := binary.Read(pm.Reader, binary.BigEndian, &opcode)
		if err != nil {
			return err
		}

		pm.currentOpcode = opcode
		err = jumpList[int(opcode)](pm)
		if err == ErrOpcodeStopped {
			return nil
		} else if err == ErrOpcodeNotImplemented {
			return pm.error(ErrOpcodeNotImplemented)
		} else if err != nil {
			return pm.error(err)
		}
	}
}

func (pm *PickleMachine) storeMemo(index int64, v interface{}) error {
	if index < 0 {
		return fmt.Errorf("Requested to write to invalid memo index:%v", index)
	}

	if int64(len(pm.Memo)) <= index {
		replacement := make([]interface{}, index+1)
		copy(replacement, pm.Memo)
		pm.Memo = replacement
	}

	pm.Memo[index] = v

	return nil
}

func (pm *PickleMachine) readFromMemo(index int64) (interface{}, error) {
	if index < 0 || index >= int64(len(pm.Memo)) {
		return nil, fmt.Errorf("Requested to read from invalid memo index %d", index)
	}

	return pm.Memo[index], nil
}

func (pm *PickleMachine) push(v interface{}) {
	pm.Stack = append(pm.Stack, v)
}

func (pm *PickleMachine) pop() (interface{}, error) {
	if len(pm.Stack) == 0 {
		return nil, ErrStackTooSmall
	}

	lastIndex := len(pm.Stack) - 1
	top := pm.Stack[lastIndex]

	pm.Stack = pm.Stack[:lastIndex]
	return top, nil
}

func (pm *PickleMachine) readFromStack(offset int) (interface{}, error) {
	return pm.readFromStackAt(len(pm.Stack) - 1 - offset)
}

func (pm *PickleMachine) readFromStackAt(position int) (interface{}, error) {

	if position < 0 {
		return nil, fmt.Errorf("Request to read from invalid stack position %d", position)
	}

	return pm.Stack[position], nil

}

func (pm *PickleMachine) readIntFromStack(offset int) (int64, error) {
	v, err := pm.readFromStack(offset)
	if err != nil {
		return 0, err
	}

	vi, ok := v.(int64)
	if !ok {
		return 0, fmt.Errorf("Type %T was requested from stack but found %v(%T)", vi, v, v)
	}

	return vi, nil
}

func (pm *PickleMachine) popAfterIndex(index int) error {
	if len(pm.Stack)-1 < index {
		return ErrStackTooSmall
	}

	pm.Stack = pm.Stack[0:index]
	return nil
}

func (pm *PickleMachine) putMemo(index int, v interface{}) {
	for len(pm.Memo) <= index {
		pm.Memo = append(pm.Memo, nil)
	}

	pm.Memo[index] = v
}

func (pm *PickleMachine) findMark() (int, error) {
	for i := len(pm.Stack) - 1; i != -1; i-- {
		if _, ok := pm.Stack[i].(PickleMark); ok {
			return i, nil
		}
	}
	return -1, ErrMarkNotFound
}

func (pm *PickleMachine) readFixedLengthRaw(l int64) ([]byte, error) {

	pm.buf.Reset()
	_, err := io.CopyN(pm.buf, pm.Reader, l)
	if err != nil {
		return nil, err
	}

	return pm.buf.Bytes(), nil
}

func (pm *PickleMachine) readFixedLengthString(l int64) (string, error) {

	//Avoid getting "<nil>"
	if l == 0 {
		return "", nil
	}

	pm.buf.Reset()
	_, err := io.CopyN(pm.buf, pm.Reader, l)
	if err != nil {
		return "", err
	}
	return pm.buf.String(), nil
}

func (pm *PickleMachine) readString() (string, error) {
	pm.buf.Reset()
	for {
		var v [1]byte
		n, err := pm.Reader.Read(v[:])
		if n != 1 {
			return "", ErrInputTruncated
		}
		if err != nil {
			return "", err
		}

		if v[0] == '\n' {
			break
		}
		pm.buf.WriteByte(v[0])
	}

	//Avoid getting "<nil>"
	if pm.buf.Len() == 0 {
		return "", nil
	}
	return pm.buf.String(), nil
}

func (pm *PickleMachine) readBinaryInto(dst interface{}, bigEndian bool) error {
	var bo binary.ByteOrder
	if bigEndian {
		bo = binary.BigEndian
	} else {
		bo = binary.LittleEndian
	}
	return binary.Read(pm.Reader, bo, dst)
}
<commit_msg>change 'structure' to 'struct'<commit_after>/*
This package reads and writes pickled data. The format is the same
as the Python "pickle" module.

Protocols 0,1,2 are implemented. These are the versions written by the Python
2.x series. Python 3 defines newer protocol versions, but can write the older
protocol versions so they are readable by this package.

To read data, see stalecucumber.Unpickle.

To write data, see stalecucumber.NewPickler.

TLDR

Read a pickled string or unicode object
	pickle.dumps("foobar")
	---
	var somePickledData io.Reader
	mystring, err := stalecucumber.String(stalecucumber.Unpickle(somePickledData))

Read a pickled integer
	pickle.dumps(42)
	---
	var somePickledData io.Reader
	myint64, err := stalecucumber.Int(stalecucumber.Unpickle(somePickledData))

Read a pickled list of numbers into a structure
	pickle.dumps([8,8,2005])
	---
	var somePickledData io.Reader
	numbers := make([]int64,0)

	err := stalecucumber.UnpackInto(&numbers).From(stalecucumber.Unpickle(somePickledData))

Read a pickled dictionary into a structure
	pickle.dumps({"apple":1,"banana":2,"cat":"hello","Dog":42.0})
	---
	var somePickledData io.Reader
	mystruct := struct{
		Apple int
		Banana uint
		Cat string
		Dog float32}{}

	err := stalecucumber.UnpackInto(&mystruct).From(stalecucumber.Unpickle(somePickledData))

Pickle a struct

	buf := new(bytes.Buffer)
	mystruct := struct{
			Apple int
			Banana uint
			Cat string
			Dog float32}{}

	err := stalecucumber.NewPickler(buf).Pickle(mystruct)

Recursive objects

You can pickle recursive objects like so

	a = {}
	a["self"] = a
	pickle.dumps(a)

Python's pickler is intelligent enough not to emit an infinite data structure
when a recursive object is pickled.

I recommend against pickling recursive objects in the first place, but this
library handles unpickling them without a problem. The result of unpickling
the above is map[interface{}]interface{} with a key "a" that contains
a reference to itself.

Attempting to unpack the result of the above python code into a structure
with UnpackInto would either fail or recurse forever.

Protocol Performance

If the version of Python you are using supports protocol version 1 or 2,
you should always specify that protocol version. By default the "pickle"
and "cPickle" modules in Python write using protocol 0. Protocol 0
requires much more space to represent the same values and is much
slower to parse.

Unsupported Opcodes

The pickle format is incredibly flexible and as a result has some
features that are impractical or unimportant when implementing a reader in
another language.

Each set of opcodes is listed below by protocol version with the impact.

Protocol 0

	GLOBAL

This opcode is equivalent to calling "import foo; foo.bar" in python. It is
generated whenever an object instance, class definition, or method definition
is serialized. As long as the pickled data does not contain an instance
of a python class or a reference to a python callable this opcode is not
emitted by the "pickle" module.

A few examples of what will definitely cause this opcode to be emitted

	pickle.dumps(range) #Pickling the range function
	pickle.dumps(Exception()) #Pickling an instance of a python class

This opcode will be partially supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	REDUCE
	BUILD
	INST

These opcodes are used in recreating pickled python objects. That is currently
not supported by this package.

These opcodes will be supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	PERSID

This opcode is used to reference concrete definitions of objects between
a pickler and an unpickler by an ID number. The pickle protocol doesn't define
what a persistent ID means.

This opcode is unlikely to ever be supported by this package.

Protocol 1

	OBJ

This opcodes is used in recreating pickled python objects. That is currently
not supported by this package.

This opcode will supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	BINPERSID

This opcode is equivalent to PERSID in protocol 0 and won't be supported
for the same reason.

Protocol 2

	NEWOBJ

This opcodes is used in recreating pickled python objects. That is currently
not supported by this package.

This opcode will supported in a future revision to this package
that allows the unpickling of instances of Python classes.

	EXT1
	EXT2
	EXT4

These opcodes allow using a registry
of popular objects that are pickled by name, typically classes.
It is envisioned that through a global negotiation and
registration process, third parties can set up a mapping between
ints and object names.

These opcodes are unlikely to ever be supported by this package.

*/
package stalecucumber

import "errors"
import "io"
import "bytes"
import "encoding/binary"
import "fmt"

var ErrOpcodeStopped = errors.New("STOP opcode found")
var ErrStackTooSmall = errors.New("Stack is too small to perform requested operation")
var ErrInputTruncated = errors.New("Input to the pickle machine was truncated")
var ErrOpcodeNotImplemented = errors.New("Input encountered opcode that is not implemented")
var ErrNoResult = errors.New("Input did not place a value onto the stack")
var ErrMarkNotFound = errors.New("Mark could not be found on the stack")

/*
Unpickle a value from a reader. This function takes a reader and
attempts to read a complete pickle program from it. This is normally
the output of the function "pickle.dump" from Python.

The returned type is interface{} because unpickling can generate any type. Use
a helper function to convert to another type without an additional type check.

This function returns an error if
the reader fails, the pickled data is invalid, or if the pickled data contains
an unsupported opcode. See unsupported opcodes in the documentation of
this package for more information.

Type Conversions

Types conversion Python types to Go types is performed as followed
	int -> int64
	string -> string
	unicode -> string
	float -> float64
	long -> big.Int from the "math/big" package
	lists -> []interface{}
	tuples -> []interface{}
	dict -> map[interface{}]interface{}

The following values are converted from Python to the Go types
	True & False -> bool
	None -> stalecucumber.PickleNone, sets pointers to nil

Helper Functions

The following helper functions were inspired by the github.com/garyburd/redigo
package. Each function takes the result of Unpickle as its arguments. If unpickle
fails it does nothing and returns that error. Otherwise it attempts to
convert to the appropriate type. If type conversion fails it returns an error

	String - string from Python string or unicode
	Int - int64 from Python int or long
	Bool - bool from Python True or False
	Big - *big.Int from Python long
	ListOrTuple - []interface{} from Python Tuple or List
	Float - float64 from Python float
	Dict - map[interface{}]interface{} from Python dictionary
	DictString -
		map[string]interface{} from Python dictionary.
		Keys must all be of type unicode or string.

Unpacking into structures

If the pickled object is a python dictionary that has only unicode and string
objects for keys, that object can be unpickled into a struct in Go by using
the "UnpackInto" function. The "From" receiver on the return value accepts
the result of "Unpickle" as its actual parameters.

The keys of the python dictionary are assigned to fields in a structure.
Structures may specify the tag "pickle" on fields. The value of this tag is taken
as the key name of the Python dictionary value to place in this field. If no
field has a matching "pickle" tag the fields are looked up by name. If
the first character of the key is not uppercase, it is uppercased. If a field
matching that name is found, the value in the python dictionary is unpacked
into the value of the field within the structure.

A list of python dictionaries can be unpickled into a slice of structures in
Go.

A homogeneous list of python values can be unpickled into a slice in
Go with the appropriate element type.

A nested python dictionary is unpickled into nested structures in Go. If a
field is of type map[interface{}]interface{} it is of course unpacked into that
as well.

By default UnpackInto skips any missing fields and fails if a field's
type is not compatible with the object's type.

This behavior can be changed by setting "AllowMissingFields" and
"AllowMismatchedFields" on the return value of UnpackInto before calling
From.

*/
func Unpickle(reader io.Reader) (interface{}, error) {
	var pm PickleMachine
	pm.buf = &bytes.Buffer{}
	pm.Reader = reader

	err := (&pm).execute()
	if err != nil {
		return nil, err
	}

	if len(pm.Stack) == 0 {
		return nil, ErrNoResult
	}

	return pm.Stack[0], nil

}

var jumpList = buildEmptyJumpList()

func init() {
	populateJumpList(&jumpList)
}

/*
This type is returned whenever Unpickle encounters an error in pickled data.
*/
type PickleMachineError struct {
	Err       error
	StackSize int
	MemoSize  int
	Opcode    uint8
}

/*
This struct is current exposed but not useful. It is likely to be hidden
in the near future.
*/
type PickleMachine struct {
	Stack  []interface{}
	Memo   []interface{}
	Reader io.Reader

	currentOpcode uint8
	buf           *bytes.Buffer
}

func (pme PickleMachineError) Error() string {
	return fmt.Sprintf("Pickle Machine failed on opcode:0x%x. Stack size:%d. Memo size:%d. Cause:%v", pme.Opcode, pme.StackSize, pme.MemoSize, pme.Err)
}

func (pm *PickleMachine) error(src error) error {
	return PickleMachineError{
		StackSize: len(pm.Stack),
		MemoSize:  len(pm.Memo),
		Err:       src,
		Opcode:    pm.currentOpcode,
	}
}

func (pm *PickleMachine) execute() error {
	for {
		var opcode uint8
		err := binary.Read(pm.Reader, binary.BigEndian, &opcode)
		if err != nil {
			return err
		}

		pm.currentOpcode = opcode
		err = jumpList[int(opcode)](pm)
		if err == ErrOpcodeStopped {
			return nil
		} else if err == ErrOpcodeNotImplemented {
			return pm.error(ErrOpcodeNotImplemented)
		} else if err != nil {
			return pm.error(err)
		}
	}
}

func (pm *PickleMachine) storeMemo(index int64, v interface{}) error {
	if index < 0 {
		return fmt.Errorf("Requested to write to invalid memo index:%v", index)
	}

	if int64(len(pm.Memo)) <= index {
		replacement := make([]interface{}, index+1)
		copy(replacement, pm.Memo)
		pm.Memo = replacement
	}

	pm.Memo[index] = v

	return nil
}

func (pm *PickleMachine) readFromMemo(index int64) (interface{}, error) {
	if index < 0 || index >= int64(len(pm.Memo)) {
		return nil, fmt.Errorf("Requested to read from invalid memo index %d", index)
	}

	return pm.Memo[index], nil
}

func (pm *PickleMachine) push(v interface{}) {
	pm.Stack = append(pm.Stack, v)
}

func (pm *PickleMachine) pop() (interface{}, error) {
	if len(pm.Stack) == 0 {
		return nil, ErrStackTooSmall
	}

	lastIndex := len(pm.Stack) - 1
	top := pm.Stack[lastIndex]

	pm.Stack = pm.Stack[:lastIndex]
	return top, nil
}

func (pm *PickleMachine) readFromStack(offset int) (interface{}, error) {
	return pm.readFromStackAt(len(pm.Stack) - 1 - offset)
}

func (pm *PickleMachine) readFromStackAt(position int) (interface{}, error) {

	if position < 0 {
		return nil, fmt.Errorf("Request to read from invalid stack position %d", position)
	}

	return pm.Stack[position], nil

}

func (pm *PickleMachine) readIntFromStack(offset int) (int64, error) {
	v, err := pm.readFromStack(offset)
	if err != nil {
		return 0, err
	}

	vi, ok := v.(int64)
	if !ok {
		return 0, fmt.Errorf("Type %T was requested from stack but found %v(%T)", vi, v, v)
	}

	return vi, nil
}

func (pm *PickleMachine) popAfterIndex(index int) error {
	if len(pm.Stack)-1 < index {
		return ErrStackTooSmall
	}

	pm.Stack = pm.Stack[0:index]
	return nil
}

func (pm *PickleMachine) putMemo(index int, v interface{}) {
	for len(pm.Memo) <= index {
		pm.Memo = append(pm.Memo, nil)
	}

	pm.Memo[index] = v
}

func (pm *PickleMachine) findMark() (int, error) {
	for i := len(pm.Stack) - 1; i != -1; i-- {
		if _, ok := pm.Stack[i].(PickleMark); ok {
			return i, nil
		}
	}
	return -1, ErrMarkNotFound
}

func (pm *PickleMachine) readFixedLengthRaw(l int64) ([]byte, error) {

	pm.buf.Reset()
	_, err := io.CopyN(pm.buf, pm.Reader, l)
	if err != nil {
		return nil, err
	}

	return pm.buf.Bytes(), nil
}

func (pm *PickleMachine) readFixedLengthString(l int64) (string, error) {

	//Avoid getting "<nil>"
	if l == 0 {
		return "", nil
	}

	pm.buf.Reset()
	_, err := io.CopyN(pm.buf, pm.Reader, l)
	if err != nil {
		return "", err
	}
	return pm.buf.String(), nil
}

func (pm *PickleMachine) readString() (string, error) {
	pm.buf.Reset()
	for {
		var v [1]byte
		n, err := pm.Reader.Read(v[:])
		if n != 1 {
			return "", ErrInputTruncated
		}
		if err != nil {
			return "", err
		}

		if v[0] == '\n' {
			break
		}
		pm.buf.WriteByte(v[0])
	}

	//Avoid getting "<nil>"
	if pm.buf.Len() == 0 {
		return "", nil
	}
	return pm.buf.String(), nil
}

func (pm *PickleMachine) readBinaryInto(dst interface{}, bigEndian bool) error {
	var bo binary.ByteOrder
	if bigEndian {
		bo = binary.BigEndian
	} else {
		bo = binary.LittleEndian
	}
	return binary.Read(pm.Reader, bo, dst)
}
<|endoftext|>


<commit_before>package connection

import (
	"encoding/hex"
	"log"
	"net"
	"strconv"

	"github.com/piot/hasty-protocol/authentication"
	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/chunk"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/packet"
	"github.com/piot/hasty-protocol/packetserializers"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-protocol/timestamp"
	"github.com/piot/hasty-protocol/user"
	"github.com/piot/hasty-server/authorization"
	"github.com/piot/hasty-server/master"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
	"github.com/piot/hasty-server/users"
)

const systemChannelID = 0

// StreamInfo : todo
type StreamInfo struct {
	lastOffsetSent uint64
}

// ConnectionHandler : todo
type ConnectionHandler struct {
	conn               *net.Conn
	storage            *filestorage.StreamStorage
	userStorage        *users.Storage
	subscribers        *subscribers.Subscribers
	streamInfos        map[uint32]*StreamInfo
	connectionID       packet.ConnectionID
	masterHandler      *master.MasterCommandHandler
	chunkStreams       map[uint32]*chunk.Stream
	authenticationInfo authentication.Info
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, masterHandler *master.MasterCommandHandler, storage *filestorage.StreamStorage, userStorage *users.Storage, subs *subscribers.Subscribers, connectionID packet.ConnectionID) *ConnectionHandler {
	return &ConnectionHandler{connectionID: connectionID, masterHandler: masterHandler, conn: connection, storage: storage, userStorage: userStorage, subscribers: subs, streamInfos: map[uint32]*StreamInfo{}, chunkStreams: map[uint32]*chunk.Stream{}}
}

// HandleConnect : todo
func (in *ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Printf("%s %s", in.connectionID, cmd)

	// _ := commands.NewConnectResult(cmd.Realm(), cmd.ProtocolVersion())
	octetsToSend := packetserializers.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

func (in *ConnectionHandler) sendPong(echoedTime timestamp.Time) {
	log.Printf("%s sendPong %s", in.connectionID, echoedTime)
	now := timestamp.Now()
	octetsToSend := packetserializers.PongToOctets(now, echoedTime)
	in.sendPacket(octetsToSend)
}

func (in *ConnectionHandler) sendLoginResult(worked bool, channelID channel.ID) {
	log.Printf("%s sendLoginResult %t", in.connectionID, worked)
	octetsToSend := packetserializers.LoginResultToOctets(channelID)
	in.sendPacket(octetsToSend)
}

// HandlePing : todo
func (in *ConnectionHandler) HandlePing(cmd commands.Ping) {
	log.Printf("%s %s", in.connectionID, cmd)
	in.sendPong(cmd.SentTime())
}

// HandlePong : todo
func (in *ConnectionHandler) HandlePong(cmd commands.Pong) {
	now := timestamp.Now()
	latency := now.Raw() - cmd.EchoedTime().Raw()
	log.Printf("%s Latency: %d ms", in.connectionID, latency)
}

// HandlePublishStream : todo
func (in *ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Printf("%s %s", in.connectionID, cmd)
	return nil
}

// StreamChanged : todo
func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.streamInfos[channelID.Raw()]
	file, fileErr := in.storage.ReadStream(channelID)
	if fileErr != nil {
		return
	}
	file.Seek(info.lastOffsetSent)
	data := make([]byte, 32*1024)
	octetsRead, readErr := file.Read(data)
	if readErr != nil {
		return
	}
	file.Close()
	in.sendStreamData(channelID, uint32(info.lastOffsetSent), data[:octetsRead])
	info.lastOffsetSent += uint64(octetsRead)
}

func (in *ConnectionHandler) sendStreamData(channelID channel.ID, lastOffsetSent uint32, data []byte) {
	log.Printf("%s sendStreamData %s offset:%d", in.connectionID, channelID, lastOffsetSent)
	payload := packetserializers.StreamDataToOctets(channelID, lastOffsetSent, data)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)

	for _, v := range cmd.Infos() {
		readFile, err := in.storage.ReadStream(v.Channel())

		if err != nil {
			return
		}
		offset := v.Offset()

		const maxSizeBuffer = 1 * 1024 * 1024
		buf := make([]byte, maxSizeBuffer)
		readFile.Seek(uint64(offset))
		octetsRead, readErr := readFile.Read(buf)
		if readErr != nil {
			return
		}
		data := buf[:octetsRead]
		lastOffset := int(offset) + octetsRead
		octetsToSend := packetserializers.StreamDataToOctets(v.Channel(), offset, data)
		in.sendPacket(octetsToSend)
		infos := in.fetchOrCreateStreamInfo(v.Channel())
		infos.lastOffsetSent = uint64(lastOffset)
		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in *ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)
}

// HandleCreateStream : todo
func (in *ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Printf("%s %s", in.connectionID, cmd)
	return channel.ID{}, nil
}

func (in *ConnectionHandler) fetchOrAssoicateChunkStream(channelID channel.ID) *chunk.Stream {
	stream := in.chunkStreams[channelID.Raw()]
	if stream == nil {
		stream = chunk.NewChunkStream(in.connectionID, channelID)
		in.chunkStreams[channelID.Raw()] = stream
	}
	return stream
}

func (in *ConnectionHandler) publishMasterStream(channel channel.ID, payload []byte, authenticationInfo authentication.Info) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	authenticationPayload, _ := packetserializers.AuthenticationChunkToOctets(authenticationInfo, payload)
	cmd := commands.NewPublishStream(channel, authenticationPayload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

// HandleStreamData : todo
func (in *ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Printf("%s %s", in.connectionID, cmd)
	chunkStream := in.fetchOrAssoicateChunkStream(cmd.Channel())
	chunkStream.Feed(cmd.Data())
	foundChunk, fetchErr := chunkStream.FetchChunk()
	if fetchErr != nil {
		_, isNotDoneError := fetchErr.(*chunk.NotDoneError)
		if isNotDoneError {
		} else {
			log.Printf("Fetcherror:%s", fetchErr)
		}
	} else {
		in.publishMasterStream(cmd.Channel(), foundChunk.Payload(), in.authenticationInfo)
	}
}

func convertFromUsernameToUserID(username string) user.ID {
	userIDValue, _ := strconv.ParseUint(username, 10, 64)
	userID, _ := user.NewID(userIDValue)

	return userID
}

// HandleLogin : todo
func (in *ConnectionHandler) HandleLogin(cmd commands.Login) error {
	log.Printf("%s", cmd)
	userID := convertFromUsernameToUserID(cmd.Username())
	userAssignedChannel, userInfoErr := in.userStorage.FindOrCreateUserInfo(userID)
	if userInfoErr != nil {
		log.Printf("ERROR:%v", userInfoErr)
		return userInfoErr
	}
	in.authenticationInfo = authentication.NewInfo(userID, userAssignedChannel)
	in.sendLoginResult(true, userAssignedChannel)

	return nil
}

func (in *ConnectionHandler) publishSystemStream(payload []byte) {
	log.Printf("Publishing to system stream %v", payload)
	channelToPublishTo, _ := channel.NewFromID(systemChannelID)
	in.publishMasterStream(channelToPublishTo, payload, in.authenticationInfo)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	payloadLength := uint16(len(octets))
	hexPayload := hex.Dump(octets)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(payloadLength)
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	log.Printf("%s Sending packet (size %d) %s", in.connectionID, payloadLength, hexPayload)
	(*in.conn).Write(lengthBuf)
	(*in.conn).Write(octets)
}

// HandleTransportDisconnect : todo
func (in *ConnectionHandler) HandleTransportDisconnect() {
	log.Printf("%s Transport disconnect", in.connectionID)
}
<commit_msg>Handle master streams and normal streams differently<commit_after>package connection

import (
	"encoding/hex"
	"log"
	"net"
	"strconv"

	"github.com/piot/hasty-protocol/authentication"
	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/chunk"
	"github.com/piot/hasty-protocol/commands"
	"github.com/piot/hasty-protocol/packet"
	"github.com/piot/hasty-protocol/packetserializers"
	"github.com/piot/hasty-protocol/serializer"
	"github.com/piot/hasty-protocol/timestamp"
	"github.com/piot/hasty-protocol/user"
	"github.com/piot/hasty-server/authorization"
	"github.com/piot/hasty-server/master"
	"github.com/piot/hasty-server/storage"
	"github.com/piot/hasty-server/subscribers"
	"github.com/piot/hasty-server/users"
)

const systemChannelID = 0

// StreamInfo : todo
type StreamInfo struct {
	lastOffsetSent uint64
}

// ConnectionHandler : todo
type ConnectionHandler struct {
	conn               *net.Conn
	storage            *filestorage.StreamStorage
	userStorage        *users.Storage
	subscribers        *subscribers.Subscribers
	streamInfos        map[uint32]*StreamInfo
	connectionID       packet.ConnectionID
	masterHandler      *master.MasterCommandHandler
	chunkStreams       map[uint32]*chunk.Stream
	authenticationInfo authentication.Info
}

// NewConnectionHandler : todo
func NewConnectionHandler(connection *net.Conn, masterHandler *master.MasterCommandHandler, storage *filestorage.StreamStorage, userStorage *users.Storage, subs *subscribers.Subscribers, connectionID packet.ConnectionID) *ConnectionHandler {
	return &ConnectionHandler{connectionID: connectionID, masterHandler: masterHandler, conn: connection, storage: storage, userStorage: userStorage, subscribers: subs, streamInfos: map[uint32]*StreamInfo{}, chunkStreams: map[uint32]*chunk.Stream{}}
}

// HandleConnect : todo
func (in *ConnectionHandler) HandleConnect(cmd commands.Connect) error {
	log.Printf("%s %s", in.connectionID, cmd)

	// _ := commands.NewConnectResult(cmd.Realm(), cmd.ProtocolVersion())
	octetsToSend := packetserializers.ConnectResultToOctets()
	in.sendPacket(octetsToSend)
	return nil
}

func (in *ConnectionHandler) sendPong(echoedTime timestamp.Time) {
	log.Printf("%s sendPong %s", in.connectionID, echoedTime)
	now := timestamp.Now()
	octetsToSend := packetserializers.PongToOctets(now, echoedTime)
	in.sendPacket(octetsToSend)
}

func (in *ConnectionHandler) sendLoginResult(worked bool, channelID channel.ID) {
	log.Printf("%s sendLoginResult %t", in.connectionID, worked)
	octetsToSend := packetserializers.LoginResultToOctets(channelID)
	in.sendPacket(octetsToSend)
}

// HandlePing : todo
func (in *ConnectionHandler) HandlePing(cmd commands.Ping) {
	log.Printf("%s %s", in.connectionID, cmd)
	in.sendPong(cmd.SentTime())
}

// HandlePong : todo
func (in *ConnectionHandler) HandlePong(cmd commands.Pong) {
	now := timestamp.Now()
	latency := now.Raw() - cmd.EchoedTime().Raw()
	log.Printf("%s Latency: %d ms", in.connectionID, latency)
}

// HandlePublishStream : todo
func (in *ConnectionHandler) HandlePublishStream(cmd commands.PublishStream) error {
	log.Printf("%s %s", in.connectionID, cmd)
	return nil
}

// StreamChanged : todo
func (in *ConnectionHandler) StreamChanged(channelID channel.ID) {
	info := in.streamInfos[channelID.Raw()]
	file, fileErr := in.storage.ReadStream(channelID)
	if fileErr != nil {
		return
	}
	file.Seek(info.lastOffsetSent)
	data := make([]byte, 32*1024)
	octetsRead, readErr := file.Read(data)
	if readErr != nil {
		return
	}
	file.Close()
	in.sendStreamData(channelID, uint32(info.lastOffsetSent), data[:octetsRead])
	info.lastOffsetSent += uint64(octetsRead)
}

func (in *ConnectionHandler) sendStreamData(channelID channel.ID, lastOffsetSent uint32, data []byte) {
	log.Printf("%s sendStreamData %s offset:%d", in.connectionID, channelID, lastOffsetSent)
	payload := packetserializers.StreamDataToOctets(channelID, lastOffsetSent, data)
	in.sendPacket(payload)
}

func (in *ConnectionHandler) fetchOrCreateStreamInfo(channelID channel.ID) *StreamInfo {
	infos := in.streamInfos[channelID.Raw()]
	if infos == nil {
		infos = &StreamInfo{}
		in.streamInfos[channelID.Raw()] = infos
	}
	return infos
}

// HandleSubscribeStream : todo
func (in *ConnectionHandler) HandleSubscribeStream(cmd commands.SubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)

	for _, v := range cmd.Infos() {
		readFile, err := in.storage.ReadStream(v.Channel())

		if err != nil {
			return
		}
		offset := v.Offset()

		const maxSizeBuffer = 1 * 1024 * 1024
		buf := make([]byte, maxSizeBuffer)
		readFile.Seek(uint64(offset))
		octetsRead, readErr := readFile.Read(buf)
		if readErr != nil {
			return
		}
		data := buf[:octetsRead]
		lastOffset := int(offset) + octetsRead
		octetsToSend := packetserializers.StreamDataToOctets(v.Channel(), offset, data)
		in.sendPacket(octetsToSend)
		infos := in.fetchOrCreateStreamInfo(v.Channel())
		infos.lastOffsetSent = uint64(lastOffset)
		in.subscribers.AddStreamSubscriber(v.Channel(), in)
	}
}

// HandleUnsubscribeStream : todo
func (in *ConnectionHandler) HandleUnsubscribeStream(cmd commands.UnsubscribeStream) {
	log.Printf("%s %s", in.connectionID, cmd)
}

// HandleCreateStream : todo
func (in *ConnectionHandler) HandleCreateStream(cmd commands.CreateStream) (channel.ID, error) {
	log.Printf("%s %s", in.connectionID, cmd)
	return channel.ID{}, nil
}

func (in *ConnectionHandler) fetchOrAssoicateChunkStream(channelID channel.ID) *chunk.Stream {
	stream := in.chunkStreams[channelID.Raw()]
	if stream == nil {
		stream = chunk.NewChunkStream(in.connectionID, channelID)
		in.chunkStreams[channelID.Raw()] = stream
	}
	return stream
}

func (in *ConnectionHandler) publishMasterStream(channel channel.ID, payload []byte, authenticationInfo authentication.Info) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	authenticationPayload, _ := packetserializers.AuthenticationChunkToOctets(authenticationInfo, payload)
	cmd := commands.NewPublishStream(channel, authenticationPayload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func (in *ConnectionHandler) publishNormalStream(channel channel.ID, payload []byte) {
	fakeClient := authorization.AdminClient{}
	hexPayload := hex.Dump(payload)
	log.Printf("publishing to channel: %v data: %v", channel, hexPayload)
	cmd := commands.NewPublishStream(channel, payload)
	in.masterHandler.HandlePublishStream(fakeClient, cmd)
}

func isMasterStream(channelID channel.ID) bool {
	return channelID.Raw() == 3
}

func (in *ConnectionHandler) handleStreamDataForMasterStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Master Stream! %v", cmd)
	chunkStream := in.fetchOrAssoicateChunkStream(cmd.Channel())
	chunkStream.Feed(cmd.Data())
	foundChunk, fetchErr := chunkStream.FetchChunk()
	if fetchErr != nil {
		_, isNotDoneError := fetchErr.(*chunk.NotDoneError)
		if isNotDoneError {
		} else {
			log.Printf("Fetcherror:%s", fetchErr)
		}
	} else {
		in.publishMasterStream(cmd.Channel(), foundChunk.Payload(), in.authenticationInfo)
	}
}

func (in *ConnectionHandler) handleStreamDataForNormalStream(cmd commands.StreamData) {
	log.Printf("Stream Data for Normal Stream! %v", cmd)
	in.publishNormalStream(cmd.Channel(), cmd.Data())
}

// HandleStreamData : todo
func (in *ConnectionHandler) HandleStreamData(cmd commands.StreamData) {
	log.Printf("%s %s", in.connectionID, cmd)
	if isMasterStream(cmd.Channel()) {
		in.handleStreamDataForMasterStream(cmd)
	} else {
		in.handleStreamDataForNormalStream(cmd)
	}
}

func convertFromUsernameToUserID(username string) user.ID {
	userIDValue, _ := strconv.ParseUint(username, 10, 64)
	userID, _ := user.NewID(userIDValue)

	return userID
}

// HandleLogin : todo
func (in *ConnectionHandler) HandleLogin(cmd commands.Login) error {
	log.Printf("%s", cmd)
	userID := convertFromUsernameToUserID(cmd.Username())
	userAssignedChannel, userInfoErr := in.userStorage.FindOrCreateUserInfo(userID)
	if userInfoErr != nil {
		log.Printf("ERROR:%v", userInfoErr)
		return userInfoErr
	}
	in.authenticationInfo = authentication.NewInfo(userID, userAssignedChannel)
	in.sendLoginResult(true, userAssignedChannel)

	return nil
}

func (in *ConnectionHandler) publishSystemStream(payload []byte) {
	log.Printf("Publishing to system stream %v", payload)
	channelToPublishTo, _ := channel.NewFromID(systemChannelID)
	in.publishMasterStream(channelToPublishTo, payload, in.authenticationInfo)
}

func (in *ConnectionHandler) sendPacket(octets []byte) {
	payloadLength := uint16(len(octets))
	hexPayload := hex.Dump(octets)
	lengthBuf, lengthErr := serializer.SmallLengthToOctets(payloadLength)
	if lengthErr != nil {
		log.Printf("We couldn't write length")
		return
	}
	log.Printf("%s Sending packet (size %d) %s", in.connectionID, payloadLength, hexPayload)
	(*in.conn).Write(lengthBuf)
	(*in.conn).Write(octets)
}

// HandleTransportDisconnect : todo
func (in *ConnectionHandler) HandleTransportDisconnect() {
	log.Printf("%s Transport disconnect", in.connectionID)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Chris Cartland
 *
 * Licensed 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.
 */
// This example demonstrates decoding a JPEG image and examining its pixels.
package main

import (
	"github.com/cartland/go/imagic"
	"image"
	"log"
	"os"
	// _ "image/gif"
	_ "image/jpeg"
	"image/png"
)

func main() {
	// Decode the JPEG data.
	reader, err := os.Open("testdata/Chefchaouen.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	bg, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	reader, err = os.Open("testdata/borrodepth.png")
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	dm, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	configWallEyed := imagic.Config{60, 100, false}
	configCrossEyed := imagic.Config{100, 160, true}

	wall := imagic.Imagic(dm, bg, configWallEyed)
	writer, err := os.Create("testdata/wallOutput.png")
	png.Encode(writer, wall)

	cross := imagic.Imagic(dm, bg, configCrossEyed)
	writer, err = os.Create("testdata/crossOutput.png")
	png.Encode(writer, cross)
}
<commit_msg>Removing old comment.<commit_after>/*
 * Copyright 2014 Chris Cartland
 *
 * Licensed 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 main

import (
	"github.com/cartland/go/imagic"
	"image"
	"log"
	"os"
	// _ "image/gif"
	_ "image/jpeg"
	"image/png"
)

func main() {
	// Decode the JPEG data.
	reader, err := os.Open("testdata/Chefchaouen.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	bg, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	reader, err = os.Open("testdata/borrodepth.png")
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()
	dm, _, err := image.Decode(reader)
	if err != nil {
		log.Fatal(err)
	}

	configWallEyed := imagic.Config{60, 100, false}
	configCrossEyed := imagic.Config{100, 160, true}

	wall := imagic.Imagic(dm, bg, configWallEyed)
	writer, err := os.Create("testdata/wallOutput.png")
	png.Encode(writer, wall)

	cross := imagic.Imagic(dm, bg, configCrossEyed)
	writer, err = os.Create("testdata/crossOutput.png")
	png.Encode(writer, cross)
}
<|endoftext|>


<commit_before>package packages

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"

	"gopkg.in/yaml.v2"
)

// PackageManager manages packages at a given path
type PackageManager struct {
	InstallPath string
}

// NewPackageManager creates a new PackageManager
func NewPackageManager(path string) *PackageManager {
	return &PackageManager{InstallPath: path}
}

// Install installs a package
func (pm *PackageManager) Install(pkg *Package) error {
	d, err := yaml.Marshal(&pkg)
	if err != nil {
		return err
	}

	packagePath := path.Join(pm.InstallPath, pkg.Name)

	if _, err := os.Stat(packagePath); err == nil {
		return fmt.Errorf("'%s' already exists", packagePath)
	}

	d = append([]byte("#!/usr/bin/env whalebrew\n"), d...)
	return ioutil.WriteFile(packagePath, d, 0755)
}

// List lists installed packages
func (pm *PackageManager) List() (map[string]*Package, error) {
	packages := make(map[string]*Package)
	files, err := ioutil.ReadDir(pm.InstallPath)
	if err != nil {
		return packages, err
	}
	for _, file := range files {
		isPackage, err := IsPackage(path.Join(pm.InstallPath, file.Name()))
		if err != nil {
			// Check for various file errors here rather than in IsPackage so it
			// does not swallow errors when checking individual files.

			// permission denied
			if os.IsPermission(err) {
				continue
			}
			// dead symlink
			if os.IsNotExist(err) {
				continue
			}

			return packages, err
		}
		if isPackage {
			pkg, err := pm.Load(file.Name())
			if err != nil {
				return packages, err
			}
			packages[file.Name()] = pkg
		}
	}
	return packages, nil
}

// Load returns an installed package given its package name
func (pm *PackageManager) Load(name string) (*Package, error) {
	return LoadPackageFromPath(path.Join(pm.InstallPath, name))
}

// Uninstall uninstalls a package
func (pm *PackageManager) Uninstall(packageName string) error {
	p := path.Join(pm.InstallPath, packageName)
	isPackage, err := IsPackage(p)
	if err != nil {
		return err
	}
	if !isPackage {
		return fmt.Errorf("%s is not a Whalebrew package", p)
	}
	return os.Remove(p)
}

// IsPackage returns true if the given path is a whalebrew package
func IsPackage(path string) (bool, error) {
	f, err := os.Open(path)
	if err != nil {
		return false, err
	}
	defer f.Close()

	info, err := f.Stat()

	if err != nil {
		return false, err
	}

	if info.IsDir() {
		return false, nil
	}

	reader := bufio.NewReader(f)
	firstTwoBytes := make([]byte, 2)
	_, err = reader.Read(firstTwoBytes)

	if err == io.EOF {
		return false, nil
	}

	if err != nil {
		return false, err
	}

	if string(firstTwoBytes) != "#!" {
		return false, nil
	}

	line, _, err := reader.ReadLine()

	if err == io.EOF {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	if strings.HasPrefix(string(line), "/usr/bin/env whalebrew") {
		return true, nil
	}

	return false, nil
}
<commit_msg>Add batch file support (for working on windows)<commit_after>package packages

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"

	"gopkg.in/yaml.v2"
)

// PackageManager manages packages at a given path
type PackageManager struct {
	InstallPath string
}

// NewPackageManager creates a new PackageManager
func NewPackageManager(path string) *PackageManager {
	return &PackageManager{InstallPath: path}
}

// Install installs a package
func (pm *PackageManager) Install(pkg *Package) error {
	d, err := yaml.Marshal(&pkg)
	if err != nil {
		return err
	}

	packagePath := path.Join(pm.InstallPath, pkg.Name)

	if _, err := os.Stat(packagePath); err == nil {
		return fmt.Errorf("'%s' already exists", packagePath)
	}

	d = append([]byte("#!/usr/bin/env whalebrew\n"), d...)

	if runtime.GOOS == "windows" {
		batch := []byte("@whalebrew %~dp0\\" + pkg.Name + " %*")
		batchPath := packagePath + ".bat"
		if err := ioutil.WriteFile(batchPath, batch, 0755); err != nil {
			return err
		}
	}

	return ioutil.WriteFile(packagePath, d, 0755)
}

// List lists installed packages
func (pm *PackageManager) List() (map[string]*Package, error) {
	packages := make(map[string]*Package)
	files, err := ioutil.ReadDir(pm.InstallPath)
	if err != nil {
		return packages, err
	}
	for _, file := range files {
		isPackage, err := IsPackage(path.Join(pm.InstallPath, file.Name()))
		if err != nil {
			// Check for various file errors here rather than in IsPackage so it
			// does not swallow errors when checking individual files.

			// permission denied
			if os.IsPermission(err) {
				continue
			}
			// dead symlink
			if os.IsNotExist(err) {
				continue
			}

			return packages, err
		}
		if isPackage {
			pkg, err := pm.Load(file.Name())
			if err != nil {
				return packages, err
			}
			packages[file.Name()] = pkg
		}
	}
	return packages, nil
}

// Load returns an installed package given its package name
func (pm *PackageManager) Load(name string) (*Package, error) {
	return LoadPackageFromPath(path.Join(pm.InstallPath, name))
}

// Uninstall uninstalls a package
func (pm *PackageManager) Uninstall(packageName string) error {
	p := path.Join(pm.InstallPath, packageName)
	isPackage, err := IsPackage(p)
	if err != nil {
		return err
	}
	if !isPackage {
		return fmt.Errorf("%s is not a Whalebrew package", p)
	}
	if runtime.GOOS == "windows" {
		batchPath := p + ".bat"
		if _, err := os.Stat(batchPath); err == nil {
			if err := os.Remove(batchPath); err != nil {
				return err
			}
		}
	}
	return os.Remove(p)
}

// IsPackage returns true if the given path is a whalebrew package
func IsPackage(path string) (bool, error) {
	f, err := os.Open(path)
	if err != nil {
		return false, err
	}
	defer f.Close()

	info, err := f.Stat()

	if err != nil {
		return false, err
	}

	if info.IsDir() {
		return false, nil
	}

	reader := bufio.NewReader(f)
	firstTwoBytes := make([]byte, 2)
	_, err = reader.Read(firstTwoBytes)

	if err == io.EOF {
		return false, nil
	}

	if err != nil {
		return false, err
	}

	if string(firstTwoBytes) != "#!" {
		return false, nil
	}

	line, _, err := reader.ReadLine()

	if err == io.EOF {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	if strings.HasPrefix(string(line), "/usr/bin/env whalebrew") {
		return true, nil
	}

	return false, nil
}
<|endoftext|>


<commit_before>package client

import (
	"github.com/michaelorr/goodall/pkg/db"
)

func Run() int {
	conn, err := db.Open()
	if err != nil {
		// TODO log
		return 1
	}
	err = db.Init()
	if err != nil {
		// TODO log
		return 2
	}

	response := make(chan int)
	go GatherMetrics(response)
	// TODO
	// select response
	// return that value
}

func GatherMetrics(killed chan int) {
	// TODO gather metrics
	// store in bolt
	// sleep for one second
}
<commit_msg>need args and return values<commit_after>package client

import (
	"github.com/michaelorr/goodall/pkg/db"
)

func Run() int {
	conn, err := db.Open()
	if err != nil {
		// TODO log
		return 1
	}
	err = db.Init(conn)
	if err != nil {
		// TODO log
		return 2
	}

	response := make(chan int)
	go GatherMetrics(response)
	// TODO
	// select response
	// return that value
	return 0
}

func GatherMetrics(killed chan int) {
	// TODO gather metrics
	// store in bolt
	// sleep for one second
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Jetstack cert-manager contributors.

Licensed 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.
*/

// This package was created to have a scheme that has the internal cert-manager types,
// and their conversion functions as well as the List object type registered, which is needed for ctl command like
// `convert` or `create certificaterequest`.
package ctl

import (
	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"

	acmeinstall "github.com/jetstack/cert-manager/pkg/internal/apis/acme/install"
	cminstall "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager/install"
	metainstall "github.com/jetstack/cert-manager/pkg/internal/apis/meta/install"
)

// Define a Scheme that has all cert-manager API types registered, including
// the internal API version, defaulting functions and conversion functions for
// all external versions.

var (
	// Scheme is a Kubernetes runtime.Scheme with all internal and external API
	// versions for cert-manager types registered.
	Scheme = runtime.NewScheme()
)

func init() {
	cminstall.Install(Scheme)
	acmeinstall.Install(Scheme)
	metainstall.Install(Scheme)

	// This is used to add the List object type
	listGroupVersion := schema.GroupVersionKind{Group: "", Version: runtime.APIVersionInternal}
	Scheme.AddKnownTypeWithName(listGroupVersion, &metainternalversion.List{})

	coreGroupVersion := schema.GroupVersion{Group: "", Version: "v1"}
	Scheme.AddKnownTypes(coreGroupVersion, &metav1.List{})
}
<commit_msg>revert scheme changes<commit_after>/*
Copyright 2020 The Jetstack cert-manager contributors.
Licensed 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.
*/

// This package was created to have a scheme that has the internal cert-manager types,
// and their conversion functions as well as the List object type registered, which is needed for ctl command like
// `convert` or `create certificaterequest`.
package ctl

import (
	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	kscheme "k8s.io/client-go/kubernetes/scheme"

	acmeinstall "github.com/jetstack/cert-manager/pkg/internal/apis/acme/install"
	cminstall "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager/install"
	metainstall "github.com/jetstack/cert-manager/pkg/internal/apis/meta/install"
)

// Define a Scheme that has all cert-manager API types registered, including
// the internal API version, defaulting functions and conversion functions for
// all external versions.

var (
	// Scheme is a Kubernetes runtime.Scheme with all internal and external API
	// versions for cert-manager types registered.
	Scheme = runtime.NewScheme()
)

func init() {
	cminstall.Install(Scheme)
	acmeinstall.Install(Scheme)
	metainstall.Install(Scheme)

	// This is used to add the List object type
	listGroupVersion := schema.GroupVersionKind{Group: "", Version: runtime.APIVersionInternal, Kind: "List"}
	Scheme.AddKnownTypeWithName(listGroupVersion, &metainternalversion.List{})

	metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
	utilruntime.Must(kscheme.AddToScheme(Scheme))
}
<|endoftext|>


<commit_before>package roles

import (
	"fmt"
	"io"

	tapi "github.com/k8sdb/apimachinery/api"
	"github.com/k8sdb/apimachinery/pkg/docker"
	kerr "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	apiv1 "k8s.io/client-go/pkg/api/v1"
	apps "k8s.io/client-go/pkg/apis/apps/v1beta1"
	batch "k8s.io/client-go/pkg/apis/batch/v1"
	extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
	rbac "k8s.io/client-go/pkg/apis/rbac/v1beta1"
)

const ServiceAccountName = docker.OperatorName

var policyRuleOperator = []rbac.PolicyRule{
	{
		APIGroups: []string{extensions.GroupName},
		Resources: []string{"thirdpartyresources"},
		Verbs:     []string{"get", "create"},
	},
	{
		APIGroups: []string{rbac.GroupName},
		Resources: []string{"roles"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{rbac.GroupName},
		Resources: []string{"rolebindings"},
		Verbs:     []string{"create", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"serviceaccounts"},
		Verbs:     []string{"create", "delete"},
	},
	{
		APIGroups: []string{apps.GroupName},
		Resources: []string{"statefulsets"},
		Verbs:     []string{"get", "create", "update", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"services", "secrets"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"endpoints"},
		Verbs:     []string{"get"},
	},
	{
		APIGroups: []string{batch.GroupName},
		Resources: []string{"jobs"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"pods"},
		Verbs:     []string{"get", "list", "delete", "deletecollection"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"persistentvolumeclaims"},
		Verbs:     []string{"list", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"events"},
		Verbs:     []string{"create"},
	},
	{
		APIGroups: []string{tapi.GroupName},
		Resources: []string{rbac.ResourceAll},
		Verbs:     []string{rbac.VerbAll},
	},
	{
		APIGroups: []string{"monitoring.coreos.com"},
		Resources: []string{"servicemonitors"},
		Verbs:     []string{"get", "create", "update"},
	},
}

func EnsureRBACStuff(client kubernetes.Interface, namespace string, out io.Writer) error {
	name := ServiceAccountName
	// Ensure ClusterRoles for operator
	clusterRoleOperator, err := client.RbacV1beta1().ClusterRoles().Get(name, metav1.GetOptions{})
	if err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}
		// Create new one
		role := &rbac.ClusterRole{
			ObjectMeta: metav1.ObjectMeta{
				Name: name,
			},
			Rules: policyRuleOperator,
		}
		if _, err := client.RbacV1beta1().ClusterRoles().Create(role); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created cluster role.")
	} else {
		// Update existing one
		clusterRoleOperator.Rules = policyRuleOperator
		if _, err := client.RbacV1beta1().ClusterRoles().Update(clusterRoleOperator); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully updated cluster role.")
	}

	// Ensure ServiceAccounts
	if _, err := client.CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{}); err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}
		sa := &apiv1.ServiceAccount{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
		}
		if _, err := client.CoreV1().ServiceAccounts(namespace).Create(sa); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created service account.")
	}

	var roleBindingRef = rbac.RoleRef{
		APIGroup: rbac.GroupName,
		Kind:     "ClusterRole",
		Name:     name,
	}
	var roleBindingSubjects = []rbac.Subject{
		{
			Kind:      rbac.ServiceAccountKind,
			Name:      name,
			Namespace: namespace,
		},
	}

	// Ensure ClusterRoleBindings
	roleBinding, err := client.RbacV1beta1().ClusterRoleBindings().Get(name, metav1.GetOptions{})
	if err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}

		roleBinding := &rbac.ClusterRoleBinding{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
			RoleRef:  roleBindingRef,
			Subjects: roleBindingSubjects,
		}

		if _, err := client.RbacV1beta1().ClusterRoleBindings().Create(roleBinding); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created cluster role bindings.")
	} else {
		roleBinding.RoleRef = roleBindingRef
		roleBinding.Subjects = roleBindingSubjects
		if _, err := client.RbacV1beta1().ClusterRoleBindings().Update(roleBinding); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully updated cluster role bindings.")
	}

	return nil
}
<commit_msg>Fix RBAC roles for kubedb-operator (#95)<commit_after>package roles

import (
	"fmt"
	"io"

	tapi "github.com/k8sdb/apimachinery/api"
	"github.com/k8sdb/apimachinery/pkg/docker"
	kerr "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	apiv1 "k8s.io/client-go/pkg/api/v1"
	apps "k8s.io/client-go/pkg/apis/apps/v1beta1"
	batch "k8s.io/client-go/pkg/apis/batch/v1"
	extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
	rbac "k8s.io/client-go/pkg/apis/rbac/v1beta1"
)

const ServiceAccountName = docker.OperatorName

var policyRuleOperator = []rbac.PolicyRule{
	{
		APIGroups: []string{extensions.GroupName},
		Resources: []string{"thirdpartyresources"},
		Verbs:     []string{"get", "create"},
	},
	{
		APIGroups: []string{rbac.GroupName},
		Resources: []string{"roles", "rolebindings"},
		Verbs:     []string{"get", "create", "update", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"serviceaccounts"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{apps.GroupName},
		Resources: []string{"statefulsets"},
		Verbs:     []string{"get", "create", "update", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"services", "secrets"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"endpoints"},
		Verbs:     []string{"get"},
	},
	{
		APIGroups: []string{batch.GroupName},
		Resources: []string{"jobs"},
		Verbs:     []string{"get", "create", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"pods"},
		Verbs:     []string{"get", "create", "list", "delete", "deletecollection"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"persistentvolumeclaims"},
		Verbs:     []string{"list", "delete"},
	},
	{
		APIGroups: []string{apiv1.GroupName},
		Resources: []string{"events"},
		Verbs:     []string{"create"},
	},
	{
		APIGroups: []string{tapi.GroupName},
		Resources: []string{rbac.ResourceAll},
		Verbs:     []string{rbac.VerbAll},
	},
	{
		APIGroups: []string{"monitoring.coreos.com"},
		Resources: []string{"servicemonitors"},
		Verbs:     []string{"get", "create", "update"},
	},
}

func EnsureRBACStuff(client kubernetes.Interface, namespace string, out io.Writer) error {
	name := ServiceAccountName
	// Ensure ClusterRoles for operator
	clusterRoleOperator, err := client.RbacV1beta1().ClusterRoles().Get(name, metav1.GetOptions{})
	if err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}
		// Create new one
		role := &rbac.ClusterRole{
			ObjectMeta: metav1.ObjectMeta{
				Name: name,
			},
			Rules: policyRuleOperator,
		}
		if _, err := client.RbacV1beta1().ClusterRoles().Create(role); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created cluster role.")
	} else {
		// Update existing one
		clusterRoleOperator.Rules = policyRuleOperator
		if _, err := client.RbacV1beta1().ClusterRoles().Update(clusterRoleOperator); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully updated cluster role.")
	}

	// Ensure ServiceAccounts
	if _, err := client.CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{}); err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}
		sa := &apiv1.ServiceAccount{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
		}
		if _, err := client.CoreV1().ServiceAccounts(namespace).Create(sa); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created service account.")
	}

	var roleBindingRef = rbac.RoleRef{
		APIGroup: rbac.GroupName,
		Kind:     "ClusterRole",
		Name:     name,
	}
	var roleBindingSubjects = []rbac.Subject{
		{
			Kind:      rbac.ServiceAccountKind,
			Name:      name,
			Namespace: namespace,
		},
	}

	// Ensure ClusterRoleBindings
	roleBinding, err := client.RbacV1beta1().ClusterRoleBindings().Get(name, metav1.GetOptions{})
	if err != nil {
		if !kerr.IsNotFound(err) {
			return err
		}

		roleBinding := &rbac.ClusterRoleBinding{
			ObjectMeta: metav1.ObjectMeta{
				Name:      name,
				Namespace: namespace,
			},
			RoleRef:  roleBindingRef,
			Subjects: roleBindingSubjects,
		}

		if _, err := client.RbacV1beta1().ClusterRoleBindings().Create(roleBinding); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully created cluster role bindings.")
	} else {
		roleBinding.RoleRef = roleBindingRef
		roleBinding.Subjects = roleBindingSubjects
		if _, err := client.RbacV1beta1().ClusterRoleBindings().Update(roleBinding); err != nil {
			return err
		}
		fmt.Fprintln(out, "Successfully updated cluster role bindings.")
	}

	return nil
}
<|endoftext|>


<commit_before>package database

import (
	"database/sql"
	"github.com/go-sql-driver/mysql"
)
<commit_msg>Delete database.go<commit_after><|endoftext|>


<commit_before>package plot

import (
	"code.google.com/p/plotinum/plt"
	"code.google.com/p/plotinum/vg"
	"code.google.com/p/plotinum/vg/veceps"
	"code.google.com/p/plotinum/vg/vecimg"
	"math/rand"
	"time"
	"testing"
)

func TestDrawImage(t *testing.T) {
	w, h := vg.Inches(4), vg.Inches(4)
	img, err := vecimg.New(w, h)
	if err != nil {
		t.Error(err)
	}
	da := plt.NewDrawArea(img, w, h)
	draw(da)
	err = img.SavePNG("test.png")
	if err != nil {
		t.Fatal(err)
	}
}

func TestDrawEps(t *testing.T) {
	w, h := vg.Inches(4), vg.Inches(4)
	da := plt.NewDrawArea(veceps.New(w, h, "test"), w, h)
	draw(da)
	err := da.Canvas.(*veceps.Canvas).Save("test.eps")
	if err != nil {
		t.Fatal(err)
	}
}

// draw draws a simple test plot
func draw(da *plt.DrawArea) {
	p := plt.New()
	p.Title.Text = "Title"
	p.Y.Label.Text = "Y Label"
	vs0 := make(Values, 10)
	rand.Seed(time.Now().UnixNano())
	for i := range vs0 {
		vs0[i] = rand.Float64()*1000
	}
	vs1 := make(Values, 10)
	for i := range vs1 {
		vs1[i] = rand.NormFloat64()*200 + 500
	}
	vs2 := make(Values, 10)
	for i := range vs2 {
		vs2[i] = rand.ExpFloat64()*300
	}
	p.AddData(MakeBox(vg.Points(18), 0, vs0))
	p.AddData(MakeBox(vg.Points(18), 1, vs1))
	p.AddData(MakeBox(vg.Points(18), 2, vs2))
	p.X.Tick.Marker = plt.ConstantTicks([]plt.Tick{
		{0, "Uniform",}, {1, "Normal",}, {2, "Exponential"},
	})
	p.X.Tick.Label.Font.Size = vg.Points(12)
	p.X.Tick.Width = 0
	p.X.Tick.Length = 0
	p.X.Width = 0

	p.Y.Min = 0
	p.Y.Max = 1000
	p.Draw(da)
}
<commit_msg>Small changes to the test plot. These changes demonstrate how you can lay out a nominal X axis.<commit_after>package plot

import (
	"code.google.com/p/plotinum/plt"
	"code.google.com/p/plotinum/vg"
	"code.google.com/p/plotinum/vg/veceps"
	"code.google.com/p/plotinum/vg/vecimg"
	"math/rand"
	"time"
	"testing"
)

func TestDrawImage(t *testing.T) {
	w, h := vg.Inches(4), vg.Inches(4)
	img, err := vecimg.New(w, h)
	if err != nil {
		t.Error(err)
	}
	da := plt.NewDrawArea(img, w, h)
	draw(da)
	err = img.SavePNG("test.png")
	if err != nil {
		t.Fatal(err)
	}
}

func TestDrawEps(t *testing.T) {
	w, h := vg.Inches(4), vg.Inches(4)
	da := plt.NewDrawArea(veceps.New(w, h, "test"), w, h)
	draw(da)
	err := da.Canvas.(*veceps.Canvas).Save("test.eps")
	if err != nil {
		t.Fatal(err)
	}
}

// draw draws a simple test plot
func draw(da *plt.DrawArea) {
	p := plt.New()
	p.Title.Text = "Title"
	p.Y.Label.Text = "Y Label"
	vs0 := make(Values, 10)
	rand.Seed(time.Now().UnixNano())
	for i := range vs0 {
		vs0[i] = rand.Float64()*1000
	}
	vs1 := make(Values, 10)
	for i := range vs1 {
		vs1[i] = rand.NormFloat64()*200 + 500
	}
	vs2 := make(Values, 10)
	for i := range vs2 {
		vs2[i] = rand.ExpFloat64()*300
	}
	p.AddData(MakeBox(vg.Points(20), 0, vs0))
	p.AddData(MakeBox(vg.Points(20), 1, vs1))
	p.AddData(MakeBox(vg.Points(20), 2, vs2))
	p.X.Tick.Marker = plt.ConstantTicks([]plt.Tick{
		{0, "Uniform\nDistribution",}, {1, "Normal\nDistribution",},
		{2, "Exponential\nDistribution"},
	})
	p.Y.Padding = p.X.Tick.Label.Width("Uniform\nDistribution")/2
	p.X.Tick.Label.Font.Size = vg.Points(12)
	p.X.Tick.Width = 0
	p.X.Tick.Length = 0
	p.X.Width = 0

	p.Y.Min = 0
	p.Y.Max = 1000
	p.Draw(da)
}
<|endoftext|>


<commit_before>/**
 * Licensed 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 realis

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"github.com/samuel/go-zookeeper/zk"
	"strconv"
	"strings"
	"time"
)

type Endpoint struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

type ServiceInstance struct {
	Service             Endpoint            `json:"serviceEndpoint"`
	AdditionalEndpoints map[string]Endpoint `json:"additionalEndpoints"`
	Status              string              `json:"status"`
}

// Loads leader from ZK endpoint.
func LeaderFromZK(cluster Cluster) (string, error) {

	endpoints := strings.Split(cluster.ZK, ",")
	//TODO (rdelvalle): When enabling debugging, change logger here
	c, _, err := zk.Connect(endpoints, time.Second*10, zk.WithoutLogger())
	defer c.Close()
	if err != nil {
		return "", errors.Wrap(err, "Failed to connect to Zookeeper at "+cluster.ZK)
	}

	children, _, _, err := c.ChildrenW(cluster.SchedZKPath)
	if err != nil {
		return "", errors.Wrapf(err, "Path %s doesn't exist on Zookeeper ", cluster.SchedZKPath)
	}

	serviceInst := new(ServiceInstance)

	for _, child := range children {

		// Only the leader will start with member_
		if strings.HasPrefix(child, "member_") {

			data, _, err := c.Get(cluster.SchedZKPath + "/" + child)
			if err != nil {
				return "", errors.Wrap(err, "Error fetching contents of leader")
			}

			err = json.Unmarshal([]byte(data), serviceInst)
			if err != nil {
				return "", errors.Wrap(err, "Unable to unmarshall contents of leader")
			}

			// Should only be one endpoint
			if len(serviceInst.AdditionalEndpoints) > 1 {
				fmt.Errorf("Ambiguous end points schemes")
			}

			var scheme, host, port string
			for k, v := range serviceInst.AdditionalEndpoints {
				scheme = k
				host = v.Host
				port = strconv.Itoa(v.Port)
			}

			return scheme + "://" + host + ":" + port, nil
		}
	}

	return "", errors.New("No leader found")
}
<commit_msg>Small bug fix. Can't close a connection that doesn't exist<commit_after>/**
 * Licensed 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 realis

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"github.com/samuel/go-zookeeper/zk"
	"strconv"
	"strings"
	"time"
)

type Endpoint struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

type ServiceInstance struct {
	Service             Endpoint            `json:"serviceEndpoint"`
	AdditionalEndpoints map[string]Endpoint `json:"additionalEndpoints"`
	Status              string              `json:"status"`
}

// Loads leader from ZK endpoint.
func LeaderFromZK(cluster Cluster) (string, error) {

	endpoints := strings.Split(cluster.ZK, ",")

	//TODO (rdelvalle): When enabling debugging, change logger here
	c, _, err := zk.Connect(endpoints, time.Second*10, zk.WithoutLogger())
	if err != nil {
		return "", errors.Wrap(err, "Failed to connect to Zookeeper at "+cluster.ZK)
	}

	defer c.Close()

	children, _, _, err := c.ChildrenW(cluster.SchedZKPath)
	if err != nil {
		return "", errors.Wrapf(err, "Path %s doesn't exist on Zookeeper ", cluster.SchedZKPath)
	}

	serviceInst := new(ServiceInstance)

	for _, child := range children {

		// Only the leader will start with member_
		if strings.HasPrefix(child, "member_") {

			data, _, err := c.Get(cluster.SchedZKPath + "/" + child)
			if err != nil {
				return "", errors.Wrap(err, "Error fetching contents of leader")
			}

			err = json.Unmarshal([]byte(data), serviceInst)
			if err != nil {
				return "", errors.Wrap(err, "Unable to unmarshall contents of leader")
			}

			// Should only be one endpoint
			if len(serviceInst.AdditionalEndpoints) > 1 {
				fmt.Errorf("Ambiguous end points schemes")
			}

			var scheme, host, port string
			for k, v := range serviceInst.AdditionalEndpoints {
				scheme = k
				host = v.Host
				port = strconv.Itoa(v.Port)
			}

			return scheme + "://" + host + ":" + port, nil
		}
	}

	return "", errors.New("No leader found")
}
<|endoftext|>