<commit_before>package irma

import (
	"time"

	"github.com/go-errors/errors"
	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"
)

// ProofStatus is the status of the complete proof
type ProofStatus string

// Status is the proof status of a single attribute
type AttributeProofStatus string

const (
	ProofStatusValid             = ProofStatus("VALID")              // Proof is valid
	ProofStatusInvalid           = ProofStatus("INVALID")            // Proof is invalid
	ProofStatusInvalidTimestamp  = ProofStatus("INVALID_TIMESTAMP")  // Attribute-based signature had invalid timestamp
	ProofStatusUnmatchedRequest  = ProofStatus("UNMATCHED_REQUEST")  // Proof does not correspond to a specified request
	ProofStatusMissingAttributes = ProofStatus("MISSING_ATTRIBUTES") // Proof does not contain all requested attributes
	ProofStatusExpired           = ProofStatus("EXPIRED")            // Attributes were expired at proof creation time (now, or according to timestamp in case of abs)

	AttributeProofStatusPresent      = AttributeProofStatus("PRESENT")       // Attribute is disclosed and matches the value
	AttributeProofStatusExtra        = AttributeProofStatus("EXTRA")         // Attribute is disclosed, but wasn't requested in request
	AttributeProofStatusMissing      = AttributeProofStatus("MISSING")       // Attribute is NOT disclosed, but should be according to request
	AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)

// DisclosedAttribute represents a disclosed attribute.
type DisclosedAttribute struct {
	Value      TranslatedString        `json:"value"` // Value of the disclosed attribute
	Identifier AttributeTypeIdentifier `json:"id"`
	Status     AttributeProofStatus    `json:"status"`
}

// ProofList is a gabi.ProofList with some extra methods.
type ProofList gabi.ProofList

var ErrorMissingPublicKey = errors.New("Missing public key")

// ExtractPublicKeys returns the public keys of each proof in the proofList, in the same order,
// for later use in verification of the proofList. If one of the proofs is not a ProofD
// an error is returned.
func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabi.PublicKey, error) {
	var publicKeys = make([]*gabi.PublicKey, 0, len(pl))

	for _, v := range pl {
		switch v.(type) {
		case *gabi.ProofD:
			proof := v.(*gabi.ProofD)
			metadata := MetadataFromInt(proof.ADisclosed[1], configuration) // index 1 is metadata attribute
			publicKey, err := metadata.PublicKey()
			if err != nil {
				return nil, err
			}
			if publicKey == nil {
				return nil, ErrorMissingPublicKey
			}
			publicKeys = append(publicKeys, publicKey)
		default:
			return nil, errors.New("Cannot extract public key, not a disclosure proofD")
		}
	}
	return publicKeys, nil
}

// VerifyProofs verifies the proofs cryptographically.
func (pl ProofList) VerifyProofs(configuration *Configuration, context *big.Int, nonce *big.Int, publickeys []*gabi.PublicKey, isSig bool) (bool, error) {
	if publickeys == nil {
		var err error
		publickeys, err = pl.ExtractPublicKeys(configuration)
		if err != nil {
			return false, err
		}
	}

	if len(pl) != len(publickeys) {
		return false, errors.New("Insufficient public keys to verify the proofs")
	}

	// Compute slice to inform gabi of which proofs should be verified to share the same secret key
	keyshareServers := make([]string, len(pl))
	for i := range pl {
		schemeID := NewIssuerIdentifier(publickeys[i].Issuer).SchemeManagerIdentifier()
		if !configuration.SchemeManagers[schemeID].Distributed() {
			keyshareServers[i] = "." // dummy value: no IRMA scheme will ever have this name
		} else {
			keyshareServers[i] = schemeID.Name()
		}
	}

	return gabi.ProofList(pl).Verify(publickeys, context, nonce, isSig, keyshareServers), nil
}

// Expired returns true if any of the contained disclosure proofs is specified at the specified time,
// or now, when the specified time is nil.
func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
	if t == nil {
		temp := time.Now()
		t = &temp
	}
	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		if metadata.Expiry().Before(*t) {
			return true
		}
	}
	return false
}

// DisclosedAttributes returns a slice containing the disclosed attributes that are present in the proof list.
// If a non-empty and non-nil AttributeDisjunctionList is included, then the first attributes in the returned slice match
// with the disjunction list in the disjunction list. If any of the given disjunctions is not matched by one
// of the disclosed attributes, then the corresponding item in the returned slice has status AttributeProofStatusMissing.
// The first return parameter of this function indicates whether or not all disjunctions (if present) are satisfied.
func (d *Disclosure) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	return ProofList(d.Proofs).DisclosedAttributes(configuration, disjunctions)

	// TODO new verification logic that uses d.Indices
}

func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	var list []*DisclosedAttribute
	list = make([]*DisclosedAttribute, len(disjunctions))
	for i := range list {
		// Populate list with AttributeProofStatusMissing; if an attribute that satisfies a disjunction
		// is found below, the corresponding entry in the list is overwritten
		list[i] = &DisclosedAttribute{
			Status: AttributeProofStatusMissing,
		}
	}

	// Temp slice for attributes that have not yet been matched to one of the disjunctions of the request
	// When we are done matching disclosed attributes against the request, filling the first few slots of list,
	// we append these to list just before returning
	extraAttrs := map[AttributeTypeIdentifier]*DisclosedAttribute{}

	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		credtype := metadata.CredentialType()
		if credtype == nil {
			return false, nil, errors.New("ProofList contained a disclosure proof of an unkown credential type")
		}

		for k, v := range proofd.ADisclosed {
			if k == 0 {
				continue // Should never be disclosed, but skip it to be sure
			}

			var attrid AttributeTypeIdentifier
			var attrval *string
			var attr *DisclosedAttribute
			if k == 1 {
				attrid = NewAttributeTypeIdentifier(credtype.Identifier().String())
				p := "present"
				attrval = &p
			} else {
				attrid = credtype.AttributeTypes[k-2].GetAttributeTypeIdentifier()
				attrval = decodeAttribute(v, metadata.Version())
			}
			attr = &DisclosedAttribute{
				Value:      translateAttribute(attrval),
				Identifier: attrid,
				Status:     AttributeProofStatusExtra,
			}

			if k > 1 { // Never add metadata (i.e. no-attribute disclosure) as extra
				extraAttrs[attrid] = attr
			}
			if len(disjunctions) == 0 {
				continue
			}

			// See if the current attribute satisfies one of the disjunctions, if so, delete it from extraAttrs
			for i, disjunction := range disjunctions {
				if disjunction.attemptSatisfy(attrid, attrval) {
					if disjunction.satisfied() {
						attr.Status = AttributeProofStatusPresent
					} else {
						attr.Status = AttributeProofStatusInvalidValue
					}
					list[i] = attr
					delete(extraAttrs, attrid)
				}
			}
		}
	}

	// Any attributes still in here do not satisfy any of the specified disjunctions; append them now
	for _, attr := range extraAttrs {
		list = append(list, attr)
	}

	return len(disjunctions) == 0 || disjunctions.satisfied(), list, nil
}

func (d *Disclosure) VerifyAgainstDisjunctions(
	configuration *Configuration,
	required AttributeDisjunctionList,
	context, nonce *big.Int,
	publickeys []*gabi.PublicKey,
	issig bool,
) ([]*DisclosedAttribute, ProofStatus, error) {
	// Cryptographically verify the IRMA disclosure proofs in the signature
	valid, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, issig)
	if !valid || err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Next extract the contained attributes from the proofs, and match them to the signature request if present
	allmatched, list, err := d.DisclosedAttributes(configuration, required)
	if err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
	if !allmatched {
		return list, ProofStatusMissingAttributes, nil
	}

	return list, ProofStatusValid, nil
}

func (d *Disclosure) Verify(configuration *Configuration, request *DisclosureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	list, status, err := d.VerifyAgainstDisjunctions(configuration, request.Content, request.Context, request.Nonce, nil, false)
	if err != nil {
		return list, status, err
	}

	now := time.Now()
	if expired := ProofList(d.Proofs).Expired(configuration, &now); expired {
		return list, ProofStatusExpired, nil
	}

	return list, status, nil
}

// Verify the attribute-based signature, optionally against a corresponding signature request. If the request is present
// (i.e. not nil), then the first attributes in the returned result match with the disjunction list in the request
// (that is, the i'th attribute in the result should satisfy the i'th disjunction in the request). If the request is not
// fully satisfied in this fasion, the Status of the result is ProofStatusMissingAttributes. Any remaining attributes
// (i.e. not asked for by the request) are also included in the result, after the attributes that match disjunctions
// in the request.
//
// The signature request is optional; if it is nil then the attribute-based signature is still verified, and all
// containing attributes returned in the result.
func (sm *SignedMessage) Verify(configuration *Configuration, request *SignatureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	var message string

	// First check if this signature matches the request
	if request != nil {
		request.Timestamp = sm.Timestamp
		if !sm.MatchesNonceAndContext(request) {
			return nil, ProofStatusUnmatchedRequest, nil
		}
		// If there is a request, then the signed message must be that of the request
		message = request.Message
	} else {
		// If not, we just verify that the signed message is a valid signature over its contained message
		message = sm.Message
	}

	// Verify the timestamp
	if sm.Timestamp != nil {
		if err := sm.VerifyTimestamp(message, configuration); err != nil {
			return nil, ProofStatusInvalidTimestamp, nil
		}
	}

	// Now, cryptographically verify the IRMA disclosure proofs in the signature
	var required AttributeDisjunctionList
	if request != nil {
		required = request.Content
	}
	result, status, err := sm.Disclosure().VerifyAgainstDisjunctions(configuration, required, sm.Context, sm.GetNonce(), nil, true)
	if status != ProofStatusValid || err != nil {
		return result, status, err
	}

	// Check if a credential is expired
	var t time.Time
	if sm.Timestamp != nil {
		t = time.Unix(sm.Timestamp.Time, 0)
	}
	if expired := ProofList(sm.Signature).Expired(configuration, &t); expired {
		// The ABS contains attributes that were expired at the time of creation of the ABS.
		return result, ProofStatusExpired, nil
	}

	// All disjunctions satisfied and nothing expired, proof is valid!
	return result, ProofStatusValid, nil
}
<commit_msg>Use disclosure indices when verifying attribute disclosures<commit_after>package irma

import (
	"time"

	"github.com/go-errors/errors"
	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/big"
)

// ProofStatus is the status of the complete proof
type ProofStatus string

// Status is the proof status of a single attribute
type AttributeProofStatus string

const (
	ProofStatusValid             = ProofStatus("VALID")              // Proof is valid
	ProofStatusInvalid           = ProofStatus("INVALID")            // Proof is invalid
	ProofStatusInvalidTimestamp  = ProofStatus("INVALID_TIMESTAMP")  // Attribute-based signature had invalid timestamp
	ProofStatusUnmatchedRequest  = ProofStatus("UNMATCHED_REQUEST")  // Proof does not correspond to a specified request
	ProofStatusMissingAttributes = ProofStatus("MISSING_ATTRIBUTES") // Proof does not contain all requested attributes
	ProofStatusExpired           = ProofStatus("EXPIRED")            // Attributes were expired at proof creation time (now, or according to timestamp in case of abs)

	AttributeProofStatusPresent      = AttributeProofStatus("PRESENT")       // Attribute is disclosed and matches the value
	AttributeProofStatusExtra        = AttributeProofStatus("EXTRA")         // Attribute is disclosed, but wasn't requested in request
	AttributeProofStatusMissing      = AttributeProofStatus("MISSING")       // Attribute is NOT disclosed, but should be according to request
	AttributeProofStatusInvalidValue = AttributeProofStatus("INVALID_VALUE") // Attribute is disclosed, but has invalid value according to request
)

// DisclosedAttribute represents a disclosed attribute.
type DisclosedAttribute struct {
	Value      TranslatedString        `json:"value"` // Value of the disclosed attribute
	Identifier AttributeTypeIdentifier `json:"id"`
	Status     AttributeProofStatus    `json:"status"`
}

// ProofList is a gabi.ProofList with some extra methods.
type ProofList gabi.ProofList

var ErrorMissingPublicKey = errors.New("Missing public key")

// ExtractPublicKeys returns the public keys of each proof in the proofList, in the same order,
// for later use in verification of the proofList. If one of the proofs is not a ProofD
// an error is returned.
func (pl ProofList) ExtractPublicKeys(configuration *Configuration) ([]*gabi.PublicKey, error) {
	var publicKeys = make([]*gabi.PublicKey, 0, len(pl))

	for _, v := range pl {
		switch v.(type) {
		case *gabi.ProofD:
			proof := v.(*gabi.ProofD)
			metadata := MetadataFromInt(proof.ADisclosed[1], configuration) // index 1 is metadata attribute
			publicKey, err := metadata.PublicKey()
			if err != nil {
				return nil, err
			}
			if publicKey == nil {
				return nil, ErrorMissingPublicKey
			}
			publicKeys = append(publicKeys, publicKey)
		default:
			return nil, errors.New("Cannot extract public key, not a disclosure proofD")
		}
	}
	return publicKeys, nil
}

// VerifyProofs verifies the proofs cryptographically.
func (pl ProofList) VerifyProofs(configuration *Configuration, context *big.Int, nonce *big.Int, publickeys []*gabi.PublicKey, isSig bool) (bool, error) {
	if publickeys == nil {
		var err error
		publickeys, err = pl.ExtractPublicKeys(configuration)
		if err != nil {
			return false, err
		}
	}

	if len(pl) != len(publickeys) {
		return false, errors.New("Insufficient public keys to verify the proofs")
	}

	// Compute slice to inform gabi of which proofs should be verified to share the same secret key
	keyshareServers := make([]string, len(pl))
	for i := range pl {
		schemeID := NewIssuerIdentifier(publickeys[i].Issuer).SchemeManagerIdentifier()
		if !configuration.SchemeManagers[schemeID].Distributed() {
			keyshareServers[i] = "." // dummy value: no IRMA scheme will ever have this name
		} else {
			keyshareServers[i] = schemeID.Name()
		}
	}

	return gabi.ProofList(pl).Verify(publickeys, context, nonce, isSig, keyshareServers), nil
}

// Expired returns true if any of the contained disclosure proofs is specified at the specified time,
// or now, when the specified time is nil.
func (pl ProofList) Expired(configuration *Configuration, t *time.Time) bool {
	if t == nil {
		temp := time.Now()
		t = &temp
	}
	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		if metadata.Expiry().Before(*t) {
			return true
		}
	}
	return false
}

// DisclosedAttributes returns a slice containing the disclosed attributes that are present in the proof list.
// If a non-empty and non-nil AttributeDisjunctionList is included, then the first attributes in the returned slice match
// with the disjunction list in the disjunction list. If any of the given disjunctions is not matched by one
// of the disclosed attributes, then the corresponding item in the returned slice has status AttributeProofStatusMissing.
// The first return parameter of this function indicates whether or not all disjunctions (if present) are satisfied.
func (d *Disclosure) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	if d.Indices == nil || len(disjunctions) == 0 {
		return ProofList(d.Proofs).DisclosedAttributes(configuration, disjunctions)
	}

	list := make([]*DisclosedAttribute, len(disjunctions))
	usedAttrs := map[int]map[int]struct{}{} // keep track of attributes that satisfy the disjunctions

	// For each of the disjunctions, lookup the attribute that the user sent to satisfy this disjunction,
	// using the indices specified by the user in d.Indices. Then see if the attribute satisfies the disjunction.
	for i, disjunction := range disjunctions {
		index := d.Indices[i][0]
		proofd, ok := d.Proofs[index.CredentialIndex].(*gabi.ProofD)
		if !ok {
			// If with the index the user told us to look for the required attribute at this specific location,
			// and the proof here is not a disclosure proof, then reject
			return false, nil, errors.New("ProofList contained proof of invalid type")
		}

		if usedAttrs[index.CredentialIndex] == nil {
			usedAttrs[index.CredentialIndex] = map[int]struct{}{}
		}
		usedAttrs[index.CredentialIndex][index.AttributeIndex] = struct{}{}

		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		attr, attrval, err := parseAttribute(index.AttributeIndex, metadata, proofd.ADisclosed[index.AttributeIndex+2])
		if err != nil {
			return false, nil, err
		}

		if disjunction.attemptSatisfy(attr.Identifier, attrval) {
			list[i] = attr
			if disjunction.satisfied() {
				list[i].Status = AttributeProofStatusPresent
			} else {
				list[i].Status = AttributeProofStatusInvalidValue
			}
		} else {
			list[i] = &DisclosedAttribute{Status: AttributeProofStatusMissing}
		}
	}

	// Loop over any extra attributes in d.Proofs not requested in any of the disjunctions
	for i, proof := range d.Proofs {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute
		for attrIndex, attrInt := range proofd.ADisclosed {
			if attrIndex == 0 || attrIndex == 1 { // Never add secret key or metadata (i.e. no-attribute disclosure) as extra
				continue // Note that the secret should never be disclosed by the client, but we skip it to be sure
			}
			if _, used := usedAttrs[i][attrIndex]; used {
				continue
			}

			attr, _, err := parseAttribute(attrIndex, metadata, attrInt)
			if err != nil {
				return false, nil, err
			}
			attr.Status = AttributeProofStatusExtra
			list = append(list, attr)
		}
	}

	return len(disjunctions) == 0 || disjunctions.satisfied(), list, nil
}

func parseAttribute(index int, metadata *MetadataAttribute, attr *big.Int) (*DisclosedAttribute, *string, error) {
	var attrid AttributeTypeIdentifier
	var attrval *string
	credtype := metadata.CredentialType()
	if credtype == nil {
		return nil, nil, errors.New("ProofList contained a disclosure proof of an unkown credential type")
	}
	if index == 1 {
		attrid = NewAttributeTypeIdentifier(credtype.Identifier().String())
		p := "present"
		attrval = &p
	} else {
		attrid = credtype.AttributeTypes[index-2].GetAttributeTypeIdentifier()
		attrval = decodeAttribute(attr, metadata.Version())
	}
	return &DisclosedAttribute{
		Identifier: attrid,
		Value:      translateAttribute(attrval),
	}, attrval, nil
}

func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctions AttributeDisjunctionList) (bool, []*DisclosedAttribute, error) {
	var list []*DisclosedAttribute
	list = make([]*DisclosedAttribute, len(disjunctions))
	for i := range list {
		// Populate list with AttributeProofStatusMissing; if an attribute that satisfies a disjunction
		// is found below, the corresponding entry in the list is overwritten
		list[i] = &DisclosedAttribute{
			Status: AttributeProofStatusMissing,
		}
	}

	// Temp slice for attributes that have not yet been matched to one of the disjunctions of the request
	// When we are done matching disclosed attributes against the request, filling the first few slots of list,
	// we append these to list just before returning
	extraAttrs := map[AttributeTypeIdentifier]*DisclosedAttribute{}

	for _, proof := range pl {
		proofd, ok := proof.(*gabi.ProofD)
		if !ok {
			continue
		}
		metadata := MetadataFromInt(proofd.ADisclosed[1], configuration) // index 1 is metadata attribute

		for attrIndex, attrInt := range proofd.ADisclosed {
			if attrIndex == 0 {
				continue // Should never be disclosed, but skip it to be sure
			}

			attr, attrval, err := parseAttribute(attrIndex, metadata, attrInt)
			if err != nil {
				return false, nil, err
			}

			if attrIndex > 1 { // Never add metadata (i.e. no-attribute disclosure) as extra
				extraAttrs[attr.Identifier] = attr
			}
			if len(disjunctions) == 0 {
				continue
			}

			// See if the current attribute satisfies one of the disjunctions, if so, delete it from extraAttrs
			for i, disjunction := range disjunctions {
				if disjunction.attemptSatisfy(attr.Identifier, attrval) {
					if disjunction.satisfied() {
						attr.Status = AttributeProofStatusPresent
					} else {
						attr.Status = AttributeProofStatusInvalidValue
					}
					list[i] = attr
					delete(extraAttrs, attr.Identifier)
				}
			}
		}
	}

	// Any attributes still in here do not satisfy any of the specified disjunctions; append them now
	for _, attr := range extraAttrs {
		list = append(list, attr)
	}

	return len(disjunctions) == 0 || disjunctions.satisfied(), list, nil
}

func (d *Disclosure) VerifyAgainstDisjunctions(
	configuration *Configuration,
	required AttributeDisjunctionList,
	context, nonce *big.Int,
	publickeys []*gabi.PublicKey,
	issig bool,
) ([]*DisclosedAttribute, ProofStatus, error) {
	// Cryptographically verify the IRMA disclosure proofs in the signature
	valid, err := ProofList(d.Proofs).VerifyProofs(configuration, context, nonce, publickeys, issig)
	if !valid || err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Next extract the contained attributes from the proofs, and match them to the signature request if present
	allmatched, list, err := d.DisclosedAttributes(configuration, required)
	if err != nil {
		return nil, ProofStatusInvalid, err
	}

	// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
	if !allmatched {
		return list, ProofStatusMissingAttributes, nil
	}

	return list, ProofStatusValid, nil
}

func (d *Disclosure) Verify(configuration *Configuration, request *DisclosureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	list, status, err := d.VerifyAgainstDisjunctions(configuration, request.Content, request.Context, request.Nonce, nil, false)
	if err != nil {
		return list, status, err
	}

	now := time.Now()
	if expired := ProofList(d.Proofs).Expired(configuration, &now); expired {
		return list, ProofStatusExpired, nil
	}

	return list, status, nil
}

// Verify the attribute-based signature, optionally against a corresponding signature request. If the request is present
// (i.e. not nil), then the first attributes in the returned result match with the disjunction list in the request
// (that is, the i'th attribute in the result should satisfy the i'th disjunction in the request). If the request is not
// fully satisfied in this fasion, the Status of the result is ProofStatusMissingAttributes. Any remaining attributes
// (i.e. not asked for by the request) are also included in the result, after the attributes that match disjunctions
// in the request.
//
// The signature request is optional; if it is nil then the attribute-based signature is still verified, and all
// containing attributes returned in the result.
func (sm *SignedMessage) Verify(configuration *Configuration, request *SignatureRequest) ([]*DisclosedAttribute, ProofStatus, error) {
	var message string

	// First check if this signature matches the request
	if request != nil {
		request.Timestamp = sm.Timestamp
		if !sm.MatchesNonceAndContext(request) {
			return nil, ProofStatusUnmatchedRequest, nil
		}
		// If there is a request, then the signed message must be that of the request
		message = request.Message
	} else {
		// If not, we just verify that the signed message is a valid signature over its contained message
		message = sm.Message
	}

	// Verify the timestamp
	if sm.Timestamp != nil {
		if err := sm.VerifyTimestamp(message, configuration); err != nil {
			return nil, ProofStatusInvalidTimestamp, nil
		}
	}

	// Now, cryptographically verify the IRMA disclosure proofs in the signature
	var required AttributeDisjunctionList
	if request != nil {
		required = request.Content
	}
	result, status, err := sm.Disclosure().VerifyAgainstDisjunctions(configuration, required, sm.Context, sm.GetNonce(), nil, true)
	if status != ProofStatusValid || err != nil {
		return result, status, err
	}

	// Check if a credential is expired
	var t time.Time
	if sm.Timestamp != nil {
		t = time.Unix(sm.Timestamp.Time, 0)
	}
	if expired := ProofList(sm.Signature).Expired(configuration, &t); expired {
		// The ABS contains attributes that were expired at the time of creation of the ABS.
		return result, ProofStatusExpired, nil
	}

	// All disjunctions satisfied and nothing expired, proof is valid!
	return result, ProofStatusValid, nil
}
<|endoftext|>


<commit_before>package xing

import (
	"fmt"
	"sync"
	"time"

	"github.com/rs/zerolog/log"
	"github.com/streadway/amqp"
	wk "github.com/wzhliang/xing/pkg/worker"
	"github.com/wzhliang/xing/utils"
)

// Worker ...
type Worker struct {
	sync.Mutex
	id         int
	ch         *amqp.Channel    // incoming channel
	sch        *amqp.Channel    // outgoing channel
	queue      amqp.Queue       // queue for consumption, for RPC client, it holds results
	conn       *amqp.Connection // own copy for detecting reconnection
	d          wk.Dispatcher
	c          *Client // the AMQP client
	rpcCounter uint
}

// SetDispatcher ...
func (w *Worker) SetDispatcher(dis wk.Dispatcher) {
	w.d = dis
}

// Close ... should be called after stopped
func (w *Worker) Close() {
	// at this time, the channel is already closed
	var err error
	if w.c.conn == nil {
		log.Error().Msg("no connection to AMQP server. can't do much")
		return
	}
	w.ch, err = w.conn.Channel()
	if err != nil {
		log.Error().Err(err).Msg("failed to create channel")
		return
	}

	n, err := w.ch.QueueDelete(w.queue.Name, false, false, false)
	if err != nil {
		log.Error().Int("n", n).Err(err).Msg("failed to delete queue")
	}
}

func (w *Worker) corrid() string {
	return fmt.Sprintf("rpc-%s-%02d-%d", w.c.name, w.id, w.rpcCounter)
}

// Loop ...
func (w *Worker) Loop() {
	for {
		req := w.d.Dispatch()
		if req.In == nil {
			break
		}
		var results chan interface{}
		var errs chan error
		ret := func(v interface{}, err error) {
			results <- v
			errs <- err
		}

		results = req.Result

		errs = req.Err
		if w.c.conn == nil {
			log.Info().Msg("connection not available, sleeping a while...")
			time.Sleep(time.Duration(utils.Random(2000, 3000)) * time.Millisecond)
			// prevent mutlple works from trying to reconnect at the same time
			_, err := w.c.ensureConnection()
			if err == nil {
				w.onConnect(w.c.conn)
			} else {
				ret(nil, fmt.Errorf("connection lost"))
				continue
			}
		} else if w.c.conn != w.conn {
			w.onConnect(w.c.conn)
		}
		ret(w.processJob(req))
	}
	log.Info().Int("id", w.id).Msg("I am done")
	w.c.wg.Done() // FIXME: should not have access to wg
}

func newWorker(conn *amqp.Connection, c *Client, id int) *Worker {
	w := Worker{
		id:         id,
		c:          c,
		conn:       conn,
		rpcCounter: uint(utils.Random(1000, 9999)),
	}
	var err error
	err = w.onConnect(conn)
	if err != nil {
		return nil
	}
	return &w
}

func (w *Worker) onConnect(conn *amqp.Connection) error {
	log.Info().Msg("connected")
	var err error
	w.Lock()
	w.conn = conn // refreshing own copy
	w.Unlock()
	w.ch, err = conn.Channel()
	if err != nil {
		return nil
	}
	w.sch, err = conn.Channel()
	if err != nil {
		return nil
	}
	err = w.ch.ExchangeDeclare(
		RPCExchange, // name
		"topic",     // kind
		true,        // durable
		false,       // autodelete
		false,       // internal
		false,       // noWait
		nil,
	)
	if err != nil {
		return err
	}
	// I have to be a client
	w.queue, err = w.ch.QueueDeclare(
		fmt.Sprintf("%s-%02d", w.c.name, w.id), // name
		true,  // durable
		false, // autoDelete
		true,  // exclusive
		false, // noWait
		amqp.Table{
			"x-expires":     ResultQueueTTL,
			"x-message-ttl": RPCTTL,
		}, // args
	)
	if err != nil {
		log.Error().Err(err).Msg("setup failed")
		return nil
	}
	key := resultTopicName(w.queue.Name) // for client, queuename is the client's name
	log.Info().Str("queue", w.queue.Name).Str("exchange", RPCExchange).Str("key", key).
		Msg("Subscribing")
	err = w.ch.QueueBind(w.queue.Name, key, RPCExchange, false, nil)
	if err != nil {
		log.Error().Err(err).Msg("setup failed")
		return err
	}

	return nil
}

func (w *Worker) sendEx(target string, _type string, event string, replyTo string, payload interface{}) error {
	var cor string

	if _type == Command { // FIXME: actuall worker should only handle Command
		w.Lock()
		w.rpcCounter++
		w.Unlock()
		cor = w.corrid()
	} else {
		cor = "N/A"
	}

	ex := w.c.exchange(_type)
	var key string
	if topicLength(target) == 2 { // load balanced rpc
		key = fmt.Sprintf("%s.*.%s.%s", target, _type, event)
	} else if topicLength(target) == 3 {
		key = fmt.Sprintf("%s.%s.%s", target, _type, event)
	} else {
		return fmt.Errorf("Invalid target: %s", target)
	}
	return w._sendEx(ex, key, cor, event, replyTo, payload)
}

func (w *Worker) _sendEx(ex string, key string, corrid string, typ string, replyTo string, payload interface{}) error {
	pl, err := w.c.serializer.Marshal(payload)
	if err != nil {
		return err
	}
	msg := amqp.Publishing{
		DeliveryMode:  amqp.Persistent,
		Timestamp:     time.Now(),
		ContentType:   w.c.serializer.ContentType(),
		ReplyTo:       replyTo,
		CorrelationId: corrid,
		Body:          []byte(pl),
	}

	log.Info().Int("id", w.id).Str("to", ex).Str("key", key).Str("corid", corrid).Str("type", typ).Str("replyTo", replyTo).
		Msg("Sending")
	return w.sch.Publish(ex, key, false, false, msg)
}

func (w *Worker) newChannel() (*amqp.Channel, error) {
	_, err := w.c.ensureConnection()
	if err != nil {
		return nil, err
	}

	return w.c.conn.Channel()
}

// this deals with a job blockingly
func (w *Worker) processJob(req wk.Request) (interface{}, error) {
	in := req.In.(Request)
	{
		var err error
		var msgs <-chan amqp.Delivery
		// receive
		w.ch, err = w.newChannel()
		if err != nil {
			log.Error().Err(err).Msg("failed to create channel")
			return nil, err
		}
		defer w.ch.Close()
		err = w.ch.Qos(1, 0, false)
		if err != nil {
			log.Error().Err(err).Msg("failed to Qos")
			return nil, err
		}
		// this has to be done before sending, otherwise it's too late
		msgs, err = w.ch.Consume(
			w.queue.Name, // queue
			"",           // consumer
			true,         // autoAck
			true,         // exclusive
			false,        // noLocal
			false,        // noWait
			nil,
		)
		if err != nil {
			log.Error().Err(err).Msg("failed to consume")
			return nil, err
		}
		// send
		err = w.sendEx(in.target, Command, in.method, w.queue.Name, in.payload)
		if err != nil {
			return nil, err
		}
		select {
		case msg := <-msgs:
			if w.corrid() != msg.CorrelationId {
				log.Warn().Str("corrid", msg.CorrelationId).Msg("It looks like you're using multiple thread to access a single channel.")
				return nil, fmt.Errorf("unexpected message received")
			}
			res, err := w.c.toResult(&msg)
			log.Info().Int("id", w.id).Str("corrid", w.corrid()).Msg("Response")
			return res, err
		case <-in.ctx.Done():
			log.Error().Int("id", w.id).Str("corrid", w.corrid()).Str("method", in.method).Msg("RPC timeout")
			err := fmt.Errorf("Your RPC has timedout, commander: %s", in.method)
			return nil, err
		}
	}
}
<commit_msg>adding comment about client queue name<commit_after>package xing

import (
	"fmt"
	"sync"
	"time"

	"github.com/rs/zerolog/log"
	"github.com/streadway/amqp"
	wk "github.com/wzhliang/xing/pkg/worker"
	"github.com/wzhliang/xing/utils"
)

// Worker ...
type Worker struct {
	sync.Mutex
	id         int
	ch         *amqp.Channel    // incoming channel
	sch        *amqp.Channel    // outgoing channel
	queue      amqp.Queue       // queue for consumption, for RPC client, it holds results
	conn       *amqp.Connection // own copy for detecting reconnection
	d          wk.Dispatcher
	c          *Client // the AMQP client
	rpcCounter uint
}

// SetDispatcher ...
func (w *Worker) SetDispatcher(dis wk.Dispatcher) {
	w.d = dis
}

// Close ... should be called after stopped
func (w *Worker) Close() {
	// at this time, the channel is already closed
	var err error
	if w.c.conn == nil {
		log.Error().Msg("no connection to AMQP server. can't do much")
		return
	}
	w.ch, err = w.conn.Channel()
	if err != nil {
		log.Error().Err(err).Msg("failed to create channel")
		return
	}

	n, err := w.ch.QueueDelete(w.queue.Name, false, false, false)
	if err != nil {
		log.Error().Int("n", n).Err(err).Msg("failed to delete queue")
	}
}

func (w *Worker) corrid() string {
	return fmt.Sprintf("rpc-%s-%02d-%d", w.c.name, w.id, w.rpcCounter)
}

// Loop ...
func (w *Worker) Loop() {
	for {
		req := w.d.Dispatch()
		if req.In == nil {
			break
		}
		var results chan interface{}
		var errs chan error
		ret := func(v interface{}, err error) {
			results <- v
			errs <- err
		}

		results = req.Result

		errs = req.Err
		if w.c.conn == nil {
			log.Info().Msg("connection not available, sleeping a while...")
			time.Sleep(time.Duration(utils.Random(2000, 3000)) * time.Millisecond)
			// prevent mutlple works from trying to reconnect at the same time
			_, err := w.c.ensureConnection()
			if err == nil {
				w.onConnect(w.c.conn)
			} else {
				ret(nil, fmt.Errorf("connection lost"))
				continue
			}
		} else if w.c.conn != w.conn {
			w.onConnect(w.c.conn)
		}
		ret(w.processJob(req))
	}
	log.Info().Int("id", w.id).Msg("I am done")
	w.c.wg.Done() // FIXME: should not have access to wg
}

func newWorker(conn *amqp.Connection, c *Client, id int) *Worker {
	w := Worker{
		id:         id,
		c:          c,
		conn:       conn,
		rpcCounter: uint(utils.Random(1000, 9999)),
	}
	var err error
	err = w.onConnect(conn)
	if err != nil {
		return nil
	}
	return &w
}

func (w *Worker) onConnect(conn *amqp.Connection) error {
	log.Info().Msg("connected")
	var err error
	w.Lock()
	w.conn = conn // refreshing own copy
	w.Unlock()
	w.ch, err = conn.Channel()
	if err != nil {
		return nil
	}
	w.sch, err = conn.Channel()
	if err != nil {
		return nil
	}
	err = w.ch.ExchangeDeclare(
		RPCExchange, // name
		"topic",     // kind
		true,        // durable
		false,       // autodelete
		false,       // internal
		false,       // noWait
		nil,
	)
	if err != nil {
		return err
	}
	// I have to be a client
	w.queue, err = w.ch.QueueDeclare(
		// for client queue, we don't care it's name
		// also, changing it will cause crash
		fmt.Sprintf("%s-%02d", w.c.name, w.id), // name
		true,  // durable
		false, // autoDelete
		true,  // exclusive
		false, // noWait
		amqp.Table{
			"x-expires":     ResultQueueTTL,
			"x-message-ttl": RPCTTL,
		}, // args
	)
	if err != nil {
		log.Error().Err(err).Msg("setup failed")
		return nil
	}
	key := resultTopicName(w.queue.Name) // for client, queuename is the client's name
	log.Info().Str("queue", w.queue.Name).Str("exchange", RPCExchange).Str("key", key).
		Msg("Subscribing")
	err = w.ch.QueueBind(w.queue.Name, key, RPCExchange, false, nil)
	if err != nil {
		log.Error().Err(err).Msg("setup failed")
		return err
	}

	return nil
}

func (w *Worker) sendEx(target string, _type string, event string, replyTo string, payload interface{}) error {
	var cor string

	if _type == Command { // FIXME: actuall worker should only handle Command
		w.Lock()
		w.rpcCounter++
		w.Unlock()
		cor = w.corrid()
	} else {
		cor = "N/A"
	}

	ex := w.c.exchange(_type)
	var key string
	if topicLength(target) == 2 { // load balanced rpc
		key = fmt.Sprintf("%s.*.%s.%s", target, _type, event)
	} else if topicLength(target) == 3 {
		key = fmt.Sprintf("%s.%s.%s", target, _type, event)
	} else {
		return fmt.Errorf("Invalid target: %s", target)
	}
	return w._sendEx(ex, key, cor, event, replyTo, payload)
}

func (w *Worker) _sendEx(ex string, key string, corrid string, typ string, replyTo string, payload interface{}) error {
	pl, err := w.c.serializer.Marshal(payload)
	if err != nil {
		return err
	}
	msg := amqp.Publishing{
		DeliveryMode:  amqp.Persistent,
		Timestamp:     time.Now(),
		ContentType:   w.c.serializer.ContentType(),
		ReplyTo:       replyTo,
		CorrelationId: corrid,
		Body:          []byte(pl),
	}

	log.Info().Int("id", w.id).Str("to", ex).Str("key", key).Str("corid", corrid).Str("type", typ).Str("replyTo", replyTo).
		Msg("Sending")
	return w.sch.Publish(ex, key, false, false, msg)
}

func (w *Worker) newChannel() (*amqp.Channel, error) {
	_, err := w.c.ensureConnection()
	if err != nil {
		return nil, err
	}

	return w.c.conn.Channel()
}

// this deals with a job blockingly
func (w *Worker) processJob(req wk.Request) (interface{}, error) {
	in := req.In.(Request)
	{
		var err error
		var msgs <-chan amqp.Delivery
		// receive
		w.ch, err = w.newChannel()
		if err != nil {
			log.Error().Err(err).Msg("failed to create channel")
			return nil, err
		}
		defer w.ch.Close()
		err = w.ch.Qos(1, 0, false)
		if err != nil {
			log.Error().Err(err).Msg("failed to Qos")
			return nil, err
		}
		// this has to be done before sending, otherwise it's too late
		msgs, err = w.ch.Consume(
			w.queue.Name, // queue
			"",           // consumer
			true,         // autoAck
			true,         // exclusive
			false,        // noLocal
			false,        // noWait
			nil,
		)
		if err != nil {
			log.Error().Err(err).Msg("failed to consume")
			return nil, err
		}
		// send
		err = w.sendEx(in.target, Command, in.method, w.queue.Name, in.payload)
		if err != nil {
			return nil, err
		}
		select {
		case msg := <-msgs:
			if w.corrid() != msg.CorrelationId {
				log.Warn().Str("corrid", msg.CorrelationId).Msg("It looks like you're using multiple thread to access a single channel.")
				return nil, fmt.Errorf("unexpected message received")
			}
			res, err := w.c.toResult(&msg)
			log.Info().Int("id", w.id).Str("corrid", w.corrid()).Msg("Response")
			return res, err
		case <-in.ctx.Done():
			log.Error().Int("id", w.id).Str("corrid", w.corrid()).Str("method", in.method).Msg("RPC timeout")
			err := fmt.Errorf("Your RPC has timedout, commander: %s", in.method)
			return nil, err
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math"
)

type Ship struct {
	Id           string  `json:"id"`
	Alive        bool    `json:"alive"`
	Position     *Point  `json:"position"`
	Angle        float64 `json:"angle"`
	Acceleration int8    `json:"acceleration"`
	Rotation     int8    `json:"rotation"`
}

const (
	ShipRadius = 10
)

func CreateShip(id string, pos *Point) *Ship {
	return &Ship{
		Id:           id,
		Alive:        true,
		Position:     pos,
		Angle:        0,
		Acceleration: 0,
		Rotation:     0,
	}
}

func (s *Ship) Tick(time uint64, state *GameState) *Ship {
	// calculate time since last update (in milliseconds)
	elapsed := time - state.Time

	// calculate new angle
	angle := s.Angle
	if s.Rotation != 0 {
		angle = s.Angle + AmountToRotate(s.Rotation, settings.constants.ShipRotation, elapsed)
	}

	// calculate new position
	pos := s.Position
	if s.Acceleration == 1 {
		// TODO: When we add drift, move velocity to ship struct, and change it due to acceleration
		velocity := AngleAndSpeedToVector(s.Angle, settings.constants.ShipAcceleration)
		x, y := AmountToMove(velocity, elapsed)
		pos = &Point{s.Position.X + x, s.Position.Y + y}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
	for _, os := range state.Ships {
		if os.Id != s.Id {
			dx := s.Position.X - os.Position.X
			dy := s.Position.Y - os.Position.Y
			distance := math.Sqrt(float64(dx*dx + dy*dy))

			if distance < ShipRadius*2 {
				if settings.debug {
					log.Println(fmt.Sprintf("Ship %v colliding with Ship %v", s.Id, os.Id))
				}
			}
		}
	}

	for _, p := range state.Projectiles {
		dx := s.Position.X - p.Position.X
		dy := s.Position.Y - p.Position.Y
		distance := math.Sqrt(float64(dx*dx + dy*dy))

		if distance < ShipRadius+ProjectileRadius {
			if settings.debug {
				log.Println(fmt.Sprintf("Ship %v colliding with Projectile %v", s.Id, p.Id))
			}
		}
	}

	return &Ship{
		Id:           s.Id,
		Alive:        s.Alive,
		Position:     pos,
		Angle:        angle,
		Acceleration: s.Acceleration,
		Rotation:     s.Rotation,
	}
}
<commit_msg>Clamp angle to 0-360 on server.<commit_after>package main

import (
	"fmt"
	"log"
	"math"
)

type Ship struct {
	Id           string  `json:"id"`
	Alive        bool    `json:"alive"`
	Position     *Point  `json:"position"`
	Angle        float64 `json:"angle"`
	Acceleration int8    `json:"acceleration"`
	Rotation     int8    `json:"rotation"`
}

const (
	ShipRadius = 10
)

func CreateShip(id string, pos *Point) *Ship {
	return &Ship{
		Id:           id,
		Alive:        true,
		Position:     pos,
		Angle:        0,
		Acceleration: 0,
		Rotation:     0,
	}
}

func (s *Ship) Tick(time uint64, state *GameState) *Ship {
	// calculate time since last update (in milliseconds)
	elapsed := time - state.Time

	// calculate new angle
	angle := s.Angle
	if s.Rotation != 0 {
		angle = s.Angle + AmountToRotate(s.Rotation, settings.constants.ShipRotation, elapsed)
		for angle < 0 {
			angle += 360
		}
		for angle >= 360 {
			angle -= 360
		}
	}

	// calculate new position
	pos := s.Position
	if s.Acceleration == 1 {
		// TODO: When we add drift, move velocity to ship struct, and change it due to acceleration
		velocity := AngleAndSpeedToVector(s.Angle, settings.constants.ShipAcceleration)
		x, y := AmountToMove(velocity, elapsed)
		pos = &Point{s.Position.X + x, s.Position.Y + y}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
	for _, os := range state.Ships {
		if os.Id != s.Id {
			dx := s.Position.X - os.Position.X
			dy := s.Position.Y - os.Position.Y
			distance := math.Sqrt(float64(dx*dx + dy*dy))

			if distance < ShipRadius*2 {
				if settings.debug {
					log.Println(fmt.Sprintf("Ship %v colliding with Ship %v", s.Id, os.Id))
				}
			}
		}
	}

	for _, p := range state.Projectiles {
		dx := s.Position.X - p.Position.X
		dy := s.Position.Y - p.Position.Y
		distance := math.Sqrt(float64(dx*dx + dy*dy))

		if distance < ShipRadius+ProjectileRadius {
			if settings.debug {
				log.Println(fmt.Sprintf("Ship %v colliding with Projectile %v", s.Id, p.Id))
			}
		}
	}

	return &Ship{
		Id:           s.Id,
		Alive:        s.Alive,
		Position:     pos,
		Angle:        angle,
		Acceleration: s.Acceleration,
		Rotation:     s.Rotation,
	}
}
<|endoftext|>


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

package dns

import (
	"fmt"
	"net"
	"runtime"
	"sync"
	"testing"
)

func HelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	w.WriteMsg(m)
}

func AnotherHelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
	w.WriteMsg(m)
}

func RunLocalUDPServer(laddr string) (*Server, string, error) {
	pc, err := net.ListenPacket("udp", laddr)
	if err != nil {
		return nil, "", err
	}
	server := &Server{PacketConn: pc}
	go func() {
		server.ActivateAndServe()
		pc.Close()
	}()
	// in order to let all Server internals to finish before test will touch
	// server's internal fields, we need to cycle thru other goroutinges for
	// one more time
	runtime.Gosched()
	return server, pc.LocalAddr().String(), nil
}

func RunLocalTCPServer(laddr string) (*Server, string, error) {
	l, err := net.Listen("tcp", laddr)
	if err != nil {
		return nil, "", err
	}
	server := &Server{Listener: l}
	go func() {
		server.ActivateAndServe()
		l.Close()
	}()
	// in order to let all Server internals to finish before test will touch
	// server's internal fields, we need to cycle thru other goroutinges for
	// one more time
	runtime.Gosched()
	return server, l.Addr().String(), nil
}

func TestServing(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	HandleFunc("example.com.", AnotherHelloServer)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange miek.nl", err)
		t.Fatal()
	}
	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello world" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
		t.Fail()
	}

	m.SetQuestion("example.com.", TypeTXT)
	r, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange example.com", err)
		t.Fatal()
	}
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}

	// Test Mixes cased as noticed by Ask.
	m.SetQuestion("eXaMplE.cOm.", TypeTXT)
	r, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange eXaMplE.cOm", err)
		t.Fail()
	}
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}
}

func BenchmarkServe(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func benchmarkServe6(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)
	s, addrstr, err := RunLocalUDPServer("[::1]:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func HelloServerCompress(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	m.Compress = true
	w.WriteMsg(m)
}

func BenchmarkServeCompress(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServerCompress)
	a := runtime.GOMAXPROCS(4)
	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func TestDotAsCatchAllWildcard(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))
	mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))

	handler := mux.match("www.miek.nl.", TypeTXT)
	if handler == nil {
		t.Error("wildcard match failed")
	}

	handler = mux.match("www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("example.com match failed")
	}

	handler = mux.match("a.www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("a.www.example.com match failed")
	}

	handler = mux.match("boe.", TypeTXT)
	if handler == nil {
		t.Error("boe. match failed")
	}
}

func TestCaseFolding(t *testing.T) {
	mux := NewServeMux()
	mux.Handle("_udp.example.com.", HandlerFunc(HelloServer))

	handler := mux.match("_dns._udp.example.com.", TypeSRV)
	if handler == nil {
		t.Error("case sensitive characters folded")
	}

	handler = mux.match("_DNS._UDP.EXAMPLE.COM.", TypeSRV)
	if handler == nil {
		t.Error("case insensitive characters not folded")
	}
}

func TestRootServer(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))

	handler := mux.match(".", TypeNS)
	if handler == nil {
		t.Error("root match failed")
	}
}

type maxRec struct {
	max int
	sync.RWMutex
}

var M = new(maxRec)

func HelloServerLargeResponse(resp ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Authoritative = true
	m1 := 0
	M.RLock()
	m1 = M.max
	M.RUnlock()
	for i := 0; i < m1; i++ {
		aRec := &A{
			Hdr: RR_Header{
				Name:   req.Question[0].Name,
				Rrtype: TypeA,
				Class:  ClassINET,
				Ttl:    0,
			},
			A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i+1)).To4(),
		}
		m.Answer = append(m.Answer, aRec)
	}
	resp.WriteMsg(m)
}

func TestServingLargeResponses(t *testing.T) {
	HandleFunc("example.", HelloServerLargeResponse)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	// Create request
	m := new(Msg)
	m.SetQuestion("web.service.example.", TypeANY)

	c := new(Client)
	c.Net = "udp"
	M.Lock()
	M.max = 2
	M.Unlock()
	_, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Logf("failed to exchange: %s", err.Error())
		t.Fail()
	}
	// This must fail
	M.Lock()
	M.max = 20
	M.Unlock()
	_, _, err = c.Exchange(m, addrstr)
	if err == nil {
		t.Logf("failed to fail exchange, this should generate packet error")
		t.Fail()
	}
	// But this must work again
	c.UDPSize = 7000
	_, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Logf("failed to exchange: %s", err.Error())
		t.Fail()
	}
}

// TODO(miek): These tests should actually fail when the server does
// not shut down.
// (asergeyev) I put err check logic which is not yet in use but IMO
// this test will not change as shutdown internals improve.
func TestShutdownTCP(t *testing.T) {
	s, _, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	err = s.Shutdown()
	if err != nil {
		t.Errorf("Could not shutdown test TCP server, %s", err)
	}
}

func TestShutdownUDP(t *testing.T) {
	s, _, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	err = s.Shutdown()
	if err != nil {
		t.Errorf("Could not shutdown test UDP server, %s", err)
	}
}
<commit_msg>Removed Goshed from RunXXXTestServer and...<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dns

import (
	"fmt"
	"net"
	"runtime"
	"sync"
	"testing"
)

func HelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	w.WriteMsg(m)
}

func AnotherHelloServer(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)

	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello example"}}
	w.WriteMsg(m)
}

func RunLocalUDPServer(laddr string) (*Server, string, error) {
	pc, err := net.ListenPacket("udp", laddr)
	if err != nil {
		return nil, "", err
	}
	server := &Server{PacketConn: pc}
	go func() {
		server.ActivateAndServe()
		pc.Close()
	}()
	return server, pc.LocalAddr().String(), nil
}

func RunLocalTCPServer(laddr string) (*Server, string, error) {
	l, err := net.Listen("tcp", laddr)
	if err != nil {
		return nil, "", err
	}
	server := &Server{Listener: l}
	go func() {
		server.ActivateAndServe()
		l.Close()
	}()
	return server, l.Addr().String(), nil
}

func TestServing(t *testing.T) {
	HandleFunc("miek.nl.", HelloServer)
	HandleFunc("example.com.", AnotherHelloServer)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl.", TypeTXT)
	r, _, err := c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange miek.nl", err)
		t.Fatal()
	}
	txt := r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello world" {
		t.Log("Unexpected result for miek.nl", txt, "!= Hello world")
		t.Fail()
	}

	m.SetQuestion("example.com.", TypeTXT)
	r, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange example.com", err)
		t.Fatal()
	}
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}

	// Test Mixes cased as noticed by Ask.
	m.SetQuestion("eXaMplE.cOm.", TypeTXT)
	r, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Log("failed to exchange eXaMplE.cOm", err)
		t.Fail()
	}
	txt = r.Extra[0].(*TXT).Txt[0]
	if txt != "Hello example" {
		t.Log("Unexpected result for example.com", txt, "!= Hello example")
		t.Fail()
	}
}

func BenchmarkServe(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func benchmarkServe6(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServer)
	a := runtime.GOMAXPROCS(4)
	s, addrstr, err := RunLocalUDPServer("[::1]:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func HelloServerCompress(w ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Extra = make([]RR, 1)
	m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello world"}}
	m.Compress = true
	w.WriteMsg(m)
}

func BenchmarkServeCompress(b *testing.B) {
	b.StopTimer()
	HandleFunc("miek.nl.", HelloServerCompress)
	a := runtime.GOMAXPROCS(4)
	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		b.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	c := new(Client)
	m := new(Msg)
	m.SetQuestion("miek.nl", TypeSOA)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		c.Exchange(m, addrstr)
	}
	runtime.GOMAXPROCS(a)
}

func TestDotAsCatchAllWildcard(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))
	mux.Handle("example.com.", HandlerFunc(AnotherHelloServer))

	handler := mux.match("www.miek.nl.", TypeTXT)
	if handler == nil {
		t.Error("wildcard match failed")
	}

	handler = mux.match("www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("example.com match failed")
	}

	handler = mux.match("a.www.example.com.", TypeTXT)
	if handler == nil {
		t.Error("a.www.example.com match failed")
	}

	handler = mux.match("boe.", TypeTXT)
	if handler == nil {
		t.Error("boe. match failed")
	}
}

func TestCaseFolding(t *testing.T) {
	mux := NewServeMux()
	mux.Handle("_udp.example.com.", HandlerFunc(HelloServer))

	handler := mux.match("_dns._udp.example.com.", TypeSRV)
	if handler == nil {
		t.Error("case sensitive characters folded")
	}

	handler = mux.match("_DNS._UDP.EXAMPLE.COM.", TypeSRV)
	if handler == nil {
		t.Error("case insensitive characters not folded")
	}
}

func TestRootServer(t *testing.T) {
	mux := NewServeMux()
	mux.Handle(".", HandlerFunc(HelloServer))

	handler := mux.match(".", TypeNS)
	if handler == nil {
		t.Error("root match failed")
	}
}

type maxRec struct {
	max int
	sync.RWMutex
}

var M = new(maxRec)

func HelloServerLargeResponse(resp ResponseWriter, req *Msg) {
	m := new(Msg)
	m.SetReply(req)
	m.Authoritative = true
	m1 := 0
	M.RLock()
	m1 = M.max
	M.RUnlock()
	for i := 0; i < m1; i++ {
		aRec := &A{
			Hdr: RR_Header{
				Name:   req.Question[0].Name,
				Rrtype: TypeA,
				Class:  ClassINET,
				Ttl:    0,
			},
			A: net.ParseIP(fmt.Sprintf("127.0.0.%d", i+1)).To4(),
		}
		m.Answer = append(m.Answer, aRec)
	}
	resp.WriteMsg(m)
}

func TestServingLargeResponses(t *testing.T) {
	HandleFunc("example.", HelloServerLargeResponse)

	s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	defer s.Shutdown()

	// Create request
	m := new(Msg)
	m.SetQuestion("web.service.example.", TypeANY)

	c := new(Client)
	c.Net = "udp"
	M.Lock()
	M.max = 2
	M.Unlock()
	_, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Logf("failed to exchange: %s", err.Error())
		t.Fail()
	}
	// This must fail
	M.Lock()
	M.max = 20
	M.Unlock()
	_, _, err = c.Exchange(m, addrstr)
	if err == nil {
		t.Logf("failed to fail exchange, this should generate packet error")
		t.Fail()
	}
	// But this must work again
	c.UDPSize = 7000
	_, _, err = c.Exchange(m, addrstr)
	if err != nil {
		t.Logf("failed to exchange: %s", err.Error())
		t.Fail()
	}
}

func TestShutdownTCP(t *testing.T) {
	s, _, err := RunLocalTCPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	// it normally is too early to shutting down because server
	// activates in goroutine.
	runtime.Gosched()
	err = s.Shutdown()
	if err != nil {
		t.Errorf("Could not shutdown test TCP server, %s", err)
	}
}

func TestShutdownUDP(t *testing.T) {
	s, _, err := RunLocalUDPServer("127.0.0.1:0")
	if err != nil {
		t.Fatalf("Unable to run test server: %s", err)
	}
	// it normally is too early to shutting down because server
	// activates in goroutine.
	runtime.Gosched()
	err = s.Shutdown()
	if err != nil {
		t.Errorf("Could not shutdown test UDP server, %s", err)
	}
}
<|endoftext|>


<commit_before>package mgo

import (
	. "launchpad.net/gocheck"
        "net"
	"testing"
)

func TestAll(t *testing.T) {
	TestingT(t)
}

type ServerSuite struct {
}

var _ = Suite(&ServerSuite{})

func (s *ServerSuite) TestCloseDuringConnect(c *C) {
    var server *mongoServer
    closeDial := func (addr net.Addr) (net.Conn, error) {
        if server != nil {
            server.Close()
        }
        return net.DialTCP("tcp", nil, addr.(*net.TCPAddr))
    }
    localhostServer, err := net.Listen("tcp", "localhost:0")
    c.Assert(err, IsNil)
    defer localhostServer.Close()
    go func() {
        // Accept a connection but don't do anything with it
        conn, err := localhostServer.Accept()
        c.Assert(err, IsNil)
        if err != nil {
            return
        }
        conn.Close()
    }()
    tcpaddr := localhostServer.Addr().(*net.TCPAddr)
    server = newServer(tcpaddr.String(), tcpaddr, make(chan bool), closeDial)
    conn, _, err := server.AcquireSocket(0)
    c.Assert(err, Equals, errServerClosed)
    c.Assert(conn, IsNil)
}
<commit_msg>go fmt<commit_after>package mgo

import (
	. "launchpad.net/gocheck"
	"net"
	"testing"
)

func TestAll(t *testing.T) {
	TestingT(t)
}

type ServerSuite struct {
}

var _ = Suite(&ServerSuite{})

func (s *ServerSuite) TestCloseDuringConnect(c *C) {
	var server *mongoServer
	closeDial := func(addr net.Addr) (net.Conn, error) {
		if server != nil {
			server.Close()
		}
		return net.DialTCP("tcp", nil, addr.(*net.TCPAddr))
	}
	localhostServer, err := net.Listen("tcp", "localhost:0")
	c.Assert(err, IsNil)
	defer localhostServer.Close()
	go func() {
		// Accept a connection but don't do anything with it
		conn, err := localhostServer.Accept()
		c.Assert(err, IsNil)
		if err != nil {
			return
		}
		conn.Close()
	}()
	tcpaddr := localhostServer.Addr().(*net.TCPAddr)
	server = newServer(tcpaddr.String(), tcpaddr, make(chan bool), closeDial)
	conn, _, err := server.AcquireSocket(0)
	c.Assert(err, Equals, errServerClosed)
	c.Assert(conn, IsNil)
}
<|endoftext|>


<commit_before>// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo

package sftp

import (
	"fmt"
	"os"
	"os/user"
	"path"
	"syscall"
	"time"
)

func runLsStatt(dirent os.FileInfo, statt *syscall.Stat_t) string {
	// example from openssh sftp server:
	// crw-rw-rw-    1 root     wheel           0 Jul 31 20:52 ttyvd
	// format:
	// {directory / char device / etc}{rwxrwxrwx}  {number of links} owner group size month day [time (this year) | year (otherwise)] name

	typeword := runLsTypeWord(dirent)
	numLinks := statt.Nlink
	username := fmt.Sprintf("%d", statt.Uid)
	if usr, err := user.LookupId(username); err == nil {
		username = usr.Username
	}
	groupname := fmt.Sprintf("%d", statt.Gid)
	if grp, err := user.LookupGroupId(groupname); err == nil {
		groupname = grp.Name
	}
	mtime := dirent.ModTime()
	monthStr := mtime.Month().String()[0:3]
	day := mtime.Day()
	year := mtime.Year()
	now := time.Now()
	isOld := mtime.Before(now.Add(-time.Hour * 24 * 365 / 2))

	yearOrTime := fmt.Sprintf("%02d:%02d", mtime.Hour(), mtime.Minute())
	if isOld {
		yearOrTime = fmt.Sprintf("%d", year)
	}

	return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %2d %5s %s", typeword,
		numLinks, username, groupname, dirent.Size(), monthStr, day,
		yearOrTime, dirent.Name())
}

// ls -l style output for a file, which is in the 'long output' section of a readdir response packet
// this is a very simple (lazy) implementation, just enough to look almost like openssh in a few basic cases
func runLs(dirname string, dirent os.FileInfo) string {
	dsys := dirent.Sys()
	if dsys == nil {
	} else if statt, ok := dsys.(*syscall.Stat_t); !ok {
	} else {
		return runLsStatt(dirent, statt)
	}

	return path.Join(dirname, dirent.Name())
}
<commit_msg>Revert "lookup username/group-name for longname"<commit_after>// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo

package sftp

import (
	"fmt"
	"os"
	"path"
	"syscall"
	"time"
)

func runLsStatt(dirent os.FileInfo, statt *syscall.Stat_t) string {
	// example from openssh sftp server:
	// crw-rw-rw-    1 root     wheel           0 Jul 31 20:52 ttyvd
	// format:
	// {directory / char device / etc}{rwxrwxrwx}  {number of links} owner group size month day [time (this year) | year (otherwise)] name

	typeword := runLsTypeWord(dirent)
	numLinks := statt.Nlink
	uid := statt.Uid
	gid := statt.Gid
	username := fmt.Sprintf("%d", uid)
	groupname := fmt.Sprintf("%d", gid)
	// TODO FIXME: uid -> username, gid -> groupname lookup for ls -l format output

	mtime := dirent.ModTime()
	monthStr := mtime.Month().String()[0:3]
	day := mtime.Day()
	year := mtime.Year()
	now := time.Now()
	isOld := mtime.Before(now.Add(-time.Hour * 24 * 365 / 2))

	yearOrTime := fmt.Sprintf("%02d:%02d", mtime.Hour(), mtime.Minute())
	if isOld {
		yearOrTime = fmt.Sprintf("%d", year)
	}

	return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %2d %5s %s", typeword, numLinks, username, groupname, dirent.Size(), monthStr, day, yearOrTime, dirent.Name())
}

// ls -l style output for a file, which is in the 'long output' section of a readdir response packet
// this is a very simple (lazy) implementation, just enough to look almost like openssh in a few basic cases
func runLs(dirname string, dirent os.FileInfo) string {
	dsys := dirent.Sys()
	if dsys == nil {
	} else if statt, ok := dsys.(*syscall.Stat_t); !ok {
	} else {
		return runLsStatt(dirent, statt)
	}

	return path.Join(dirname, dirent.Name())
}
<|endoftext|>


<commit_before>package config

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

// Option holds information for a configuration option
type Option struct {
	// The name of the option is what's used to reference the option and its value during the program
	Name string

	// What the option is for. This also shows up when invoking `program --help`.
	Description string

	// Holds the actual value contained by this option
	Value interface{}

	// Holds the default value for this option
	DefaultValue interface{}

	// Holds the type of this option
	Type reflect.Type

	// Extra options
	Options OptionMeta
}

// OptionMeta holds information for configuring options on Options
type OptionMeta struct {
	// Exportable is true if the option is exportable to a config.json file
	Exportable bool

	// Required is true if the option is required
	Required bool

	// Filters is a set of boolean functions that are tested with the given value. If Required is true, all of these must succeed.
	Filters []FilterFunction
}

type FilterFunction func(*Option) bool

// DefaultOptionMeta returns the default OptionMeta object
var DefaultOptionMeta = OptionMeta{
	Exportable: false,
	Required:   false,
	Filters:    []FilterFunction{},
}

// String returns the string value of the option. Will panic if the Option's type is not a string.
func (o Option) String() string {
	return reflect.ValueOf(o.Value).String()
}

// Bool returns the bool value of the option. Will panic if the Option's type is not a bool.
func (o Option) Bool() bool {
	return reflect.ValueOf(o.Value).Bool()
}

// Float returns the float64 value of the option. Will panic if the Option's type is not a float64.
func (o Option) Float() float64 {
	return reflect.ValueOf(o.Value).Float()
}

// Int returns the int64 value of the option. Will panic if the Option's type not an int64.
func (o Option) Int() int64 {
	return reflect.ValueOf(o.Value).Int()
}

// DefaultValueString returns the Option's default value as a string
func (o Option) DefaultValueString() string {
	v := o.DefaultValue.(reflect.Value)

	switch o.Type.Kind() {
	case reflect.String:
		return fmt.Sprintf(`%v`, v.String())
	case reflect.Int64:
		return fmt.Sprintf(`%v`, v.Int())
	case reflect.Float64:
		return fmt.Sprintf(`%v`, v.Float())
	case reflect.Bool:
		return fmt.Sprintf(`%v`, v.Bool())
	}

	return ""
}

// SetFromString attempts to set the Option's value as its proper type by parsing the string argument
func (o *Option) SetFromString(val string) (err error) {
	switch o.Type.Kind() {
	case reflect.String:
		o.Value = val

	case reflect.Int64:
		v, err := strconv.ParseInt(val, 0, 64)
		if err == nil {
			o.Value = v
		}

	case reflect.Float64:
		v, err := strconv.ParseFloat(val, 64)
		if err == nil {
			o.Value = v
		}

	case reflect.Bool:
		switch val {
		case "1", "t", "T", "true", "TRUE", "True":
			o.Value = true
		case "0", "f", "F", "false", "FALSE", "False":
			o.Value = false
		default:
			err = fmt.Errorf("Invalid boolean value: %s", val)
		}
	}

	return
}

type sortedOptionSlice []Option

func (s sortedOptionSlice) Less(a, b int) bool { return s[a].Name < s[b].Name }
func (s sortedOptionSlice) Swap(a, b int)      { s[a], s[b] = s[b], s[a] }
func (s sortedOptionSlice) Len() int           { return len(s) }
<commit_msg>Don't bother with custom type<commit_after>package config

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

// Option holds information for a configuration option
type Option struct {
	// The name of the option is what's used to reference the option and its value during the program
	Name string

	// What the option is for. This also shows up when invoking `program --help`.
	Description string

	// Holds the actual value contained by this option
	Value interface{}

	// Holds the default value for this option
	DefaultValue interface{}

	// Holds the type of this option
	Type reflect.Type

	// Extra options
	Options OptionMeta
}

// OptionMeta holds information for configuring options on Options
type OptionMeta struct {
	// Exportable is true if the option is exportable to a config.json file
	Exportable bool

	// Required is true if the option is required
	Required bool

	// Filters is a set of boolean functions that are tested with the given value. If Required is true, all of these must succeed.
	Filters []func(*Option) bool
}

// DefaultOptionMeta returns the default OptionMeta object
var DefaultOptionMeta = OptionMeta{
	Exportable: false,
	Required:   false,
	Filters:    []func(*Option) bool{},
}

// String returns the string value of the option. Will panic if the Option's type is not a string.
func (o Option) String() string {
	return reflect.ValueOf(o.Value).String()
}

// Bool returns the bool value of the option. Will panic if the Option's type is not a bool.
func (o Option) Bool() bool {
	return reflect.ValueOf(o.Value).Bool()
}

// Float returns the float64 value of the option. Will panic if the Option's type is not a float64.
func (o Option) Float() float64 {
	return reflect.ValueOf(o.Value).Float()
}

// Int returns the int64 value of the option. Will panic if the Option's type not an int64.
func (o Option) Int() int64 {
	return reflect.ValueOf(o.Value).Int()
}

// DefaultValueString returns the Option's default value as a string
func (o Option) DefaultValueString() string {
	v := o.DefaultValue.(reflect.Value)

	switch o.Type.Kind() {
	case reflect.String:
		return fmt.Sprintf(`%v`, v.String())
	case reflect.Int64:
		return fmt.Sprintf(`%v`, v.Int())
	case reflect.Float64:
		return fmt.Sprintf(`%v`, v.Float())
	case reflect.Bool:
		return fmt.Sprintf(`%v`, v.Bool())
	}

	return ""
}

// SetFromString attempts to set the Option's value as its proper type by parsing the string argument
func (o *Option) SetFromString(val string) (err error) {
	switch o.Type.Kind() {
	case reflect.String:
		o.Value = val

	case reflect.Int64:
		v, err := strconv.ParseInt(val, 0, 64)
		if err == nil {
			o.Value = v
		}

	case reflect.Float64:
		v, err := strconv.ParseFloat(val, 64)
		if err == nil {
			o.Value = v
		}

	case reflect.Bool:
		switch val {
		case "1", "t", "T", "true", "TRUE", "True":
			o.Value = true
		case "0", "f", "F", "false", "FALSE", "False":
			o.Value = false
		default:
			err = fmt.Errorf("Invalid boolean value: %s", val)
		}
	}

	return
}

type sortedOptionSlice []Option

func (s sortedOptionSlice) Less(a, b int) bool { return s[a].Name < s[b].Name }
func (s sortedOptionSlice) Swap(a, b int)      { s[a], s[b] = s[b], s[a] }
func (s sortedOptionSlice) Len() int           { return len(s) }
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	u "github.com/araddon/gou"
)

var (
	_ = u.DEBUG
)

// Search is the entry point to the SearchDsl, it is a chainable set of utilities
// to create searches.
//
// params
//    @index = elasticsearch index to search
//
//    out, err := Search("github").Type("Issues").Pretty().Query(
//    Query().Range(
//         Range().Field("created_at").From("2012-12-10T15:00:00-08:00").To("2012-12-10T15:10:00-08:00"),
//       ).Search("add"),
//     ).Result()
func Search(index string) *SearchDsl {
	return &SearchDsl{Index: index, args: map[string]interface{}{}}
}

type SearchDsl struct {
	args          map[string]interface{}
	types         []string
	FromVal       int                      `json:"from,omitempty"`
	SizeVal       int                      `json:"size,omitempty"`
	Index         string                   `json:"-"`
	FacetVal      *FacetDsl                `json:"facets,omitempty"`
	QueryVal      *QueryDsl                `json:"query,omitempty"`
	SortBody      []*SortDsl               `json:"sort,omitempty"`
	FilterVal     *FilterWrap              `json:"filter,omitempty"`
	AggregatesVal map[string]*AggregateDsl `json:"aggregations,omitempty"`
	SourceFilter  *SourceFilter            `json:"_source,omitempty"`
}

type SourceFilter struct {
	Include []string `json:"include,omitempty"`
	Exclude []string `json:"exclude,omitempty"`
}

func (s *SearchDsl) Bytes(conn *Conn) ([]byte, error) {
	return conn.DoCommand("POST", s.url(), s.args, s)
}

func (s *SearchDsl) Result(conn *Conn) (*SearchResult, error) {
	var retval SearchResult
	body, err := s.Bytes(conn)
	retval.RawJSON = body
	if err != nil {
		u.Errorf("%v", err)
		return nil, err
	}
	jsonErr := json.Unmarshal(body, &retval)
	if jsonErr != nil {
		u.Errorf("%v \n\t%s", jsonErr, string(body))
	}
	return &retval, jsonErr
}

func (s *SearchDsl) url() string {
	url := fmt.Sprintf("/%s%s/_search", s.Index, s.getType())
	return url
}

func (s *SearchDsl) Pretty() *SearchDsl {
	s.args["pretty"] = "1"
	return s
}

// Type is the elasticsearch *Type* within a specific index
func (s *SearchDsl) Type(indexType string) *SearchDsl {
	if len(s.types) == 0 {
		s.types = make([]string, 0)
	}
	s.types = append(s.types, indexType)
	return s
}

func (s *SearchDsl) getType() string {
	if len(s.types) > 0 {
		return "/" + strings.Join(s.types, ",")
	}
	return ""
}

func (s *SearchDsl) From(from string) *SearchDsl {
	s.args["from"] = from
	return s
}

// Search is a simple interface to search, doesn't have the power of query
// but uses a simple query_string search
func (s *SearchDsl) Search(srch string) *SearchDsl {
	s.QueryVal = Query().Search(srch)
	return s
}

func (s *SearchDsl) Size(size string) *SearchDsl {
	s.args["size"] = size
	return s
}

func (s *SearchDsl) Fields(fields ...string) *SearchDsl {
	s.args["fields"] = strings.Join(fields, ",")
	return s
}

func (s *SearchDsl) Source(returnSource bool) *SearchDsl {
	s.args["_source"] = strconv.FormatBool(returnSource)
	return s
}

// Facet passes a Query expression to this search
//
//		qry := Search("github").Size("0").Facet(
//					Facet().Regex("repository.name", "no.*").Size("8"),
//				)
//
//		qry := Search("github").Pretty().Facet(
//					Facet().Fields("type").Size("25"),
//				)
func (s *SearchDsl) Facet(f *FacetDsl) *SearchDsl {
	s.FacetVal = f
	return s
}

func (s *SearchDsl) Aggregates(aggs ...*AggregateDsl) *SearchDsl {
	if len(aggs) < 1 {
		return s
	}
	if len(s.AggregatesVal) == 0 {
		s.AggregatesVal = make(map[string]*AggregateDsl)
	}

	for _, agg := range aggs {
		s.AggregatesVal[agg.Name] = agg
	}
	return s
}

func (s *SearchDsl) Query(q *QueryDsl) *SearchDsl {
	s.QueryVal = q
	return s
}

// Filter adds a Filter Clause with optional Boolean Clause.  This accepts n number of
// filter clauses.  If more than one, and missing Boolean Clause it assumes "and"
//
//     qry := Search("github").Filter(
//         Filter().Exists("repository.name"),
//     )
//
//     qry := Search("github").Filter(
//         "or",
//         Filter().Exists("repository.name"),
//         Filter().Terms("actor_attributes.location", "portland"),
//     )
//
//     qry := Search("github").Filter(
//         Filter().Exists("repository.name"),
//         Filter().Terms("repository.has_wiki", true)
//     )
func (s *SearchDsl) Filter(fl ...interface{}) *SearchDsl {
	if s.FilterVal == nil {
		s.FilterVal = NewFilterWrap()
	}

	s.FilterVal.addFilters(fl)
	return s
}

func (s *SearchDsl) Sort(sort ...*SortDsl) *SearchDsl {
	if s.SortBody == nil {
		s.SortBody = make([]*SortDsl, 0)
	}
	s.SortBody = append(s.SortBody, sort...)
	return s
}

func (s *SearchDsl) Scroll(duration string) *SearchDsl {
	s.args["scroll"] = duration
	return s
}

func (s *SearchDsl) SearchType(searchType string) *SearchDsl {
	s.args["search_type"] = searchType
	return s
}
<commit_msg>Support for custom query parameters in search DSL<commit_after>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	u "github.com/araddon/gou"
)

var (
	_ = u.DEBUG
)

// Search is the entry point to the SearchDsl, it is a chainable set of utilities
// to create searches.
//
// params
//    @index = elasticsearch index to search
//
//    out, err := Search("github").Type("Issues").Pretty().Query(
//    Query().Range(
//         Range().Field("created_at").From("2012-12-10T15:00:00-08:00").To("2012-12-10T15:10:00-08:00"),
//       ).Search("add"),
//     ).Result()
func Search(index string) *SearchDsl {
	return &SearchDsl{Index: index, args: map[string]interface{}{}}
}

type SearchDsl struct {
	args          map[string]interface{}
	types         []string
	FromVal       int                      `json:"from,omitempty"`
	SizeVal       int                      `json:"size,omitempty"`
	Index         string                   `json:"-"`
	FacetVal      *FacetDsl                `json:"facets,omitempty"`
	QueryVal      *QueryDsl                `json:"query,omitempty"`
	SortBody      []*SortDsl               `json:"sort,omitempty"`
	FilterVal     *FilterWrap              `json:"filter,omitempty"`
	AggregatesVal map[string]*AggregateDsl `json:"aggregations,omitempty"`
	SourceFilter  *SourceFilter            `json:"_source,omitempty"`
}

type SourceFilter struct {
	Include []string `json:"include,omitempty"`
	Exclude []string `json:"exclude,omitempty"`
}

func (s *SearchDsl) Bytes(conn *Conn) ([]byte, error) {
	return conn.DoCommand("POST", s.url(), s.args, s)
}

func (s *SearchDsl) Result(conn *Conn) (*SearchResult, error) {
	var retval SearchResult
	body, err := s.Bytes(conn)
	retval.RawJSON = body
	if err != nil {
		u.Errorf("%v", err)
		return nil, err
	}
	jsonErr := json.Unmarshal(body, &retval)
	if jsonErr != nil {
		u.Errorf("%v \n\t%s", jsonErr, string(body))
	}
	return &retval, jsonErr
}

func (s *SearchDsl) url() string {
	url := fmt.Sprintf("/%s%s/_search", s.Index, s.getType())
	return url
}

func (s *SearchDsl) Pretty() *SearchDsl {
	s.args["pretty"] = "1"
	return s
}

// Type is the elasticsearch *Type* within a specific index
func (s *SearchDsl) Type(indexType string) *SearchDsl {
	if len(s.types) == 0 {
		s.types = make([]string, 0)
	}
	s.types = append(s.types, indexType)
	return s
}

func (s *SearchDsl) getType() string {
	if len(s.types) > 0 {
		return "/" + strings.Join(s.types, ",")
	}
	return ""
}

func (s *SearchDsl) From(from string) *SearchDsl {
	s.args["from"] = from
	return s
}

// Search is a simple interface to search, doesn't have the power of query
// but uses a simple query_string search
func (s *SearchDsl) Search(srch string) *SearchDsl {
	s.QueryVal = Query().Search(srch)
	return s
}

func (s *SearchDsl) Size(size string) *SearchDsl {
	s.args["size"] = size
	return s
}

func (s *SearchDsl) Fields(fields ...string) *SearchDsl {
	s.args["fields"] = strings.Join(fields, ",")
	return s
}

func (s *SearchDsl) Source(returnSource bool) *SearchDsl {
	s.args["_source"] = strconv.FormatBool(returnSource)
	return s
}

// Facet passes a Query expression to this search
//
//		qry := Search("github").Size("0").Facet(
//					Facet().Regex("repository.name", "no.*").Size("8"),
//				)
//
//		qry := Search("github").Pretty().Facet(
//					Facet().Fields("type").Size("25"),
//				)
func (s *SearchDsl) Facet(f *FacetDsl) *SearchDsl {
	s.FacetVal = f
	return s
}

func (s *SearchDsl) Aggregates(aggs ...*AggregateDsl) *SearchDsl {
	if len(aggs) < 1 {
		return s
	}
	if len(s.AggregatesVal) == 0 {
		s.AggregatesVal = make(map[string]*AggregateDsl)
	}

	for _, agg := range aggs {
		s.AggregatesVal[agg.Name] = agg
	}
	return s
}

func (s *SearchDsl) Query(q *QueryDsl) *SearchDsl {
	s.QueryVal = q
	return s
}

// Filter adds a Filter Clause with optional Boolean Clause.  This accepts n number of
// filter clauses.  If more than one, and missing Boolean Clause it assumes "and"
//
//     qry := Search("github").Filter(
//         Filter().Exists("repository.name"),
//     )
//
//     qry := Search("github").Filter(
//         "or",
//         Filter().Exists("repository.name"),
//         Filter().Terms("actor_attributes.location", "portland"),
//     )
//
//     qry := Search("github").Filter(
//         Filter().Exists("repository.name"),
//         Filter().Terms("repository.has_wiki", true)
//     )
func (s *SearchDsl) Filter(fl ...interface{}) *SearchDsl {
	if s.FilterVal == nil {
		s.FilterVal = NewFilterWrap()
	}

	s.FilterVal.addFilters(fl)
	return s
}

func (s *SearchDsl) Sort(sort ...*SortDsl) *SearchDsl {
	if s.SortBody == nil {
		s.SortBody = make([]*SortDsl, 0)
	}
	s.SortBody = append(s.SortBody, sort...)
	return s
}

func (s *SearchDsl) Scroll(duration string) *SearchDsl {
	s.args["scroll"] = duration
	return s
}

func (s *SearchDsl) SearchType(searchType string) *SearchDsl {
	s.args["search_type"] = searchType
	return s
}

// AddQueryParam adds a custom query parameter to the search request.
func (s *SearchDsl) AddQueryParam(name string, value interface{}) *SearchDsl {
	// s.args is transformed into the query string for the request
	// URL.
	s.args[name] = value

	return s
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

func resourceAwsCloudWatchEventTarget() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchEventTargetCreate,
		Read:   resourceAwsCloudWatchEventTargetRead,
		Update: resourceAwsCloudWatchEventTargetUpdate,
		Delete: resourceAwsCloudWatchEventTargetDelete,

		Schema: map[string]*schema.Schema{
			"rule": &schema.Schema{
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventRuleName,
			},

			"target_id": &schema.Schema{
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventTargetId,
			},

			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"input": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"input_path"},
				// We could be normalizing the JSON here,
				// but for built-in targets input may not be JSON
			},

			"input_path": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"input"},
			},
		},
	}
}

func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	rule := d.Get("rule").(string)

	var targetId string
	if v, ok := d.GetOk("target_id"); ok {
		targetId = v.(string)
	} else {
		targetId = resource.UniqueId()
		d.Set("target_id", targetId)
	}

	input := buildPutTargetInputStruct(d)
	log.Printf("[DEBUG] Creating CloudWatch Event Target: %s", input)
	out, err := conn.PutTargets(input)
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Target failed: %s", err)
	}

	if len(out.FailedEntries) > 0 {
		return fmt.Errorf("Creating CloudWatch Event Target failed: %s",
			out.FailedEntries)
	}

	id := rule + "-" + targetId
	d.SetId(id)

	log.Printf("[INFO] CloudWatch Event Target %q created", d.Id())

	return resourceAwsCloudWatchEventTargetRead(d, meta)
}

func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	t, err := findEventTargetById(
		d.Get("target_id").(string),
		d.Get("rule").(string),
		nil, conn)
	if err != nil {
		if regexp.MustCompile(" not found$").MatchString(err.Error()) {
			log.Printf("[WARN] Removing CloudWatch Event Target %q because it's gone.", d.Id())
			d.SetId("")
			return nil
		}
		if awsErr, ok := err.(awserr.Error); ok {
			// This should never happen, but it's useful
			// for recovering from https://github.com/hashicorp/terraform/issues/5389
			if awsErr.Code() == "ValidationException" {
				log.Printf("[WARN] Removing CloudWatch Event Target %q because it never existed.", d.Id())
				d.SetId("")
				return nil
			}
		}
		return err
	}
	log.Printf("[DEBUG] Found Event Target: %s", t)

	d.Set("arn", t.Arn)
	d.Set("target_id", t.Id)
	d.Set("input", t.Input)
	d.Set("input_path", t.InputPath)

	return nil
}

func findEventTargetById(id, rule string, nextToken *string, conn *events.CloudWatchEvents) (
	*events.Target, error) {
	input := events.ListTargetsByRuleInput{
		Rule:      aws.String(rule),
		NextToken: nextToken,
		Limit:     aws.Int64(100), // Set limit to allowed maximum to prevent API throttling
	}
	log.Printf("[DEBUG] Reading CloudWatch Event Target: %s", input)
	out, err := conn.ListTargetsByRule(&input)
	if err != nil {
		return nil, err
	}

	for _, t := range out.Targets {
		if *t.Id == id {
			return t, nil
		}
	}

	if out.NextToken != nil {
		return findEventTargetById(id, rule, nextToken, conn)
	}

	return nil, fmt.Errorf("CloudWatch Event Target %q (%q) not found", id, rule)
}

func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	input := buildPutTargetInputStruct(d)
	log.Printf("[DEBUG] Updating CloudWatch Event Target: %s", input)
	_, err := conn.PutTargets(input)
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Target failed: %s", err)
	}

	return resourceAwsCloudWatchEventTargetRead(d, meta)
}

func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	input := events.RemoveTargetsInput{
		Ids:  []*string{aws.String(d.Get("target_id").(string))},
		Rule: aws.String(d.Get("rule").(string)),
	}
	log.Printf("[INFO] Deleting CloudWatch Event Target: %s", input)
	_, err := conn.RemoveTargets(&input)
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Event Target: %s", err)
	}
	log.Println("[INFO] CloudWatch Event Target deleted")

	d.SetId("")

	return nil
}

func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput {
	e := &events.Target{
		Arn: aws.String(d.Get("arn").(string)),
		Id:  aws.String(d.Get("target_id").(string)),
	}

	if v, ok := d.GetOk("input"); ok {
		e.Input = aws.String(v.(string))
	}
	if v, ok := d.GetOk("input_path"); ok {
		e.InputPath = aws.String(v.(string))
	}

	input := events.PutTargetsInput{
		Rule:    aws.String(d.Get("rule").(string)),
		Targets: []*events.Target{e},
	}

	return &input
}
<commit_msg>provider/aws: Refresh `aws_cloudwatch_event_target` from state on `ResourceNotFoundException` (#8442)<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
)

func resourceAwsCloudWatchEventTarget() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchEventTargetCreate,
		Read:   resourceAwsCloudWatchEventTargetRead,
		Update: resourceAwsCloudWatchEventTargetUpdate,
		Delete: resourceAwsCloudWatchEventTargetDelete,

		Schema: map[string]*schema.Schema{
			"rule": &schema.Schema{
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventRuleName,
			},

			"target_id": &schema.Schema{
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventTargetId,
			},

			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"input": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"input_path"},
				// We could be normalizing the JSON here,
				// but for built-in targets input may not be JSON
			},

			"input_path": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ConflictsWith: []string{"input"},
			},
		},
	}
}

func resourceAwsCloudWatchEventTargetCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	rule := d.Get("rule").(string)

	var targetId string
	if v, ok := d.GetOk("target_id"); ok {
		targetId = v.(string)
	} else {
		targetId = resource.UniqueId()
		d.Set("target_id", targetId)
	}

	input := buildPutTargetInputStruct(d)
	log.Printf("[DEBUG] Creating CloudWatch Event Target: %s", input)
	out, err := conn.PutTargets(input)
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Target failed: %s", err)
	}

	if len(out.FailedEntries) > 0 {
		return fmt.Errorf("Creating CloudWatch Event Target failed: %s",
			out.FailedEntries)
	}

	id := rule + "-" + targetId
	d.SetId(id)

	log.Printf("[INFO] CloudWatch Event Target %q created", d.Id())

	return resourceAwsCloudWatchEventTargetRead(d, meta)
}

func resourceAwsCloudWatchEventTargetRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	t, err := findEventTargetById(
		d.Get("target_id").(string),
		d.Get("rule").(string),
		nil, conn)
	if err != nil {
		if regexp.MustCompile(" not found$").MatchString(err.Error()) {
			log.Printf("[WARN] Removing CloudWatch Event Target %q because it's gone.", d.Id())
			d.SetId("")
			return nil
		}
		if awsErr, ok := err.(awserr.Error); ok {
			// This should never happen, but it's useful
			// for recovering from https://github.com/hashicorp/terraform/issues/5389
			if awsErr.Code() == "ValidationException" {
				log.Printf("[WARN] Removing CloudWatch Event Target %q because it never existed.", d.Id())
				d.SetId("")
				return nil
			}

			if awsErr.Code() == "ResourceNotFoundException" {
				log.Printf("[WARN] CloudWatch Event Target (%q) not found. Removing it from state.", d.Id())
				d.SetId("")
				return nil
			}

		}
		return err
	}
	log.Printf("[DEBUG] Found Event Target: %s", t)

	d.Set("arn", t.Arn)
	d.Set("target_id", t.Id)
	d.Set("input", t.Input)
	d.Set("input_path", t.InputPath)

	return nil
}

func findEventTargetById(id, rule string, nextToken *string, conn *events.CloudWatchEvents) (
	*events.Target, error) {
	input := events.ListTargetsByRuleInput{
		Rule:      aws.String(rule),
		NextToken: nextToken,
		Limit:     aws.Int64(100), // Set limit to allowed maximum to prevent API throttling
	}
	log.Printf("[DEBUG] Reading CloudWatch Event Target: %s", input)
	out, err := conn.ListTargetsByRule(&input)
	if err != nil {
		return nil, err
	}

	for _, t := range out.Targets {
		if *t.Id == id {
			return t, nil
		}
	}

	if out.NextToken != nil {
		return findEventTargetById(id, rule, nextToken, conn)
	}

	return nil, fmt.Errorf("CloudWatch Event Target %q (%q) not found", id, rule)
}

func resourceAwsCloudWatchEventTargetUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	input := buildPutTargetInputStruct(d)
	log.Printf("[DEBUG] Updating CloudWatch Event Target: %s", input)
	_, err := conn.PutTargets(input)
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Target failed: %s", err)
	}

	return resourceAwsCloudWatchEventTargetRead(d, meta)
}

func resourceAwsCloudWatchEventTargetDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).cloudwatcheventsconn

	input := events.RemoveTargetsInput{
		Ids:  []*string{aws.String(d.Get("target_id").(string))},
		Rule: aws.String(d.Get("rule").(string)),
	}
	log.Printf("[INFO] Deleting CloudWatch Event Target: %s", input)
	_, err := conn.RemoveTargets(&input)
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Event Target: %s", err)
	}
	log.Println("[INFO] CloudWatch Event Target deleted")

	d.SetId("")

	return nil
}

func buildPutTargetInputStruct(d *schema.ResourceData) *events.PutTargetsInput {
	e := &events.Target{
		Arn: aws.String(d.Get("arn").(string)),
		Id:  aws.String(d.Get("target_id").(string)),
	}

	if v, ok := d.GetOk("input"); ok {
		e.Input = aws.String(v.(string))
	}
	if v, ok := d.GetOk("input_path"); ok {
		e.InputPath = aws.String(v.(string))
	}

	input := events.PutTargetsInput{
		Rule:    aws.String(d.Get("rule").(string)),
		Targets: []*events.Target{e},
	}

	return &input
}
<|endoftext|>


<commit_before>package husky

import (
	"encoding/json"
	"net/http"
)

type Output struct {
	resp       http.ResponseWriter
	statusCode int
	headers    map[string]string
	headerSent bool
}

func NewOutput(res http.ResponseWriter) *Output {
	return &Output{
		resp:       res,
		statusCode: 200,
		headerSent: false,
		headers:    map[string]string{},
	}
}

func (o *Output) IsHeadersSent() bool {
	return o.headerSent
}

func (o *Output) SetStatus(code int) *Output {
	o.statusCode = code

	return o
}

func (o *Output) SetHeader(key, value string) *Output {
	o.headers[key] = value

	return o
	o.resp.Header().Set(key, value)
}

func (o *Output) SendHeader() *Output {
	if o.IsHeadersSent() == false {
		header := o.resp.Header()

		for key, value := range o.headers {
			header.Set(key, value)
		}

		header.WriteHeader(o.statusCode)
	}

	return o
}

func (o *Output) Send(out interface{}) {
	o.SendHeader()

	if buf, ok := toBuffer(out); ok {
		o.resp.Write(buf)
		return
	}

	panic("Invalid output data")
}

func (o *Output) SendJSON(out interface{}) {
	if buf, ok := toJSONString(out); ok {
		o.SetHeader("Content-Type", "application/json")
		o.resp.Write(buf)
		return
	}

	panic("Invalid output data for JSON")
}

func toBuffer(data interface{}) ([]byte, bool) {
	if str, ok := data.(string); ok {
		return []byte(str), true
	} else if b, ok := data.([]byte); ok {
		return b, true
	} else {
		return nil, false
	}
}

func toJSONString(data interface{}) ([]byte, bool) {
	if str, ok := data.(string); ok {
		return []byte(str), true
	} else if json, err := json.Marshal(data); err != nil {
		return json, true
	} else {
		return nil, false
	}
}
<commit_msg>Fixed status header send bug<commit_after>package husky

import (
	"encoding/json"
	"net/http"
)

type Output struct {
	resp       http.ResponseWriter
	statusCode int
	headers    map[string]string
	headerSent bool
}

func NewOutput(res http.ResponseWriter) *Output {
	return &Output{
		resp:       res,
		statusCode: 200,
		headerSent: false,
		headers:    map[string]string{},
	}
}

func (o *Output) IsHeadersSent() bool {
	return o.headerSent
}

func (o *Output) SetStatus(code int) *Output {
	o.statusCode = code

	return o
}

func (o *Output) SetHeader(key, value string) *Output {
	o.headers[key] = value

	return o
	o.resp.Header().Set(key, value)
}

func (o *Output) SendHeader() *Output {
	if o.IsHeadersSent() == false {
		header := o.resp.Header()

		for key, value := range o.headers {
			header.Set(key, value)
		}

		o.resp.WriteHeader(o.statusCode)
	}

	return o
}

func (o *Output) Send(out interface{}) {
	o.SendHeader()

	if buf, ok := toBuffer(out); ok {
		o.resp.Write(buf)
		return
	}

	panic("Invalid output data")
}

func (o *Output) SendJSON(out interface{}) {
	if buf, ok := toJSONString(out); ok {
		o.SetHeader("Content-Type", "application/json")
		o.resp.Write(buf)
		return
	}

	panic("Invalid output data for JSON")
}

func toBuffer(data interface{}) ([]byte, bool) {
	if str, ok := data.(string); ok {
		return []byte(str), true
	} else if b, ok := data.([]byte); ok {
		return b, true
	} else {
		return nil, false
	}
}

func toJSONString(data interface{}) ([]byte, bool) {
	if str, ok := data.(string); ok {
		return []byte(str), true
	} else if json, err := json.Marshal(data); err != nil {
		return json, true
	} else {
		return nil, false
	}
}
<|endoftext|>