<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

import "fmt"

// Block represents a basic block in the control flow graph of a function.
type Block struct {
	// A unique identifier for the block. The system will attempt to allocate
	// these IDs densely, but no guarantees.
	ID ID

	// Line number for block's control operation
	Line int32

	// The kind of block this is.
	Kind BlockKind

	// Likely direction for branches.
	// If BranchLikely, Succs[0] is the most likely branch taken.
	// If BranchUnlikely, Succs[1] is the most likely branch taken.
	// Ignored if len(Succs) < 2.
	// Fatal if not BranchUnknown and len(Succs) > 2.
	Likely BranchPrediction

	// After flagalloc, records whether flags are live at the end of the block.
	FlagsLiveAtEnd bool

	// Subsequent blocks, if any. The number and order depend on the block kind.
	Succs []Edge

	// Inverse of successors.
	// The order is significant to Phi nodes in the block.
	// TODO: predecessors is a pain to maintain. Can we somehow order phi
	// arguments by block id and have this field computed explicitly when needed?
	Preds []Edge

	// A value that determines how the block is exited. Its value depends on the kind
	// of the block. For instance, a BlockIf has a boolean control value and BlockExit
	// has a memory control value.
	Control *Value

	// Auxiliary info for the block. Its value depends on the Kind.
	Aux interface{}

	// The unordered set of Values that define the operation of this block.
	// The list must include the control value, if any. (TODO: need this last condition?)
	// After the scheduling pass, this list is ordered.
	Values []*Value

	// The containing function
	Func *Func

	// Storage for Succs, Preds, and Values
	succstorage [2]Edge
	predstorage [4]Edge
	valstorage  [9]*Value
}

// Edge represents a CFG edge.
// Example edges for b branching to either c or d.
// (c and d have other predecessors.)
//   b.Succs = [{c,3}, {d,1}]
//   c.Preds = [?, ?, ?, {b,0}]
//   d.Preds = [?, {b,1}, ?]
// These indexes allow us to edit the CFG in constant time.
// In addition, it informs phi ops in degenerate cases like:
// b:
//    if k then c else c
// c:
//    v = Phi(x, y)
// Then the indexes tell you whether x is chosen from
// the if or else branch from b.
//   b.Succs = [{c,0},{c,1}]
//   c.Preds = [{b,0},{b,1}]
// means x is chosen if k is true.
type Edge struct {
	// block edge goes to (in a Succs list) or from (in a Preds list)
	b *Block
	// index of reverse edge.  Invariant:
	//   e := x.Succs[idx]
	//   e.b.Preds[e.i] = Edge{x,idx}
	// and similarly for predecessors.
	i int
}

func (e Edge) Block() *Block {
	return e.b
}
func (e Edge) Index() int {
	return e.i
}

//     kind           control    successors
//   ------------------------------------------
//     Exit        return mem                []
//    Plain               nil            [next]
//       If   a boolean Value      [then, else]
//     Call               mem  [nopanic, panic]  (control opcode should be OpCall or OpStaticCall)
type BlockKind int8

// short form print
func (b *Block) String() string {
	return fmt.Sprintf("b%d", b.ID)
}

// long form print
func (b *Block) LongString() string {
	s := b.Kind.String()
	if b.Aux != nil {
		s += fmt.Sprintf(" %s", b.Aux)
	}
	if b.Control != nil {
		s += fmt.Sprintf(" %s", b.Control)
	}
	if len(b.Succs) > 0 {
		s += " ->"
		for _, c := range b.Succs {
			s += " " + c.b.String()
		}
	}
	switch b.Likely {
	case BranchUnlikely:
		s += " (unlikely)"
	case BranchLikely:
		s += " (likely)"
	}
	return s
}

func (b *Block) SetControl(v *Value) {
	if w := b.Control; w != nil {
		w.Uses--
	}
	b.Control = v
	if v != nil {
		v.Uses++
	}
}

// AddEdgeTo adds an edge from block b to block c. Used during building of the
// SSA graph; do not use on an already-completed SSA graph.
func (b *Block) AddEdgeTo(c *Block) {
	i := len(b.Succs)
	j := len(c.Preds)
	b.Succs = append(b.Succs, Edge{c, j})
	c.Preds = append(c.Preds, Edge{b, i})
	b.Func.invalidateCFG()
}

// removePred removes the ith input edge from b.
// It is the responsibility of the caller to remove
// the corresponding successor edge.
func (b *Block) removePred(i int) {
	n := len(b.Preds) - 1
	if i != n {
		e := b.Preds[n]
		b.Preds[i] = e
		// Update the other end of the edge we moved.
		e.b.Succs[e.i].i = i
	}
	b.Preds[n] = Edge{}
	b.Preds = b.Preds[:n]
	b.Func.invalidateCFG()
}

// removeSucc removes the ith output edge from b.
// It is the responsibility of the caller to remove
// the corresponding predecessor edge.
func (b *Block) removeSucc(i int) {
	n := len(b.Succs) - 1
	if i != n {
		e := b.Succs[n]
		b.Succs[i] = e
		// Update the other end of the edge we moved.
		e.b.Preds[e.i].i = i
	}
	b.Succs[n] = Edge{}
	b.Succs = b.Succs[:n]
	b.Func.invalidateCFG()
}

func (b *Block) swapSuccessors() {
	if len(b.Succs) != 2 {
		b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
	}
	e0 := b.Succs[0]
	e1 := b.Succs[1]
	b.Succs[0] = e1
	b.Succs[1] = e0
	e0.b.Preds[e0.i].i = 1
	e1.b.Preds[e1.i].i = 0
	b.Likely *= -1
}

func (b *Block) Logf(msg string, args ...interface{})   { b.Func.Logf(msg, args...) }
func (b *Block) Log() bool                              { return b.Func.Log() }
func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }

type BranchPrediction int8

const (
	BranchUnlikely = BranchPrediction(-1)
	BranchUnknown  = BranchPrediction(0)
	BranchLikely   = BranchPrediction(+1)
)
<commit_msg>cmd/compile/internal/ssa: update BlockKind documentation<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

import "fmt"

// Block represents a basic block in the control flow graph of a function.
type Block struct {
	// A unique identifier for the block. The system will attempt to allocate
	// these IDs densely, but no guarantees.
	ID ID

	// Line number for block's control operation
	Line int32

	// The kind of block this is.
	Kind BlockKind

	// Likely direction for branches.
	// If BranchLikely, Succs[0] is the most likely branch taken.
	// If BranchUnlikely, Succs[1] is the most likely branch taken.
	// Ignored if len(Succs) < 2.
	// Fatal if not BranchUnknown and len(Succs) > 2.
	Likely BranchPrediction

	// After flagalloc, records whether flags are live at the end of the block.
	FlagsLiveAtEnd bool

	// Subsequent blocks, if any. The number and order depend on the block kind.
	Succs []Edge

	// Inverse of successors.
	// The order is significant to Phi nodes in the block.
	// TODO: predecessors is a pain to maintain. Can we somehow order phi
	// arguments by block id and have this field computed explicitly when needed?
	Preds []Edge

	// A value that determines how the block is exited. Its value depends on the kind
	// of the block. For instance, a BlockIf has a boolean control value and BlockExit
	// has a memory control value.
	Control *Value

	// Auxiliary info for the block. Its value depends on the Kind.
	Aux interface{}

	// The unordered set of Values that define the operation of this block.
	// The list must include the control value, if any. (TODO: need this last condition?)
	// After the scheduling pass, this list is ordered.
	Values []*Value

	// The containing function
	Func *Func

	// Storage for Succs, Preds, and Values
	succstorage [2]Edge
	predstorage [4]Edge
	valstorage  [9]*Value
}

// Edge represents a CFG edge.
// Example edges for b branching to either c or d.
// (c and d have other predecessors.)
//   b.Succs = [{c,3}, {d,1}]
//   c.Preds = [?, ?, ?, {b,0}]
//   d.Preds = [?, {b,1}, ?]
// These indexes allow us to edit the CFG in constant time.
// In addition, it informs phi ops in degenerate cases like:
// b:
//    if k then c else c
// c:
//    v = Phi(x, y)
// Then the indexes tell you whether x is chosen from
// the if or else branch from b.
//   b.Succs = [{c,0},{c,1}]
//   c.Preds = [{b,0},{b,1}]
// means x is chosen if k is true.
type Edge struct {
	// block edge goes to (in a Succs list) or from (in a Preds list)
	b *Block
	// index of reverse edge.  Invariant:
	//   e := x.Succs[idx]
	//   e.b.Preds[e.i] = Edge{x,idx}
	// and similarly for predecessors.
	i int
}

func (e Edge) Block() *Block {
	return e.b
}
func (e Edge) Index() int {
	return e.i
}

//     kind           control    successors
//   ------------------------------------------
//     Exit        return mem                []
//    Plain               nil            [next]
//       If   a boolean Value      [then, else]
//    Defer               mem  [nopanic, panic]  (control opcode should be OpDeferCall)
type BlockKind int8

// short form print
func (b *Block) String() string {
	return fmt.Sprintf("b%d", b.ID)
}

// long form print
func (b *Block) LongString() string {
	s := b.Kind.String()
	if b.Aux != nil {
		s += fmt.Sprintf(" %s", b.Aux)
	}
	if b.Control != nil {
		s += fmt.Sprintf(" %s", b.Control)
	}
	if len(b.Succs) > 0 {
		s += " ->"
		for _, c := range b.Succs {
			s += " " + c.b.String()
		}
	}
	switch b.Likely {
	case BranchUnlikely:
		s += " (unlikely)"
	case BranchLikely:
		s += " (likely)"
	}
	return s
}

func (b *Block) SetControl(v *Value) {
	if w := b.Control; w != nil {
		w.Uses--
	}
	b.Control = v
	if v != nil {
		v.Uses++
	}
}

// AddEdgeTo adds an edge from block b to block c. Used during building of the
// SSA graph; do not use on an already-completed SSA graph.
func (b *Block) AddEdgeTo(c *Block) {
	i := len(b.Succs)
	j := len(c.Preds)
	b.Succs = append(b.Succs, Edge{c, j})
	c.Preds = append(c.Preds, Edge{b, i})
	b.Func.invalidateCFG()
}

// removePred removes the ith input edge from b.
// It is the responsibility of the caller to remove
// the corresponding successor edge.
func (b *Block) removePred(i int) {
	n := len(b.Preds) - 1
	if i != n {
		e := b.Preds[n]
		b.Preds[i] = e
		// Update the other end of the edge we moved.
		e.b.Succs[e.i].i = i
	}
	b.Preds[n] = Edge{}
	b.Preds = b.Preds[:n]
	b.Func.invalidateCFG()
}

// removeSucc removes the ith output edge from b.
// It is the responsibility of the caller to remove
// the corresponding predecessor edge.
func (b *Block) removeSucc(i int) {
	n := len(b.Succs) - 1
	if i != n {
		e := b.Succs[n]
		b.Succs[i] = e
		// Update the other end of the edge we moved.
		e.b.Preds[e.i].i = i
	}
	b.Succs[n] = Edge{}
	b.Succs = b.Succs[:n]
	b.Func.invalidateCFG()
}

func (b *Block) swapSuccessors() {
	if len(b.Succs) != 2 {
		b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
	}
	e0 := b.Succs[0]
	e1 := b.Succs[1]
	b.Succs[0] = e1
	b.Succs[1] = e0
	e0.b.Preds[e0.i].i = 1
	e1.b.Preds[e1.i].i = 0
	b.Likely *= -1
}

func (b *Block) Logf(msg string, args ...interface{})   { b.Func.Logf(msg, args...) }
func (b *Block) Log() bool                              { return b.Func.Log() }
func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }

type BranchPrediction int8

const (
	BranchUnlikely = BranchPrediction(-1)
	BranchUnknown  = BranchPrediction(0)
	BranchLikely   = BranchPrediction(+1)
)
<|endoftext|>


<commit_before>package rest

import (
	"fmt"
	"log"
	"reflect"
	"strconv"
)

// Type is a data type to coerce a value to specified with a Rule.
type Type uint

const (
	// Interface represents the interface{} data type.
	Interface Type = iota

	// Int represents the int data type.
	Int

	// Int8 represents the int8 data type.
	Int8

	// Int16 represents the int16 data type.
	Int16

	// Int32 represents the int32 data type.
	Int32

	// Int64 represents the int64 data type.
	Int64

	// Uint represents the uint data type.
	Uint

	// Uint8 represents the uint8 data type.
	Uint8

	// Uint16 represents the uint16 data type.
	Uint16

	// Uint32 represents the uint32 data type.
	Uint32

	// Uint64 represents the uint64 data type.
	Uint64

	// Float32 represents the float32 data type.
	Float32

	// Float64 represents the float64 data type.
	Float64

	// String represents the string data type.
	String

	// Bool represents the bool data type.
	Bool

	// Array represents the []interface{} data type.
	Array

	// Map represents the map[string]interface{} data type.
	Map

	// Byte represents the byte data type.
	Byte = Uint8

	// Unspecified represents the interface{} data type.
	Unspecified = Interface
)

// typeName maps Types to their human-readable names.
var typeName = map[Type]string{
	Interface: "interface{}",
	Int:       "int",
	Int8:      "int8",
	Int16:     "int16",
	Int32:     "int32",
	Int64:     "int64",
	Uint:      "uint",
	Uint8:     "uint8",
	Uint16:    "uint16",
	Uint32:    "uint32",
	Uint64:    "uint64",
	Float32:   "float32",
	Float64:   "float64",
	String:    "string",
	Bool:      "bool",
	Array:     "[]interface{}",
	Map:       "map[string]interface{}",
}

// Rule provides schema validation and type coercion for request input and fine-grained
// control over response output. If a ResourceHandler provides input Rules which specify
// types, input fields will attempt to be coerced to those types. If coercion fails, an
// error will be returned in the response. If a ResourceHandler provides output Rules,
// only the fields corresponding to those Rules will be sent back. This prevents new
// fields from leaking into old API versions.
type Rule struct {
	// Name of the resource field. This is the name as it appears in the struct
	// definition.
	Field string

	// Name of the input/output field. Defaults to resource field name if not specified.
	ValueName string

	// Type to coerce field value to. If the value cannot be coerced, an error will be
	// returned in the response. Defaults to Unspecified, which is the equivalent of
	// an interface{} value.
	Type Type

	// Indicates if the Rule should only be applied to requests.
	InputOnly bool

	// Indicates if the Rule should only be applied to responses.
	OutputOnly bool

	// Function which produces the field value to receive.
	InputHandler func(interface{}) interface{}

	// Function which produces the field value to send.
	OutputHandler func(interface{}) interface{}
}

// applyInboundRules applies Rules which are not specified as output only to the provided
// Payload. If the Payload is nil, an empty Payload will be returned. If no Rules are
// provided, this acts as an identity function. If Rules are provided, any incoming
// fields which are not specified will be discarded. If Rules specify types, incoming
// values will attempted to be coerced. If coercion fails, an error will be returned.
func applyInboundRules(payload Payload, rules []Rule) (Payload, error) {
	if payload == nil {
		return Payload{}, nil
	}

	// Apply only inbound Rules.
	rules = filterRules(rules, true)

	if len(rules) == 0 {
		return payload, nil
	}

	newPayload := Payload{}

fieldLoop:
	for field, value := range payload {
		for _, rule := range rules {
			if rule.ValueName == field {
				if rule.Type != Unspecified {
					// Coerce to specified type.
					coerced, err := coerceType(value, rule.Type)
					if err != nil {
						return nil, err
					}
					value = coerced
				}
				if rule.InputHandler != nil {
					value = rule.InputHandler(value)
				}
				newPayload[field] = value
				continue fieldLoop
			}
		}

		log.Printf("Discarding field '%s'", field)
	}

	return newPayload, nil
}

// applyOutboundRules applies Rules which are not specified as input only to the provided
// Resource. If the Resource is nil, not a struct, or no Rules are provided, this acts as
// an identity function. If Rules are provided, only the fields specified by them will be
// included in the returned Resource. This is to prevent new fields from leaking into old
// API versions.
func applyOutboundRules(resource Resource, rules []Rule) Resource {
	// Apply only outbound Rules.
	rules = filterRules(rules, false)

	if resource == nil || len(rules) == 0 {
		// Return resource as-is if no Rules are provided.
		return resource
	}

	// Get the underlying value by dereferencing the pointer if there is one.
	resourceValue := reflect.Indirect(reflect.ValueOf(resource))
	resource = resourceValue.Interface()
	resourceType := reflect.TypeOf(resource)

	if resourceType.Kind() != reflect.Struct {
		// Only apply Rules to structs.
		// TODO: Can probably apply them to maps as well.
		return resource
	}

	payload := Payload{}

	for _, rule := range rules {
		field := resourceValue.FieldByName(rule.Field)
		if !field.IsValid() {
			// The field doesn't exist.
			log.Printf("%s has no field '%s'", reflect.TypeOf(resource).Name(), rule.Field)
			continue
		}

		valueName := rule.ValueName
		if valueName == "" {
			// Use field name if value name isn't specified.
			valueName = rule.Field
		}

		fieldValue := field.Interface()
		if rule.OutputHandler != nil {
			fieldValue = rule.OutputHandler(fieldValue)
		}
		payload[valueName] = fieldValue
	}

	return payload
}

// filterRules filters the array of Rules based on the specified bool. True means to
// filter out outbound Rules such that the returned array contains only inbound Rules.
// False means to filter out inbound Rules such that the returned array contains only
// outbound Rules.
func filterRules(rules []Rule, inbound bool) []Rule {
	filtered := make([]Rule, 0, len(rules))
	for _, rule := range rules {
		if inbound && rule.OutputOnly {
			// Filter out outbound Rules.
			continue
		} else if !inbound && rule.InputOnly {
			// Filter out inbound Rules.
			continue
		}
		filtered = append(filtered, rule)
	}

	return filtered
}

// coerceType attempts to convert the given value to the specified Type. If it cannot
// be coerced, nil will be returned along with an error.
func coerceType(value interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Interface {
		return value, nil
	}

	// json.Unmarshal converts values to bool, float64, string, nil, array, and map.
	switch value.(type) {
	case bool:
		return coerceFromBool(value.(bool), coerceTo)
	case float64:
		return coerceFromFloat(value.(float64), coerceTo)
	case string:
		return coerceFromString(value.(string), coerceTo)
	case nil:
		return value, nil
	case []interface{}:
		return coerceFromArray(value.([]interface{}), coerceTo)
	case map[string]interface{}:
		return coerceFromMap(value.(map[string]interface{}), coerceTo)
	default:
		return nil, fmt.Errorf("Unable to coerce %s to %s",
			reflect.TypeOf(value), typeName[coerceTo])
	}
}

// coerceFromBool attempts to convert the given bool to the specified Type. If it
// cannot be coerced, nil will be returned along with an error.
func coerceFromBool(value bool, coerceTo Type) (interface{}, error) {
	if coerceTo == Bool {
		return value, nil
	}
	if coerceTo == String {
		if value {
			return "true", nil
		}
		return "false", nil
	}

	return nil, fmt.Errorf("Unable to coerce bool to %s", typeName[coerceTo])
}

// coerceFromFloat attempts to convert the given float64 to the specified Type.
// If it cannot be coerced, nil will be returned along with an error.
func coerceFromFloat(value float64, coerceTo Type) (interface{}, error) {
	switch coerceTo {
	// To int.
	case Int:
		return int(value), nil
	case Int8:
		return int8(value), nil
	case Int16:
		return int16(value), nil
	case Int32:
		return int32(value), nil
	case Int64:
		return int64(value), nil

	// To unsigned int.
	case Uint:
		return uint(value), nil
	case Uint8:
		return uint8(value), nil
	case Uint16:
		return uint16(value), nil
	case Uint32:
		return uint32(value), nil
	case Uint64:
		return uint64(value), nil

	// To float.
	case Float32:
		return float32(value), nil
	case Float64:
		return value, nil

	// To string.
	case String:
		return strconv.FormatFloat(value, 'f', -1, 64), nil

	// Bool case left off intentionally.
	default:
		return nil, fmt.Errorf("Unable to coerce float to %s", typeName[coerceTo])
	}
}

// coerceFromString attempts to convert the given string to the specified Type. If
// it cannot be coerced, nil will be returned along with an error.
func coerceFromString(value string, coerceTo Type) (interface{}, error) {
	switch coerceTo {
	// To int.
	case Int:
		val, err := strconv.ParseInt(value, 0, 0)
		if err != nil {
			return nil, err
		}
		return int(val), nil
	case Int8:
		val, err := strconv.ParseInt(value, 0, 8)
		if err != nil {
			return nil, err
		}
		return int8(val), nil
	case Int16:
		val, err := strconv.ParseInt(value, 0, 16)
		if err != nil {
			return nil, err
		}
		return int16(val), nil
	case Int32:
		val, err := strconv.ParseInt(value, 0, 32)
		if err != nil {
			return nil, err
		}
		return int32(val), nil
	case Int64:
		val, err := strconv.ParseInt(value, 0, 64)
		if err != nil {
			return nil, err
		}
		return int64(val), nil

	// To unsigned int.
	case Uint:
		val, err := strconv.ParseUint(value, 0, 0)
		if err != nil {
			return nil, err
		}
		return uint(val), nil
	case Uint8:
		val, err := strconv.ParseUint(value, 0, 8)
		if err != nil {
			return nil, err
		}
		return uint8(val), nil
	case Uint16:
		val, err := strconv.ParseUint(value, 0, 16)
		if err != nil {
			return nil, err
		}
		return uint16(val), nil
	case Uint32:
		val, err := strconv.ParseUint(value, 0, 32)
		if err != nil {
			return nil, err
		}
		return uint32(val), nil
	case Uint64:
		val, err := strconv.ParseUint(value, 0, 64)
		if err != nil {
			return nil, err
		}
		return uint64(val), nil

	// To float.
	case Float32:
		val, err := strconv.ParseFloat(value, 32)
		if err != nil {
			return nil, err
		}
		return float32(val), nil
	case Float64:
		val, err := strconv.ParseFloat(value, 64)
		if err != nil {
			return nil, err
		}
		return float64(val), nil

	// To string.
	case String:
		return value, nil

	// To bool.
	case Bool:
		val, err := strconv.ParseBool(value)
		if err != nil {
			return nil, err
		}
		return val, nil

	default:
		return nil, fmt.Errorf("Unable to coerce string to %s", typeName[coerceTo])
	}
}

// coerceFromArray attempts to convert the given array to the specified Type. Currently,
// arrays can only be coerced to arrays (identity). If it cannot be coerced, nil will be
// returned along with an error.
func coerceFromArray(value []interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Array {
		return value, nil
	}

	return nil, fmt.Errorf("Unable to coerce array to %s", typeName[coerceTo])
}

// coerceFromMap attempts to convert the given map to the specified Type. Currently,
// maps can only be coerced to maps (identity). If it cannot be coerced, nil will be
// returned along with an error.
func coerceFromMap(value map[string]interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Map {
		return value, nil
	}

	return nil, fmt.Errorf("Unable to coerce map to %s", typeName[coerceTo])
}
<commit_msg>Add comment on data validation<commit_after>package rest

import (
	"fmt"
	"log"
	"reflect"
	"strconv"
)

// Type is a data type to coerce a value to specified with a Rule.
type Type uint

const (
	// Interface represents the interface{} data type.
	Interface Type = iota

	// Int represents the int data type.
	Int

	// Int8 represents the int8 data type.
	Int8

	// Int16 represents the int16 data type.
	Int16

	// Int32 represents the int32 data type.
	Int32

	// Int64 represents the int64 data type.
	Int64

	// Uint represents the uint data type.
	Uint

	// Uint8 represents the uint8 data type.
	Uint8

	// Uint16 represents the uint16 data type.
	Uint16

	// Uint32 represents the uint32 data type.
	Uint32

	// Uint64 represents the uint64 data type.
	Uint64

	// Float32 represents the float32 data type.
	Float32

	// Float64 represents the float64 data type.
	Float64

	// String represents the string data type.
	String

	// Bool represents the bool data type.
	Bool

	// Array represents the []interface{} data type.
	Array

	// Map represents the map[string]interface{} data type.
	Map

	// Byte represents the byte data type.
	Byte = Uint8

	// Unspecified represents the interface{} data type.
	Unspecified = Interface
)

// typeName maps Types to their human-readable names.
var typeName = map[Type]string{
	Interface: "interface{}",
	Int:       "int",
	Int8:      "int8",
	Int16:     "int16",
	Int32:     "int32",
	Int64:     "int64",
	Uint:      "uint",
	Uint8:     "uint8",
	Uint16:    "uint16",
	Uint32:    "uint32",
	Uint64:    "uint64",
	Float32:   "float32",
	Float64:   "float64",
	String:    "string",
	Bool:      "bool",
	Array:     "[]interface{}",
	Map:       "map[string]interface{}",
}

// Rule provides schema validation and type coercion for request input and fine-grained
// control over response output. If a ResourceHandler provides input Rules which specify
// types, input fields will attempt to be coerced to those types. If coercion fails, an
// error will be returned in the response. If a ResourceHandler provides output Rules,
// only the fields corresponding to those Rules will be sent back. This prevents new
// fields from leaking into old API versions.
type Rule struct {
	// Name of the resource field. This is the name as it appears in the struct
	// definition.
	Field string

	// Name of the input/output field. Defaults to resource field name if not specified.
	ValueName string

	// Type to coerce field value to. If the value cannot be coerced, an error will be
	// returned in the response. Defaults to Unspecified, which is the equivalent of
	// an interface{} value.
	Type Type

	// Indicates if the Rule should only be applied to requests.
	InputOnly bool

	// Indicates if the Rule should only be applied to responses.
	OutputOnly bool

	// Function which produces the field value to receive.
	InputHandler func(interface{}) interface{}

	// Function which produces the field value to send.
	OutputHandler func(interface{}) interface{}
}

// applyInboundRules applies Rules which are not specified as output only to the provided
// Payload. If the Payload is nil, an empty Payload will be returned. If no Rules are
// provided, this acts as an identity function. If Rules are provided, any incoming
// fields which are not specified will be discarded. If Rules specify types, incoming
// values will attempted to be coerced. If coercion fails, an error will be returned.
func applyInboundRules(payload Payload, rules []Rule) (Payload, error) {
	if payload == nil {
		return Payload{}, nil
	}

	// Apply only inbound Rules.
	rules = filterRules(rules, true)

	if len(rules) == 0 {
		return payload, nil
	}

	newPayload := Payload{}

	// TODO: Consider using/writing a more robust data validation library.
	// E.g. https://github.com/Assembli/beautiful-validity
	// This would allow for semantic validation and custom validation logic.
	// For now, we are only providing type validation.

fieldLoop:
	for field, value := range payload {
		for _, rule := range rules {
			if rule.ValueName == field {
				if rule.Type != Unspecified {
					// Coerce to specified type.
					coerced, err := coerceType(value, rule.Type)
					if err != nil {
						return nil, err
					}
					value = coerced
				}
				if rule.InputHandler != nil {
					value = rule.InputHandler(value)
				}
				newPayload[field] = value
				continue fieldLoop
			}
		}

		log.Printf("Discarding field '%s'", field)
	}

	return newPayload, nil
}

// applyOutboundRules applies Rules which are not specified as input only to the provided
// Resource. If the Resource is nil, not a struct, or no Rules are provided, this acts as
// an identity function. If Rules are provided, only the fields specified by them will be
// included in the returned Resource. This is to prevent new fields from leaking into old
// API versions.
func applyOutboundRules(resource Resource, rules []Rule) Resource {
	// Apply only outbound Rules.
	rules = filterRules(rules, false)

	if resource == nil || len(rules) == 0 {
		// Return resource as-is if no Rules are provided.
		return resource
	}

	// Get the underlying value by dereferencing the pointer if there is one.
	resourceValue := reflect.Indirect(reflect.ValueOf(resource))
	resource = resourceValue.Interface()
	resourceType := reflect.TypeOf(resource)

	if resourceType.Kind() != reflect.Struct {
		// Only apply Rules to structs.
		// TODO: Can probably apply them to maps as well.
		return resource
	}

	payload := Payload{}

	for _, rule := range rules {
		field := resourceValue.FieldByName(rule.Field)
		if !field.IsValid() {
			// The field doesn't exist.
			log.Printf("%s has no field '%s'", reflect.TypeOf(resource).Name(), rule.Field)
			continue
		}

		valueName := rule.ValueName
		if valueName == "" {
			// Use field name if value name isn't specified.
			valueName = rule.Field
		}

		fieldValue := field.Interface()
		if rule.OutputHandler != nil {
			fieldValue = rule.OutputHandler(fieldValue)
		}
		payload[valueName] = fieldValue
	}

	return payload
}

// filterRules filters the array of Rules based on the specified bool. True means to
// filter out outbound Rules such that the returned array contains only inbound Rules.
// False means to filter out inbound Rules such that the returned array contains only
// outbound Rules.
func filterRules(rules []Rule, inbound bool) []Rule {
	filtered := make([]Rule, 0, len(rules))
	for _, rule := range rules {
		if inbound && rule.OutputOnly {
			// Filter out outbound Rules.
			continue
		} else if !inbound && rule.InputOnly {
			// Filter out inbound Rules.
			continue
		}
		filtered = append(filtered, rule)
	}

	return filtered
}

// coerceType attempts to convert the given value to the specified Type. If it cannot
// be coerced, nil will be returned along with an error.
func coerceType(value interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Interface {
		return value, nil
	}

	// json.Unmarshal converts values to bool, float64, string, nil, array, and map.
	switch value.(type) {
	case bool:
		return coerceFromBool(value.(bool), coerceTo)
	case float64:
		return coerceFromFloat(value.(float64), coerceTo)
	case string:
		return coerceFromString(value.(string), coerceTo)
	case nil:
		return value, nil
	case []interface{}:
		return coerceFromArray(value.([]interface{}), coerceTo)
	case map[string]interface{}:
		return coerceFromMap(value.(map[string]interface{}), coerceTo)
	default:
		return nil, fmt.Errorf("Unable to coerce %s to %s",
			reflect.TypeOf(value), typeName[coerceTo])
	}
}

// coerceFromBool attempts to convert the given bool to the specified Type. If it
// cannot be coerced, nil will be returned along with an error.
func coerceFromBool(value bool, coerceTo Type) (interface{}, error) {
	if coerceTo == Bool {
		return value, nil
	}
	if coerceTo == String {
		if value {
			return "true", nil
		}
		return "false", nil
	}

	return nil, fmt.Errorf("Unable to coerce bool to %s", typeName[coerceTo])
}

// coerceFromFloat attempts to convert the given float64 to the specified Type.
// If it cannot be coerced, nil will be returned along with an error.
func coerceFromFloat(value float64, coerceTo Type) (interface{}, error) {
	switch coerceTo {
	// To int.
	case Int:
		return int(value), nil
	case Int8:
		return int8(value), nil
	case Int16:
		return int16(value), nil
	case Int32:
		return int32(value), nil
	case Int64:
		return int64(value), nil

	// To unsigned int.
	case Uint:
		return uint(value), nil
	case Uint8:
		return uint8(value), nil
	case Uint16:
		return uint16(value), nil
	case Uint32:
		return uint32(value), nil
	case Uint64:
		return uint64(value), nil

	// To float.
	case Float32:
		return float32(value), nil
	case Float64:
		return value, nil

	// To string.
	case String:
		return strconv.FormatFloat(value, 'f', -1, 64), nil

	// Bool case left off intentionally.
	default:
		return nil, fmt.Errorf("Unable to coerce float to %s", typeName[coerceTo])
	}
}

// coerceFromString attempts to convert the given string to the specified Type. If
// it cannot be coerced, nil will be returned along with an error.
func coerceFromString(value string, coerceTo Type) (interface{}, error) {
	switch coerceTo {
	// To int.
	case Int:
		val, err := strconv.ParseInt(value, 0, 0)
		if err != nil {
			return nil, err
		}
		return int(val), nil
	case Int8:
		val, err := strconv.ParseInt(value, 0, 8)
		if err != nil {
			return nil, err
		}
		return int8(val), nil
	case Int16:
		val, err := strconv.ParseInt(value, 0, 16)
		if err != nil {
			return nil, err
		}
		return int16(val), nil
	case Int32:
		val, err := strconv.ParseInt(value, 0, 32)
		if err != nil {
			return nil, err
		}
		return int32(val), nil
	case Int64:
		val, err := strconv.ParseInt(value, 0, 64)
		if err != nil {
			return nil, err
		}
		return int64(val), nil

	// To unsigned int.
	case Uint:
		val, err := strconv.ParseUint(value, 0, 0)
		if err != nil {
			return nil, err
		}
		return uint(val), nil
	case Uint8:
		val, err := strconv.ParseUint(value, 0, 8)
		if err != nil {
			return nil, err
		}
		return uint8(val), nil
	case Uint16:
		val, err := strconv.ParseUint(value, 0, 16)
		if err != nil {
			return nil, err
		}
		return uint16(val), nil
	case Uint32:
		val, err := strconv.ParseUint(value, 0, 32)
		if err != nil {
			return nil, err
		}
		return uint32(val), nil
	case Uint64:
		val, err := strconv.ParseUint(value, 0, 64)
		if err != nil {
			return nil, err
		}
		return uint64(val), nil

	// To float.
	case Float32:
		val, err := strconv.ParseFloat(value, 32)
		if err != nil {
			return nil, err
		}
		return float32(val), nil
	case Float64:
		val, err := strconv.ParseFloat(value, 64)
		if err != nil {
			return nil, err
		}
		return float64(val), nil

	// To string.
	case String:
		return value, nil

	// To bool.
	case Bool:
		val, err := strconv.ParseBool(value)
		if err != nil {
			return nil, err
		}
		return val, nil

	default:
		return nil, fmt.Errorf("Unable to coerce string to %s", typeName[coerceTo])
	}
}

// coerceFromArray attempts to convert the given array to the specified Type. Currently,
// arrays can only be coerced to arrays (identity). If it cannot be coerced, nil will be
// returned along with an error.
func coerceFromArray(value []interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Array {
		return value, nil
	}

	return nil, fmt.Errorf("Unable to coerce array to %s", typeName[coerceTo])
}

// coerceFromMap attempts to convert the given map to the specified Type. Currently,
// maps can only be coerced to maps (identity). If it cannot be coerced, nil will be
// returned along with an error.
func coerceFromMap(value map[string]interface{}, coerceTo Type) (interface{}, error) {
	if coerceTo == Map {
		return value, nil
	}

	return nil, fmt.Errorf("Unable to coerce map to %s", typeName[coerceTo])
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"io"
	"log"
	"math/rand"
	"net"
	"os"
	"runtime"
	"time"

	"golang.org/x/crypto/pbkdf2"

	"github.com/golang/snappy"
	"github.com/urfave/cli"
	kcp "github.com/xtaci/kcp-go"
	"github.com/xtaci/yamux"
)

var (
	// VERSION is injected by buildflags
	VERSION = "SELFBUILD"
	// SALT is use for pbkdf2 key expansion
	SALT = "kcp-go"
)

type compStream struct {
	conn net.Conn
	w    *snappy.Writer
	r    *snappy.Reader
}

func (c *compStream) Read(p []byte) (n int, err error) {
	return c.r.Read(p)
}

func (c *compStream) Write(p []byte) (n int, err error) {
	n, err = c.w.Write(p)
	err = c.w.Flush()
	return n, err
}

func (c *compStream) Close() error {
	return c.conn.Close()
}

func newCompStream(conn net.Conn) *compStream {
	c := new(compStream)
	c.conn = conn
	c.w = snappy.NewBufferedWriter(conn)
	c.r = snappy.NewReader(conn)
	return c
}

func handleClient(p1, p2 io.ReadWriteCloser) {
	log.Println("stream opened")
	defer log.Println("stream closed")
	defer p1.Close()
	defer p2.Close()

	// start tunnel
	p1die := make(chan struct{})
	go func() {
		io.Copy(p1, p2)
		close(p1die)
	}()

	p2die := make(chan struct{})
	go func() {
		io.Copy(p2, p1)
		close(p2die)
	}()

	// wait for tunnel termination
	select {
	case <-p1die:
	case <-p2die:
	}
}

func checkError(err error) {
	if err != nil {
		log.Println(err)
		os.Exit(-1)
	}
}

func main() {
	rand.Seed(int64(time.Now().Nanosecond()))
	if VERSION == "SELFBUILD" {
		// add more log flags for debugging
		log.SetFlags(log.LstdFlags | log.Lshortfile)
	}
	myApp := cli.NewApp()
	myApp.Name = "kcptun"
	myApp.Usage = "kcptun client"
	myApp.Version = VERSION
	myApp.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "localaddr,l",
			Value: ":12948",
			Usage: "local listen address",
		},
		cli.StringFlag{
			Name:  "remoteaddr, r",
			Value: "vps:29900",
			Usage: "kcp server address",
		},
		cli.StringFlag{
			Name:   "key",
			Value:  "it's a secrect",
			Usage:  "pre-shared secret between client and server",
			EnvVar: "KCPTUN_KEY",
		},
		cli.StringFlag{
			Name:  "crypt",
			Value: "aes",
			Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
		},
		cli.StringFlag{
			Name:  "mode",
			Value: "fast",
			Usage: "profiles: fast3, fast2, fast, normal",
		},
		cli.IntFlag{
			Name:  "conn",
			Value: 1,
			Usage: "set num of UDP connections to server",
		},
		cli.IntFlag{
			Name:  "autoexpire",
			Value: 0,
			Usage: "set auto expiration time(in seconds) for a single UDP connection, 0 to disable",
		},
		cli.IntFlag{
			Name:  "mtu",
			Value: 1350,
			Usage: "set maximum transmission unit for UDP packets",
		},
		cli.IntFlag{
			Name:  "sndwnd",
			Value: 128,
			Usage: "set send window size(num of packets)",
		},
		cli.IntFlag{
			Name:  "rcvwnd",
			Value: 1024,
			Usage: "set receive window size(num of packets)",
		},
		cli.IntFlag{
			Name:  "datashard",
			Value: 10,
			Usage: "set reed-solomon erasure coding - datashard",
		},
		cli.IntFlag{
			Name:  "parityshard",
			Value: 3,
			Usage: "set reed-solomon erasure coding - parityshard",
		},
		cli.BoolFlag{
			Name:   "acknodelay",
			Usage:  "flush ack immediately when a packet is received",
			Hidden: true,
		},
		cli.IntFlag{
			Name:  "dscp",
			Value: 0,
			Usage: "set DSCP(6bit)",
		},
		cli.BoolFlag{
			Name:  "nocomp",
			Usage: "disable compression",
		},
		cli.IntFlag{
			Name:   "nodelay",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "interval",
			Value:  40,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "resend",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "nc",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "sockbuf",
			Value:  4194304, // socket buffer size in bytes
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "keepalive",
			Value:  10, // nat keepalive interval in seconds
			Hidden: true,
		},
	}
	myApp.Action = func(c *cli.Context) error {
		log.Println("version:", VERSION)
		addr, err := net.ResolveTCPAddr("tcp", c.String("localaddr"))
		checkError(err)
		listener, err := net.ListenTCP("tcp", addr)
		checkError(err)

		// kcp server
		nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")

		switch c.String("mode") {
		case "normal":
			nodelay, interval, resend, nc = 0, 30, 2, 1
		case "fast":
			nodelay, interval, resend, nc = 0, 20, 2, 1
		case "fast2":
			nodelay, interval, resend, nc = 1, 20, 2, 1
		case "fast3":
			nodelay, interval, resend, nc = 1, 10, 2, 1
		}

		crypt := c.String("crypt")
		pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
		var block kcp.BlockCrypt
		switch c.String("crypt") {
		case "tea":
			block, _ = kcp.NewTEABlockCrypt(pass[:16])
		case "xor":
			block, _ = kcp.NewSimpleXORBlockCrypt(pass)
		case "none":
			block, _ = kcp.NewNoneBlockCrypt(pass)
		case "aes-128":
			block, _ = kcp.NewAESBlockCrypt(pass[:16])
		case "aes-192":
			block, _ = kcp.NewAESBlockCrypt(pass[:24])
		case "blowfish":
			block, _ = kcp.NewBlowfishBlockCrypt(pass)
		case "twofish":
			block, _ = kcp.NewTwofishBlockCrypt(pass)
		case "cast5":
			block, _ = kcp.NewCast5BlockCrypt(pass[:16])
		case "3des":
			block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
		case "xtea":
			block, _ = kcp.NewXTEABlockCrypt(pass[:16])
		case "salsa20":
			block, _ = kcp.NewSalsa20BlockCrypt(pass)
		default:
			crypt = "aes"
			block, _ = kcp.NewAESBlockCrypt(pass)
		}

		remoteaddr := c.String("remoteaddr")
		datashard, parityshard := c.Int("datashard"), c.Int("parityshard")
		mtu, sndwnd, rcvwnd := c.Int("mtu"), c.Int("sndwnd"), c.Int("rcvwnd")
		nocomp, acknodelay := c.Bool("nocomp"), c.Bool("acknodelay")
		dscp, sockbuf, keepalive, conn := c.Int("dscp"), c.Int("sockbuf"), c.Int("keepalive"), c.Int("conn")
		autoexpire := c.Int("autoexpire")

		log.Println("listening on:", listener.Addr())
		log.Println("encryption:", crypt)
		log.Println("nodelay parameters:", nodelay, interval, resend, nc)
		log.Println("remote address:", remoteaddr)
		log.Println("sndwnd:", sndwnd, "rcvwnd:", rcvwnd)
		log.Println("compression:", !nocomp)
		log.Println("mtu:", mtu)
		log.Println("datashard:", datashard, "parityshard:", parityshard)
		log.Println("acknodelay:", acknodelay)
		log.Println("dscp:", dscp)
		log.Println("sockbuf:", sockbuf)
		log.Println("keepalive:", keepalive)
		log.Println("conn:", conn)
		log.Println("autoexpire:", autoexpire)

		config := &yamux.Config{
			AcceptBacklog:          256,
			EnableKeepAlive:        true,
			KeepAliveInterval:      30 * time.Second,
			ConnectionWriteTimeout: 10 * time.Second,
			MaxStreamWindowSize:    uint32(sockbuf),
			LogOutput:              os.Stderr,
		}
		createConn := func() *yamux.Session {
			kcpconn, err := kcp.DialWithOptions(remoteaddr, block, datashard, parityshard)
			checkError(err)
			kcpconn.SetStreamMode(true)
			kcpconn.SetNoDelay(nodelay, interval, resend, nc)
			kcpconn.SetWindowSize(sndwnd, rcvwnd)
			kcpconn.SetMtu(mtu)
			kcpconn.SetACKNoDelay(acknodelay)
			kcpconn.SetKeepAlive(keepalive)

			if err := kcpconn.SetDSCP(dscp); err != nil {
				log.Println("SetDSCP:", err)
			}
			if err := kcpconn.SetReadBuffer(sockbuf); err != nil {
				log.Println("SetReadBuffer:", err)
			}
			if err := kcpconn.SetWriteBuffer(sockbuf); err != nil {
				log.Println("SetWriteBuffer:", err)
			}

			// stream multiplex
			var session *yamux.Session
			if nocomp {
				session, err = yamux.Client(kcpconn, config)
			} else {
				session, err = yamux.Client(newCompStream(kcpconn), config)
			}
			checkError(err)
			runtime.SetFinalizer(session, func(s *yamux.Session) {
				s.Close()
			})
			return session
		}

		numconn := uint16(conn)
		muxes := make([]struct {
			session *yamux.Session
			ttl     time.Time
		}, numconn)

		for k := range muxes {
			muxes[k].session = createConn()
			muxes[k].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
		}

		rr := uint16(0)
		for {
			p1, err := listener.AcceptTCP()
			if err := p1.SetReadBuffer(sockbuf); err != nil {
				log.Println("TCP SetReadBuffer:", err)
			}
			if err := p1.SetWriteBuffer(sockbuf); err != nil {
				log.Println("TCP SetWriteBuffer:", err)
			}
			checkError(err)
			idx := rr % numconn
			mux := muxes[idx]
			p2, err := mux.session.Open()
			if err != nil { // yamux failure
				log.Println(err)
				p1.Close()
				muxes[idx].session = createConn()
				muxes[idx].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
				continue
			}
			if autoexpire > 0 && time.Now().After(muxes[idx].ttl) { // auto expiration
				log.Println("autoexpired")
				muxes[idx].session = createConn()
				muxes[idx].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
			}
			go handleClient(p1, p2)
			rr++
		}
	}
	myApp.Run(os.Args)
}
<commit_msg>optimize retry strategy<commit_after>package main

import (
	"crypto/sha1"
	"io"
	"log"
	"math/rand"
	"net"
	"os"
	"runtime"
	"time"

	"golang.org/x/crypto/pbkdf2"

	"github.com/golang/snappy"
	"github.com/urfave/cli"
	kcp "github.com/xtaci/kcp-go"
	"github.com/xtaci/yamux"
)

var (
	// VERSION is injected by buildflags
	VERSION = "SELFBUILD"
	// SALT is use for pbkdf2 key expansion
	SALT = "kcp-go"
)

type compStream struct {
	conn net.Conn
	w    *snappy.Writer
	r    *snappy.Reader
}

func (c *compStream) Read(p []byte) (n int, err error) {
	return c.r.Read(p)
}

func (c *compStream) Write(p []byte) (n int, err error) {
	n, err = c.w.Write(p)
	err = c.w.Flush()
	return n, err
}

func (c *compStream) Close() error {
	return c.conn.Close()
}

func newCompStream(conn net.Conn) *compStream {
	c := new(compStream)
	c.conn = conn
	c.w = snappy.NewBufferedWriter(conn)
	c.r = snappy.NewReader(conn)
	return c
}

func handleClient(p1, p2 io.ReadWriteCloser) {
	log.Println("stream opened")
	defer log.Println("stream closed")
	defer p1.Close()
	defer p2.Close()

	// start tunnel
	p1die := make(chan struct{})
	go func() {
		io.Copy(p1, p2)
		close(p1die)
	}()

	p2die := make(chan struct{})
	go func() {
		io.Copy(p2, p1)
		close(p2die)
	}()

	// wait for tunnel termination
	select {
	case <-p1die:
	case <-p2die:
	}
}

func checkError(err error) {
	if err != nil {
		log.Println(err)
		os.Exit(-1)
	}
}

func main() {
	rand.Seed(int64(time.Now().Nanosecond()))
	if VERSION == "SELFBUILD" {
		// add more log flags for debugging
		log.SetFlags(log.LstdFlags | log.Lshortfile)
	}
	myApp := cli.NewApp()
	myApp.Name = "kcptun"
	myApp.Usage = "kcptun client"
	myApp.Version = VERSION
	myApp.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "localaddr,l",
			Value: ":12948",
			Usage: "local listen address",
		},
		cli.StringFlag{
			Name:  "remoteaddr, r",
			Value: "vps:29900",
			Usage: "kcp server address",
		},
		cli.StringFlag{
			Name:   "key",
			Value:  "it's a secrect",
			Usage:  "pre-shared secret between client and server",
			EnvVar: "KCPTUN_KEY",
		},
		cli.StringFlag{
			Name:  "crypt",
			Value: "aes",
			Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
		},
		cli.StringFlag{
			Name:  "mode",
			Value: "fast",
			Usage: "profiles: fast3, fast2, fast, normal",
		},
		cli.IntFlag{
			Name:  "conn",
			Value: 1,
			Usage: "set num of UDP connections to server",
		},
		cli.IntFlag{
			Name:  "autoexpire",
			Value: 0,
			Usage: "set auto expiration time(in seconds) for a single UDP connection, 0 to disable",
		},
		cli.IntFlag{
			Name:  "mtu",
			Value: 1350,
			Usage: "set maximum transmission unit for UDP packets",
		},
		cli.IntFlag{
			Name:  "sndwnd",
			Value: 128,
			Usage: "set send window size(num of packets)",
		},
		cli.IntFlag{
			Name:  "rcvwnd",
			Value: 1024,
			Usage: "set receive window size(num of packets)",
		},
		cli.IntFlag{
			Name:  "datashard",
			Value: 10,
			Usage: "set reed-solomon erasure coding - datashard",
		},
		cli.IntFlag{
			Name:  "parityshard",
			Value: 3,
			Usage: "set reed-solomon erasure coding - parityshard",
		},
		cli.BoolFlag{
			Name:   "acknodelay",
			Usage:  "flush ack immediately when a packet is received",
			Hidden: true,
		},
		cli.IntFlag{
			Name:  "dscp",
			Value: 0,
			Usage: "set DSCP(6bit)",
		},
		cli.BoolFlag{
			Name:  "nocomp",
			Usage: "disable compression",
		},
		cli.IntFlag{
			Name:   "nodelay",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "interval",
			Value:  40,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "resend",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "nc",
			Value:  0,
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "sockbuf",
			Value:  4194304, // socket buffer size in bytes
			Hidden: true,
		},
		cli.IntFlag{
			Name:   "keepalive",
			Value:  10, // nat keepalive interval in seconds
			Hidden: true,
		},
	}
	myApp.Action = func(c *cli.Context) error {
		log.Println("version:", VERSION)
		addr, err := net.ResolveTCPAddr("tcp", c.String("localaddr"))
		checkError(err)
		listener, err := net.ListenTCP("tcp", addr)
		checkError(err)

		// kcp server
		nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")

		switch c.String("mode") {
		case "normal":
			nodelay, interval, resend, nc = 0, 30, 2, 1
		case "fast":
			nodelay, interval, resend, nc = 0, 20, 2, 1
		case "fast2":
			nodelay, interval, resend, nc = 1, 20, 2, 1
		case "fast3":
			nodelay, interval, resend, nc = 1, 10, 2, 1
		}

		crypt := c.String("crypt")
		pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
		var block kcp.BlockCrypt
		switch c.String("crypt") {
		case "tea":
			block, _ = kcp.NewTEABlockCrypt(pass[:16])
		case "xor":
			block, _ = kcp.NewSimpleXORBlockCrypt(pass)
		case "none":
			block, _ = kcp.NewNoneBlockCrypt(pass)
		case "aes-128":
			block, _ = kcp.NewAESBlockCrypt(pass[:16])
		case "aes-192":
			block, _ = kcp.NewAESBlockCrypt(pass[:24])
		case "blowfish":
			block, _ = kcp.NewBlowfishBlockCrypt(pass)
		case "twofish":
			block, _ = kcp.NewTwofishBlockCrypt(pass)
		case "cast5":
			block, _ = kcp.NewCast5BlockCrypt(pass[:16])
		case "3des":
			block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
		case "xtea":
			block, _ = kcp.NewXTEABlockCrypt(pass[:16])
		case "salsa20":
			block, _ = kcp.NewSalsa20BlockCrypt(pass)
		default:
			crypt = "aes"
			block, _ = kcp.NewAESBlockCrypt(pass)
		}

		remoteaddr := c.String("remoteaddr")
		datashard, parityshard := c.Int("datashard"), c.Int("parityshard")
		mtu, sndwnd, rcvwnd := c.Int("mtu"), c.Int("sndwnd"), c.Int("rcvwnd")
		nocomp, acknodelay := c.Bool("nocomp"), c.Bool("acknodelay")
		dscp, sockbuf, keepalive, conn := c.Int("dscp"), c.Int("sockbuf"), c.Int("keepalive"), c.Int("conn")
		autoexpire := c.Int("autoexpire")

		log.Println("listening on:", listener.Addr())
		log.Println("encryption:", crypt)
		log.Println("nodelay parameters:", nodelay, interval, resend, nc)
		log.Println("remote address:", remoteaddr)
		log.Println("sndwnd:", sndwnd, "rcvwnd:", rcvwnd)
		log.Println("compression:", !nocomp)
		log.Println("mtu:", mtu)
		log.Println("datashard:", datashard, "parityshard:", parityshard)
		log.Println("acknodelay:", acknodelay)
		log.Println("dscp:", dscp)
		log.Println("sockbuf:", sockbuf)
		log.Println("keepalive:", keepalive)
		log.Println("conn:", conn)
		log.Println("autoexpire:", autoexpire)

		config := &yamux.Config{
			AcceptBacklog:          256,
			EnableKeepAlive:        true,
			KeepAliveInterval:      30 * time.Second,
			ConnectionWriteTimeout: 10 * time.Second,
			MaxStreamWindowSize:    uint32(sockbuf),
			LogOutput:              os.Stderr,
		}
		createConn := func() *yamux.Session {
			kcpconn, err := kcp.DialWithOptions(remoteaddr, block, datashard, parityshard)
			checkError(err)
			kcpconn.SetStreamMode(true)
			kcpconn.SetNoDelay(nodelay, interval, resend, nc)
			kcpconn.SetWindowSize(sndwnd, rcvwnd)
			kcpconn.SetMtu(mtu)
			kcpconn.SetACKNoDelay(acknodelay)
			kcpconn.SetKeepAlive(keepalive)

			if err := kcpconn.SetDSCP(dscp); err != nil {
				log.Println("SetDSCP:", err)
			}
			if err := kcpconn.SetReadBuffer(sockbuf); err != nil {
				log.Println("SetReadBuffer:", err)
			}
			if err := kcpconn.SetWriteBuffer(sockbuf); err != nil {
				log.Println("SetWriteBuffer:", err)
			}

			// stream multiplex
			var session *yamux.Session
			if nocomp {
				session, err = yamux.Client(kcpconn, config)
			} else {
				session, err = yamux.Client(newCompStream(kcpconn), config)
			}
			checkError(err)
			runtime.SetFinalizer(session, func(s *yamux.Session) {
				s.Close()
			})
			return session
		}

		numconn := uint16(conn)
		muxes := make([]struct {
			session *yamux.Session
			ttl     time.Time
		}, numconn)

		for k := range muxes {
			muxes[k].session = createConn()
			muxes[k].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
		}

		rr := uint16(0)
		for {
			p1, err := listener.AcceptTCP()
			if err := p1.SetReadBuffer(sockbuf); err != nil {
				log.Println("TCP SetReadBuffer:", err)
			}
			if err := p1.SetWriteBuffer(sockbuf); err != nil {
				log.Println("TCP SetWriteBuffer:", err)
			}
			checkError(err)
			idx := rr % numconn

		OPEN_P2:
			// do auto expiration
			if autoexpire > 0 && time.Now().After(muxes[idx].ttl) {
				log.Println("autoexpired")
				muxes[idx].session = createConn()
				muxes[idx].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
			}

			// do session open
			p2, err := muxes[idx].session.Open()
			if err != nil { // yamux failure
				log.Println(err)
				p1.Close()
				muxes[idx].session = createConn()
				muxes[idx].ttl = time.Now().Add(time.Duration(autoexpire) * time.Second)
				goto OPEN_P2
			}
			go handleClient(p1, p2)
			rr++
		}
	}
	myApp.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"io"
	"regexp"
	"strings"
	"flag"
	"time"
	"compress/gzip"
)

const TIME_LAYOUT string = "[2006-01-02 15:04:05 MST]"

func main() {
	job_flag := flag.Int("jobs", 0, "Show background jobs")
	sql_flag := flag.Int("sql", 0, "Show SQL statements")
	after_str := flag.String("after", "", "Show logs after this time (YYYY-MM-DD HH:II::SS")
	match_str := flag.String("match", "", "Regexp for requests to gather")

	flag.Parse()
	args := flag.Args()

	// Time layouts must use the
	// reference time `Mon Jan 2 15:04:05 MST 2006` to show the
	// pattern with which to format/parse a given time/string

	time_after, e    := time.Parse(TIME_LAYOUT, fmt.Sprintf("[%s UTC]", *after_str))
	parse_time       := false

	if e != nil {
		if len(*after_str) > 0 {
			fmt.Println(fmt.Sprintf("Invalid time format \"%s\" - Must be YYYY-MM-DD HH::II::SS", *after_str))
			os.Exit(4)
		}
	} else {
		parse_time = true
	}

	if len(args) < 1 {
		usage()
		os.Exit(1)
	}

	fmt.Println(fmt.Sprintf("Show background jobs: %d", *job_flag))
	fmt.Println(fmt.Sprintf("Show SQL: %d", *sql_flag))
	fmt.Println(fmt.Sprintf("After: %s", *after_str))

	filename := args[0]
	fmt.Println(fmt.Sprintf("Opening file: %s", filename))

	file := openFile(filename)
	defer file.Close()

	var reader io.Reader = file

	if isGzip(filename) {
		parse_gz_reader := getGzipReader(file)
		defer parse_gz_reader.Close()

		reader = parse_gz_reader
	}

	timestamp_regexp := regexp.MustCompile("^(\\[[0-9-]+ [0-9:]+ UTC\\])")
	sql_regexp       := regexp.MustCompile("(SQL \\()|(EXEC sp_executesql N)|( CACHE \\()")
	nltm_regexp      := regexp.MustCompile(" \\(NTLM\\) ")
	request_regexp   := regexp.MustCompile("\\] (P[0-9]+[A-Za-z]+[0-9]+) ")

	var unique_map map[string]bool;

	line_strexp := *match_str

	if line_regexp, err := regexp.Compile(line_strexp); len(line_strexp) > 0 && err == nil {
		line_count  := 0
		line_after  := !parse_time // if not parsing time, then all lines are valid
		request_ids := make([]string, 0)

		scanner := bufio.NewScanner(reader);

		for scanner.Scan() {
			line := scanner.Text();
			if line_regexp.MatchString(line) {

				if !line_after {
					if timestamp := timestamp_regexp.FindStringSubmatch(line); len(timestamp) > 1 {
						if is_after_time(&timestamp[1], &time_after) {
							line_after = true
						}
					}
				}

				if line_after {
					request := request_regexp.FindStringSubmatch(line)

					if len(request) > 1 {
						is_job := strings.Contains(request[1], "DJ")

						if is_job {
							if *job_flag > 0 {
								request_ids = append(request_ids, request[1])
							} else {
								//fmt.Println(line)
							}
						} else {
							request_ids = append(request_ids, request[1])
						}
					}
				}
			}

			if line_count++; line_count % 10000 == 0 {
				fmt.Print(fmt.Sprintf("Reading: %d\r", line_count))
			}
		}

		fmt.Println("") // empty line

		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}

		fmt.Println(fmt.Sprintf("Found %d lines matching \"%s\"", len(request_ids), line_strexp))
		unique_map = generateRequestIdMap(&request_ids)

		if len(unique_map) < 1 {
			fmt.Println(fmt.Sprintf("Found 0 request identifiers", line_strexp))
			os.Exit(2)
		}

		file.Seek(0, 0)  // go back to the top (rewind)
	} else {
		fmt.Println("No matchers provided, skipping match phase")
	}

	if isGzip(filename) {
		output_gz_reader := getGzipReader(file)
		defer output_gz_reader.Close()

		reader = output_gz_reader
	}

	line_count := 0
	line_after := !parse_time // if not parsing time, then all lines are valid

	output_scanner := bufio.NewScanner(reader);

	for output_scanner.Scan() {
		line := output_scanner.Text();

		output := false

		if !line_after {
			if line_count++; line_count % 10000 == 0 {
				fmt.Print(fmt.Sprintf("Reading: %d\r", line_count))
			}

			if timestamp := timestamp_regexp.FindStringSubmatch(line); len(timestamp) > 1 {
				if is_after_time(&timestamp[1], &time_after) {
					fmt.Println("\n") // empty line
					line_after = true
				}
			}
		}

		if line_after {
			if request_id := request_regexp.FindStringSubmatch(line); len(request_id) > 1 {
				output = len(request_id[1]) > 0 && unique_map[request_id[1]]
			}
		}

		if output {
			if *sql_flag < 1 && sql_regexp.MatchString(line) {
				output = false
			} else if nltm_regexp.MatchString(line) {
				output = false
			}
		}

		if output {
			fmt.Println(line)
		}
	}

	if err := output_scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func usage() {
	fmt.Println(fmt.Sprintf("Usage: avmlog -match=\"regexp\" -jobs=0|1 -sql=0|1 -after=\"YYYY-MM-DD HH:II::SS\" avmanager_filename.log"))
	fmt.Println("Example: avm -match=\"username|computername\" \"/path/to/manager/log/production.log\"")
}

func is_after_time(timestamp *string, time_after *time.Time) bool {
	if line_time, e := time.Parse(TIME_LAYOUT, *timestamp); e != nil {
		fmt.Println("Got error %s", e)
		return false
	} else if line_time.Before(*time_after) {
		return false
	}

	return true
}

func generateRequestIdMap(request_ids *[]string) map[string]bool {
	unique_map := make(map[string]bool, len(*request_ids))

	for _, x := range *request_ids {
		unique_map[x] = true
	}

	for k, _ := range unique_map {
		fmt.Println(fmt.Sprintf("Request ID: %s", k))
	}

	return unique_map
}

func openFile(filename string) *os.File {
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	return file
}

func isGzip(filename string) bool {
	return strings.HasSuffix(filename, ".gz")
}

func getGzipReader(file *os.File) *gzip.Reader {
	gz_reader, err := gzip.NewReader(file)
	if err != nil {
	log.Fatal(err)
	}

	return gz_reader
}<commit_msg>Make timestamp_regexp a global and create extractTimestamp function and rename is_after_time() to isAfterTime()<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"io"
	"regexp"
	"strings"
	"flag"
	"time"
	"compress/gzip"
)

const TIME_LAYOUT string = "[2006-01-02 15:04:05 MST]"
var timestamp_regexp *regexp.Regexp = regexp.MustCompile("^(\\[[0-9-]+ [0-9:]+ UTC\\])")

func main() {
	job_flag := flag.Int("jobs", 0, "Show background jobs")
	sql_flag := flag.Int("sql", 0, "Show SQL statements")
	after_str := flag.String("after", "", "Show logs after this time (YYYY-MM-DD HH:II::SS")
	match_str := flag.String("match", "", "Regexp for requests to gather")

	flag.Parse()
	args := flag.Args()

	// Time layouts must use the
	// reference time `Mon Jan 2 15:04:05 MST 2006` to show the
	// pattern with which to format/parse a given time/string

	time_after, e    := time.Parse(TIME_LAYOUT, fmt.Sprintf("[%s UTC]", *after_str))
	parse_time       := false

	if e != nil {
		if len(*after_str) > 0 {
			fmt.Println(fmt.Sprintf("Invalid time format \"%s\" - Must be YYYY-MM-DD HH::II::SS", *after_str))
			os.Exit(4)
		}
	} else {
		parse_time = true
	}

	if len(args) < 1 {
		usage()
		os.Exit(1)
	}

	fmt.Println(fmt.Sprintf("Show background jobs: %d", *job_flag))
	fmt.Println(fmt.Sprintf("Show SQL: %d", *sql_flag))
	fmt.Println(fmt.Sprintf("After: %s", *after_str))

	filename := args[0]
	fmt.Println(fmt.Sprintf("Opening file: %s", filename))

	file := openFile(filename)
	defer file.Close()

	var reader io.Reader = file

	if isGzip(filename) {
		parse_gz_reader := getGzipReader(file)
		defer parse_gz_reader.Close()

		reader = parse_gz_reader
	}

	sql_regexp       := regexp.MustCompile("(SQL \\()|(EXEC sp_executesql N)|( CACHE \\()")
	nltm_regexp      := regexp.MustCompile(" \\(NTLM\\) ")
	request_regexp   := regexp.MustCompile("\\] (P[0-9]+[A-Za-z]+[0-9]+) ")

	var unique_map map[string]bool;

	line_strexp := *match_str

	if line_regexp, err := regexp.Compile(line_strexp); len(line_strexp) > 0 && err == nil {
		line_count  := 0
		line_after  := !parse_time // if not parsing time, then all lines are valid
		request_ids := make([]string, 0)

		scanner := bufio.NewScanner(reader);

		for scanner.Scan() {
			line := scanner.Text();
			if line_regexp.MatchString(line) {

				if !line_after {
					if timestamp := extractTimestamp(line); len(timestamp) > 1 {
						if isAfterTime(timestamp, &time_after) {
							line_after = true
						}
					}
				}

				if line_after {
					request := request_regexp.FindStringSubmatch(line)

					if len(request) > 1 {
						is_job := strings.Contains(request[1], "DJ")

						if is_job {
							if *job_flag > 0 {
								request_ids = append(request_ids, request[1])
							} else {
								//fmt.Println(line)
							}
						} else {
							request_ids = append(request_ids, request[1])
						}
					}
				}
			}

			if line_count++; line_count % 10000 == 0 {
				fmt.Print(fmt.Sprintf("Reading: %d\r", line_count))
			}
		}

		fmt.Println("") // empty line

		if err := scanner.Err(); err != nil {
			log.Fatal(err)
		}

		fmt.Println(fmt.Sprintf("Found %d lines matching \"%s\"", len(request_ids), line_strexp))
		unique_map = generateRequestIdMap(&request_ids)

		if len(unique_map) < 1 {
			fmt.Println(fmt.Sprintf("Found 0 request identifiers", line_strexp))
			os.Exit(2)
		}

		file.Seek(0, 0)  // go back to the top (rewind)
	} else {
		fmt.Println("No matchers provided, skipping match phase")
	}

	if isGzip(filename) {
		output_gz_reader := getGzipReader(file)
		defer output_gz_reader.Close()

		reader = output_gz_reader
	}

	line_count := 0
	line_after := !parse_time // if not parsing time, then all lines are valid

	output_scanner := bufio.NewScanner(reader);

	for output_scanner.Scan() {
		line := output_scanner.Text();

		output := false

		if !line_after {
			if line_count++; line_count % 10000 == 0 {
				fmt.Print(fmt.Sprintf("Reading: %d\r", line_count))
			}

			if timestamp := extractTimestamp(line); len(timestamp) > 1 {
				if isAfterTime(timestamp, &time_after) {
					fmt.Println("\n") // empty line
					line_after = true
				}
			}
		}

		if line_after {
			if request_id := request_regexp.FindStringSubmatch(line); len(request_id) > 1 {
				output = len(request_id[1]) > 0 && unique_map[request_id[1]]
			}
		}

		if output {
			if *sql_flag < 1 && sql_regexp.MatchString(line) {
				output = false
			} else if nltm_regexp.MatchString(line) {
				output = false
			}
		}

		if output {
			fmt.Println(line)
		}
	}

	if err := output_scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

func usage() {
	fmt.Println(fmt.Sprintf("Usage: avmlog -match=\"regexp\" -jobs=0|1 -sql=0|1 -after=\"YYYY-MM-DD HH:II::SS\" avmanager_filename.log"))
	fmt.Println("Example: avm -match=\"username|computername\" \"/path/to/manager/log/production.log\"")
}

func isAfterTime(timestamp string, time_after *time.Time) bool {
	if line_time, e := time.Parse(TIME_LAYOUT, timestamp); e != nil {
		fmt.Println("Got error %s", e)
		return false
	} else if line_time.Before(*time_after) {
		return false
	}

	return true
}

func extractTimestamp(line string) string {
	if timestamp := timestamp_regexp.FindStringSubmatch(line); len(timestamp) > 1 {
		return timestamp[1]
	} else {
		return ""
	}
}

func generateRequestIdMap(request_ids *[]string) map[string]bool {
	unique_map := make(map[string]bool, len(*request_ids))

	for _, x := range *request_ids {
		unique_map[x] = true
	}

	for k, _ := range unique_map {
		fmt.Println(fmt.Sprintf("Request ID: %s", k))
	}

	return unique_map
}

func openFile(filename string) *os.File {
	file, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	return file
}

func isGzip(filename string) bool {
	return strings.HasSuffix(filename, ".gz")
}

func getGzipReader(file *os.File) *gzip.Reader {
	gz_reader, err := gzip.NewReader(file)
	if err != nil {
	log.Fatal(err)
	}

	return gz_reader
}<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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 kubectl

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/golang/glog"
)

// Describer generates output for the named resource or an error
// if the output could not be generated.
type Describer interface {
	Describe(namespace, name string) (output string, err error)
}

// Describer returns the default describe functions for each of the standard
// Kubernetes types.
func DescriberFor(kind string, c *client.Client) (Describer, bool) {
	switch kind {
	case "Pod":
		return &PodDescriber{c}, true
	case "ReplicationController":
		return &ReplicationControllerDescriber{c}, true
	case "Service":
		return &ServiceDescriber{c}, true
	case "Minion", "Node":
		return &MinionDescriber{c}, true
	case "LimitRange":
		return &LimitRangeDescriber{c}, true
	}
	return nil, false
}

// LimitRangeDescriber generates information about a limit range
type LimitRangeDescriber struct {
	client.Interface
}

func (d *LimitRangeDescriber) Describe(namespace, name string) (string, error) {
	lr := d.LimitRanges(namespace)

	limitRange, err := lr.Get(name)
	if err != nil {
		return "", err
	}

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", limitRange.Name)
		fmt.Fprintf(out, "Type\tResource\tMin\tMax\n")
		fmt.Fprintf(out, "----\t--------\t---\t---\n")
		for i, _ := range limitRange.Spec.Limits {
			item := limitRange.Spec.Limits[i]
			maxResources := item.Max
			minResources := item.Min

			set := map[api.ResourceName]bool{}
			for k, _ := range maxResources {
				set[k] = true
			}
			for k, _ := range minResources {
				set[k] = true
			}

			for k, _ := range set {
				// if no value is set, we output -
				maxValue := "-"
				minValue := "-"

				maxQuantity, maxQuantityFound := maxResources[k]
				if maxQuantityFound {
					maxValue = maxQuantity.String()
				}

				minQuantity, minQuantityFound := minResources[k]
				if minQuantityFound {
					minValue = minQuantity.String()
				}

				msg := "%v\t%v\t%v\t%v\n"
				fmt.Fprintf(out, msg, item.Type, k, minValue, maxValue)
			}
		}
		return nil
	})
}

// PodDescriber generates information about a pod and the replication controllers that
// create it.
type PodDescriber struct {
	client.Interface
}

func (d *PodDescriber) Describe(namespace, name string) (string, error) {
	rc := d.ReplicationControllers(namespace)
	pc := d.Pods(namespace)

	pod, err := pc.Get(name)
	if err != nil {
		events, err2 := d.Events(namespace).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.name":      name,
				"involvedObject.namespace": namespace,
			}.AsSelector(),
		)
		if err2 == nil && len(events.Items) > 0 {
			return tabbedString(func(out io.Writer) error {
				fmt.Fprintf(out, "Pod '%v': error '%v', but found events.\n", name, err)
				describeEvents(events, out)
				return nil
			})
		}
		return "", err
	}

	// TODO: remove me when pods are converted
	spec := &api.PodSpec{}
	if err := api.Scheme.Convert(&pod.Spec, spec); err != nil {
		glog.Errorf("Unable to convert pod manifest: %v", err)
	}

	var events *api.EventList
	if ref, err := api.GetReference(pod); err != nil {
		glog.Errorf("Unable to construct reference to '%#v': %v", pod, err)
	} else {
		ref.Kind = "" // Find BoundPod objects, too!
		events, _ = d.Events(namespace).Search(ref)
	}

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", pod.Name)
		fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(spec))
		fmt.Fprintf(out, "Host:\t%s\n", pod.Status.Host+"/"+pod.Status.HostIP)
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(pod.Labels))
		fmt.Fprintf(out, "Status:\t%s\n", string(pod.Status.Phase))
		fmt.Fprintf(out, "Replication Controllers:\t%s\n", getReplicationControllersForLabels(rc, labels.Set(pod.Labels)))
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// ReplicationControllerDescriber generates information about a replication controller
// and the pods it has created.
type ReplicationControllerDescriber struct {
	client.Interface
}

func (d *ReplicationControllerDescriber) Describe(namespace, name string) (string, error) {
	rc := d.ReplicationControllers(namespace)
	pc := d.Pods(namespace)

	controller, err := rc.Get(name)
	if err != nil {
		return "", err
	}

	running, waiting, succeeded, failed, err := getPodStatusForReplicationController(pc, controller)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(controller)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", controller.Name)
		fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&controller.Spec.Template.Spec))
		fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(controller.Spec.Selector))
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(controller.Labels))
		fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, controller.Spec.Replicas)
		fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// ServiceDescriber generates information about a service.
type ServiceDescriber struct {
	client.Interface
}

func (d *ServiceDescriber) Describe(namespace, name string) (string, error) {
	c := d.Services(namespace)

	service, err := c.Get(name)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(service)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", service.Name)
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(service.Labels))
		fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(service.Spec.Selector))
		fmt.Fprintf(out, "Port:\t%d\n", service.Spec.Port)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// MinionDescriber generates information about a minion.
type MinionDescriber struct {
	client.Interface
}

func (d *MinionDescriber) Describe(namespace, name string) (string, error) {
	mc := d.Nodes()
	minion, err := mc.Get(name)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(minion)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", minion.Name)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

func describeEvents(el *api.EventList, w io.Writer) {
	if len(el.Items) == 0 {
		fmt.Fprint(w, "No events.")
		return
	}
	sort.Sort(SortableEvents(el.Items))
	fmt.Fprint(w, "Events:\nTime\tFrom\tSubobjectPath\tReason\tMessage\n")
	for _, e := range el.Items {
		fmt.Fprintf(w, "%s\t%v\t%v\t%v\t%v\t%v\n",
			e.Timestamp.Time.Format(time.RFC1123Z),
			e.Source,
			e.InvolvedObject.FieldPath,
			e.Reason,
			e.Message)
	}
}

// Get all replication controllers whose selectors would match a given set of
// labels.
// TODO Move this to pkg/client and ideally implement it server-side (instead
// of getting all RC's and searching through them manually).
func getReplicationControllersForLabels(c client.ReplicationControllerInterface, labelsToMatch labels.Labels) string {
	// Get all replication controllers.
	// TODO this needs a namespace scope as argument
	rcs, err := c.List(labels.Everything())
	if err != nil {
		glog.Fatalf("Error getting replication controllers: %v\n", err)
	}

	// Find the ones that match labelsToMatch.
	var matchingRCs []api.ReplicationController
	for _, controller := range rcs.Items {
		selector := labels.SelectorFromSet(controller.Spec.Selector)
		if selector.Matches(labelsToMatch) {
			matchingRCs = append(matchingRCs, controller)
		}
	}

	// Format the matching RC's into strings.
	var rcStrings []string
	for _, controller := range matchingRCs {
		rcStrings = append(rcStrings, fmt.Sprintf("%s (%d/%d replicas created)", controller.Name, controller.Status.Replicas, controller.Spec.Replicas))
	}

	list := strings.Join(rcStrings, ", ")
	if list == "" {
		return "<none>"
	}
	return list
}

func getPodStatusForReplicationController(c client.PodInterface, controller *api.ReplicationController) (running, waiting, succeeded, failed int, err error) {
	rcPods, err := c.List(labels.SelectorFromSet(controller.Spec.Selector))
	if err != nil {
		return
	}
	for _, pod := range rcPods.Items {
		switch pod.Status.Phase {
		case api.PodRunning:
			running++
		case api.PodPending:
			waiting++
		case api.PodSucceeded:
			succeeded++
		case api.PodFailed:
			failed++
		}
	}
	return
}
<commit_msg>Fix gofmt complaint<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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 kubectl

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/golang/glog"
)

// Describer generates output for the named resource or an error
// if the output could not be generated.
type Describer interface {
	Describe(namespace, name string) (output string, err error)
}

// Describer returns the default describe functions for each of the standard
// Kubernetes types.
func DescriberFor(kind string, c *client.Client) (Describer, bool) {
	switch kind {
	case "Pod":
		return &PodDescriber{c}, true
	case "ReplicationController":
		return &ReplicationControllerDescriber{c}, true
	case "Service":
		return &ServiceDescriber{c}, true
	case "Minion", "Node":
		return &MinionDescriber{c}, true
	case "LimitRange":
		return &LimitRangeDescriber{c}, true
	}
	return nil, false
}

// LimitRangeDescriber generates information about a limit range
type LimitRangeDescriber struct {
	client.Interface
}

func (d *LimitRangeDescriber) Describe(namespace, name string) (string, error) {
	lr := d.LimitRanges(namespace)

	limitRange, err := lr.Get(name)
	if err != nil {
		return "", err
	}

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", limitRange.Name)
		fmt.Fprintf(out, "Type\tResource\tMin\tMax\n")
		fmt.Fprintf(out, "----\t--------\t---\t---\n")
		for i := range limitRange.Spec.Limits {
			item := limitRange.Spec.Limits[i]
			maxResources := item.Max
			minResources := item.Min

			set := map[api.ResourceName]bool{}
			for k := range maxResources {
				set[k] = true
			}
			for k := range minResources {
				set[k] = true
			}

			for k := range set {
				// if no value is set, we output -
				maxValue := "-"
				minValue := "-"

				maxQuantity, maxQuantityFound := maxResources[k]
				if maxQuantityFound {
					maxValue = maxQuantity.String()
				}

				minQuantity, minQuantityFound := minResources[k]
				if minQuantityFound {
					minValue = minQuantity.String()
				}

				msg := "%v\t%v\t%v\t%v\n"
				fmt.Fprintf(out, msg, item.Type, k, minValue, maxValue)
			}
		}
		return nil
	})
}

// PodDescriber generates information about a pod and the replication controllers that
// create it.
type PodDescriber struct {
	client.Interface
}

func (d *PodDescriber) Describe(namespace, name string) (string, error) {
	rc := d.ReplicationControllers(namespace)
	pc := d.Pods(namespace)

	pod, err := pc.Get(name)
	if err != nil {
		events, err2 := d.Events(namespace).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.name":      name,
				"involvedObject.namespace": namespace,
			}.AsSelector(),
		)
		if err2 == nil && len(events.Items) > 0 {
			return tabbedString(func(out io.Writer) error {
				fmt.Fprintf(out, "Pod '%v': error '%v', but found events.\n", name, err)
				describeEvents(events, out)
				return nil
			})
		}
		return "", err
	}

	// TODO: remove me when pods are converted
	spec := &api.PodSpec{}
	if err := api.Scheme.Convert(&pod.Spec, spec); err != nil {
		glog.Errorf("Unable to convert pod manifest: %v", err)
	}

	var events *api.EventList
	if ref, err := api.GetReference(pod); err != nil {
		glog.Errorf("Unable to construct reference to '%#v': %v", pod, err)
	} else {
		ref.Kind = "" // Find BoundPod objects, too!
		events, _ = d.Events(namespace).Search(ref)
	}

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", pod.Name)
		fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(spec))
		fmt.Fprintf(out, "Host:\t%s\n", pod.Status.Host+"/"+pod.Status.HostIP)
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(pod.Labels))
		fmt.Fprintf(out, "Status:\t%s\n", string(pod.Status.Phase))
		fmt.Fprintf(out, "Replication Controllers:\t%s\n", getReplicationControllersForLabels(rc, labels.Set(pod.Labels)))
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// ReplicationControllerDescriber generates information about a replication controller
// and the pods it has created.
type ReplicationControllerDescriber struct {
	client.Interface
}

func (d *ReplicationControllerDescriber) Describe(namespace, name string) (string, error) {
	rc := d.ReplicationControllers(namespace)
	pc := d.Pods(namespace)

	controller, err := rc.Get(name)
	if err != nil {
		return "", err
	}

	running, waiting, succeeded, failed, err := getPodStatusForReplicationController(pc, controller)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(controller)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", controller.Name)
		fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&controller.Spec.Template.Spec))
		fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(controller.Spec.Selector))
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(controller.Labels))
		fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, controller.Spec.Replicas)
		fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// ServiceDescriber generates information about a service.
type ServiceDescriber struct {
	client.Interface
}

func (d *ServiceDescriber) Describe(namespace, name string) (string, error) {
	c := d.Services(namespace)

	service, err := c.Get(name)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(service)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", service.Name)
		fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(service.Labels))
		fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(service.Spec.Selector))
		fmt.Fprintf(out, "Port:\t%d\n", service.Spec.Port)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

// MinionDescriber generates information about a minion.
type MinionDescriber struct {
	client.Interface
}

func (d *MinionDescriber) Describe(namespace, name string) (string, error) {
	mc := d.Nodes()
	minion, err := mc.Get(name)
	if err != nil {
		return "", err
	}

	events, _ := d.Events(namespace).Search(minion)

	return tabbedString(func(out io.Writer) error {
		fmt.Fprintf(out, "Name:\t%s\n", minion.Name)
		if events != nil {
			describeEvents(events, out)
		}
		return nil
	})
}

func describeEvents(el *api.EventList, w io.Writer) {
	if len(el.Items) == 0 {
		fmt.Fprint(w, "No events.")
		return
	}
	sort.Sort(SortableEvents(el.Items))
	fmt.Fprint(w, "Events:\nTime\tFrom\tSubobjectPath\tReason\tMessage\n")
	for _, e := range el.Items {
		fmt.Fprintf(w, "%s\t%v\t%v\t%v\t%v\t%v\n",
			e.Timestamp.Time.Format(time.RFC1123Z),
			e.Source,
			e.InvolvedObject.FieldPath,
			e.Reason,
			e.Message)
	}
}

// Get all replication controllers whose selectors would match a given set of
// labels.
// TODO Move this to pkg/client and ideally implement it server-side (instead
// of getting all RC's and searching through them manually).
func getReplicationControllersForLabels(c client.ReplicationControllerInterface, labelsToMatch labels.Labels) string {
	// Get all replication controllers.
	// TODO this needs a namespace scope as argument
	rcs, err := c.List(labels.Everything())
	if err != nil {
		glog.Fatalf("Error getting replication controllers: %v\n", err)
	}

	// Find the ones that match labelsToMatch.
	var matchingRCs []api.ReplicationController
	for _, controller := range rcs.Items {
		selector := labels.SelectorFromSet(controller.Spec.Selector)
		if selector.Matches(labelsToMatch) {
			matchingRCs = append(matchingRCs, controller)
		}
	}

	// Format the matching RC's into strings.
	var rcStrings []string
	for _, controller := range matchingRCs {
		rcStrings = append(rcStrings, fmt.Sprintf("%s (%d/%d replicas created)", controller.Name, controller.Status.Replicas, controller.Spec.Replicas))
	}

	list := strings.Join(rcStrings, ", ")
	if list == "" {
		return "<none>"
	}
	return list
}

func getPodStatusForReplicationController(c client.PodInterface, controller *api.ReplicationController) (running, waiting, succeeded, failed int, err error) {
	rcPods, err := c.List(labels.SelectorFromSet(controller.Spec.Selector))
	if err != nil {
		return
	}
	for _, pod := range rcPods.Items {
		switch pod.Status.Phase {
		case api.PodRunning:
			running++
		case api.PodPending:
			waiting++
		case api.PodSucceeded:
			succeeded++
		case api.PodFailed:
			failed++
		}
	}
	return
}
<|endoftext|>