<commit_before>// +build integration

package tests

import (
	"math/rand"
	"os"
	"testing"

	"github.com/deis/deis/tests/utils"
)

var (
	appsCreateCmd          = "apps:create {{.AppName}}"
	appsCreateCmdNoRemote  = "apps:create {{.AppName}} --no-remote"
	appsCreateCmdBuildpack = "apps:create {{.AppName}} --buildpack https://example.com"
	appsListCmd            = "apps:list"
	appsRunCmd             = "apps:run echo hello"
	appsOpenCmd            = "apps:open --app={{.AppName}}"
	appsLogsCmd            = "apps:logs --app={{.AppName}}"
	appsInfoCmd            = "apps:info --app={{.AppName}}"
	appsDestroyCmd         = "apps:destroy --app={{.AppName}} --confirm={{.AppName}}"
)

func randomString(n int) string {
	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func TestApps(t *testing.T) {
	params := appsSetup(t)
	appsCreateTest(t, params)
	appsListTest(t, params, false)
	appsLogsTest(t, params)
	appsInfoTest(t, params)
	appsRunTest(t, params)
	appsOpenTest(t, params)
	appsDestroyTest(t, params)
	appsListTest(t, params, true)
}

func appsSetup(t *testing.T) *utils.DeisTestConfig {
	cfg := utils.GetGlobalConfig()
	cfg.AppName = "appssample"
	utils.Execute(t, authLoginCmd, cfg, false, "")
	utils.Execute(t, gitCloneCmd, cfg, false, "")
	return cfg
}

func appsCreateTest(t *testing.T, params *utils.DeisTestConfig) {
	wd, _ := os.Getwd()
	defer os.Chdir(wd)
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	// TODO: move --buildpack to client unit tests
	utils.Execute(t, appsCreateCmdBuildpack, params, false, "BUILDPACK_URL")
	utils.Execute(t, appsDestroyCmd, params, false, "")
	utils.Execute(t, appsCreateCmd, params, false, "")
	utils.Execute(t, appsCreateCmd, params, true, "App with this Id already exists")
}

func appsDestroyTest(t *testing.T, params *utils.DeisTestConfig) {
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, appsDestroyCmd, params, false, "")
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
	if err := utils.Rmdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
}

func appsInfoTest(t *testing.T, params *utils.DeisTestConfig) {
	utils.Execute(t, appsInfoCmd, params, false, "")
}

func appsListTest(t *testing.T, params *utils.DeisTestConfig, notflag bool) {
	utils.CheckList(t, appsListCmd, params, params.AppName, notflag)
}

func appsLogsTest(t *testing.T, params *utils.DeisTestConfig) {
	cmd := appsLogsCmd
	// test for application lifecycle logs
	utils.Execute(t, cmd, params, false, "204 NO CONTENT")
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, gitPushCmd, params, false, "")
	utils.Curl(t, params)
	utils.Execute(t, cmd, params, false, "created initial release")
	utils.Execute(t, cmd, params, false, "listening on 5000...")
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
}

func appsOpenTest(t *testing.T, params *utils.DeisTestConfig) {
	utils.Curl(t, params)
}

func appsRunTest(t *testing.T, params *utils.DeisTestConfig) {
	cmd := appsRunCmd
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, cmd, params, false, "hello")
	utils.Execute(t, "apps:run env", params, true, "GIT_SHA")
	// run a REALLY large command to test https://github.com/deis/deis/issues/2046
	largeString := randomString(1024)
	utils.Execute(t, "apps:run echo "+largeString, params, false, largeString)
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, cmd, params, true, "Not found")
}
<commit_msg>fix(tests): destroy without --app flag to remove git remote<commit_after>// +build integration

package tests

import (
	"math/rand"
	"os"
	"testing"

	"github.com/deis/deis/tests/utils"
)

var (
	appsCreateCmd          = "apps:create {{.AppName}}"
	appsCreateCmdNoRemote  = "apps:create {{.AppName}} --no-remote"
	appsCreateCmdBuildpack = "apps:create {{.AppName}} --buildpack https://example.com"
	appsListCmd            = "apps:list"
	appsRunCmd             = "apps:run echo hello"
	appsOpenCmd            = "apps:open --app={{.AppName}}"
	appsLogsCmd            = "apps:logs --app={{.AppName}}"
	appsInfoCmd            = "apps:info --app={{.AppName}}"
	appsDestroyCmd         = "apps:destroy --app={{.AppName}} --confirm={{.AppName}}"
	appsDestroyCmdNoApp    = "apps:destroy --confirm={{.AppName}}"
)

func randomString(n int) string {
	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func TestApps(t *testing.T) {
	params := appsSetup(t)
	appsCreateTest(t, params)
	appsListTest(t, params, false)
	appsLogsTest(t, params)
	appsInfoTest(t, params)
	appsRunTest(t, params)
	appsOpenTest(t, params)
	appsDestroyTest(t, params)
	appsListTest(t, params, true)
}

func appsSetup(t *testing.T) *utils.DeisTestConfig {
	cfg := utils.GetGlobalConfig()
	cfg.AppName = "appssample"
	utils.Execute(t, authLoginCmd, cfg, false, "")
	utils.Execute(t, gitCloneCmd, cfg, false, "")
	return cfg
}

func appsCreateTest(t *testing.T, params *utils.DeisTestConfig) {
	wd, _ := os.Getwd()
	defer os.Chdir(wd)
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	// TODO: move --buildpack to client unit tests
	utils.Execute(t, appsCreateCmdBuildpack, params, false, "BUILDPACK_URL")
	utils.Execute(t, appsDestroyCmdNoApp, params, false, "")
	utils.Execute(t, appsCreateCmd, params, false, "")
	utils.Execute(t, appsCreateCmd, params, true, "App with this Id already exists")
}

func appsDestroyTest(t *testing.T, params *utils.DeisTestConfig) {
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, appsDestroyCmd, params, false, "")
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
	if err := utils.Rmdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
}

func appsInfoTest(t *testing.T, params *utils.DeisTestConfig) {
	utils.Execute(t, appsInfoCmd, params, false, "")
}

func appsListTest(t *testing.T, params *utils.DeisTestConfig, notflag bool) {
	utils.CheckList(t, appsListCmd, params, params.AppName, notflag)
}

func appsLogsTest(t *testing.T, params *utils.DeisTestConfig) {
	cmd := appsLogsCmd
	// test for application lifecycle logs
	utils.Execute(t, cmd, params, false, "204 NO CONTENT")
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, gitPushCmd, params, false, "")
	utils.Curl(t, params)
	utils.Execute(t, cmd, params, false, "created initial release")
	utils.Execute(t, cmd, params, false, "listening on 5000...")
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
}

func appsOpenTest(t *testing.T, params *utils.DeisTestConfig) {
	utils.Curl(t, params)
}

func appsRunTest(t *testing.T, params *utils.DeisTestConfig) {
	cmd := appsRunCmd
	if err := utils.Chdir(params.ExampleApp); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, cmd, params, false, "hello")
	utils.Execute(t, "apps:run env", params, true, "GIT_SHA")
	// run a REALLY large command to test https://github.com/deis/deis/issues/2046
	largeString := randomString(1024)
	utils.Execute(t, "apps:run echo "+largeString, params, false, largeString)
	if err := utils.Chdir(".."); err != nil {
		t.Fatal(err)
	}
	utils.Execute(t, cmd, params, true, "Not found")
}
<|endoftext|>


<commit_before>package errorx

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

const (
	Info = iota
	Verbose
	Debug
	Trace
)

// verbosity variable stores global verbosity setting for errorx package
// based on it's value different level of error details will be provided
// by Error, Errorf, Json and Jsonf
var verbosity int

// Errorx is a more feature rich implementation of error interface inspired
// by PostgreSQL error style guide
type Errorx struct {
	Code    int      `json:"error_code"`
	Message string   `json:"error_message"`
	Details []string `json:"error_details,omitempty"`
	Cause   error    `json:"cause,omitempty"`
	Stack   Stack    `json:"stack,omitempty"`
}

type StackFrame struct {
	File     string `json:"file,omitempty"`
	Line     int    `json:"line,omitempty"`
	Function string `json:"function,omitempty"`
}

type Stack []StackFrame

func (s Stack) String() string {
	var buffer bytes.Buffer
	for i := 0; i < len(s); i++ {
		buffer.WriteString(fmt.Sprintf("%s:%d %s\n", s[i].File, s[i].Line, s[i].Function))
	}
	return buffer.String()
}

// New returns an error with error code and error messages provided in
// function params
func New(code int, ErrorMsg ...string) *Errorx {
	e := Errorx{Code: code}

	msgCount := len(ErrorMsg)
	if msgCount > 0 {
		e.Message = ErrorMsg[0]
	}
	if msgCount > 1 {
		e.Details = ErrorMsg[1:]
	}

	return &e
}

// Wrap
func (e *Errorx) Wrap(err error) {
	e.Cause = err
}

// SetVerbosity changes global verbosity setting
func SetVerbosity(v int) {
	verbosity = v
}

// ErrorCode returns Errorx error code value. It's intended primarily to allow
// easy error comparison / matching
func (e Errorx) ErrorCode() int {
	return e.Code
}

// Error returns a string representation of errorx. It includes at least
// error code and message. Error details and hint are provided depending
// on verbosity level set
func (e Errorx) Error() string {
	maxMsg := len(e.Details)
	if maxMsg > verbosity {
		maxMsg = verbosity
	}

	switch verbosity {
	case 0:
		return fmt.Sprintf("error %d: %s", e.Code, e.Message)
	case 1:
		if e.Cause == nil {
			return fmt.Sprintf("error %d: %s | %s", e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "))
		}
		return fmt.Sprintf("error %d: %s | %s\ncause: %s", e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error())
	case 2:
		e.getTrace()

		if e.Cause == nil {
			return fmt.Sprintf("%s:%d: error %d: %s | %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "))
		}
		return fmt.Sprintf("%s:%d: error %d: %s | %s\ncause: %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error())
	default:
		e.getTrace()

		if e.Cause == nil {
			return fmt.Sprintf("%s:%d: error %d: %s | %s\n%s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Stack.String())
		}
		return fmt.Sprintf("%s:%d: error %d: %s | %s\ncause: %s\n%s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error(), e.Stack.String())
	}
}

// Errorf is a variant of Error that formats according to ErrorMsg
// speficier and returns resulting string. Error details and hint
// will not be formated
/*
func (e Errorx) Errorf(params ...interface{}) string {
	if verbosity == 0 || (e.ErrorDetails == "" && e.ErrorHint == "") {
		return fmt.Sprintf("error %d: %s", e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...))
	}
	if verbosity == 1 {
		return fmt.Sprintf("error %d: %s - %s", e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...), e.ErrorDetails)
	}
	_, fn, line, _ := runtime.Caller(1)
	_, file := filepath.Split(fn)
	return fmt.Sprintf("%s:%d: error %d: %s - %s - %s", file, line, e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...), e.ErrorDetails, e.ErrorHint)
}*/

// Json returns a json representation (as []byte) of errorx and error
// if marshaling fails
func (e Errorx) Json() ([]byte, error) {
	e.getTrace()
	err := e.verbositySubset(verbosity > 1)

	return json.Marshal(err)
}

// Jsonf is a variant of Json that formats according to ErrorMsg
// speficier and returns resulting string. Error details and hint
// will not be formated
/*
func (e Errorx) Jsonf(params ...interface{}) ([]byte, error) {
	e.getTrace()
	err := e.verbositySubset()

	return json.Marshal(err)
}*/

func (e Errorx) verbositySubset(trace bool) Errorx {
	err := Errorx{Code: e.Code, Message: e.Message}
	maxMsg := len(e.Details)
	if maxMsg > verbosity {
		maxMsg = verbosity
	}

	if verbosity > 0 {
		err.Details = e.Details[0:maxMsg]
	}
	if verbosity > 1 {
		if e.Cause != nil {
			if cause, ok := e.Cause.(Errorx); ok {
				err.Cause = cause.verbositySubset(false)
			} else {
				err.Cause = Errorx{Message: e.Cause.Error()}
			}
		}
		err.Stack = e.Stack
	}
	return err
}

func (e *Errorx) getTrace() {
	if verbosity < 2 {
		return
	}

	if verbosity == 2 {
		pc, fn, line, ok := runtime.Caller(2)
		if !ok {
			return
		}

		s := StackFrame{}
		s.Function = funcName(pc)
		s.Line = line
		_, s.File = filepath.Split(fn)

		e.Stack = []StackFrame{s}
		return
	}

	for i := 2; ; i++ {
		e.Stack = make([]StackFrame, 0)
		pc, fn, line, ok := runtime.Caller(i)
		if !ok {
			// no more frames - we're done
			break
		}

		f := StackFrame{File: fn, Line: line, Function: funcName(pc)}
		e.Stack = append(e.Stack, f)
	}
}

// funcName gets the name of the function at pointer or "??" if one can't be found
func funcName(pc uintptr) string {
	if f := runtime.FuncForPC(pc); f != nil {
		return f.Name()
	}
	return "??"
}
<commit_msg>fix panic<commit_after>package errorx

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

const (
	Info = iota
	Verbose
	Debug
	Trace
)

// verbosity variable stores global verbosity setting for errorx package
// based on it's value different level of error details will be provided
// by Error, Errorf, Json and Jsonf
var verbosity int

// Errorx is a more feature rich implementation of error interface inspired
// by PostgreSQL error style guide
type Errorx struct {
	Code    int      `json:"error_code"`
	Message string   `json:"error_message"`
	Details []string `json:"error_details,omitempty"`
	Cause   error    `json:"cause,omitempty"`
	Stack   Stack    `json:"stack,omitempty"`
}

type StackFrame struct {
	File     string `json:"file,omitempty"`
	Line     int    `json:"line,omitempty"`
	Function string `json:"function,omitempty"`
}

type Stack []StackFrame

func (s Stack) String() string {
	var buffer bytes.Buffer
	for i := 0; i < len(s); i++ {
		buffer.WriteString(fmt.Sprintf("\n%s:%d %s", s[i].File, s[i].Line, s[i].Function))
	}
	return buffer.String()
}

// New returns an error with error code and error messages provided in
// function params
func New(code int, ErrorMsg ...string) *Errorx {
	e := Errorx{Code: code}

	msgCount := len(ErrorMsg)
	if msgCount > 0 {
		e.Message = ErrorMsg[0]
	}
	if msgCount > 1 {
		e.Details = ErrorMsg[1:]
	}

	return &e
}

// Wrap
func (e *Errorx) Wrap(err error) {
	e.Cause = err
}

// SetVerbosity changes global verbosity setting
func SetVerbosity(v int) {
	verbosity = v
}

// ErrorCode returns Errorx error code value. It's intended primarily to allow
// easy error comparison / matching
func (e Errorx) ErrorCode() int {
	return e.Code
}

// Error returns a string representation of errorx. It includes at least
// error code and message. Error details and hint are provided depending
// on verbosity level set
func (e Errorx) Error() string {
	maxMsg := len(e.Details)
	if maxMsg > verbosity {
		maxMsg = verbosity
	}

	switch verbosity {
	case 0:
		return fmt.Sprintf("error %d: %s", e.Code, e.Message)
	case 1:
		if e.Cause == nil {
			return fmt.Sprintf("error %d: %s | %s", e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "))
		}
		return fmt.Sprintf("error %d: %s | %s\ncause: %s", e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error())
	case 2:
		e.getTrace()

		if e.Cause == nil {
			return fmt.Sprintf("%s:%d: error %d: %s | %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "))
		}
		return fmt.Sprintf("%s:%d: error %d: %s | %s\ncause: %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error())
	default:
		e.getTrace()

		if e.Cause == nil {
			return fmt.Sprintf("%s:%d: error %d: %s | %s %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Stack.String())
		}
		return fmt.Sprintf("%s:%d: error %d: %s | %s\ncause: %s %s", e.Stack[0].File, e.Stack[0].Line, e.Code, e.Message, strings.Join(e.Details[0:maxMsg], "; "), e.Cause.Error(), e.Stack.String())
	}
}

// Errorf is a variant of Error that formats according to ErrorMsg
// speficier and returns resulting string. Error details and hint
// will not be formated
/*
func (e Errorx) Errorf(params ...interface{}) string {
	if verbosity == 0 || (e.ErrorDetails == "" && e.ErrorHint == "") {
		return fmt.Sprintf("error %d: %s", e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...))
	}
	if verbosity == 1 {
		return fmt.Sprintf("error %d: %s - %s", e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...), e.ErrorDetails)
	}
	_, fn, line, _ := runtime.Caller(1)
	_, file := filepath.Split(fn)
	return fmt.Sprintf("%s:%d: error %d: %s - %s - %s", file, line, e.ErrorCode, fmt.Sprintf(e.ErrorMsg, params...), e.ErrorDetails, e.ErrorHint)
}*/

// Json returns a json representation (as []byte) of errorx and error
// if marshaling fails
func (e Errorx) Json() ([]byte, error) {
	e.getTrace()
	err := e.verbositySubset(verbosity > 1)

	return json.Marshal(err)
}

// Jsonf is a variant of Json that formats according to ErrorMsg
// speficier and returns resulting string. Error details and hint
// will not be formated
/*
func (e Errorx) Jsonf(params ...interface{}) ([]byte, error) {
	e.getTrace()
	err := e.verbositySubset()

	return json.Marshal(err)
}*/

func (e Errorx) verbositySubset(trace bool) Errorx {
	err := Errorx{Code: e.Code, Message: e.Message}
	maxMsg := len(e.Details)
	if maxMsg > verbosity {
		maxMsg = verbosity
	}

	if verbosity > 0 {
		err.Details = e.Details[0:maxMsg]
	}
	if verbosity > 1 {
		if e.Cause != nil {
			if cause, ok := e.Cause.(Errorx); ok {
				err.Cause = cause.verbositySubset(false)
			} else {
				err.Cause = Errorx{Message: e.Cause.Error()}
			}
		}
		err.Stack = e.Stack
	}
	return err
}

func (e *Errorx) getTrace() {
	if verbosity < 2 {
		return
	}

	if verbosity == 2 {
		pc, fn, line, ok := runtime.Caller(2)
		if !ok {
			return
		}

		s := StackFrame{}
		s.Function = funcName(pc)
		s.Line = line
		_, s.File = filepath.Split(fn)

		e.Stack = []StackFrame{s}
		return
	}

	e.Stack = make([]StackFrame, 0)

	for i := 2; ; i++ {
		pc, fn, line, ok := runtime.Caller(i)
		if !ok {
			// no more frames - we're done
			break
		}

		f := StackFrame{File: fn, Line: line, Function: funcName(pc)}
		e.Stack = append(e.Stack, f)
	}
}

// funcName gets the name of the function at pointer or "??" if one can't be found
func funcName(pc uintptr) string {
	if f := runtime.FuncForPC(pc); f != nil {
		return f.Name()
	}
	return "??"
}
<|endoftext|>


<commit_before>package autonat

import (
	"time"

	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
)

var _ inet.Notifiee = (*AmbientAutoNAT)(nil)

func (as *AmbientAutoNAT) Listen(net inet.Network, a ma.Multiaddr)      {}
func (as *AmbientAutoNAT) ListenClose(net inet.Network, a ma.Multiaddr) {}
func (as *AmbientAutoNAT) OpenedStream(net inet.Network, s inet.Stream) {}
func (as *AmbientAutoNAT) ClosedStream(net inet.Network, s inet.Stream) {}

func (as *AmbientAutoNAT) Connected(net inet.Network, c inet.Conn) {
	p := c.RemotePeer()

	go func() {
		// add some delay for identify
		time.Sleep(250 * time.Millisecond)

		protos, err := as.host.Peerstore().SupportsProtocols(p, AutoNATProto)
		if err != nil {
			log.Debugf("error retrieving supported protocols for peer %s: %s", p, err)
			return
		}

		if len(protos) > 0 {
			log.Infof("Discovered AutoNAT peer %s", p.Pretty())
			as.mx.Lock()
			as.peers[p] = struct{}{}
			as.mx.Unlock()
		}
	}()
}

func (as *AmbientAutoNAT) Disconnected(net inet.Network, c inet.Conn) {}
<commit_msg>increase identify delay to 500ms<commit_after>package autonat

import (
	"time"

	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
)

var _ inet.Notifiee = (*AmbientAutoNAT)(nil)

func (as *AmbientAutoNAT) Listen(net inet.Network, a ma.Multiaddr)      {}
func (as *AmbientAutoNAT) ListenClose(net inet.Network, a ma.Multiaddr) {}
func (as *AmbientAutoNAT) OpenedStream(net inet.Network, s inet.Stream) {}
func (as *AmbientAutoNAT) ClosedStream(net inet.Network, s inet.Stream) {}

func (as *AmbientAutoNAT) Connected(net inet.Network, c inet.Conn) {
	p := c.RemotePeer()

	go func() {
		// add some delay for identify
		time.Sleep(500 * time.Millisecond)

		protos, err := as.host.Peerstore().SupportsProtocols(p, AutoNATProto)
		if err != nil {
			log.Debugf("error retrieving supported protocols for peer %s: %s", p, err)
			return
		}

		if len(protos) > 0 {
			log.Infof("Discovered AutoNAT peer %s", p.Pretty())
			as.mx.Lock()
			as.peers[p] = struct{}{}
			as.mx.Unlock()
		}
	}()
}

func (as *AmbientAutoNAT) Disconnected(net inet.Network, c inet.Conn) {}
<|endoftext|>


<commit_before>package connmgr

import (
	"context"
	"sort"
	"sync"
	"time"

	logging "github.com/ipfs/go-log"
	ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

var log = logging.Logger("connmgr")

type BasicConnMgr struct {
	highWater int
	lowWater  int

	gracePeriod time.Duration

	peers     map[peer.ID]*peerInfo
	connCount int

	lk sync.Mutex

	lastTrim time.Time
}

var _ ifconnmgr.ConnManager = (*BasicConnMgr)(nil)

func NewConnManager(low, hi int, grace time.Duration) *BasicConnMgr {
	return &BasicConnMgr{
		highWater:   hi,
		lowWater:    low,
		gracePeriod: grace,
		peers:       make(map[peer.ID]*peerInfo),
	}
}

type peerInfo struct {
	tags  map[string]int
	value int

	conns map[inet.Conn]time.Time

	firstSeen time.Time
}

func (cm *BasicConnMgr) TrimOpenConns(ctx context.Context) {
	defer log.EventBegin(ctx, "connCleanup").Done()
	for _, c := range cm.getConnsToClose(ctx) {
		log.Info("closing conn: ", c.RemotePeer())
		log.Event(ctx, "closeConn", c.RemotePeer())
		c.Close()
	}
}

func (cm *BasicConnMgr) getConnsToClose(ctx context.Context) []inet.Conn {
	cm.lk.Lock()
	defer cm.lk.Unlock()
	if cm.lowWater == 0 || cm.highWater == 0 {
		// disabled
		return nil
	}
	now := time.Now()
	cm.lastTrim = now

	if len(cm.peers) < cm.lowWater {
		log.Info("open connection count below limit")
		return nil
	}

	var infos []*peerInfo

	for _, inf := range cm.peers {
		infos = append(infos, inf)
	}

	sort.Slice(infos, func(i, j int) bool {
		return infos[i].value < infos[j].value
	})

	closeCount := len(infos) - cm.lowWater
	toclose := infos[:closeCount]

	// 2x number of peers we're disconnecting from because we may have more
	// than one connection per peer. Slightly over allocating isn't an issue
	// as this is a very short-lived array.
	closed := make([]inet.Conn, 0, len(toclose)*2)

	for _, inf := range toclose {
		// TODO: should we be using firstSeen or the time associated with the connection itself?
		if inf.firstSeen.Add(cm.gracePeriod).After(now) {
			continue
		}

		// TODO: if a peer has more than one connection, maybe only close one?
		for c := range inf.conns {
			// TODO: probably don't want to always do this in a goroutine
			closed = append(closed, c)
		}
	}

	return closed
}

func (cm *BasicConnMgr) GetTagInfo(p peer.ID) *ifconnmgr.TagInfo {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		return nil
	}

	out := &ifconnmgr.TagInfo{
		FirstSeen: pi.firstSeen,
		Value:     pi.value,
		Tags:      make(map[string]int),
		Conns:     make(map[string]time.Time),
	}

	for t, v := range pi.tags {
		out.Tags[t] = v
	}
	for c, t := range pi.conns {
		out.Conns[c.RemoteMultiaddr().String()] = t
	}

	return out
}

func (cm *BasicConnMgr) TagPeer(p peer.ID, tag string, val int) {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		log.Info("tried to tag conn from untracked peer: ", p)
		return
	}

	pi.value += (val - pi.tags[tag])
	pi.tags[tag] = val
}

func (cm *BasicConnMgr) UntagPeer(p peer.ID, tag string) {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		log.Info("tried to remove tag from untracked peer: ", p)
		return
	}

	pi.value -= pi.tags[tag]
	delete(pi.tags, tag)
}

type CMInfo struct {
	LowWater    int
	HighWater   int
	LastTrim    time.Time
	GracePeriod time.Duration
	ConnCount   int
}

func (cm *BasicConnMgr) GetInfo() CMInfo {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	return CMInfo{
		HighWater:   cm.highWater,
		LowWater:    cm.lowWater,
		LastTrim:    cm.lastTrim,
		GracePeriod: cm.gracePeriod,
		ConnCount:   cm.connCount,
	}
}

func (cm *BasicConnMgr) Notifee() inet.Notifiee {
	return (*cmNotifee)(cm)
}

type cmNotifee BasicConnMgr

func (nn *cmNotifee) cm() *BasicConnMgr {
	return (*BasicConnMgr)(nn)
}

func (nn *cmNotifee) Connected(n inet.Network, c inet.Conn) {
	cm := nn.cm()

	cm.lk.Lock()
	defer cm.lk.Unlock()

	pinfo, ok := cm.peers[c.RemotePeer()]
	if !ok {
		pinfo = &peerInfo{
			firstSeen: time.Now(),
			tags:      make(map[string]int),
			conns:     make(map[inet.Conn]time.Time),
		}
		cm.peers[c.RemotePeer()] = pinfo
	}

	_, ok = pinfo.conns[c]
	if ok {
		log.Error("received connected notification for conn we are already tracking: ", c.RemotePeer())
		return
	}

	pinfo.conns[c] = time.Now()
	cm.connCount++

	if cm.connCount > nn.highWater {
		if cm.lastTrim.IsZero() || time.Since(cm.lastTrim) > time.Second*10 {
			go cm.TrimOpenConns(context.Background())
		}
	}
}

func (nn *cmNotifee) Disconnected(n inet.Network, c inet.Conn) {
	cm := nn.cm()

	cm.lk.Lock()
	defer cm.lk.Unlock()

	cinf, ok := cm.peers[c.RemotePeer()]
	if !ok {
		log.Error("received disconnected notification for peer we are not tracking: ", c.RemotePeer())
		return
	}

	_, ok = cinf.conns[c]
	if !ok {
		log.Error("received disconnected notification for conn we are not tracking: ", c.RemotePeer())
		return
	}

	delete(cinf.conns, c)
	cm.connCount--
	if len(cinf.conns) == 0 {
		delete(cm.peers, c.RemotePeer())
	}
}

func (nn *cmNotifee) Listen(n inet.Network, addr ma.Multiaddr)      {}
func (nn *cmNotifee) ListenClose(n inet.Network, addr ma.Multiaddr) {}
func (nn *cmNotifee) OpenedStream(inet.Network, inet.Stream)        {}
func (nn *cmNotifee) ClosedStream(inet.Network, inet.Stream)        {}
<commit_msg>add docs to BasicConnMgr<commit_after>package connmgr

import (
	"context"
	"sort"
	"sync"
	"time"

	logging "github.com/ipfs/go-log"
	"github.com/libp2p/go-libp2p-interface-connmgr"
	inet "github.com/libp2p/go-libp2p-net"
	"github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

var log = logging.Logger("connmgr")

// BasicConnMgr is a ConnManager that trims connections whenever the count exceeds the
// high watermark. New connections are given a grace period before they're subject
// to trimming. Trims are automatically run on demand, only if the time from the
// previous trim is higher than 10 seconds. Furthermore, trims can be explicitly
// requested through the public interface of this struct (see TrimOpenConns).

// See configuration parameters in NewConnManager.
type BasicConnMgr struct {
	highWater int
	lowWater  int

	gracePeriod time.Duration

	peers     map[peer.ID]*peerInfo
	connCount int

	lk sync.Mutex

	lastTrim time.Time
}

var _ ifconnmgr.ConnManager = (*BasicConnMgr)(nil)

// NewConnManager creates a new BasicConnMgr with the provided params:
// * lo and hi are watermarks governing the number of connections that'll be maintained.
//   When the peer count exceeds the 'high watermark', as many peers will be pruned (and
//   their connections terminated) until 'low watermark' peers remain.
// * grace is the amount of time a newly opened connection is given before it becomes
//   subject to pruning.
func NewConnManager(low, hi int, grace time.Duration) *BasicConnMgr {
	return &BasicConnMgr{
		highWater:   hi,
		lowWater:    low,
		gracePeriod: grace,
		peers:       make(map[peer.ID]*peerInfo),
	}
}

// peerInfo stores metadata for a given peer.
type peerInfo struct {
	tags  map[string]int // value for each tag
	value int            // cached sum of all tag values

	conns map[inet.Conn]time.Time // start time of each connection

	firstSeen time.Time // timestamp when we began tracking this peer.
}

// TrimOpenConns closes the connections of as many peers as needed to make the peer count
// equal the low watermark. Peers are sorted in ascending order based on their total value,
// pruning those peers with the lowest scores first, as long as they are not within their
// grace period.
func (cm *BasicConnMgr) TrimOpenConns(ctx context.Context) {
	defer log.EventBegin(ctx, "connCleanup").Done()
	for _, c := range cm.getConnsToClose(ctx) {
		log.Info("closing conn: ", c.RemotePeer())
		log.Event(ctx, "closeConn", c.RemotePeer())
		c.Close()
	}
}

// getConnsToClose runs the heuristics described in TrimOpenConns and returns the
// connections to close.
func (cm *BasicConnMgr) getConnsToClose(ctx context.Context) []inet.Conn {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	if cm.lowWater == 0 || cm.highWater == 0 {
		// disabled
		return nil
	}
	now := time.Now()
	cm.lastTrim = now

	if len(cm.peers) < cm.lowWater {
		log.Info("open connection count below limit")
		return nil
	}

	var infos []*peerInfo

	for _, inf := range cm.peers {
		infos = append(infos, inf)
	}

	// Sort peers according to their value.
	sort.Slice(infos, func(i, j int) bool {
		return infos[i].value < infos[j].value
	})

	closeCount := len(infos) - cm.lowWater
	toclose := infos[:closeCount]

	// 2x number of peers we're disconnecting from because we may have more
	// than one connection per peer. Slightly over allocating isn't an issue
	// as this is a very short-lived array.
	closed := make([]inet.Conn, 0, len(toclose)*2)

	for _, inf := range toclose {
		// TODO: should we be using firstSeen or the time associated with the connection itself?
		if inf.firstSeen.Add(cm.gracePeriod).After(now) {
			continue
		}

		// TODO: if a peer has more than one connection, maybe only close one?
		for c := range inf.conns {
			// TODO: probably don't want to always do this in a goroutine
			closed = append(closed, c)
		}
	}

	return closed
}

func (cm *BasicConnMgr) GetTagInfo(p peer.ID) *ifconnmgr.TagInfo {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		return nil
	}

	out := &ifconnmgr.TagInfo{
		FirstSeen: pi.firstSeen,
		Value:     pi.value,
		Tags:      make(map[string]int),
		Conns:     make(map[string]time.Time),
	}

	for t, v := range pi.tags {
		out.Tags[t] = v
	}
	for c, t := range pi.conns {
		out.Conns[c.RemoteMultiaddr().String()] = t
	}

	return out
}

func (cm *BasicConnMgr) TagPeer(p peer.ID, tag string, val int) {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		log.Info("tried to tag conn from untracked peer: ", p)
		return
	}

	// Update the total value of the peer.
	pi.value += (val - pi.tags[tag])
	pi.tags[tag] = val
}

func (cm *BasicConnMgr) UntagPeer(p peer.ID, tag string) {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	pi, ok := cm.peers[p]
	if !ok {
		log.Info("tried to remove tag from untracked peer: ", p)
		return
	}

	// Update the total value of the peer.
	pi.value -= pi.tags[tag]
	delete(pi.tags, tag)
}

// CMInfo holds the configuration for BasicConnMgr, as well as status data.
type CMInfo struct {
	// The low watermark, as described in NewConnManager.
	LowWater int

	// The high watermark, as described in NewConnManager.
	HighWater int

	// The timestamp when the last trim was triggered.
	LastTrim time.Time

	// The configured grace period, as described in NewConnManager.
	GracePeriod time.Duration

	// The current connection count.
	ConnCount int
}

// GetInfo returns the configuration and status data for this connection manager.
func (cm *BasicConnMgr) GetInfo() CMInfo {
	cm.lk.Lock()
	defer cm.lk.Unlock()

	return CMInfo{
		HighWater:   cm.highWater,
		LowWater:    cm.lowWater,
		LastTrim:    cm.lastTrim,
		GracePeriod: cm.gracePeriod,
		ConnCount:   cm.connCount,
	}
}

// Notifee returns a sink through which Notifiers can inform the BasicConnMgr when
// events occur. Currently, the notifee only reacts upon connection events
// {Connected, Disconnected}.
func (cm *BasicConnMgr) Notifee() inet.Notifiee {
	return (*cmNotifee)(cm)
}

type cmNotifee BasicConnMgr

func (nn *cmNotifee) cm() *BasicConnMgr {
	return (*BasicConnMgr)(nn)
}

// Connected is called by notifiers to inform that a new connection has been established.
// The notifee updates the BasicConnMgr to start tracking the connection. If the new connection
// count exceeds the high watermark, a trim may be triggered.
func (nn *cmNotifee) Connected(n inet.Network, c inet.Conn) {
	cm := nn.cm()

	cm.lk.Lock()
	defer cm.lk.Unlock()

	pinfo, ok := cm.peers[c.RemotePeer()]
	if !ok {
		pinfo = &peerInfo{
			firstSeen: time.Now(),
			tags:      make(map[string]int),
			conns:     make(map[inet.Conn]time.Time),
		}
		cm.peers[c.RemotePeer()] = pinfo
	}

	_, ok = pinfo.conns[c]
	if ok {
		log.Error("received connected notification for conn we are already tracking: ", c.RemotePeer())
		return
	}

	pinfo.conns[c] = time.Now()
	cm.connCount++

	if cm.connCount > nn.highWater {
		if cm.lastTrim.IsZero() || time.Since(cm.lastTrim) > time.Second*10 {
			go cm.TrimOpenConns(context.Background())
		}
	}
}

// Disconnected is called by notifiers to inform that an existing connection has been closed or terminated.
// The notifee updates the BasicConnMgr accordingly to stop tracking the connection, and performs housekeeping.
func (nn *cmNotifee) Disconnected(n inet.Network, c inet.Conn) {
	cm := nn.cm()

	cm.lk.Lock()
	defer cm.lk.Unlock()

	cinf, ok := cm.peers[c.RemotePeer()]
	if !ok {
		log.Error("received disconnected notification for peer we are not tracking: ", c.RemotePeer())
		return
	}

	_, ok = cinf.conns[c]
	if !ok {
		log.Error("received disconnected notification for conn we are not tracking: ", c.RemotePeer())
		return
	}

	delete(cinf.conns, c)
	cm.connCount--
	if len(cinf.conns) == 0 {
		delete(cm.peers, c.RemotePeer())
	}
}

// Listen is no-op in this implementation.
func (nn *cmNotifee) Listen(n inet.Network, addr ma.Multiaddr)      {}

// ListenClose is no-op in this implementation.
func (nn *cmNotifee) ListenClose(n inet.Network, addr ma.Multiaddr) {}

// OpenedStream is no-op in this implementation.
func (nn *cmNotifee) OpenedStream(inet.Network, inet.Stream)        {}

// ClosedStream is no-op in this implementation.
func (nn *cmNotifee) ClosedStream(inet.Network, inet.Stream)        {}
<|endoftext|>


<commit_before>package zmq2

/*
#include <zmq.h>
#ifndef ENOTSOCK
#define ENOTSOCK (ZMQ_HAUSNUMERO + 9)
#endif
*/
import "C"

import (
	"syscall"
)

// An Errno is an unsigned number describing an error condition as returned by a call to ZeroMQ.
// It implements the error interface.
// The number is either a standard system error, or an error defined by the C library of ZeroMQ.
type Errno uintptr

const (
	// Error conditions defined by the C library of ZeroMQ.

	// On Windows platform some of the standard POSIX errnos are not defined.
	EADDRINUSE      = Errno(C.EADDRINUSE)
	EADDRNOTAVAIL   = Errno(C.EADDRNOTAVAIL)
	ECONNREFUSED    = Errno(C.ECONNREFUSED)
	EINPROGRESS     = Errno(C.EINPROGRESS)
	ENETDOWN        = Errno(C.ENETDOWN)
	ENOBUFS         = Errno(C.ENOBUFS)
	ENOTSOCK        = Errno(C.ENOTSOCK)
	ENOTSUP         = Errno(C.ENOTSUP)
	EPROTONOSUPPORT = Errno(C.EPROTONOSUPPORT)

	// Native 0MQ error codes.
	EFSM           = Errno(C.EFSM)
	EMTHREAD       = Errno(C.EMTHREAD)
	ENOCOMPATPROTO = Errno(C.ENOCOMPATPROTO)
	ETERM          = Errno(C.ETERM)
)

func errget(err error) error {
	eno, ok := err.(syscall.Errno)
	if ok {
		return Errno(eno)
	}
	return err
}

// Return Errno as string.
func (errno Errno) Error() string {
	if errno >= C.ZMQ_HAUSNUMERO {
		return C.GoString(C.zmq_strerror(C.int(errno)))
	}
	return syscall.Errno(errno).Error()
}

/*
Covert error to Errno.

Example usage:

    switch AsErrno(err) {

    case zmq.Errno(syscall.EINTR):
        // standard system error

        // call was interrupted

    case zmq.ETERM:
        // error defined by ZeroMQ

        // context was terminated

    }

See also: examples/interrupt.go
*/
func AsErrno(err error) Errno {
	if eno, ok := err.(Errno); ok {
		return eno
	}
	if eno, ok := err.(syscall.Errno); ok {
		return Errno(eno)
	}
	return Errno(0)
}
<commit_msg>Typo in docstring of AsErrno()<commit_after>package zmq2

/*
#include <zmq.h>
#ifndef ENOTSOCK
#define ENOTSOCK (ZMQ_HAUSNUMERO + 9)
#endif
*/
import "C"

import (
	"syscall"
)

// An Errno is an unsigned number describing an error condition as returned by a call to ZeroMQ.
// It implements the error interface.
// The number is either a standard system error, or an error defined by the C library of ZeroMQ.
type Errno uintptr

const (
	// Error conditions defined by the C library of ZeroMQ.

	// On Windows platform some of the standard POSIX errnos are not defined.
	EADDRINUSE      = Errno(C.EADDRINUSE)
	EADDRNOTAVAIL   = Errno(C.EADDRNOTAVAIL)
	ECONNREFUSED    = Errno(C.ECONNREFUSED)
	EINPROGRESS     = Errno(C.EINPROGRESS)
	ENETDOWN        = Errno(C.ENETDOWN)
	ENOBUFS         = Errno(C.ENOBUFS)
	ENOTSOCK        = Errno(C.ENOTSOCK)
	ENOTSUP         = Errno(C.ENOTSUP)
	EPROTONOSUPPORT = Errno(C.EPROTONOSUPPORT)

	// Native 0MQ error codes.
	EFSM           = Errno(C.EFSM)
	EMTHREAD       = Errno(C.EMTHREAD)
	ENOCOMPATPROTO = Errno(C.ENOCOMPATPROTO)
	ETERM          = Errno(C.ETERM)
)

func errget(err error) error {
	eno, ok := err.(syscall.Errno)
	if ok {
		return Errno(eno)
	}
	return err
}

// Return Errno as string.
func (errno Errno) Error() string {
	if errno >= C.ZMQ_HAUSNUMERO {
		return C.GoString(C.zmq_strerror(C.int(errno)))
	}
	return syscall.Errno(errno).Error()
}

/*
Convert error to Errno.

Example usage:

    switch AsErrno(err) {

    case zmq.Errno(syscall.EINTR):
        // standard system error

        // call was interrupted

    case zmq.ETERM:
        // error defined by ZeroMQ

        // context was terminated

    }

See also: examples/interrupt.go
*/
func AsErrno(err error) Errno {
	if eno, ok := err.(Errno); ok {
		return eno
	}
	if eno, ok := err.(syscall.Errno); ok {
		return Errno(eno)
	}
	return Errno(0)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"fmt"

	"golang.org/x/net/context"
)

const (
	// Message id for protocol level errors
	invalidMessageID uint32 = 0xFFFFFFFF
)

// A SystemErrCode indicates how a caller should handle a system error returned from a peer
type SystemErrCode byte

//go:generate stringer -type=SystemErrCode

const (
	// ErrCodeInvalid is an invalid error code, and should not be used
	ErrCodeInvalid SystemErrCode = 0x00

	// ErrCodeTimeout indicates the peer timed out.  Callers can retry the request
	// on another peer if the request is safe to retry.
	ErrCodeTimeout SystemErrCode = 0x01

	// ErrCodeCancelled indicates that the request was cancelled on the peer.  Callers
	// can retry the request on the same or another peer if the request is safe to retry
	ErrCodeCancelled SystemErrCode = 0x02

	// ErrCodeBusy indicates that the request was not dispatched because the peer
	// was too busy to handle it.  Callers can retry the request on another peer, and should
	// reweight their connections to direct less traffic to this peer until it recovers.
	ErrCodeBusy SystemErrCode = 0x03

	// ErrCodeDeclined indicates that the request not dispatched because the peer
	// declined to handle it, typically because the peer is not yet ready to handle it.
	// Callers can retry the request on another peer, but should not reweight their connections
	// and should continue to send traffic to this peer.
	ErrCodeDeclined SystemErrCode = 0x04

	// ErrCodeUnexpected indicates that the request failed for an unexpected reason, typically
	// a crash or other unexpected handling.  The request may have been processed before the failure;
	// callers should retry the request on this or another peer only if the request is safe to retry
	ErrCodeUnexpected SystemErrCode = 0x05

	// ErrCodeBadRequest indicates that the request was malformed, and could not be processed.
	// Callers should not bother to retry the request, as there is no chance it will be handled.
	ErrCodeBadRequest SystemErrCode = 0x06

	// ErrCodeNetwork indicates a network level error, such as a connection reset.
	// Callers can retry the request if the request is safe to retry
	ErrCodeNetwork SystemErrCode = 0x07

	// ErrCodeProtocol indincates a fatal protocol error communicating with the peer.  The connection
	// will be terminated.
	ErrCodeProtocol SystemErrCode = 0xFF
)

var (
	// ErrServerBusy is a SystemError indicating the server is busy
	ErrServerBusy = NewSystemError(ErrCodeBusy, "server busy")

	// ErrRequestCancelled is a SystemError indicating the request has been cancelled on the peer
	ErrRequestCancelled = NewSystemError(ErrCodeCancelled, "request cancelled")

	// ErrTimeout is a SytemError indicating the request has timed out
	ErrTimeout = NewSystemError(ErrCodeTimeout, "timeout")

	// ErrTimeoutRequired is a SystemError indicating that timeouts must be specified.
	ErrTimeoutRequired = NewSystemError(ErrCodeBadRequest, "timeout required")

	// ErrChannelClosed is a SystemError indicating that the channel has been closed.
	ErrChannelClosed = NewSystemError(ErrCodeDeclined, "closed channel")

	// ErrMethodTooLarge is a SystemError indicating that the method is too large.
	ErrMethodTooLarge = NewSystemError(ErrCodeProtocol, "method too large")
)

// MetricsKey is a string representation of the error code that's suitable for
// inclusion in metrics tags.
func (c SystemErrCode) MetricsKey() string {
	switch c {
	case ErrCodeInvalid:
		// Shouldn't ever need this.
		return "invalid"
	case ErrCodeTimeout:
		return "timeout"
	case ErrCodeCancelled:
		return "cancelled"
	case ErrCodeBusy:
		return "busy"
	case ErrCodeDeclined:
		return "declined"
	case ErrCodeUnexpected:
		return "unexpected-error"
	case ErrCodeBadRequest:
		return "bad-request"
	case ErrCodeNetwork:
		return "network-error"
	case ErrCodeProtocol:
		return "protocol-error"
	default:
		return c.String()
	}
}

// A SystemError is a system-level error, containing an error code and message
// TODO(mmihic): Probably we want to hide this interface, and let application code
// just deal with standard raw errors.
type SystemError struct {
	code    SystemErrCode
	msg     string
	wrapped error
}

// NewSystemError defines a new SystemError with a code and message
func NewSystemError(code SystemErrCode, msg string, args ...interface{}) error {
	return SystemError{code: code, msg: fmt.Sprintf(msg, args...)}
}

// NewWrappedSystemError defines a new SystemError wrapping an existing error
func NewWrappedSystemError(code SystemErrCode, wrapped error) error {
	if se, ok := wrapped.(SystemError); ok {
		return se
	}

	return SystemError{code: code, msg: fmt.Sprint(wrapped), wrapped: wrapped}
}

// Error returns the code and message, conforming to the error interface
func (se SystemError) Error() string {
	return fmt.Sprintf("tchannel error %v: %s", se.Code(), se.msg)
}

// Wrapped returns the wrapped error
func (se SystemError) Wrapped() error { return se.wrapped }

// Code returns the SystemError code, for sending to a peer
func (se SystemError) Code() SystemErrCode {
	return se.code
}

// Message returns the SystemError message.
func (se SystemError) Message() string {
	return se.msg
}

// GetContextError converts the context error to a tchannel error.
func GetContextError(err error) error {
	if err == context.DeadlineExceeded {
		return ErrTimeout
	}
	return err
}

// GetSystemErrorCode returns the code to report for the given error.  If the error is a
// SystemError, we can get the code directly.  Otherwise treat it as an unexpected error
func GetSystemErrorCode(err error) SystemErrCode {
	if se, ok := err.(SystemError); ok {
		return se.Code()
	}

	return ErrCodeUnexpected
}

// GetSystemErrorMessage returns the message to report for the given error.  If the error is a
// SystemError, we can get the underlying message. Otherwise, use the Error() method.
func GetSystemErrorMessage(err error) string {
	if se, ok := err.(SystemError); ok {
		return se.Message()
	}

	return err.Error()
}
<commit_msg>Non error is an invalid error<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"fmt"

	"golang.org/x/net/context"
)

const (
	// Message id for protocol level errors
	invalidMessageID uint32 = 0xFFFFFFFF
)

// A SystemErrCode indicates how a caller should handle a system error returned from a peer
type SystemErrCode byte

//go:generate stringer -type=SystemErrCode

const (
	// ErrCodeInvalid is an invalid error code, and should not be used
	ErrCodeInvalid SystemErrCode = 0x00

	// ErrCodeTimeout indicates the peer timed out.  Callers can retry the request
	// on another peer if the request is safe to retry.
	ErrCodeTimeout SystemErrCode = 0x01

	// ErrCodeCancelled indicates that the request was cancelled on the peer.  Callers
	// can retry the request on the same or another peer if the request is safe to retry
	ErrCodeCancelled SystemErrCode = 0x02

	// ErrCodeBusy indicates that the request was not dispatched because the peer
	// was too busy to handle it.  Callers can retry the request on another peer, and should
	// reweight their connections to direct less traffic to this peer until it recovers.
	ErrCodeBusy SystemErrCode = 0x03

	// ErrCodeDeclined indicates that the request not dispatched because the peer
	// declined to handle it, typically because the peer is not yet ready to handle it.
	// Callers can retry the request on another peer, but should not reweight their connections
	// and should continue to send traffic to this peer.
	ErrCodeDeclined SystemErrCode = 0x04

	// ErrCodeUnexpected indicates that the request failed for an unexpected reason, typically
	// a crash or other unexpected handling.  The request may have been processed before the failure;
	// callers should retry the request on this or another peer only if the request is safe to retry
	ErrCodeUnexpected SystemErrCode = 0x05

	// ErrCodeBadRequest indicates that the request was malformed, and could not be processed.
	// Callers should not bother to retry the request, as there is no chance it will be handled.
	ErrCodeBadRequest SystemErrCode = 0x06

	// ErrCodeNetwork indicates a network level error, such as a connection reset.
	// Callers can retry the request if the request is safe to retry
	ErrCodeNetwork SystemErrCode = 0x07

	// ErrCodeProtocol indincates a fatal protocol error communicating with the peer.  The connection
	// will be terminated.
	ErrCodeProtocol SystemErrCode = 0xFF
)

var (
	// ErrServerBusy is a SystemError indicating the server is busy
	ErrServerBusy = NewSystemError(ErrCodeBusy, "server busy")

	// ErrRequestCancelled is a SystemError indicating the request has been cancelled on the peer
	ErrRequestCancelled = NewSystemError(ErrCodeCancelled, "request cancelled")

	// ErrTimeout is a SytemError indicating the request has timed out
	ErrTimeout = NewSystemError(ErrCodeTimeout, "timeout")

	// ErrTimeoutRequired is a SystemError indicating that timeouts must be specified.
	ErrTimeoutRequired = NewSystemError(ErrCodeBadRequest, "timeout required")

	// ErrChannelClosed is a SystemError indicating that the channel has been closed.
	ErrChannelClosed = NewSystemError(ErrCodeDeclined, "closed channel")

	// ErrMethodTooLarge is a SystemError indicating that the method is too large.
	ErrMethodTooLarge = NewSystemError(ErrCodeProtocol, "method too large")
)

// MetricsKey is a string representation of the error code that's suitable for
// inclusion in metrics tags.
func (c SystemErrCode) MetricsKey() string {
	switch c {
	case ErrCodeInvalid:
		// Shouldn't ever need this.
		return "invalid"
	case ErrCodeTimeout:
		return "timeout"
	case ErrCodeCancelled:
		return "cancelled"
	case ErrCodeBusy:
		return "busy"
	case ErrCodeDeclined:
		return "declined"
	case ErrCodeUnexpected:
		return "unexpected-error"
	case ErrCodeBadRequest:
		return "bad-request"
	case ErrCodeNetwork:
		return "network-error"
	case ErrCodeProtocol:
		return "protocol-error"
	default:
		return c.String()
	}
}

// A SystemError is a system-level error, containing an error code and message
// TODO(mmihic): Probably we want to hide this interface, and let application code
// just deal with standard raw errors.
type SystemError struct {
	code    SystemErrCode
	msg     string
	wrapped error
}

// NewSystemError defines a new SystemError with a code and message
func NewSystemError(code SystemErrCode, msg string, args ...interface{}) error {
	return SystemError{code: code, msg: fmt.Sprintf(msg, args...)}
}

// NewWrappedSystemError defines a new SystemError wrapping an existing error
func NewWrappedSystemError(code SystemErrCode, wrapped error) error {
	if se, ok := wrapped.(SystemError); ok {
		return se
	}

	return SystemError{code: code, msg: fmt.Sprint(wrapped), wrapped: wrapped}
}

// Error returns the code and message, conforming to the error interface
func (se SystemError) Error() string {
	return fmt.Sprintf("tchannel error %v: %s", se.Code(), se.msg)
}

// Wrapped returns the wrapped error
func (se SystemError) Wrapped() error { return se.wrapped }

// Code returns the SystemError code, for sending to a peer
func (se SystemError) Code() SystemErrCode {
	return se.code
}

// Message returns the SystemError message.
func (se SystemError) Message() string {
	return se.msg
}

// GetContextError converts the context error to a tchannel error.
func GetContextError(err error) error {
	if err == context.DeadlineExceeded {
		return ErrTimeout
	}
	return err
}

// GetSystemErrorCode returns the code to report for the given error.  If the error is a
// SystemError, we can get the code directly.  Otherwise treat it as an unexpected error
func GetSystemErrorCode(err error) SystemErrCode {
	if err == nil {
		return ErrCodeInvalid
	}

	if se, ok := err.(SystemError); ok {
		return se.Code()
	}

	return ErrCodeUnexpected
}

// GetSystemErrorMessage returns the message to report for the given error.  If the error is a
// SystemError, we can get the underlying message. Otherwise, use the Error() method.
func GetSystemErrorMessage(err error) string {
	if se, ok := err.(SystemError); ok {
		return se.Message()
	}

	return err.Error()
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Space Monkey, Inc.

package errors

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync/atomic"
	"syscall"
)

var (
	stackLogSize = flag.Int("errors.stack_trace_log_length", 4096,
		"The max stack trace byte length to log")
	lastId int32 = 0
)

type DataKey struct{ id int32 }

func GenSym() DataKey { return DataKey{id: atomic.AddInt32(&lastId, 1)} }

var (
	logOnCreation      = GenSym()
	captureStack       = GenSym()
	disableInheritance = GenSym()
)

type ErrorClass struct {
	parent *ErrorClass
	name   string
	data   map[DataKey]interface{}
}

var (
	// base error classes. To construct your own error class, use New.
	SystemError = &ErrorClass{
		parent: nil,
		name:   "System Error",
		data:   map[DataKey]interface{}{}}
	HierarchicalError = &ErrorClass{
		parent: nil,
		name:   "Error",
		data:   map[DataKey]interface{}{captureStack: true}}
)

type ErrorOption func(map[DataKey]interface{})

func SetData(key DataKey, value interface{}) ErrorOption {
	return func(m map[DataKey]interface{}) {
		m[key] = value
	}
}

func LogOnCreation() ErrorOption {
	return SetData(logOnCreation, true)
}

func CaptureStack() ErrorOption {
	return SetData(captureStack, true)
}

func NoLogOnCreation() ErrorOption {
	return SetData(logOnCreation, false)
}

func NoCaptureStack() ErrorOption {
	return SetData(captureStack, false)
}

func DisableInheritance() ErrorOption {
	return SetData(disableInheritance, true)
}

func boolWrapper(val interface{}, default_value bool) bool {
	rv, ok := val.(bool)
	if ok {
		return rv
	}
	return default_value
}

// New creates an error class with the provided name and options.
func New(parent *ErrorClass, name string, options ...ErrorOption) *ErrorClass {
	if parent == nil {
		parent = HierarchicalError
	}
	ec := &ErrorClass{parent: parent,
		name: name,
		data: make(map[DataKey]interface{})}
	for _, option := range options {
		option(ec.data)
	}
	if !boolWrapper(ec.data[disableInheritance], false) {
		// hoist options for speed
		for key, val := range parent.data {
			_, exists := ec.data[key]
			if !exists {
				ec.data[key] = val
			}
		}
		return ec
	} else {
		delete(ec.data, disableInheritance)
	}
	return ec
}

func (e *ErrorClass) Parent() *ErrorClass {
	return e.parent
}

func (e *ErrorClass) String() string {
	return e.name
}

func (e *ErrorClass) Is(parent *ErrorClass) bool {
	for check := e; check != nil; check = check.parent {
		if check == parent {
			return true
		}
	}
	return false
}

// frame logs the pc at some point during execution.
type frame struct {
	pc uintptr
}

// String returns a human readable form of the frame.
func (e frame) String() string {
	if e.pc == 0 {
		return "unknown.unknown:0"
	}
	f := runtime.FuncForPC(e.pc)
	if f == nil {
		return "unknown.unknown:0"
	}
	file, line := f.FileLine(e.pc)
	return fmt.Sprintf("%s:%s:%d", f.Name(), filepath.Base(file), line)
}

// callerState records the pc into an frame for two callers up.
func callerState(depth int) frame {
	pc, _, _, ok := runtime.Caller(depth)
	if !ok {
		return frame{pc: 0}
	}
	return frame{pc: pc}
}

// record will record the pc at the given depth into the error if it is
// capable of recording it.
func record(err error, depth int) error {
	if err == nil {
		return nil
	}
	cast, ok := err.(*Error)
	if !ok {
		return err
	}
	cast.exits = append(cast.exits, callerState(depth))
	return cast
}

// Record will record the pc of where it is called on to the error.
func Record(err error) error {
	return record(err, 3)
}

// RecordBefore will record the pc depth frames above of where it is called on
// to the error. Record(err) is equivalent to RecordBefore(err, 0)
func RecordBefore(err error, depth int) error {
	return record(err, 3+depth)
}

type Error struct {
	err   error
	class *ErrorClass
	stack []frame
	exits []frame
	data  map[DataKey]interface{}
}

func (e *Error) GetData(key DataKey) interface{} {
	if e.data != nil {
		val, ok := e.data[key]
		if ok {
			return val
		}
		if boolWrapper(e.data[disableInheritance], false) {
			return nil
		}
	}
	return e.class.data[key]
}

func GetData(err error, key DataKey) interface{} {
	cast, ok := err.(*Error)
	if ok {
		return cast.GetData(key)
	}
	return nil
}

func (e *ErrorClass) wrap(err error, classes []*ErrorClass,
	options []ErrorOption) error {
	if err == nil {
		return nil
	}
	if ec, ok := err.(*Error); ok {
		if ec.Is(e) {
			if len(options) == 0 {
				return ec
			}
			// if we have options, we have to wrap it cause we don't want to
			// mutate the existing error.
		} else {
			for _, class := range classes {
				if ec.Is(class) {
					return err
				}
			}
		}
	}

	rv := &Error{err: err, class: e}
	if len(options) > 0 {
		rv.data = make(map[DataKey]interface{})
		for _, option := range options {
			option(rv.data)
		}
	}

	if boolWrapper(rv.GetData(captureStack), false) {
		var pcs [256]uintptr
		amount := runtime.Callers(3, pcs[:])
		rv.stack = make([]frame, amount)
		for i := 0; i < amount; i++ {
			rv.stack[i] = frame{pcs[i]}
		}
	}
	if boolWrapper(rv.GetData(logOnCreation), false) {
		LogWithStack(rv.Error())
	}
	return rv
}

func (e *ErrorClass) WrapUnless(err error, classes ...*ErrorClass) error {
	return e.wrap(err, classes, nil)
}

func (e *ErrorClass) Wrap(err error, options ...ErrorOption) error {
	return e.wrap(err, nil, options)
}

func (e *ErrorClass) New(format string, args ...interface{}) error {
	return e.wrap(fmt.Errorf(format, args...), nil, nil)
}

func (e *ErrorClass) NewWith(message string, options ...ErrorOption) error {
	return e.wrap(errors.New(message), nil, options)
}

func (e *Error) Error() string {
	message := strings.TrimRight(e.err.Error(), "\n ")
	if strings.Contains(message, "\n") {
		message = fmt.Sprintf("%s:\n  %s", e.class.String(),
			strings.Replace(message, "\n", "\n  ", -1))
	} else {
		message = fmt.Sprintf("%s: %s", e.class.String(), message)
	}
	if stack := e.Stack(); stack != "" {
		message = fmt.Sprintf(
			"%s\n\"%s\" backtrace:\n%s", message, e.class, stack)
	}
	if exits := e.Exits(); exits != "" {
		message = fmt.Sprintf(
			"%s\n\"%s\" exits:\n%s", message, e.class, exits)
	}
	return message
}

func (e *Error) Message() string {
	message := strings.TrimRight(GetMessage(e.err), "\n ")
	if strings.Contains(message, "\n") {
		return fmt.Sprintf("%s:\n  %s", e.class.String(),
			strings.Replace(message, "\n", "\n  ", -1))
	}
	return fmt.Sprintf("%s: %s", e.class.String(), message)
}

func (e *Error) WrappedErr() error {
	return e.err
}

func (e *Error) Class() *ErrorClass {
	return e.class
}

func (e *Error) Stack() string {
	if len(e.stack) > 0 {
		frames := make([]string, len(e.stack))
		for i, f := range e.stack {
			frames[i] = f.String()
		}
		return strings.Join(frames, "\n")
	}
	return ""
}

func (e *Error) Exits() string {
	if len(e.exits) > 0 {
		exits := make([]string, len(e.exits))
		for i, ex := range e.exits {
			exits[i] = ex.String()
		}
		return strings.Join(exits, "\n")
	}
	return ""
}

func WrappedErr(err error) error {
	cast, ok := err.(*Error)
	if !ok {
		return err
	}
	return cast.WrappedErr()
}

func GetClass(err error) *ErrorClass {
	if err == nil {
		return nil
	}
	cast, ok := err.(*Error)
	if !ok {
		return findSystemErrorClass(err)
	}
	return cast.class
}

func GetMessage(err error) string {
	if err == nil {
		return ""
	}
	cast, ok := err.(*Error)
	if !ok {
		return err.Error()
	}
	return cast.Message()
}

type EquivalenceOption int

const (
	IncludeWrapped EquivalenceOption = 1
)

func combineEquivOpts(opts []EquivalenceOption) (rv EquivalenceOption) {
	for _, opt := range opts {
		rv |= opt
	}
	return rv
}

func (e *Error) Is(ec *ErrorClass, opts ...EquivalenceOption) bool {
	return ec.Contains(e, opts...)
}

func (e *ErrorClass) Contains(err error, opts ...EquivalenceOption) bool {
	if err == nil {
		return false
	}
	cast, ok := err.(*Error)
	if !ok {
		return findSystemErrorClass(err).Is(e)
	}
	if cast.class.Is(e) {
		return true
	}
	if combineEquivOpts(opts)&IncludeWrapped == 0 {
		return false
	}
	return e.Contains(cast.err, opts...)
}

func LogWithStack(messages ...interface{}) {
	buf := make([]byte, *stackLogSize)
	buf = buf[:runtime.Stack(buf, false)]
	log.Printf("%s\n%s", fmt.Sprintln(messages...), buf)
}

var (
	// useful error classes
	NotImplementedError = New(nil, "Not Implemented Error", LogOnCreation())
	ProgrammerError     = New(nil, "Programmer Error", LogOnCreation())
	PanicError          = New(nil, "Panic Error", LogOnCreation())
	ErrorGroupError     = New(nil, "Error Group Error")

	// classes we fake

	// from os
	SyscallError = New(SystemError, "Syscall Error")

	// from syscall
	ErrnoError = New(SystemError, "Errno Error")

	// from net
	NetworkError        = New(SystemError, "Network Error")
	UnknownNetworkError = New(NetworkError, "Unknown Network Error")
	AddrError           = New(NetworkError, "Addr Error")
	InvalidAddrError    = New(AddrError, "Invalid Addr Error")
	NetOpError          = New(NetworkError, "Network Op Error")
	NetParseError       = New(NetworkError, "Network Parse Error")
	DNSError            = New(NetworkError, "DNS Error")
	DNSConfigError      = New(DNSError, "DNS Config Error")

	// from io
	IOError            = New(SystemError, "IO Error")
	EOF                = New(IOError, "EOF")
	ClosedPipeError    = New(IOError, "Closed Pipe Error")
	NoProgressError    = New(IOError, "No Progress Error")
	ShortBufferError   = New(IOError, "Short Buffer Error")
	ShortWriteError    = New(IOError, "Short Write Error")
	UnexpectedEOFError = New(IOError, "Unexpected EOF Error")
)

func findSystemErrorClass(err error) *ErrorClass {
	switch err {
	case io.EOF:
		return EOF
	case io.ErrUnexpectedEOF:
		return UnexpectedEOFError
	case io.ErrClosedPipe:
		return ClosedPipeError
	case io.ErrNoProgress:
		return NoProgressError
	case io.ErrShortBuffer:
		return ShortBufferError
	case io.ErrShortWrite:
		return ShortWriteError
	default:
		break
	}
	switch err.(type) {
	case *os.SyscallError:
		return SyscallError
	case syscall.Errno:
		return ErrnoError
	case net.UnknownNetworkError:
		return UnknownNetworkError
	case *net.AddrError:
		return AddrError
	case net.InvalidAddrError:
		return InvalidAddrError
	case *net.OpError:
		return NetOpError
	case *net.ParseError:
		return NetParseError
	case *net.DNSError:
		return DNSError
	case *net.DNSConfigError:
		return DNSConfigError
	case net.Error:
		return NetworkError
	default:
		return SystemError
	}
}

func Recover() error {
	r := recover()
	if r == nil {
		return nil
	}
	err, ok := r.(error)
	if ok {
		return err
	}
	return PanicError.New("%v", r)
}

func CatchPanic(err_ref *error) {
	r := Recover()
	if r != nil {
		*err_ref = r
	}
}

type ErrorGroup struct {
	Errors []error
}

func NewErrorGroup() *ErrorGroup { return &ErrorGroup{} }

func (e *ErrorGroup) Add(err error) {
	if err != nil {
		e.Errors = append(e.Errors, err)
	}
}

func (e *ErrorGroup) Finalize() error {
	if len(e.Errors) == 0 {
		return nil
	}
	if len(e.Errors) == 1 {
		return e.Errors[0]
	}
	msgs := make([]string, 0, len(e.Errors))
	for _, err := range e.Errors {
		msgs = append(msgs, err.Error())
	}
	return ErrorGroupError.New(strings.Join(msgs, "\n"))
}
<commit_msg>space monkey internal commit export<commit_after>// Copyright (C) 2013 Space Monkey, Inc.

package errors

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync/atomic"
	"syscall"
)

var (
	stackLogSize = flag.Int("errors.stack_trace_log_length", 4096,
		"The max stack trace byte length to log")
	lastId int32 = 0
)

type DataKey struct{ id int32 }

func GenSym() DataKey { return DataKey{id: atomic.AddInt32(&lastId, 1)} }

var (
	logOnCreation      = GenSym()
	captureStack       = GenSym()
	disableInheritance = GenSym()
)

type ErrorClass struct {
	parent *ErrorClass
	name   string
	data   map[DataKey]interface{}
}

var (
	// base error classes. To construct your own error class, use New.
	SystemError = &ErrorClass{
		parent: nil,
		name:   "System Error",
		data:   map[DataKey]interface{}{}}
	HierarchicalError = &ErrorClass{
		parent: nil,
		name:   "Error",
		data:   map[DataKey]interface{}{captureStack: true}}
)

type ErrorOption func(map[DataKey]interface{})

func SetData(key DataKey, value interface{}) ErrorOption {
	return func(m map[DataKey]interface{}) {
		m[key] = value
	}
}

func LogOnCreation() ErrorOption {
	return SetData(logOnCreation, true)
}

func CaptureStack() ErrorOption {
	return SetData(captureStack, true)
}

func NoLogOnCreation() ErrorOption {
	return SetData(logOnCreation, false)
}

func NoCaptureStack() ErrorOption {
	return SetData(captureStack, false)
}

func DisableInheritance() ErrorOption {
	return SetData(disableInheritance, true)
}

func boolWrapper(val interface{}, default_value bool) bool {
	rv, ok := val.(bool)
	if ok {
		return rv
	}
	return default_value
}

// New creates an error class with the provided name and options.
func New(parent *ErrorClass, name string, options ...ErrorOption) *ErrorClass {
	if parent == nil {
		parent = HierarchicalError
	}
	ec := &ErrorClass{parent: parent,
		name: name,
		data: make(map[DataKey]interface{})}
	for _, option := range options {
		option(ec.data)
	}
	if !boolWrapper(ec.data[disableInheritance], false) {
		// hoist options for speed
		for key, val := range parent.data {
			_, exists := ec.data[key]
			if !exists {
				ec.data[key] = val
			}
		}
		return ec
	} else {
		delete(ec.data, disableInheritance)
	}
	return ec
}

func (e *ErrorClass) Parent() *ErrorClass {
	return e.parent
}

func (e *ErrorClass) String() string {
	return e.name
}

func (e *ErrorClass) Is(parent *ErrorClass) bool {
	for check := e; check != nil; check = check.parent {
		if check == parent {
			return true
		}
	}
	return false
}

// frame logs the pc at some point during execution.
type frame struct {
	pc uintptr
}

// String returns a human readable form of the frame.
func (e frame) String() string {
	if e.pc == 0 {
		return "unknown.unknown:0"
	}
	f := runtime.FuncForPC(e.pc)
	if f == nil {
		return "unknown.unknown:0"
	}
	file, line := f.FileLine(e.pc)
	return fmt.Sprintf("%s:%s:%d", f.Name(), filepath.Base(file), line)
}

// callerState records the pc into an frame for two callers up.
func callerState(depth int) frame {
	pc, _, _, ok := runtime.Caller(depth)
	if !ok {
		return frame{pc: 0}
	}
	return frame{pc: pc}
}

// record will record the pc at the given depth into the error if it is
// capable of recording it.
func record(err error, depth int) error {
	if err == nil {
		return nil
	}
	cast, ok := err.(*Error)
	if !ok {
		return err
	}
	cast.exits = append(cast.exits, callerState(depth))
	return cast
}

// Record will record the pc of where it is called on to the error.
func Record(err error) error {
	return record(err, 3)
}

// RecordBefore will record the pc depth frames above of where it is called on
// to the error. Record(err) is equivalent to RecordBefore(err, 0)
func RecordBefore(err error, depth int) error {
	return record(err, 3+depth)
}

type Error struct {
	err   error
	class *ErrorClass
	stack []frame
	exits []frame
	data  map[DataKey]interface{}
}

func (e *Error) GetData(key DataKey) interface{} {
	if e.data != nil {
		val, ok := e.data[key]
		if ok {
			return val
		}
		if boolWrapper(e.data[disableInheritance], false) {
			return nil
		}
	}
	return e.class.data[key]
}

func GetData(err error, key DataKey) interface{} {
	cast, ok := err.(*Error)
	if ok {
		return cast.GetData(key)
	}
	return nil
}

func (e *ErrorClass) wrap(err error, classes []*ErrorClass,
	options []ErrorOption) error {
	if err == nil {
		return nil
	}
	if ec, ok := err.(*Error); ok {
		if ec.Is(e) {
			if len(options) == 0 {
				return ec
			}
			// if we have options, we have to wrap it cause we don't want to
			// mutate the existing error.
		} else {
			for _, class := range classes {
				if ec.Is(class) {
					return err
				}
			}
		}
	}

	rv := &Error{err: err, class: e}
	if len(options) > 0 {
		rv.data = make(map[DataKey]interface{})
		for _, option := range options {
			option(rv.data)
		}
	}

	if boolWrapper(rv.GetData(captureStack), false) {
		var pcs [256]uintptr
		amount := runtime.Callers(3, pcs[:])
		rv.stack = make([]frame, amount)
		for i := 0; i < amount; i++ {
			rv.stack[i] = frame{pcs[i]}
		}
	}
	if boolWrapper(rv.GetData(logOnCreation), false) {
		LogWithStack(rv.Error())
	}
	return rv
}

func (e *ErrorClass) WrapUnless(err error, classes ...*ErrorClass) error {
	return e.wrap(err, classes, nil)
}

func (e *ErrorClass) Wrap(err error, options ...ErrorOption) error {
	return e.wrap(err, nil, options)
}

func (e *ErrorClass) New(format string, args ...interface{}) error {
	return e.wrap(fmt.Errorf(format, args...), nil, nil)
}

func (e *ErrorClass) NewWith(message string, options ...ErrorOption) error {
	return e.wrap(errors.New(message), nil, options)
}

func (e *Error) Error() string {
	message := strings.TrimRight(e.err.Error(), "\n ")
	if strings.Contains(message, "\n") {
		message = fmt.Sprintf("%s:\n  %s", e.class.String(),
			strings.Replace(message, "\n", "\n  ", -1))
	} else {
		message = fmt.Sprintf("%s: %s", e.class.String(), message)
	}
	if stack := e.Stack(); stack != "" {
		message = fmt.Sprintf(
			"%s\n\"%s\" backtrace:\n%s", message, e.class, stack)
	}
	if exits := e.Exits(); exits != "" {
		message = fmt.Sprintf(
			"%s\n\"%s\" exits:\n%s", message, e.class, exits)
	}
	return message
}

func (e *Error) Message() string {
	message := strings.TrimRight(GetMessage(e.err), "\n ")
	if strings.Contains(message, "\n") {
		return fmt.Sprintf("%s:\n  %s", e.class.String(),
			strings.Replace(message, "\n", "\n  ", -1))
	}
	return fmt.Sprintf("%s: %s", e.class.String(), message)
}

func (e *Error) WrappedErr() error {
	return e.err
}

func (e *Error) Class() *ErrorClass {
	return e.class
}

func (e *Error) Stack() string {
	if len(e.stack) > 0 {
		frames := make([]string, len(e.stack))
		for i, f := range e.stack {
			frames[i] = f.String()
		}
		return strings.Join(frames, "\n")
	}
	return ""
}

func (e *Error) Exits() string {
	if len(e.exits) > 0 {
		exits := make([]string, len(e.exits))
		for i, ex := range e.exits {
			exits[i] = ex.String()
		}
		return strings.Join(exits, "\n")
	}
	return ""
}

func WrappedErr(err error) error {
	cast, ok := err.(*Error)
	if !ok {
		return err
	}
	return cast.WrappedErr()
}

func GetClass(err error) *ErrorClass {
	if err == nil {
		return nil
	}
	cast, ok := err.(*Error)
	if !ok {
		return findSystemErrorClass(err)
	}
	return cast.class
}

func GetMessage(err error) string {
	if err == nil {
		return ""
	}
	cast, ok := err.(*Error)
	if !ok {
		return err.Error()
	}
	return cast.Message()
}

type EquivalenceOption int

const (
	IncludeWrapped EquivalenceOption = 1
)

func combineEquivOpts(opts []EquivalenceOption) (rv EquivalenceOption) {
	for _, opt := range opts {
		rv |= opt
	}
	return rv
}

func (e *Error) Is(ec *ErrorClass, opts ...EquivalenceOption) bool {
	return ec.Contains(e, opts...)
}

func (e *ErrorClass) Contains(err error, opts ...EquivalenceOption) bool {
	if err == nil {
		return false
	}
	cast, ok := err.(*Error)
	if !ok {
		return findSystemErrorClass(err).Is(e)
	}
	if cast.class.Is(e) {
		return true
	}
	if combineEquivOpts(opts)&IncludeWrapped == 0 {
		return false
	}
	return e.Contains(cast.err, opts...)
}

func LogWithStack(messages ...interface{}) {
	buf := make([]byte, *stackLogSize)
	buf = buf[:runtime.Stack(buf, false)]
	log.Printf("%s\n%s", fmt.Sprintln(messages...), buf)
}

var (
	// useful error classes
	NotImplementedError = New(nil, "Not Implemented Error", LogOnCreation())
	ProgrammerError     = New(nil, "Programmer Error", LogOnCreation())
	PanicError          = New(nil, "Panic Error", LogOnCreation())
	ErrorGroupError     = New(nil, "Error Group Error")

	// classes we fake

	// from os
	SyscallError = New(SystemError, "Syscall Error")

	// from syscall
	ErrnoError = New(SystemError, "Errno Error")

	// from net
	NetworkError        = New(SystemError, "Network Error")
	UnknownNetworkError = New(NetworkError, "Unknown Network Error")
	AddrError           = New(NetworkError, "Addr Error")
	InvalidAddrError    = New(AddrError, "Invalid Addr Error")
	NetOpError          = New(NetworkError, "Network Op Error")
	NetParseError       = New(NetworkError, "Network Parse Error")
	DNSError            = New(NetworkError, "DNS Error")
	DNSConfigError      = New(DNSError, "DNS Config Error")

	// from io
	IOError            = New(SystemError, "IO Error")
	EOF                = New(IOError, "EOF")
	ClosedPipeError    = New(IOError, "Closed Pipe Error")
	NoProgressError    = New(IOError, "No Progress Error")
	ShortBufferError   = New(IOError, "Short Buffer Error")
	ShortWriteError    = New(IOError, "Short Write Error")
	UnexpectedEOFError = New(IOError, "Unexpected EOF Error")
)

func findSystemErrorClass(err error) *ErrorClass {
	switch err {
	case io.EOF:
		return EOF
	case io.ErrUnexpectedEOF:
		return UnexpectedEOFError
	case io.ErrClosedPipe:
		return ClosedPipeError
	case io.ErrNoProgress:
		return NoProgressError
	case io.ErrShortBuffer:
		return ShortBufferError
	case io.ErrShortWrite:
		return ShortWriteError
	default:
		break
	}
	switch err.(type) {
	case *os.SyscallError:
		return SyscallError
	case syscall.Errno:
		return ErrnoError
	case net.UnknownNetworkError:
		return UnknownNetworkError
	case *net.AddrError:
		return AddrError
	case net.InvalidAddrError:
		return InvalidAddrError
	case *net.OpError:
		return NetOpError
	case *net.ParseError:
		return NetParseError
	case *net.DNSError:
		return DNSError
	case *net.DNSConfigError:
		return DNSConfigError
	case net.Error:
		return NetworkError
	default:
		return SystemError
	}
}

func CatchPanic(err_ref *error) {
	r := recover()
	if r == nil {
		return
	}
	err, ok := r.(error)
	if ok {
		*err_ref = err
		return
	}
	*err_ref = PanicError.New("%v", r)
}

type ErrorGroup struct {
	Errors []error
}

func NewErrorGroup() *ErrorGroup { return &ErrorGroup{} }

func (e *ErrorGroup) Add(err error) {
	if err != nil {
		e.Errors = append(e.Errors, err)
	}
}

func (e *ErrorGroup) Finalize() error {
	if len(e.Errors) == 0 {
		return nil
	}
	if len(e.Errors) == 1 {
		return e.Errors[0]
	}
	msgs := make([]string, 0, len(e.Errors))
	for _, err := range e.Errors {
		msgs = append(msgs, err.Error())
	}
	return ErrorGroupError.New(strings.Join(msgs, "\n"))
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package bilateralrpc

import (
	zmq "github.com/pebbe/zmq4"
)

// send a packet
func sendPacket(socket *zmq.Socket, to string, command string, data []byte) error {

	if _, err := socket.Send(to, zmq.SNDMORE|zmq.DONTWAIT); nil != err {
		return err
	}
	if _, err := socket.Send(command, zmq.SNDMORE|zmq.DONTWAIT); nil != err {
		return err
	}
	_, err := socket.SendBytes(data, 0|zmq.DONTWAIT)

	return err
}

// receive a packet
func receivePacket(socket *zmq.Socket) (from string, command string, data []byte, err error) {

	from, err = socket.Recv(0)
	if nil != err {
		return "", "", []byte{}, err
	}

	if more, _ := socket.GetRcvmore(); !more {
		return from, "", []byte{}, nil
	}

	command, err = socket.Recv(0)
	if nil != err {
		return "", "", []byte{}, err
	}

	if more, _ := socket.GetRcvmore(); !more {
		return from, command, []byte{}, nil
	}

	data, err = socket.RecvBytes(0)
	if nil != err {
		return "", "", []byte{}, err
	}
	return from, command, data, nil
}
<commit_msg>add debug info<commit_after>// Copyright (c) 2014-2015 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package bilateralrpc

import (
	zmq "github.com/pebbe/zmq4"
)

// send a packet
func sendPacket(socket *zmq.Socket, to string, command string, data []byte) error {

	m1, err := socket.Send(to, zmq.SNDMORE|zmq.DONTWAIT)
	if nil != err {
		return err
	}
	m2, err := socket.Send(command, zmq.SNDMORE|zmq.DONTWAIT)
	if nil != err {
		return err
	}
	m3, err := socket.SendBytes(data, 0|zmq.DONTWAIT)

	n1 := len(to)
	n2 := len(command)
	n3 := len(data)

	log.Infof("sp: %d/%d  %d/%d  %d/%d", m1, n1, m2, n2, m3, n3)

	return err
}

// receive a packet
func receivePacket(socket *zmq.Socket) (from string, command string, data []byte, err error) {

	from, err = socket.Recv(0)
	if nil != err {
		return "", "", []byte{}, err
	}

	if more, _ := socket.GetRcvmore(); !more {
		return from, "", []byte{}, nil
	}

	command, err = socket.Recv(0)
	if nil != err {
		return "", "", []byte{}, err
	}

	if more, _ := socket.GetRcvmore(); !more {
		return from, command, []byte{}, nil
	}

	data, err = socket.RecvBytes(0)
	if nil != err {
		return "", "", []byte{}, err
	}
	return from, command, data, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Markus Dittrich. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// pagoda is a go library for command line parsing
package pagoda

import (
  "encoding/json"
  "os"
  "fmt"
  "unicode/utf8"
  "log"
//  "io/ioutil"
)

// packet_options holds the parsed values of a command line
// spec at runtime
var parse_info parse_spec

// parse_spec is the parent type describing all options and usage
type parse_spec struct {
  Usage string
  Options []json_option    // options parsed from spec file
  ArgOptions []option      // options present and parsed from command line
}

// json_option describes a single option specification as parsed from the
// JSON description
type json_option struct {
  Short_option string
  Long_option string
  Description string
  Default string
}

// option describes an option based on json_option with value
type option struct {
  json_option
  value interface{}
}

// Usage prints the usage information for the package
func Usage() {
  fmt.Printf("Usage: %s %s\n", os.Args[0], parse_info.Usage)
  fmt.Println()
  for _, opt := range parse_info.Options {
    fmt.Printf("\t-%s  --%s  %s\n", opt.Short_option, opt.Long_option,
      opt.Description)
  }
}

// parse_specs parses the specification of option in JSON format
func Parse_specs(content []byte) error {

  err := json.Unmarshal(content, &parse_info)
  if err != nil {
    return err
  }

  err = match_spec_to_args(parse_info, os.Args)
  if err != nil {
    return err
  }

  return nil
}

// test_for_option determines if a string is an option (i.e. starts
// either with a dash ('-') or a double dash ('--')). In that
// case it returns the name of the option and the value if the
// option was given via --opt=val.
func decode_option(item string) (string, string, error) {

  // check for dash
  c, s := utf8.DecodeRuneInString(item)
  if s == 0 || string(c) != "-" {
    return "", "", fmt.Errorf("%s is not an option\n", item)
  }
  i := s

  // skip next dash if present
  c, s = utf8.DecodeRuneInString(item[i:])
  if s != 0 && string(c) == "-" {
    i += s;
  }

  // scan until end or until we hit a "="
  opt := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", fmt.Errorf("failed to decode %s\n", item)
    } else if string(c) == "=" {
      break
    }

    opt += string(c)
  }

  val := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", fmt.Errorf("failed to decode %s\n", item)
    }

    val += string(c)
  }

  return opt, val, nil
}

// match_spec_to_args matches a parse_info spec to the provided command
// line options. Entries in parse_info which are lacking are ignored.
// If the command line contains entries which are not in the spec the
// function throws an error.
func match_spec_to_args(parsed parse_spec, args []string) error {
  fmt.Println("got it")

  i := 1
  for i < len(args) {

    currentArg := args[i]
    opt, val, err := decode_option(currentArg)
    if err != nil {
      log.Fatal(err)
    }

    fmt.Println("option ****", opt, val)

    i++
  }

  return nil
}

<commit_msg>Added more code for command line parsing.<commit_after>// Copyright 2014 Markus Dittrich. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// pagoda is a go library for command line parsing
package pagoda

import (
  "encoding/json"
  "os"
  "fmt"
  "unicode/utf8"
//  "log"
//  "io/ioutil"
)

// parse_info holds the parsed values of a command line spec
var parse_info parseSpec

// option_info holds the filled in values of present on the actual
// command line value corresponding to a command line spec at runtime
var option_info optionSpec

// option_spec is the type describing a filled in view of all
// parsed commandline options which matched the parse_spec
type optionSpec struct {
  argOptions []option      // options present and parsed from command line
}

// parse_spec is the parent type describing all options and usage
type parseSpec struct {
  Usage string
  Options []jsonOption    // options according to the spec
}

// json_option describes a single option specification as parsed from the
// JSON description
type jsonOption struct {
  Short_option string
  Long_option string
  Description string
  Default string
}

// option describes an option based on json_option with value
type option struct {
  jsonOption
  value interface{}
}

// Usage prints the usage information for the package
func Usage() {
  fmt.Printf("Usage: %s %s\n", os.Args[0], parse_info.Usage)
  fmt.Println()
  for _, opt := range parse_info.Options {
    fmt.Printf("\t-%s  --%s  %s\n", opt.Short_option, opt.Long_option,
      opt.Description)
  }
}

// parse_specs parses the specification of option in JSON format
func Parse_specs(content []byte) error {

  err := json.Unmarshal(content, &parse_info)
  if err != nil {
    return err
  }

  // initialize the option_spec
  option_info.argOptions = make([]option, 0)

  err = match_spec_to_args(parse_info, os.Args)
  if err != nil {
    return err
  }

  return nil
}

// test_for_option determines if a string is an option (i.e. starts
// either with a dash ('-') or a double dash ('--')). In that
// case it returns the name of the option and the value if the
// option was given via --opt=val.
func decode_option(item string) (string, string, bool) {

  // check for dash
  c, s := utf8.DecodeRuneInString(item)
  if s == 0 || string(c) != "-" {
    return "", "", false
  }
  i := s

  // skip next dash if present
  c, s = utf8.DecodeRuneInString(item[i:])
  if s != 0 && string(c) == "-" {
    i += s;
  }

  // scan until end of string or until we hit a "="
  opt := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    } else if string(c) == "=" {
      break
    }

    opt += string(c)
  }

  // scan for optional value specified via opt=val
  val := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    }

    val += string(c)
  }

  return opt, val, true
}

// find_option retrieves the parse_spec option entry corresponding
// to the given name f present. Otherwise returns false.
func find_parse_spec(spec parseSpec, name string) (jsonOption, bool) {

  for _, opt := range spec.Options {
    if opt.Short_option == name || opt.Long_option == name {
      return opt, true
    }
  }

  return jsonOption{}, false
}

// match_spec_to_args matches a parse_info spec to the provided command
// line options. Entries in parse_info which are lacking are ignored.
// If the command line contains entries which are not in the spec the
// function throws an error.
func match_spec_to_args(parsed parseSpec, args []string) error {
  fmt.Println("got it")

  var opt_name, opt_val string
  var ok bool
  for i := 1; i < len(args); i++ {
    opt_name, opt_val, ok = decode_option(args[i])
    if !ok {
      continue
    }

    _, ok := find_parse_spec(parsed, opt_name)
    if !ok {
      continue
    }

    fmt.Println("option ****", opt_name, opt_val)
  }

  return nil
}

<|endoftext|>


<commit_before>package text

import "github.com/qlova/uct/compiler"
import "github.com/qlova/ilang/syntax/errors"
import "github.com/qlova/ilang/syntax/symbols"

func init() {
	Type.EmbeddedStatement = func(c *compiler.Compiler, list compiler.Type) {
		statement(c, true)
	}
}

func statement(c *compiler.Compiler, embed bool) bool {
	if embed || c.GetVariable(c.Token()).Type.Equals(Type) {

			var name = c.Token()

			switch c.Scan() {

				case symbols.Equals:
					if embed {
						//Garbage collect! >:)
						c.Get()
						c.Copy()
						c.If()
							c.Flip()
							c.HeapList()
						c.Or()
							c.Drop()
						c.No()
					}

					var t = c.ScanExpression()
					if !t.Equals(Type) {
						c.RaiseError(errors.AssignmentMismatch(t, Type))
					}

					if embed {
						c.Int(0)
						c.HeapList()
						c.Set()
					} else {

						c.NameList(name)

					}

				default:
					c.Unexpected(c.Token())
			}

			return true
		}
		return false
}

<commit_msg>text += ""<commit_after>package text

import "github.com/qlova/uct/compiler"
import "github.com/qlova/ilang/syntax/errors"
import "github.com/qlova/ilang/syntax/symbols"

func init() {
	Type.EmbeddedStatement = func(c *compiler.Compiler, list compiler.Type) {
		statement(c, true)
	}
}

var Statement = compiler.Statement {
	Detect: func(c *compiler.Compiler) bool {
		return statement(c, false)
	},
}

func statement(c *compiler.Compiler, embed bool) bool {
	if embed || c.GetVariable(c.Token()).Type.Equals(Type) {

			var name = c.Token()

			switch c.Scan() {

				case symbols.Equals:
					if embed {
						//Garbage collect! >:)
						c.Get()
						c.Copy()
						c.If()
							c.Flip()
							c.HeapList()
						c.Or()
							c.Drop()
						c.No()
					}

					var t = c.ScanExpression()
					if !t.Equals(Type) {
						c.RaiseError(errors.AssignmentMismatch(t, Type))
					}

					if embed {
						c.Int(0)
						c.HeapList()
						c.Set()
					} else {

						c.NameList(name)

					}

				case symbols.Plus:
					if embed {
						c.Unimplemented()
					}

					c.Expecting(symbols.Equals)

					c.PushList(name)

					var t = c.ScanExpression()
					if !t.Equals(Type) {
						c.RaiseError(errors.AssignmentMismatch(t, Type))
					}

					c.Call(&Join)

					c.NameList(name)

				default:
					c.Unexpected(c.Token())
			}

			return true
		}
		return false
}

<|endoftext|>