<commit_before>package channeldb

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

	"github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/lnwire"
)

var (
	// paymentBucket is the name of the bucket within the database that
	// stores all data related to payments.
	//
	// Within the payments bucket, each invoice is keyed by its invoice ID
	// which is a monotonically increasing uint64.  BoltDB's sequence
	// feature is used for generating monotonically increasing id.
	paymentBucket = []byte("payments")

	// paymentStatusBucket is the name of the bucket within the database that
	// stores the status of a payment indexed by the payment's preimage.
	paymentStatusBucket = []byte("payment-status")
)

// PaymentStatus represent current status of payment
type PaymentStatus byte

const (
	// StatusGrounded is status where payment is initiated and received
	// an intermittent failure
	StatusGrounded PaymentStatus = 0

	// StatusInFlight is status where payment is initiated, but a response
	// has not been received
	StatusInFlight PaymentStatus = 1

	// StatusCompleted is status where payment is initiated and complete
	// a payment successfully
	StatusCompleted PaymentStatus = 2
)

// Bytes returns status as slice of bytes
func (ps PaymentStatus) Bytes() []byte {
	return []byte{byte(ps)}
}

// FromBytes sets status from slice of bytes
func (ps *PaymentStatus) FromBytes(status []byte) error {
	if len(status) != 1 {
		return errors.New("payment status is empty")
	}

	switch PaymentStatus(status[0]) {
	case StatusGrounded, StatusInFlight, StatusCompleted:
		*ps = PaymentStatus(status[0])
	default:
		return errors.New("unknown payment status")
	}

	return nil
}

// String returns readable representation of payment status
func (ps PaymentStatus) String() string {
	switch ps {
	case StatusGrounded:
		return "Grounded"
	case StatusInFlight:
		return "In Flight"
	case StatusCompleted:
		return "Completed"
	default:
		return "Unknown"
	}
}

// OutgoingPayment represents a successful payment between the daemon and a
// remote node. Details such as the total fee paid, and the time of the payment
// are stored.
type OutgoingPayment struct {
	Invoice

	// Fee is the total fee paid for the payment in milli-satoshis.
	Fee lnwire.MilliSatoshi

	// TotalTimeLock is the total cumulative time-lock in the HTLC extended
	// from the second-to-last hop to the destination.
	TimeLockLength uint32

	// Path encodes the path the payment took through the network. The path
	// excludes the outgoing node and consists of the hex-encoded
	// compressed public key of each of the nodes involved in the payment.
	Path [][33]byte

	// PaymentPreimage is the preImage of a successful payment. This is used
	// to calculate the PaymentHash as well as serve as a proof of payment.
	PaymentPreimage [32]byte
}

// AddPayment saves a successful payment to the database. It is assumed that
// all payment are sent using unique payment hashes.
func (db *DB) AddPayment(payment *OutgoingPayment) error {
	// Validate the field of the inner voice within the outgoing payment,
	// these must also adhere to the same constraints as regular invoices.
	if err := validateInvoice(&payment.Invoice); err != nil {
		return err
	}

	// We first serialize the payment before starting the database
	// transaction so we can avoid creating a DB payment in the case of a
	// serialization error.
	var b bytes.Buffer
	if err := serializeOutgoingPayment(&b, payment); err != nil {
		return err
	}
	paymentBytes := b.Bytes()

	return db.Batch(func(tx *bolt.Tx) error {
		payments, err := tx.CreateBucketIfNotExists(paymentBucket)
		if err != nil {
			return err
		}

		// Obtain the new unique sequence number for this payment.
		paymentID, err := payments.NextSequence()
		if err != nil {
			return err
		}

		// We use BigEndian for keys as it orders keys in
		// ascending order. This allows bucket scans to order payments
		// in the order in which they were created.
		paymentIDBytes := make([]byte, 8)
		binary.BigEndian.PutUint64(paymentIDBytes, paymentID)

		return payments.Put(paymentIDBytes, paymentBytes)
	})
}

// FetchAllPayments returns all outgoing payments in DB.
func (db *DB) FetchAllPayments() ([]*OutgoingPayment, error) {
	var payments []*OutgoingPayment

	err := db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(paymentBucket)
		if bucket == nil {
			return ErrNoPaymentsCreated
		}

		return bucket.ForEach(func(k, v []byte) error {
			// If the value is nil, then we ignore it as it may be
			// a sub-bucket.
			if v == nil {
				return nil
			}

			r := bytes.NewReader(v)
			payment, err := deserializeOutgoingPayment(r)
			if err != nil {
				return err
			}

			payments = append(payments, payment)
			return nil
		})
	})
	if err != nil {
		return nil, err
	}

	return payments, nil
}

// DeleteAllPayments deletes all payments from DB.
func (db *DB) DeleteAllPayments() error {
	return db.Update(func(tx *bolt.Tx) error {
		err := tx.DeleteBucket(paymentBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		_, err = tx.CreateBucket(paymentBucket)
		return err
	})
}

// UpdatePaymentStatus sets status for outgoing/finished payment to store status in
// local database.
func (db *DB) UpdatePaymentStatus(paymentHash [32]byte, status PaymentStatus) error {
	return db.Batch(func(tx *bolt.Tx) error {
		paymentStatuses, err := tx.CreateBucketIfNotExists(paymentStatusBucket)
		if err != nil {
			return err
		}

		return paymentStatuses.Put(paymentHash[:], status.Bytes())
	})
}

// FetchPaymentStatus returns payment status for outgoing payment
// if status of the payment isn't found it set to default status "StatusGrounded".
func (db *DB) FetchPaymentStatus(paymentHash [32]byte) (PaymentStatus, error) {
	// default status for all payments that wasn't recorded in database
	paymentStatus := StatusGrounded

	err := db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(paymentStatusBucket)
		if bucket == nil {
			return nil
		}

		paymentStatusBytes := bucket.Get(paymentHash[:])
		if paymentStatusBytes == nil {
			return nil
		}

		return paymentStatus.FromBytes(paymentStatusBytes)
	})
	if err != nil {
		return StatusGrounded, err
	}

	return paymentStatus, nil
}

func serializeOutgoingPayment(w io.Writer, p *OutgoingPayment) error {
	var scratch [8]byte

	if err := serializeInvoice(w, &p.Invoice); err != nil {
		return err
	}

	byteOrder.PutUint64(scratch[:], uint64(p.Fee))
	if _, err := w.Write(scratch[:]); err != nil {
		return err
	}

	// First write out the length of the bytes to prefix the value.
	pathLen := uint32(len(p.Path))
	byteOrder.PutUint32(scratch[:4], pathLen)
	if _, err := w.Write(scratch[:4]); err != nil {
		return err
	}

	// Then with the path written, we write out the series of public keys
	// involved in the path.
	for _, hop := range p.Path {
		if _, err := w.Write(hop[:]); err != nil {
			return err
		}
	}

	byteOrder.PutUint32(scratch[:4], p.TimeLockLength)
	if _, err := w.Write(scratch[:4]); err != nil {
		return err
	}

	if _, err := w.Write(p.PaymentPreimage[:]); err != nil {
		return err
	}

	return nil
}

func deserializeOutgoingPayment(r io.Reader) (*OutgoingPayment, error) {
	var scratch [8]byte

	p := &OutgoingPayment{}

	inv, err := deserializeInvoice(r)
	if err != nil {
		return nil, err
	}
	p.Invoice = inv

	if _, err := r.Read(scratch[:]); err != nil {
		return nil, err
	}
	p.Fee = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))

	if _, err = r.Read(scratch[:4]); err != nil {
		return nil, err
	}
	pathLen := byteOrder.Uint32(scratch[:4])

	path := make([][33]byte, pathLen)
	for i := uint32(0); i < pathLen; i++ {
		if _, err := r.Read(path[i][:]); err != nil {
			return nil, err
		}
	}
	p.Path = path

	if _, err = r.Read(scratch[:4]); err != nil {
		return nil, err
	}
	p.TimeLockLength = byteOrder.Uint32(scratch[:4])

	if _, err := r.Read(p.PaymentPreimage[:]); err != nil {
		return nil, err
	}

	return p, nil
}
<commit_msg>channeldb/payments: touch up docs<commit_after>package channeldb

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

	"github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/lnwire"
)

var (
	// paymentBucket is the name of the bucket within the database that
	// stores all data related to payments.
	//
	// Within the payments bucket, each invoice is keyed by its invoice ID
	// which is a monotonically increasing uint64.  BoltDB's sequence
	// feature is used for generating monotonically increasing id.
	paymentBucket = []byte("payments")

	// paymentStatusBucket is the name of the bucket within the database that
	// stores the status of a payment indexed by the payment's preimage.
	paymentStatusBucket = []byte("payment-status")
)

// PaymentStatus represent current status of payment
type PaymentStatus byte

const (
	// StatusGrounded is the status where a payment has never been
	// initiated, or has been initiated and received an intermittent
	// failure.
	StatusGrounded PaymentStatus = 0

	// StatusInFlight is the status where a payment has been initiated, but
	// a response has not been received.
	StatusInFlight PaymentStatus = 1

	// StatusCompleted is the status where a payment has been initiated and
	// the payment was completed successfully.
	StatusCompleted PaymentStatus = 2
)

// Bytes returns status as slice of bytes.
func (ps PaymentStatus) Bytes() []byte {
	return []byte{byte(ps)}
}

// FromBytes sets status from slice of bytes.
func (ps *PaymentStatus) FromBytes(status []byte) error {
	if len(status) != 1 {
		return errors.New("payment status is empty")
	}

	switch PaymentStatus(status[0]) {
	case StatusGrounded, StatusInFlight, StatusCompleted:
		*ps = PaymentStatus(status[0])
	default:
		return errors.New("unknown payment status")
	}

	return nil
}

// String returns readable representation of payment status.
func (ps PaymentStatus) String() string {
	switch ps {
	case StatusGrounded:
		return "Grounded"
	case StatusInFlight:
		return "In Flight"
	case StatusCompleted:
		return "Completed"
	default:
		return "Unknown"
	}
}

// OutgoingPayment represents a successful payment between the daemon and a
// remote node. Details such as the total fee paid, and the time of the payment
// are stored.
type OutgoingPayment struct {
	Invoice

	// Fee is the total fee paid for the payment in milli-satoshis.
	Fee lnwire.MilliSatoshi

	// TotalTimeLock is the total cumulative time-lock in the HTLC extended
	// from the second-to-last hop to the destination.
	TimeLockLength uint32

	// Path encodes the path the payment took through the network. The path
	// excludes the outgoing node and consists of the hex-encoded
	// compressed public key of each of the nodes involved in the payment.
	Path [][33]byte

	// PaymentPreimage is the preImage of a successful payment. This is used
	// to calculate the PaymentHash as well as serve as a proof of payment.
	PaymentPreimage [32]byte
}

// AddPayment saves a successful payment to the database. It is assumed that
// all payment are sent using unique payment hashes.
func (db *DB) AddPayment(payment *OutgoingPayment) error {
	// Validate the field of the inner voice within the outgoing payment,
	// these must also adhere to the same constraints as regular invoices.
	if err := validateInvoice(&payment.Invoice); err != nil {
		return err
	}

	// We first serialize the payment before starting the database
	// transaction so we can avoid creating a DB payment in the case of a
	// serialization error.
	var b bytes.Buffer
	if err := serializeOutgoingPayment(&b, payment); err != nil {
		return err
	}
	paymentBytes := b.Bytes()

	return db.Batch(func(tx *bolt.Tx) error {
		payments, err := tx.CreateBucketIfNotExists(paymentBucket)
		if err != nil {
			return err
		}

		// Obtain the new unique sequence number for this payment.
		paymentID, err := payments.NextSequence()
		if err != nil {
			return err
		}

		// We use BigEndian for keys as it orders keys in
		// ascending order. This allows bucket scans to order payments
		// in the order in which they were created.
		paymentIDBytes := make([]byte, 8)
		binary.BigEndian.PutUint64(paymentIDBytes, paymentID)

		return payments.Put(paymentIDBytes, paymentBytes)
	})
}

// FetchAllPayments returns all outgoing payments in DB.
func (db *DB) FetchAllPayments() ([]*OutgoingPayment, error) {
	var payments []*OutgoingPayment

	err := db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(paymentBucket)
		if bucket == nil {
			return ErrNoPaymentsCreated
		}

		return bucket.ForEach(func(k, v []byte) error {
			// If the value is nil, then we ignore it as it may be
			// a sub-bucket.
			if v == nil {
				return nil
			}

			r := bytes.NewReader(v)
			payment, err := deserializeOutgoingPayment(r)
			if err != nil {
				return err
			}

			payments = append(payments, payment)
			return nil
		})
	})
	if err != nil {
		return nil, err
	}

	return payments, nil
}

// DeleteAllPayments deletes all payments from DB.
func (db *DB) DeleteAllPayments() error {
	return db.Update(func(tx *bolt.Tx) error {
		err := tx.DeleteBucket(paymentBucket)
		if err != nil && err != bolt.ErrBucketNotFound {
			return err
		}

		_, err = tx.CreateBucket(paymentBucket)
		return err
	})
}

// UpdatePaymentStatus sets the payment status for outgoing/finished payments in
// local database.
func (db *DB) UpdatePaymentStatus(paymentHash [32]byte, status PaymentStatus) error {
	return db.Batch(func(tx *bolt.Tx) error {
		paymentStatuses, err := tx.CreateBucketIfNotExists(paymentStatusBucket)
		if err != nil {
			return err
		}

		return paymentStatuses.Put(paymentHash[:], status.Bytes())
	})
}

// FetchPaymentStatus returns the payment status for outgoing payment.
// If status of the payment isn't found, it will default to "StatusGrounded".
func (db *DB) FetchPaymentStatus(paymentHash [32]byte) (PaymentStatus, error) {
	// The default status for all payments that aren't recorded in database.
	paymentStatus := StatusGrounded

	err := db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(paymentStatusBucket)
		if bucket == nil {
			return nil
		}

		paymentStatusBytes := bucket.Get(paymentHash[:])
		if paymentStatusBytes == nil {
			return nil
		}

		return paymentStatus.FromBytes(paymentStatusBytes)
	})
	if err != nil {
		return StatusGrounded, err
	}

	return paymentStatus, nil
}

func serializeOutgoingPayment(w io.Writer, p *OutgoingPayment) error {
	var scratch [8]byte

	if err := serializeInvoice(w, &p.Invoice); err != nil {
		return err
	}

	byteOrder.PutUint64(scratch[:], uint64(p.Fee))
	if _, err := w.Write(scratch[:]); err != nil {
		return err
	}

	// First write out the length of the bytes to prefix the value.
	pathLen := uint32(len(p.Path))
	byteOrder.PutUint32(scratch[:4], pathLen)
	if _, err := w.Write(scratch[:4]); err != nil {
		return err
	}

	// Then with the path written, we write out the series of public keys
	// involved in the path.
	for _, hop := range p.Path {
		if _, err := w.Write(hop[:]); err != nil {
			return err
		}
	}

	byteOrder.PutUint32(scratch[:4], p.TimeLockLength)
	if _, err := w.Write(scratch[:4]); err != nil {
		return err
	}

	if _, err := w.Write(p.PaymentPreimage[:]); err != nil {
		return err
	}

	return nil
}

func deserializeOutgoingPayment(r io.Reader) (*OutgoingPayment, error) {
	var scratch [8]byte

	p := &OutgoingPayment{}

	inv, err := deserializeInvoice(r)
	if err != nil {
		return nil, err
	}
	p.Invoice = inv

	if _, err := r.Read(scratch[:]); err != nil {
		return nil, err
	}
	p.Fee = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))

	if _, err = r.Read(scratch[:4]); err != nil {
		return nil, err
	}
	pathLen := byteOrder.Uint32(scratch[:4])

	path := make([][33]byte, pathLen)
	for i := uint32(0); i < pathLen; i++ {
		if _, err := r.Read(path[i][:]); err != nil {
			return nil, err
		}
	}
	p.Path = path

	if _, err = r.Read(scratch[:4]); err != nil {
		return nil, err
	}
	p.TimeLockLength = byteOrder.Uint32(scratch[:4])

	if _, err := r.Read(p.PaymentPreimage[:]); err != nil {
		return nil, err
	}

	return p, nil
}
<|endoftext|>


<commit_before>package checkers

import (
	"reflect"
	"testing"
)

func TestNewGame(t *testing.T) {
	game := NewGame()
	board := game.GetBoard()
	if board == nil {
		t.Error("Board wasn't created.")
	}
}

func TestGetAvailableMoves(t *testing.T) {
	// TODO: Fix positions (checkers are placed on white cells!)
	checkers := []*struct {
		ch   Checker
		X, Y int
	}{
		{newChecker(false), 4, 5},
		{newChecker(true), 5, 6},
		{newChecker(false), 3, 6},
		{newChecker(true), 3, 4},
		{newChecker(false), 5, 4},
		{newChecker(true), 6, 7},
		{newChecker(false), 2, 7},
		{newChecker(true), 2, 3},
		{newChecker(false), 6, 3},
	}

	expectedMoves := [][]Move{
		nil,
		{Move{Target: Point{X: 4, Y: 7}, BecomeQueen: true}},
		{Move{Target: Point{X: 2, Y: 5}}},
		{Move{Target: Point{X: 2, Y: 5}}},
		{Move{Target: Point{X: 4, Y: 3}}},
		nil,
		{Move{Target: Point{X: 1, Y: 6}}},
		{Move{Target: Point{X: 1, Y: 4}}},
		{
			Move{Target: Point{X: 5, Y: 2}},
			Move{Target: Point{X: 7, Y: 2}},
		},
	}

	game := NewGame()
	board := game.GetBoard()

	for _, c := range checkers {
		moves := game.getAvailableMoves(&c.ch, false)
		if len(moves) > 0 {
			t.Error("Checker at", c.ch.Position(), "is not on board but has moves:", moves)
		}
	}

	for _, c := range checkers {
		board.placeChecker(c.X, c.Y, &c.ch)
	}

	for i, c := range checkers {
		moves := game.getAvailableMoves(&c.ch, false)
		// we should compare sorted moves (both expected and acquired from game)
		// since order can be different. First we have to compare lengths of
		// both slices and only the do in-depth compare (i.e. sort and compare
		// elements). It's requied to extract comparison code ino separate
		// function.
		if !reflect.DeepEqual(moves, expectedMoves[i]) {
			if expectedMoves[i] == nil {
				t.Error("Checker at", c.ch.Position(), "shouldn't have moves.")
			} else {
				t.Error("Checker at", c.ch.Position(), "should have at least 1 move.")
			}
		}
	}

	if t.Failed() {
		t.Logf("Current board state:\n%s", board.DebugString())
	}
}
<commit_msg>Place checkers on black cells Resolve cl0ne/go-checkers#2<commit_after>package checkers

import (
	"reflect"
	"testing"
)

func TestNewGame(t *testing.T) {
	game := NewGame()
	board := game.GetBoard()
	if board == nil {
		t.Error("Board wasn't created.")
	}
}

func TestGetAvailableMoves(t *testing.T) {
	checkers := []*struct {
		ch   Checker
		X, Y int
	}{
		{newChecker(false), 4, 4},
		{newChecker(true), 5, 5},
		{newChecker(false), 3, 5},
		{newChecker(true), 3, 3},
		{newChecker(false), 5, 3},
		{newChecker(true), 6, 6},
		{newChecker(false), 2, 6},
		{newChecker(true), 2, 2},
		{newChecker(false), 6, 2},
	}

	expectedMoves := [][]Move{
		nil,
		{Move{Target: Point{X: 4, Y: 6}}},
		{Move{Target: Point{X: 2, Y: 4}}},
		{Move{Target: Point{X: 2, Y: 4}}},
		{Move{Target: Point{X: 4, Y: 2}}},
		{
			Move{Target: Point{X: 7, Y: 7}, BecomeQueen: true},
			Move{Target: Point{X: 5, Y: 7}, BecomeQueen: true},
		},
		{Move{Target: Point{X: 1, Y: 5}}},
		{Move{Target: Point{X: 1, Y: 3}}},
		{
			Move{Target: Point{X: 5, Y: 1}},
			Move{Target: Point{X: 7, Y: 1}},
		},
	}

	game := NewGame()
	board := game.GetBoard()

	for _, c := range checkers {
		moves := game.getAvailableMoves(&c.ch, false)
		if len(moves) > 0 {
			t.Error("Checker at", c.ch.Position(), "is not on board but has moves:", moves)
		}
	}

	for _, c := range checkers {
		board.placeChecker(c.X, c.Y, &c.ch)
	}

	for i, c := range checkers {
		moves := game.getAvailableMoves(&c.ch, false)
		// we should compare sorted moves (both expected and acquired from game)
		// since order can be different. First we have to compare lengths of
		// both slices and only the do in-depth compare (i.e. sort and compare
		// elements). It's requied to extract comparison code ino separate
		// function.
		if !reflect.DeepEqual(moves, expectedMoves[i]) {
			if expectedMoves[i] == nil {
				t.Error("Checker at", c.ch.Position(), "shouldn't have moves.")
			} else {
				t.Error("Checker at", c.ch.Position(), "should have at least 1 move.")
			}
		}
	}

	if t.Failed() {
		t.Logf("Current board state:\n%s", board.DebugString())
	}
}
<|endoftext|>


<commit_before>package jobspec

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"

	"github.com/hashicorp/hcl"
	hclobj "github.com/hashicorp/hcl/hcl"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

// Parse parses the job spec from the given io.Reader.
//
// Due to current internal limitations, the entire contents of the
// io.Reader will be copied into memory first before parsing.
func Parse(r io.Reader) (*structs.Job, error) {
	// Copy the reader into an in-memory buffer first since HCL requires it.
	var buf bytes.Buffer
	if _, err := io.Copy(&buf, r); err != nil {
		return nil, err
	}

	// Parse the buffer
	obj, err := hcl.Parse(buf.String())
	if err != nil {
		return nil, fmt.Errorf("error parsing: %s", err)
	}
	buf.Reset()

	var job structs.Job

	// Parse the job out
	jobO := obj.Get("job", false)
	if jobO == nil {
		return nil, fmt.Errorf("'job' stanza not found")
	}
	if err := parseJob(&job, jobO); err != nil {
		return nil, fmt.Errorf("error parsing 'job': %s", err)
	}

	return &job, nil
}

// ParseFile parses the given path as a job spec.
func ParseFile(path string) (*structs.Job, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return Parse(f)
}

func parseJob(result *structs.Job, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'job' block allowed")
	}

	// Get our job object
	obj = obj.Elem(true)[0]

	// Decode the full thing into a map[string]interface for ease
	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}
	delete(m, "constraint")
	delete(m, "meta")
	delete(m, "update")

	// Set the ID and name to the object key
	result.ID = obj.Key
	result.Name = obj.Key

	// Defaults
	result.Priority = 50
	result.Region = "global"
	result.Type = "service"

	// Decode the rest
	if err := mapstructure.WeakDecode(m, result); err != nil {
		return err
	}

	// Parse constraints
	if o := obj.Get("constraint", false); o != nil {
		if err := parseConstraints(&result.Constraints, o); err != nil {
			return err
		}
	}

	// If we have an update strategy, then parse that
	if o := obj.Get("update", false); o != nil {
		if err := parseUpdate(&result.Update, o); err != nil {
			return err
		}
	}

	// Parse out meta fields. These are in HCL as a list so we need
	// to iterate over them and merge them.
	if metaO := obj.Get("meta", false); metaO != nil {
		for _, o := range metaO.Elem(false) {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o); err != nil {
				return err
			}
			if err := mapstructure.WeakDecode(m, &result.Meta); err != nil {
				return err
			}
		}
	}

	// If we have tasks outside, do those
	if o := obj.Get("task", false); o != nil {
		var tasks []*structs.Task
		if err := parseTasks(&tasks, o); err != nil {
			return err
		}

		result.TaskGroups = make([]*structs.TaskGroup, len(tasks), len(tasks)*2)
		for i, t := range tasks {
			result.TaskGroups[i] = &structs.TaskGroup{
				Name:  t.Name,
				Count: 1,
				Tasks: []*structs.Task{t},
			}
		}
	}

	// Parse the task groups
	if o := obj.Get("group", false); o != nil {
		if err := parseGroups(result, o); err != nil {
			return fmt.Errorf("error parsing 'group': %s", err)
		}
	}

	return nil
}

func parseGroups(result *structs.Job, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*structs.TaskGroup, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "task")

		// Build the group with the basic decode
		var g structs.TaskGroup
		g.Name = n
		if err := mapstructure.WeakDecode(m, &g); err != nil {
			return err
		}

		// Parse constraints
		if o := o.Get("constraint", false); o != nil {
			if err := parseConstraints(&g.Constraints, o); err != nil {
				return err
			}
		}

		// Parse out meta fields. These are in HCL as a list so we need
		// to iterate over them and merge them.
		if metaO := o.Get("meta", false); metaO != nil {
			for _, o := range metaO.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &g.Meta); err != nil {
					return err
				}
			}
		}

		// Parse tasks
		if o := o.Get("task", false); o != nil {
			if err := parseTasks(&g.Tasks, o); err != nil {
				return err
			}
		}

		collection = append(collection, &g)
	}

	result.TaskGroups = append(result.TaskGroups, collection...)
	return nil
}

func parseConstraints(result *[]*structs.Constraint, obj *hclobj.Object) error {
	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		m["LTarget"] = m["attribute"]
		m["RTarget"] = m["value"]
		m["Operand"] = m["operator"]

		// Default constraint to being hard
		if _, ok := m["hard"]; !ok {
			m["hard"] = true
		}

		// Build the constraint
		var c structs.Constraint
		if err := mapstructure.WeakDecode(m, &c); err != nil {
			return err
		}
		if c.Operand == "" {
			c.Operand = "="
		}

		*result = append(*result, &c)
	}

	return nil
}

func parseTasks(result *[]*structs.Task, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 5)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	for _, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "config")
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "resources")

		// Build the task
		var t structs.Task
		t.Name = o.Key
		if err := mapstructure.WeakDecode(m, &t); err != nil {
			return err
		}

		// If we have config, then parse that
		if o := o.Get("config", false); o != nil {
			for _, o := range o.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &t.Config); err != nil {
					return err
				}
			}
		}

		// Parse constraints
		if o := o.Get("constraint", false); o != nil {
			if err := parseConstraints(&t.Constraints, o); err != nil {
				return err
			}
		}

		// Parse out meta fields. These are in HCL as a list so we need
		// to iterate over them and merge them.
		if metaO := o.Get("meta", false); metaO != nil {
			for _, o := range metaO.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &t.Meta); err != nil {
					return err
				}
			}
		}

		// If we have resources, then parse that
		if o := o.Get("resources", false); o != nil {
			var r structs.Resources
			if err := parseResources(&r, o); err != nil {
				return fmt.Errorf("task '%s': %s", t.Name, err)
			}

			t.Resources = &r
		}

		*result = append(*result, &t)
	}

	return nil
}

func parseResources(result *structs.Resources, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'resource' block allowed per task")
	}

	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "network")

		if err := mapstructure.WeakDecode(m, result); err != nil {
			return err
		}

		// Parse the network resources
		if o := o.Get("network", false); o != nil {
			if o.Len() > 1 {
				return fmt.Errorf("only one 'network' resource allowed")
			}

			var r structs.NetworkResource
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o); err != nil {
				return err
			}
			if err := mapstructure.WeakDecode(m, &r); err != nil {
				return err
			}

			result.Networks = []*structs.NetworkResource{&r}
		}

	}

	return nil
}

func parseUpdate(result *structs.UpdateStrategy, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'update' block allowed per job")
	}

	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		for _, key := range []string{"stagger", "Stagger"} {
			if raw, ok := m[key]; ok {
				switch v := raw.(type) {
				case string:
					dur, err := time.ParseDuration(v)
					if err != nil {
						return fmt.Errorf("invalid stagger time '%s'", raw)
					}
					m[key] = dur
				case int:
					m[key] = time.Duration(v) * time.Second
				default:
					return fmt.Errorf("invalid type for stagger time '%s'",
						raw)
				}
			}
		}

		if err := mapstructure.WeakDecode(m, result); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>jobspec: default count of group to 1 if not specified<commit_after>package jobspec

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"

	"github.com/hashicorp/hcl"
	hclobj "github.com/hashicorp/hcl/hcl"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

// Parse parses the job spec from the given io.Reader.
//
// Due to current internal limitations, the entire contents of the
// io.Reader will be copied into memory first before parsing.
func Parse(r io.Reader) (*structs.Job, error) {
	// Copy the reader into an in-memory buffer first since HCL requires it.
	var buf bytes.Buffer
	if _, err := io.Copy(&buf, r); err != nil {
		return nil, err
	}

	// Parse the buffer
	obj, err := hcl.Parse(buf.String())
	if err != nil {
		return nil, fmt.Errorf("error parsing: %s", err)
	}
	buf.Reset()

	var job structs.Job

	// Parse the job out
	jobO := obj.Get("job", false)
	if jobO == nil {
		return nil, fmt.Errorf("'job' stanza not found")
	}
	if err := parseJob(&job, jobO); err != nil {
		return nil, fmt.Errorf("error parsing 'job': %s", err)
	}

	return &job, nil
}

// ParseFile parses the given path as a job spec.
func ParseFile(path string) (*structs.Job, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return Parse(f)
}

func parseJob(result *structs.Job, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'job' block allowed")
	}

	// Get our job object
	obj = obj.Elem(true)[0]

	// Decode the full thing into a map[string]interface for ease
	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}
	delete(m, "constraint")
	delete(m, "meta")
	delete(m, "update")

	// Set the ID and name to the object key
	result.ID = obj.Key
	result.Name = obj.Key

	// Defaults
	result.Priority = 50
	result.Region = "global"
	result.Type = "service"

	// Decode the rest
	if err := mapstructure.WeakDecode(m, result); err != nil {
		return err
	}

	// Parse constraints
	if o := obj.Get("constraint", false); o != nil {
		if err := parseConstraints(&result.Constraints, o); err != nil {
			return err
		}
	}

	// If we have an update strategy, then parse that
	if o := obj.Get("update", false); o != nil {
		if err := parseUpdate(&result.Update, o); err != nil {
			return err
		}
	}

	// Parse out meta fields. These are in HCL as a list so we need
	// to iterate over them and merge them.
	if metaO := obj.Get("meta", false); metaO != nil {
		for _, o := range metaO.Elem(false) {
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o); err != nil {
				return err
			}
			if err := mapstructure.WeakDecode(m, &result.Meta); err != nil {
				return err
			}
		}
	}

	// If we have tasks outside, do those
	if o := obj.Get("task", false); o != nil {
		var tasks []*structs.Task
		if err := parseTasks(&tasks, o); err != nil {
			return err
		}

		result.TaskGroups = make([]*structs.TaskGroup, len(tasks), len(tasks)*2)
		for i, t := range tasks {
			result.TaskGroups[i] = &structs.TaskGroup{
				Name:  t.Name,
				Count: 1,
				Tasks: []*structs.Task{t},
			}
		}
	}

	// Parse the task groups
	if o := obj.Get("group", false); o != nil {
		if err := parseGroups(result, o); err != nil {
			return fmt.Errorf("error parsing 'group': %s", err)
		}
	}

	return nil
}

func parseGroups(result *structs.Job, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*structs.TaskGroup, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "task")

		// Default count to 1 if not specified
		if _, ok := m["count"]; !ok {
			m["count"] = 1
		}

		// Build the group with the basic decode
		var g structs.TaskGroup
		g.Name = n
		if err := mapstructure.WeakDecode(m, &g); err != nil {
			return err
		}

		// Parse constraints
		if o := o.Get("constraint", false); o != nil {
			if err := parseConstraints(&g.Constraints, o); err != nil {
				return err
			}
		}

		// Parse out meta fields. These are in HCL as a list so we need
		// to iterate over them and merge them.
		if metaO := o.Get("meta", false); metaO != nil {
			for _, o := range metaO.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &g.Meta); err != nil {
					return err
				}
			}
		}

		// Parse tasks
		if o := o.Get("task", false); o != nil {
			if err := parseTasks(&g.Tasks, o); err != nil {
				return err
			}
		}

		collection = append(collection, &g)
	}

	result.TaskGroups = append(result.TaskGroups, collection...)
	return nil
}

func parseConstraints(result *[]*structs.Constraint, obj *hclobj.Object) error {
	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		m["LTarget"] = m["attribute"]
		m["RTarget"] = m["value"]
		m["Operand"] = m["operator"]

		// Default constraint to being hard
		if _, ok := m["hard"]; !ok {
			m["hard"] = true
		}

		// Build the constraint
		var c structs.Constraint
		if err := mapstructure.WeakDecode(m, &c); err != nil {
			return err
		}
		if c.Operand == "" {
			c.Operand = "="
		}

		*result = append(*result, &c)
	}

	return nil
}

func parseTasks(result *[]*structs.Task, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 5)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"group '%s' defined more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	for _, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "config")
		delete(m, "constraint")
		delete(m, "meta")
		delete(m, "resources")

		// Build the task
		var t structs.Task
		t.Name = o.Key
		if err := mapstructure.WeakDecode(m, &t); err != nil {
			return err
		}

		// If we have config, then parse that
		if o := o.Get("config", false); o != nil {
			for _, o := range o.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &t.Config); err != nil {
					return err
				}
			}
		}

		// Parse constraints
		if o := o.Get("constraint", false); o != nil {
			if err := parseConstraints(&t.Constraints, o); err != nil {
				return err
			}
		}

		// Parse out meta fields. These are in HCL as a list so we need
		// to iterate over them and merge them.
		if metaO := o.Get("meta", false); metaO != nil {
			for _, o := range metaO.Elem(false) {
				var m map[string]interface{}
				if err := hcl.DecodeObject(&m, o); err != nil {
					return err
				}
				if err := mapstructure.WeakDecode(m, &t.Meta); err != nil {
					return err
				}
			}
		}

		// If we have resources, then parse that
		if o := o.Get("resources", false); o != nil {
			var r structs.Resources
			if err := parseResources(&r, o); err != nil {
				return fmt.Errorf("task '%s': %s", t.Name, err)
			}

			t.Resources = &r
		}

		*result = append(*result, &t)
	}

	return nil
}

func parseResources(result *structs.Resources, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'resource' block allowed per task")
	}

	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		delete(m, "network")

		if err := mapstructure.WeakDecode(m, result); err != nil {
			return err
		}

		// Parse the network resources
		if o := o.Get("network", false); o != nil {
			if o.Len() > 1 {
				return fmt.Errorf("only one 'network' resource allowed")
			}

			var r structs.NetworkResource
			var m map[string]interface{}
			if err := hcl.DecodeObject(&m, o); err != nil {
				return err
			}
			if err := mapstructure.WeakDecode(m, &r); err != nil {
				return err
			}

			result.Networks = []*structs.NetworkResource{&r}
		}

	}

	return nil
}

func parseUpdate(result *structs.UpdateStrategy, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'update' block allowed per job")
	}

	for _, o := range obj.Elem(false) {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}
		for _, key := range []string{"stagger", "Stagger"} {
			if raw, ok := m[key]; ok {
				switch v := raw.(type) {
				case string:
					dur, err := time.ParseDuration(v)
					if err != nil {
						return fmt.Errorf("invalid stagger time '%s'", raw)
					}
					m[key] = dur
				case int:
					m[key] = time.Duration(v) * time.Second
				default:
					return fmt.Errorf("invalid type for stagger time '%s'",
						raw)
				}
			}
		}

		if err := mapstructure.WeakDecode(m, result); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 CoreOS, Inc.
//
// 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.

// etcdctl is a command line application that controls etcd.
package main

import (
	"fmt"
	"os"

	"github.com/coreos/etcd/etcdctl/ctlv2"
	"github.com/coreos/etcd/etcdctl/ctlv3"
)

const (
	apiEnv = "ETCDCTL_API"
)

func main() {
	apiv := os.Getenv(apiEnv)
	// unset apiEnv to avoid side-effect for future env and flag parsing.
	os.Unsetenv(apiv)
	if len(apiv) == 0 || apiv == "2" {
		ctlv2.Start()
		return
	}

	if apiv == "3" {
		ctlv3.Start()
		return
	}

	fmt.Fprintln(os.Stderr, "unsupported API version", apiv)
	os.Exit(1)
}
<commit_msg>etcdctl: unset ETCDCTL_API env var properly<commit_after>// Copyright 2016 CoreOS, Inc.
//
// 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.

// etcdctl is a command line application that controls etcd.
package main

import (
	"fmt"
	"os"

	"github.com/coreos/etcd/etcdctl/ctlv2"
	"github.com/coreos/etcd/etcdctl/ctlv3"
)

const (
	apiEnv = "ETCDCTL_API"
)

func main() {
	apiv := os.Getenv(apiEnv)
	// unset apiEnv to avoid side-effect for future env and flag parsing.
	os.Unsetenv(apiEnv)
	if len(apiv) == 0 || apiv == "2" {
		ctlv2.Start()
		return
	}

	if apiv == "3" {
		ctlv3.Start()
		return
	}

	fmt.Fprintln(os.Stderr, "unsupported API version", apiv)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package eval

import (
	"fmt"
)

type ioType byte

const (
	fileIO ioType = iota // Default IO type. Corresponds to io.f.
	chanIO // Corresponds to io.ch.
	unusedIO
)

type builtinFunc func(*Evaluator, []Value, [3]*io) string

type builtin struct {
	fn builtinFunc
	ioTypes [3]ioType
}

var builtins = map[string]builtin {
	"set": builtin{implSet, [3]ioType{unusedIO, unusedIO}},
	"put": builtin{implPut, [3]ioType{unusedIO, chanIO}},
	"print": builtin{implPrint, [3]ioType{unusedIO}},
	"println": builtin{implPrintln, [3]ioType{unusedIO}},
	"printchan": builtin{implPrintchan, [3]ioType{chanIO, fileIO}},
}

func implSet(ev *Evaluator, args []Value, ios [3]*io) string {
	// TODO Support setting locals
	// TODO Prevent overriding builtin variables e.g. $pid $env
	if len(args) != 3 || args[1].String(ev) != "=" {
		return "args error"
	}
	ev.globals[args[0].String(ev)] = args[2]
	return ""
}

func implPut(ev *Evaluator, args []Value, ios [3]*io) string {
	out := ios[1].ch
	for _, a := range args {
		out <- a
	}
	close(out)
	return ""
}

func implPrint(ev *Evaluator, args []Value, ios [3]*io) string {
	out := ios[1].f
	for _, a := range args {
		fmt.Fprint(out, a.String(ev))
	}
	return ""
}

func implPrintln(ev *Evaluator, args []Value, ios [3]*io) string {
	args = append(args, NewScalar("\n"))
	return implPrint(ev, args, ios)
}

func implPrintchan(ev *Evaluator, args []Value, ios [3]*io) string {
	if len(args) > 0 {
		return "args error"
	}
	in := ios[0].ch
	out := ios[1].f

	for s := range in {
		fmt.Fprintf(out, "%q\n", s)
	}
	return ""
}
<commit_msg>Add builtin `fn`, for defining function<commit_after>package eval

import (
	"fmt"
)

type ioType byte

const (
	fileIO ioType = iota // Default IO type. Corresponds to io.f.
	chanIO // Corresponds to io.ch.
	unusedIO
)

type builtinFunc func(*Evaluator, []Value, [3]*io) string

type builtin struct {
	fn builtinFunc
	ioTypes [3]ioType
}

var builtins = map[string]builtin {
	"set": builtin{implSet, [3]ioType{unusedIO, unusedIO}},
	"fn": builtin{implFn, [3]ioType{unusedIO, unusedIO}},
	"put": builtin{implPut, [3]ioType{unusedIO, chanIO}},
	"print": builtin{implPrint, [3]ioType{unusedIO}},
	"println": builtin{implPrintln, [3]ioType{unusedIO}},
	"printchan": builtin{implPrintchan, [3]ioType{chanIO, fileIO}},
}

func doSet(ev *Evaluator, name Value, value Value) string {
	// TODO Support setting locals
	// TODO Prevent overriding builtin variables e.g. $pid $env
	ev.globals[name.String(ev)] = value
	return ""
}

func implSet(ev *Evaluator, args []Value, ios [3]*io) string {
	if len(args) != 3 || args[1].String(ev) != "=" {
		return "args error"
	}
	return doSet(ev, args[0], args[2])
}

func implFn(ev *Evaluator, args []Value, ios [3]*io) string {
	// TODO Support `fn f a b c { cmd }` as sugar for `fn f { | a b c | cmd }`
	if len(args) != 2 {
		return "args error"
	}
	if _, ok := args[1].(*Closure); !ok {
		return "args error"
	}
	return doSet(ev, args[0], args[1])
}

func implPut(ev *Evaluator, args []Value, ios [3]*io) string {
	out := ios[1].ch
	for _, a := range args {
		out <- a
	}
	close(out)
	return ""
}

func implPrint(ev *Evaluator, args []Value, ios [3]*io) string {
	out := ios[1].f
	for _, a := range args {
		fmt.Fprint(out, a.String(ev))
	}
	return ""
}

func implPrintln(ev *Evaluator, args []Value, ios [3]*io) string {
	args = append(args, NewScalar("\n"))
	return implPrint(ev, args, ios)
}

func implPrintchan(ev *Evaluator, args []Value, ios [3]*io) string {
	if len(args) > 0 {
		return "args error"
	}
	in := ios[0].ch
	out := ios[1].f

	for s := range in {
		fmt.Fprintf(out, "%q\n", s)
	}
	return ""
}
<|endoftext|>


<commit_before>package eval

import (
	"errors"
	"fmt"
)

var ErrArityMismatch = errors.New("arity mismatch")

var unnamedRestArg = ":"

// Closure is a closure defined in elvish script.
type Closure struct {
	ArgNames []string
	// The name for the rest argument. If empty, the function has fixed arity.
	// If equal to unnamedRestArg, the rest argument is unnamed but can be
	// accessed via $args.
	RestArg  string
	Op       Op
	Captured map[string]Variable
}

func (*Closure) Kind() string {
	return "fn"
}

func newClosure(a []string, r string, op Op, e map[string]Variable) *Closure {
	return &Closure{a, r, op, e}
}

func (c *Closure) Repr(int) string {
	return fmt.Sprintf("<Closure%v>", *c)
}

// Call calls a closure.
func (c *Closure) Call(ec *EvalCtx, args []Value) {
	// TODO Support keyword arguments
	if c.RestArg != "" {
		if len(c.ArgNames) > len(args) {
			throw(ErrArityMismatch)
		}
	} else {
		if len(c.ArgNames) != len(args) {
			throw(ErrArityMismatch)
		}
	}

	// This evalCtx is dedicated to the current form, so we modify it in place.
	// BUG(xiaq): When evaluating closures, async access to global variables
	// and ports can be problematic.

	// Make upvalue namespace and capture variables.
	ec.up = make(map[string]Variable)
	for name, variable := range c.Captured {
		ec.up[name] = variable
	}
	// Make local namespace and pass arguments.
	ec.local = make(map[string]Variable)
	for i, name := range c.ArgNames {
		ec.local[name] = NewPtrVariable(args[i])
	}
	if c.RestArg != "" && c.RestArg != unnamedRestArg {
		ec.local[c.RestArg] = NewPtrVariable(NewList(args[len(c.ArgNames):]...))
	}
	Logger.Printf("EvalCtx=%p, args=%v", ec, args)
	ec.positionals = args
	ec.local["args"] = NewPtrVariable(List{&args})
	ec.local["kwargs"] = NewPtrVariable(Map{&map[Value]Value{}})

	// TODO(xiaq): Also change ec.name and ec.text since the closure being
	// called can come from another source.

	c.Op.Exec(ec)
}
<commit_msg>Slightly prettier Repr of closure.<commit_after>package eval

import (
	"errors"
	"fmt"
)

var ErrArityMismatch = errors.New("arity mismatch")

var unnamedRestArg = "@"

// Closure is a closure defined in elvish script.
type Closure struct {
	ArgNames []string
	// The name for the rest argument. If empty, the function has fixed arity.
	// If equal to unnamedRestArg, the rest argument is unnamed but can be
	// accessed via $args.
	RestArg  string
	Op       Op
	Captured map[string]Variable
}

func (*Closure) Kind() string {
	return "fn"
}

func newClosure(a []string, r string, op Op, e map[string]Variable) *Closure {
	return &Closure{a, r, op, e}
}

func (c *Closure) Repr(int) string {
	return fmt.Sprintf("<closure%v>", *c)
}

// Call calls a closure.
func (c *Closure) Call(ec *EvalCtx, args []Value) {
	// TODO Support keyword arguments
	if c.RestArg != "" {
		if len(c.ArgNames) > len(args) {
			throw(ErrArityMismatch)
		}
	} else {
		if len(c.ArgNames) != len(args) {
			throw(ErrArityMismatch)
		}
	}

	// This evalCtx is dedicated to the current form, so we modify it in place.
	// BUG(xiaq): When evaluating closures, async access to global variables
	// and ports can be problematic.

	// Make upvalue namespace and capture variables.
	ec.up = make(map[string]Variable)
	for name, variable := range c.Captured {
		ec.up[name] = variable
	}
	// Make local namespace and pass arguments.
	ec.local = make(map[string]Variable)
	for i, name := range c.ArgNames {
		ec.local[name] = NewPtrVariable(args[i])
	}
	if c.RestArg != "" && c.RestArg != unnamedRestArg {
		ec.local[c.RestArg] = NewPtrVariable(NewList(args[len(c.ArgNames):]...))
	}
	Logger.Printf("EvalCtx=%p, args=%v", ec, args)
	ec.positionals = args
	ec.local["args"] = NewPtrVariable(List{&args})
	ec.local["kwargs"] = NewPtrVariable(Map{&map[Value]Value{}})

	// TODO(xiaq): Also change ec.name and ec.text since the closure being
	// called can come from another source.

	c.Op.Exec(ec)
}
<|endoftext|>


<commit_before>package audru

import (
	"testing"
)

func TestWriterManager(t *testing.T) {
	piper, err := NewWriterManager(2, "")

	if err != nil {
		t.FailNow()
	}
	w, err := piper.NewWriter()
	if err != nil {
		t.FailNow()
	}
	w.Write([]byte("hello"))
}
<commit_msg>Concurrent test added<commit_after>package audru

import (
	"sync"
	"testing"
)

func TestWriterManager(t *testing.T) {
	piper, err := NewWriterManager(2, "")

	if err != nil {
		t.FailNow()
	}

	var wg sync.WaitGroup

	for i := 0; i < 4; i++ {
		wg.Add(1)
		go func() {
			w, err := piper.NewWriter()
			if err != nil {
				t.FailNow()
			}
			w.Write([]byte("hello"))
		}()
	}
	wg.Wait()
}
<|endoftext|>


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

package main

import (
	"errors"
	"io"
	"regexp"
	"strconv"
	"time"

	"github.com/tsuru/tsuru-autoscale/db"
	"github.com/tsuru/tsuru/log"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func StartAutoScale() {
	go runAutoScale()
}

// Event represents an auto scale event with
// the scale metadata.
type Event struct {
	ID         bson.ObjectId `bson:"_id"`
	StartTime  time.Time
	EndTime    time.Time `bson:",omitempty"`
	Config     *Config
	Type       string
	Successful bool
	Error      string `bson:",omitempty"`
}

func NewEvent(config *Config, scaleType string) (*Event, error) {
	evt := Event{
		ID:        bson.NewObjectId(),
		StartTime: time.Now().UTC(),
		Config:    config,
		Type:      scaleType,
	}
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	return &evt, conn.AutoScale().Insert(evt)
}

func (evt *Event) update(err error) error {
	if err != nil {
		evt.Error = err.Error()
	}
	evt.Successful = err == nil
	evt.EndTime = time.Now().UTC()
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.AutoScale().UpdateId(evt.ID, evt)
}

// Action represents an AutoScale action to increase or decrease the
// number of the units.
type Action struct {
	Wait       time.Duration `json:"wait"`
	Expression string        `json:"expression"`
	Units      uint          `json:"units"`
}

func NewAction(expression string, units uint, wait time.Duration) (*Action, error) {
	if expressionIsValid(expression) {
		return &Action{Wait: wait, Expression: expression, Units: units}, nil
	}
	return nil, errors.New("Expression is not valid.")
}

var expressionRegex = regexp.MustCompile("{(.*)} ([><=]) ([0-9]+)")

func expressionIsValid(expression string) bool {
	return expressionRegex.MatchString(expression)
}

func (action *Action) metric() string {
	return expressionRegex.FindStringSubmatch(action.Expression)[1]
}

func (action *Action) operator() string {
	return expressionRegex.FindStringSubmatch(action.Expression)[2]
}

func (action *Action) value() (float64, error) {
	return strconv.ParseFloat(expressionRegex.FindStringSubmatch(action.Expression)[3], 64)
}

// Config represents the configuration for the auto scale.
type Config struct {
	Name     string `json:"increase"`
	Increase Action `json:"increase"`
	Decrease Action `json:"decrease"`
	MinUnits uint   `json:"minUnits"`
	MaxUnits uint   `json:"maxUnits"`
	Enabled  bool   `json:"enabled"`
}

type App struct {
	Name string
}

func (a *App) Units() []string {
	return nil
}

func (a *App) Metric(kind string) (float64, error) {
	return float64(0), nil
}

func (a *App) AddUnits(n uint, writer io.Writer) error {
	return nil
}

func (a *App) RemoveUnits(n uint) error {
	return nil
}

func runAutoScaleOnce() {
	configs := []Config{}
	for _, config := range configs {
		err := scaleIfNeeded(&config)
		if err != nil {
			log.Error(err.Error())
		}
	}
}

func runAutoScale() {
	for {
		runAutoScaleOnce()
		time.Sleep(30 * time.Second)
	}
}

func scaleIfNeeded(config *Config) error {
	if config == nil {
		return errors.New("AutoScale is not configured.")
	}
	/*
		increaseMetric, _ := app.Metric(config.Increase.metric())
		value, _ := config.Increase.value()
		if increaseMetric > value {
			currentUnits := uint(len(app.Units()))
			maxUnits := config.MaxUnits
			if maxUnits == 0 {
				maxUnits = 1
			}
			if currentUnits >= maxUnits {
				return nil
			}
			if wait, err := shouldWait(app, config.Increase.Wait); err != nil {
				return err
			} else if wait {
				return nil
			}
			evt, err := NewEvent(app, "increase")
			if err != nil {
				return fmt.Errorf("Error trying to insert auto scale event, auto scale aborted: %s", err.Error())
		 	}
			inc := config.Increase.Units
			if currentUnits+inc > config.MaxUnits {
				inc = config.MaxUnits - currentUnits
			}
			addUnitsErr := app.AddUnits(inc, nil)
			err = evt.update(addUnitsErr)
			if err != nil {
				log.Errorf("Error trying to update auto scale event: %s", err.Error())
			}
			return addUnitsErr
		}
		decreaseMetric, _ := app.Metric(config.Decrease.metric())
		value, _ = config.Decrease.value()
		if decreaseMetric < value {
			currentUnits := uint(len(app.Units()))
			minUnits := config.MinUnits
			if minUnits == 0 {
				minUnits = 1
			}
			if currentUnits <= minUnits {
				return nil
			}
			if wait, err := shouldWait(app, config.Decrease.Wait); err != nil {
				return err
			} else if wait {
				return nil
			}
			evt, err := NewEvent(app, "decrease")
			if err != nil {
				return fmt.Errorf("Error trying to insert auto scale event, auto scale aborted: %s", err.Error())
			}
			dec := config.Decrease.Units
			if currentUnits-dec < config.MinUnits {
				dec = currentUnits - config.MinUnits
			}
			removeUnitsErr := app.RemoveUnits(dec)
			err = evt.update(removeUnitsErr)
			if err != nil {
				log.Errorf("Error trying to update auto scale event: %s", err.Error())
			}
			return removeUnitsErr
		}
	*/
	return nil
}

func shouldWait(app *App, waitPeriod time.Duration) (bool, error) {
	now := time.Now().UTC()
	lastEvent, err := lastScaleEvent(app.Name)
	if err != nil && err != mgo.ErrNotFound {
		return false, err
	}
	if err != mgo.ErrNotFound && lastEvent.EndTime.IsZero() {
		return true, nil
	}
	diff := now.Sub(lastEvent.EndTime)
	if diff > waitPeriod {
		return false, nil
	}
	return true, nil
}

func lastScaleEvent(appName string) (Event, error) {
	var event Event
	conn, err := db.Conn()
	if err != nil {
		return event, err
	}
	defer conn.Close()
	err = conn.AutoScale().Find(bson.M{"appname": appName}).Sort("-starttime").One(&event)
	return event, err
}

func ListAutoScaleHistory(appName string) ([]Event, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var history []Event
	q := bson.M{}
	if appName != "" {
		q["appname"] = appName
	}
	err = conn.AutoScale().Find(q).Sort("-_id").Limit(200).All(&history)
	if err != nil {
		return nil, err
	}
	return history, nil
}

func AutoScaleEnable(config *Config) error {
	config.Enabled = true
	return nil
}

func AutoScaleDisable(config *Config) error {
	config.Enabled = false
	return nil
}
<commit_msg>remove unused App struct<commit_after>// Copyright 2015 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"regexp"
	"strconv"
	"time"

	"github.com/tsuru/tsuru-autoscale/db"
	"github.com/tsuru/tsuru/log"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func StartAutoScale() {
	go runAutoScale()
}

// Event represents an auto scale event with
// the scale metadata.
type Event struct {
	ID         bson.ObjectId `bson:"_id"`
	StartTime  time.Time
	EndTime    time.Time `bson:",omitempty"`
	Config     *Config
	Type       string
	Successful bool
	Error      string `bson:",omitempty"`
}

func NewEvent(config *Config, scaleType string) (*Event, error) {
	evt := Event{
		ID:        bson.NewObjectId(),
		StartTime: time.Now().UTC(),
		Config:    config,
		Type:      scaleType,
	}
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	return &evt, conn.AutoScale().Insert(evt)
}

func (evt *Event) update(err error) error {
	if err != nil {
		evt.Error = err.Error()
	}
	evt.Successful = err == nil
	evt.EndTime = time.Now().UTC()
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.AutoScale().UpdateId(evt.ID, evt)
}

// Action represents an AutoScale action to increase or decrease the
// number of the units.
type Action struct {
	Wait       time.Duration `json:"wait"`
	Expression string        `json:"expression"`
	Units      uint          `json:"units"`
}

func NewAction(expression string, units uint, wait time.Duration) (*Action, error) {
	if expressionIsValid(expression) {
		return &Action{Wait: wait, Expression: expression, Units: units}, nil
	}
	return nil, errors.New("Expression is not valid.")
}

var expressionRegex = regexp.MustCompile("{(.*)} ([><=]) ([0-9]+)")

func expressionIsValid(expression string) bool {
	return expressionRegex.MatchString(expression)
}

func (action *Action) metric() string {
	return expressionRegex.FindStringSubmatch(action.Expression)[1]
}

func (action *Action) operator() string {
	return expressionRegex.FindStringSubmatch(action.Expression)[2]
}

func (action *Action) value() (float64, error) {
	return strconv.ParseFloat(expressionRegex.FindStringSubmatch(action.Expression)[3], 64)
}

// Config represents the configuration for the auto scale.
type Config struct {
	Name     string `json:"increase"`
	Increase Action `json:"increase"`
	Decrease Action `json:"decrease"`
	MinUnits uint   `json:"minUnits"`
	MaxUnits uint   `json:"maxUnits"`
	Enabled  bool   `json:"enabled"`
}

func runAutoScaleOnce() {
	configs := []Config{}
	for _, config := range configs {
		err := scaleIfNeeded(&config)
		if err != nil {
			log.Error(err.Error())
		}
	}
}

func runAutoScale() {
	for {
		runAutoScaleOnce()
		time.Sleep(30 * time.Second)
	}
}

func scaleIfNeeded(config *Config) error {
	if config == nil {
		return errors.New("AutoScale is not configured.")
	}
	/*
		increaseMetric, _ := app.Metric(config.Increase.metric())
		value, _ := config.Increase.value()
		if increaseMetric > value {
			currentUnits := uint(len(app.Units()))
			maxUnits := config.MaxUnits
			if maxUnits == 0 {
				maxUnits = 1
			}
			if currentUnits >= maxUnits {
				return nil
			}
			if wait, err := shouldWait(app, config.Increase.Wait); err != nil {
				return err
			} else if wait {
				return nil
			}
			evt, err := NewEvent(app, "increase")
			if err != nil {
				return fmt.Errorf("Error trying to insert auto scale event, auto scale aborted: %s", err.Error())
		 	}
			inc := config.Increase.Units
			if currentUnits+inc > config.MaxUnits {
				inc = config.MaxUnits - currentUnits
			}
			addUnitsErr := app.AddUnits(inc, nil)
			err = evt.update(addUnitsErr)
			if err != nil {
				log.Errorf("Error trying to update auto scale event: %s", err.Error())
			}
			return addUnitsErr
		}
		decreaseMetric, _ := app.Metric(config.Decrease.metric())
		value, _ = config.Decrease.value()
		if decreaseMetric < value {
			currentUnits := uint(len(app.Units()))
			minUnits := config.MinUnits
			if minUnits == 0 {
				minUnits = 1
			}
			if currentUnits <= minUnits {
				return nil
			}
			if wait, err := shouldWait(app, config.Decrease.Wait); err != nil {
				return err
			} else if wait {
				return nil
			}
			evt, err := NewEvent(app, "decrease")
			if err != nil {
				return fmt.Errorf("Error trying to insert auto scale event, auto scale aborted: %s", err.Error())
			}
			dec := config.Decrease.Units
			if currentUnits-dec < config.MinUnits {
				dec = currentUnits - config.MinUnits
			}
			removeUnitsErr := app.RemoveUnits(dec)
			err = evt.update(removeUnitsErr)
			if err != nil {
				log.Errorf("Error trying to update auto scale event: %s", err.Error())
			}
			return removeUnitsErr
		}
	*/
	return nil
}

func shouldWait(config *Config, waitPeriod time.Duration) (bool, error) {
	now := time.Now().UTC()
	lastEvent, err := lastScaleEvent(config.Name)
	if err != nil && err != mgo.ErrNotFound {
		return false, err
	}
	if err != mgo.ErrNotFound && lastEvent.EndTime.IsZero() {
		return true, nil
	}
	diff := now.Sub(lastEvent.EndTime)
	if diff > waitPeriod {
		return false, nil
	}
	return true, nil
}

func lastScaleEvent(appName string) (Event, error) {
	var event Event
	conn, err := db.Conn()
	if err != nil {
		return event, err
	}
	defer conn.Close()
	err = conn.AutoScale().Find(bson.M{"appname": appName}).Sort("-starttime").One(&event)
	return event, err
}

func ListAutoScaleHistory(appName string) ([]Event, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var history []Event
	q := bson.M{}
	if appName != "" {
		q["appname"] = appName
	}
	err = conn.AutoScale().Find(q).Sort("-_id").Limit(200).All(&history)
	if err != nil {
		return nil, err
	}
	return history, nil
}

func AutoScaleEnable(config *Config) error {
	config.Enabled = true
	return nil
}

func AutoScaleDisable(config *Config) error {
	config.Enabled = false
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/zserge/hid"
)

func main() {
	hid.UsbWalk(func(device hid.Device) {
		log.Printf("%+v\n", device.Info())
		if err := device.Open(); err != nil {
			log.Println("Open error: ", err)
			return
		}
		defer device.Close()

		log.Println(device.HIDReport())

		for i := 0; i < 10; i++ {
			log.Println(device.Read(8, 0))
		}
	})
}
<commit_msg>added interactive shell<commit_after>package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/peterh/liner"
	"github.com/zserge/hid"
)

func shell(device hid.Device, inputReportSize int) {
	if err := device.Open(); err != nil {
		fmt.Println("Open error: ", err)
		return
	}
	defer device.Close()

	if report, err := device.HIDReport(); err != nil {
		fmt.Println("HID report error:", err)
		return
	} else {
		fmt.Println("HID report", hex.EncodeToString(report))
	}

	go func() {
		for {
			if buf, err := device.Read(inputReportSize, 1*time.Second); err == nil {
				fmt.Println("\rInput report:  ", hex.EncodeToString(buf))
				syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
			}
		}
	}()

	commands := map[string]func([]byte){
		"output": func(b []byte) {
			if len(b) == 0 {
				fmt.Println("Invalid input: output report data expected")
			} else if n, err := device.Write(b, 1*time.Second); err != nil {
				fmt.Println("Output report write failed:", err)
			} else {
				fmt.Printf("Output report: written %d bytes\n", n)
			}
		},
		"set-feature": func(b []byte) {
			if len(b) == 0 {
				fmt.Println("Invalid input: feature report data expected")
			} else if err := device.SetReport(0, b); err != nil {
				fmt.Println("Feature report write failed:", err)
			} else {
				fmt.Printf("Feature report: " + hex.EncodeToString(b) + "\n")
			}
		},
		"get-feature": func(b []byte) {
			if b, err := device.GetReport(0); err != nil {
				fmt.Println("Feature report read failed:", err)
			} else {
				fmt.Println("Feature report: " + hex.EncodeToString(b) + "\n")
			}
		},
	}

	line := liner.NewLiner()
	defer line.Close()
	line.SetCtrlCAborts(true)
	line.SetCompleter(func(line string) (c []string) {
		for cmd, _ := range commands {
			if strings.HasPrefix(cmd, strings.ToLower(line)) {
				c = append(c, cmd+" ")
			}
		}
		return
	})

out:
	for {
		if s, err := line.Prompt("$ "); err == nil {
			if len(s) > 0 {
				line.AppendHistory(s)
				s = strings.ToLower(s)
				for cmd, f := range commands {
					if strings.HasPrefix(s, cmd) {
						s = strings.TrimSpace(s[len(cmd):])
						raw := []byte{}
						if len(s) > 0 {
							raw = make([]byte, len(s)/2, len(s)/2)
							if _, err := hex.Decode(raw, []byte(s)); err != nil {
								fmt.Println("Invalid input:", err)
								fmt.Println(">>", hex.EncodeToString(raw))
								continue out
							}
						}
						f(raw)
						continue out
					}
				}
			}
		} else {
			if err != liner.ErrPromptAborted {
				fmt.Println("Input error:", err)
			}
			break
		}
	}
}

func main() {

	if len(os.Args) == 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
		fmt.Println("USAGE:")
		fmt.Printf("  %s                list USB HID devices\n", os.Args[0])
		fmt.Printf("  %s <id> [size]    open USB HID device shell for the given input report size\n", os.Args[0])
		fmt.Printf("  %s -h|--help      show this help\n", os.Args[0])
		fmt.Println()
		return
	}

	// Without arguments - enumerate all HID devices
	if len(os.Args) == 1 {
		found := false
		hid.UsbWalk(func(device hid.Device) {
			info := device.Info()
			fmt.Printf("%04x:%04x:%04x\n", info.Vendor, info.Product, info.Revision)
			found = true
		})
		if !found {
			fmt.Println("No USB HID devices found\n")
		}
		return
	}

	inputReportSize := 1

	if len(os.Args) > 2 {
		if n, err := strconv.Atoi(os.Args[2]); err == nil {
			inputReportSize = n
		} else {
			log.Fatal(err)
		}
	}

	hid.UsbWalk(func(device hid.Device) {
		info := device.Info()
		id := fmt.Sprintf("%04x:%04x:%04x", info.Vendor, info.Product, info.Revision)
		if id != os.Args[1] {
			return
		}

		shell(device, inputReportSize)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/DataDog/dd-trace-go/tracer"
	"github.com/Sirupsen/logrus"
	"github.com/flachnetz/dd-zipkin-proxy"
	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	converter := DefaultSpanConverter{}
	zipkinproxy.Main(converter.Convert)
}

var reHash = regexp.MustCompile("\\b(?:[a-f0-9]{32}|[a-f0-9-]{8}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{12})\\b")
var reNumber = regexp.MustCompile("\\b[0-9]{2,}\\b")
var reIwgHash = regexp.MustCompile("iwg\\.[A-Za-z0-9]{12}\\b")

func SimplifyResourceName(value string) string {
	// check if we need to apply the regexp by checking if a match is possible or not
	digitCount := 0
	hashCharCount := 0
	for _, char := range value {
		isDigit := char >= '0' && char <= '9'
		if isDigit {
			digitCount++
		}

		if isDigit || char >= 'a' && char <= 'f' {
			hashCharCount++
		}
	}

	// only search for hash, if we have enough chars for it
	if hashCharCount >= 32 {
		value = reHash.ReplaceAllString(value, "_HASH_")
	}

	// only replace numbers, if we have enough digits for a match
	if digitCount >= 2 {
		value = reNumber.ReplaceAllString(value, "_NUMBER_")
	}

	if strings.HasPrefix(value, "iwg.") {
		value = reIwgHash.ReplaceAllString(value, "iwg._HASH_")
	}

	return value
}

type DefaultSpanConverter struct {
	current  map[uint64]string
	previous map[uint64]string
}

func (converter *DefaultSpanConverter) Convert(span *zipkincore.Span) *tracer.Span {
	if span.Name == "watch-config-key-values" {
		return nil
	}

	name := SimplifyResourceName(span.Name)

	converted := &tracer.Span{
		SpanID:   uint64(span.ID),
		ParentID: uint64(span.GetParentID()),
		TraceID:  uint64(span.TraceID),
		Name:     name,
		Resource: name,
		Start:    1000 * span.GetTimestamp(),
		Duration: 1000 * span.GetDuration(),
		Sampled:  true,
	}

	// datadog traces use a trace of 0
	if converted.ParentID == converted.SpanID {
		converted.ParentID = 0
	}

	// split "http:/some/url" or "get:/some/url"
	for _, prefix := range []string{"http:/", "get:/", "post:/"} {
		if strings.HasPrefix(converted.Name, prefix) {
			converted.Resource = converted.Name[len(prefix)-1:]
			converted.Name = prefix[:len(prefix)-2]
			break
		}
	}

	// convert binary annotations (like tags)
	if len(span.BinaryAnnotations) > 0 {
		converted.Meta = make(map[string]string, len(span.BinaryAnnotations))
		for _, an := range span.BinaryAnnotations {
			if an.AnnotationType == zipkincore.AnnotationType_STRING {
				key := an.Key

				// rename keys to better match the datadog one.
				switch key {
				case "http.status":
					key = "http.status_code"

				case "client.url":
					key = "http.url"
				}

				converted.Meta[key] = string(an.Value)
			}

			if an.Host != nil && an.Host.ServiceName != "" {
				converted.Service = an.Host.ServiceName
			}
		}

		if url := converted.Meta["http.url"]; url != "" {
			converted.Resource = SimplifyResourceName(url)
		}

		if status := converted.Meta["http.status_code"]; status != "" {
			if len(status) > 0 && '3' <= status[0] && status[0] <= '9' {
				if statusValue, err := strconv.Atoi(status); err == nil && statusValue >= 400 {
					converted.Error = int32(statusValue)
				}
			}
		}
	}

	// try to get the service from the cs/cr or sr/ss annotations
	var minTimestamp, maxTimestamp int64
	for _, an := range span.Annotations {
		if an.Host != nil && an.Host.ServiceName != "" {
			if an.Value == "sr" {
				converted.Service = an.Host.ServiceName
			}
		}

		if an.Timestamp < minTimestamp || minTimestamp == 0 {
			minTimestamp = an.Timestamp
		}

		if an.Timestamp > maxTimestamp {
			maxTimestamp = an.Timestamp
		}
	}

	if converted.Start == 0 {
		converted.Start = 1000 * minTimestamp
		converted.Duration = 1000 * (maxTimestamp - minTimestamp)
	}

	// simplify some names
	if strings.HasPrefix(converted.Name, "http:") {
		converted.Service = converted.Name[5:]
	}

	if converted.Name == "transaction" {
		converted.Service = "oracle"
	}

	if sql := converted.Meta["sql"]; sql != "" {
		delete(converted.Meta, "sql")
		converted.Service = "sql"
		converted.Resource = sql
	}

	if strings.HasPrefix(converted.Name, "redis:") {
		converted.Service = "redis"

		if key := converted.Meta["redis.key"]; key != "" {
			converted.Resource = SimplifyResourceName(key)

			// the hash is not really important later on. lets not spam datadog with it.
			delete(converted.Meta, "redis.key")
		}
	}

	if converted.Service == "core-services" {
		if strings.Contains(converted.Meta["http.url"], ":6080/") {
			converted.Service = "iwg-restrictor"
			converted.Name = iwgNameFromResource(converted.Resource, converted.Name)
			converted.Resource = dropDomainFromUrl(converted.Resource)
		}

		if strings.Contains(converted.Meta["http.url"], ":2080/") {
			converted.Service = "instant-win-game"
			converted.Name = "iwg-game"
			converted.Resource = dropDomainFromUrl(converted.Resource)
		}
	}

	// If we could not get a service, we'll try to get it from the parent span.
	// Try first in the current map, then in the previous one.
	if converted.Service == "" {
		parentService := converter.current[converted.ParentID]
		if parentService != "" {
			converted.Service = parentService
		} else {
			parentService = converter.previous[converted.ParentID]
			if parentService != "" {
				converted.Service = parentService
			}
		}

		// if we did not get a service, use a fallback
		if converted.Service == "" {
			logrus.Warnf("Could not get a service for this span: %+v", span)
			converted.Service = "unknown"
		}
	}

	if lc := converted.Meta["lc"]; lc != "" {
		delete(converted.Meta, "lc")

		if converted.Name == "" {
			converted.Name = converted.Meta["lc"]
		}

		if lc == "consul" {
			converted.Service = "consul"
		}
	}

	// guess a type for the datadog ui.
	if converted.Name == "transaction" || converted.Service == "redis" {
		converted.Type = "db"
	} else {
		converted.Type = "http"
	}

	if converted.Name == "hystrix" {
		converted.Resource = converted.Meta["thread"]
	}

	if converted.Name == "" {
		logrus.Warnf("Could not get a name for this span: %+v converted: %+v", span, converted)
	}

	// initialize history maps for span -> parent assignment
	if len(converter.current) >= 40000 || converter.current == nil {
		converter.previous = converter.current
		converter.current = make(map[uint64]string, 40000)
	}

	// remember the service for a short while
	converter.current[converted.SpanID] = converted.Service

	return converted
}

func dropDomainFromUrl(url string) string {
	switch {
	case strings.HasPrefix(url, "http://"):
		index := strings.IndexRune(url[7:], '/')
		return url[7+index:]

	case strings.HasPrefix(url, "https://"):
		index := strings.IndexRune(url[8:], '/')
		return url[8+index:]
	}

	return url
}

func iwgNameFromResource(resource string, fallback string) string {
	splittedUrl := strings.Split(strings.Trim(resource, "/"), "/")
	if len(splittedUrl) == 1 && splittedUrl[0] != "" {
		return splittedUrl[0]
	} else if len(splittedUrl) > 1 {
		return splittedUrl[len(splittedUrl)-2] + "/" + splittedUrl[len(splittedUrl)-1]
	}
	return fallback
}
<commit_msg>Use local component as service name.<commit_after>package main

import (
	"github.com/DataDog/dd-trace-go/tracer"
	"github.com/Sirupsen/logrus"
	"github.com/flachnetz/dd-zipkin-proxy"
	"github.com/openzipkin/zipkin-go-opentracing/_thrift/gen-go/zipkincore"
	"regexp"
	"strconv"
	"strings"
)

func main() {
	converter := DefaultSpanConverter{}
	zipkinproxy.Main(converter.Convert)
}

var reHash = regexp.MustCompile("\\b(?:[a-f0-9]{32}|[a-f0-9-]{8}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{4}-[a-f0-9-]{12})\\b")
var reNumber = regexp.MustCompile("\\b[0-9]{2,}\\b")
var reIwgHash = regexp.MustCompile("iwg\\.[A-Za-z0-9]{12}\\b")

func SimplifyResourceName(value string) string {
	// check if we need to apply the regexp by checking if a match is possible or not
	digitCount := 0
	hashCharCount := 0
	for _, char := range value {
		isDigit := char >= '0' && char <= '9'
		if isDigit {
			digitCount++
		}

		if isDigit || char >= 'a' && char <= 'f' {
			hashCharCount++
		}
	}

	// only search for hash, if we have enough chars for it
	if hashCharCount >= 32 {
		value = reHash.ReplaceAllString(value, "_HASH_")
	}

	// only replace numbers, if we have enough digits for a match
	if digitCount >= 2 {
		value = reNumber.ReplaceAllString(value, "_NUMBER_")
	}

	if strings.HasPrefix(value, "iwg.") {
		value = reIwgHash.ReplaceAllString(value, "iwg._HASH_")
	}

	return value
}

type DefaultSpanConverter struct {
	current  map[uint64]string
	previous map[uint64]string
}

func (converter *DefaultSpanConverter) Convert(span *zipkincore.Span) *tracer.Span {
	if span.Name == "watch-config-key-values" {
		return nil
	}

	name := SimplifyResourceName(span.Name)

	converted := &tracer.Span{
		SpanID:   uint64(span.ID),
		ParentID: uint64(span.GetParentID()),
		TraceID:  uint64(span.TraceID),
		Name:     name,
		Resource: name,
		Start:    1000 * span.GetTimestamp(),
		Duration: 1000 * span.GetDuration(),
		Sampled:  true,
	}

	// datadog traces use a trace of 0
	if converted.ParentID == converted.SpanID {
		converted.ParentID = 0
	}

	// split "http:/some/url" or "get:/some/url"
	for _, prefix := range []string{"http:/", "get:/", "post:/"} {
		if strings.HasPrefix(converted.Name, prefix) {
			converted.Resource = converted.Name[len(prefix)-1:]
			converted.Name = prefix[:len(prefix)-2]
			break
		}
	}

	// convert binary annotations (like tags)
	if len(span.BinaryAnnotations) > 0 {
		converted.Meta = make(map[string]string, len(span.BinaryAnnotations))
		for _, an := range span.BinaryAnnotations {
			if an.AnnotationType == zipkincore.AnnotationType_STRING {
				key := an.Key

				// rename keys to better match the datadog one.
				switch key {
				case "http.status":
					key = "http.status_code"

				case "client.url":
					key = "http.url"
				}

				converted.Meta[key] = string(an.Value)
			}

			if an.Host != nil && an.Host.ServiceName != "" {
				converted.Service = an.Host.ServiceName
			}
		}

		if url := converted.Meta["http.url"]; url != "" {
			converted.Resource = SimplifyResourceName(url)
		}

		if status := converted.Meta["http.status_code"]; status != "" {
			if len(status) > 0 && '3' <= status[0] && status[0] <= '9' {
				if statusValue, err := strconv.Atoi(status); err == nil && statusValue >= 400 {
					converted.Error = int32(statusValue)
				}
			}
		}
	}

	// try to get the service from the cs/cr or sr/ss annotations
	var minTimestamp, maxTimestamp int64
	for _, an := range span.Annotations {
		if an.Host != nil && an.Host.ServiceName != "" {
			if an.Value == "sr" {
				converted.Service = an.Host.ServiceName
			}
		}

		if an.Timestamp < minTimestamp || minTimestamp == 0 {
			minTimestamp = an.Timestamp
		}

		if an.Timestamp > maxTimestamp {
			maxTimestamp = an.Timestamp
		}
	}

	if converted.Start == 0 {
		converted.Start = 1000 * minTimestamp
		converted.Duration = 1000 * (maxTimestamp - minTimestamp)
	}

	// simplify some names
	if strings.HasPrefix(converted.Name, "http:") {
		converted.Service = converted.Name[5:]
	}

	if converted.Name == "transaction" {
		converted.Service = "oracle"
	}

	if sql := converted.Meta["sql"]; sql != "" {
		delete(converted.Meta, "sql")
		converted.Service = "sql"
		converted.Resource = sql
	}

	if strings.HasPrefix(converted.Name, "redis:") {
		converted.Service = "redis"

		if key := converted.Meta["redis.key"]; key != "" {
			converted.Resource = SimplifyResourceName(key)

			// the hash is not really important later on. lets not spam datadog with it.
			delete(converted.Meta, "redis.key")
		}
	}

	if converted.Service == "core-services" {
		if strings.Contains(converted.Meta["http.url"], ":6080/") {
			converted.Service = "iwg-restrictor"
			converted.Name = iwgNameFromResource(converted.Resource, converted.Name)
			converted.Resource = dropDomainFromUrl(converted.Resource)
		}

		if strings.Contains(converted.Meta["http.url"], ":2080/") {
			converted.Service = "instant-win-game"
			converted.Name = "iwg-game"
			converted.Resource = dropDomainFromUrl(converted.Resource)
		}

		if lc := converted.Meta["lc"]; lc != "" {
			converted.Name = lc
			converted.Service = lc
		}
	}

	// If we could not get a service, we'll try to get it from the parent span.
	// Try first in the current map, then in the previous one.
	if converted.Service == "" {
		parentService := converter.current[converted.ParentID]
		if parentService != "" {
			converted.Service = parentService
		} else {
			parentService = converter.previous[converted.ParentID]
			if parentService != "" {
				converted.Service = parentService
			}
		}

		// if we did not get a service, use a fallback
		if converted.Service == "" {
			logrus.Warnf("Could not get a service for this span: %+v", span)
			converted.Service = "unknown"
		}
	}

	if lc := converted.Meta["lc"]; lc != "" {
		delete(converted.Meta, "lc")

		if converted.Name == "" {
			converted.Name = converted.Meta["lc"]
		}

		if lc == "consul" {
			converted.Service = "consul"
		}
	}

	// guess a type for the datadog ui.
	if converted.Name == "transaction" || converted.Service == "redis" {
		converted.Type = "db"
	} else {
		converted.Type = "http"
	}

	if converted.Name == "hystrix" {
		converted.Resource = converted.Meta["thread"]
	}

	if converted.Name == "" {
		logrus.Warnf("Could not get a name for this span: %+v converted: %+v", span, converted)
	}

	// initialize history maps for span -> parent assignment
	if len(converter.current) >= 40000 || converter.current == nil {
		converter.previous = converter.current
		converter.current = make(map[uint64]string, 40000)
	}

	// remember the service for a short while
	converter.current[converted.SpanID] = converted.Service

	return converted
}

func dropDomainFromUrl(url string) string {
	switch {
	case strings.HasPrefix(url, "http://"):
		index := strings.IndexRune(url[7:], '/')
		return url[7+index:]

	case strings.HasPrefix(url, "https://"):
		index := strings.IndexRune(url[8:], '/')
		return url[8+index:]
	}

	return url
}

func iwgNameFromResource(resource string, fallback string) string {
	splittedUrl := strings.Split(strings.Trim(resource, "/"), "/")
	if len(splittedUrl) == 1 && splittedUrl[0] != "" {
		return splittedUrl[0]
	} else if len(splittedUrl) > 1 {
		return splittedUrl[len(splittedUrl)-2] + "/" + splittedUrl[len(splittedUrl)-1]
	}
	return fallback
}
<|endoftext|>


<commit_before>package main

import "fmt"

func a() error {
	fmt.Println("this function returns an error")
	return nil
}

func b() (int, error) {
	fmt.Println("this function returns an int and an error")
	return 0, nil
}

func main() {
	// Single error return
	_ = a()
	a()

	// Return another value and an error
	_, _ = b()
	b()

	// Method with a single error return
	x := t{}
	_ = x.a()
	x.a()

	// Method call on a struct member
	y := u{x}
	_ = y.t.a()
	y.t.a()

	m1 := map[string]func() error{"a": a}
	_ = m1["a"]()
	m1["a"]()
}
<commit_msg>Add extra test cases for blank identifiers<commit_after>package main

import "fmt"

func a() error {
	fmt.Println("this function returns an error")
	return nil
}

func b() (int, error) {
	fmt.Println("this function returns an int and an error")
	return 0, nil
}

func main() {
	// Single error return
	_ = a()
	a()

	// Return another value and an error
	_, _ = b()
	b()

	// Method with a single error return
	x := t{}
	_ = x.a()
	x.a()

	// Method call on a struct member
	y := u{x}
	_ = y.t.a()
	y.t.a()

	m1 := map[string]func() error{"a": a}
	_ = m1["a"]()
	m1["a"]()

	// Additional cases for assigning errors to blank identifier
	z, _ := b()
	_, w := a(), 5
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"net/http"

	"github.com/bradfitz/slice"
	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
	"github.com/samsarahq/thunder/livesql"
	"github.com/samsarahq/thunder/sqlgen"
)

var reactionTypes = map[string]bool{
	":)": true,
	":(": true,
}

type Message struct {
	Id   int64 `sql:",primary" graphql:",key"`
	Text string
}

type ReactionInstance struct {
	Id        int64 `sql:",primary"`
	MessageId int64
	Reaction  string
}

type Reaction struct {
	Reaction string `graphql:",key"`
	Count    int
}

type Server struct {
	db *livesql.LiveDB
}

type Query struct{}

func (s *Server) Query() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Query{},
	}
	spec.FieldFunc("messages", s.messages)
	return spec
}

func (s *Server) messages(ctx context.Context) ([]*Message, error) {
	var result []*Message
	if err := s.db.Query(ctx, &result, nil, nil); err != nil {
		return nil, err
	}
	return result, nil
}

type Mutation struct{}

func (s *Server) Mutation() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Mutation{},
	}
	spec.FieldFunc("addMessage", func(ctx context.Context, args struct{ Text string }) error {
		_, err := s.db.InsertRow(ctx, &Message{Text: args.Text})
		return err
	})
	spec.FieldFunc("deleteMessage", func(ctx context.Context, args struct{ Id int64 }) error {
		return s.db.DeleteRow(ctx, &Message{Id: args.Id})
	})
	spec.FieldFunc("addReaction", func(ctx context.Context, args struct {
		MessageId int64
		Reaction  string
	}) error {
		if _, ok := reactionTypes[args.Reaction]; !ok {
			return errors.New("reaction not allowed")
		}

		_, err := s.db.InsertRow(ctx, &ReactionInstance{MessageId: args.MessageId, Reaction: args.Reaction})
		return err
	})
	return spec
}

func (s *Server) Message() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Message{},
	}
	spec.FieldFunc("reactions", s.messageReactions)
	return spec
}

func (s *Server) messageReactions(ctx context.Context, m *Message) ([]*Reaction, error) {
	reactions := make(map[string]*Reaction)
	for reactionType := range reactionTypes {
		reactions[reactionType] = &Reaction{
			Reaction: reactionType,
		}
	}

	var instances []*ReactionInstance
	if err := s.db.Query(ctx, &instances, sqlgen.Filter{"message_id": m.Id}, nil); err != nil {
		return nil, err
	}
	for _, instance := range instances {
		reactions[instance.Reaction].Count++
	}

	var result []*Reaction
	for _, reaction := range reactions {
		result = append(result, reaction)
	}
	slice.Sort(result, func(a, b int) bool { return result[a].Reaction < result[b].Reaction })

	return result, nil
}

func main() {
	sqlgenSchema := sqlgen.NewSchema()
	sqlgenSchema.MustRegisterType("messages", sqlgen.AutoIncrement, Message{})
	sqlgenSchema.MustRegisterType("reaction_instances", sqlgen.AutoIncrement, ReactionInstance{})

	liveDB, err := livesql.Open("localhost", 3307, "root", "", "chat", sqlgenSchema)
	if err != nil {
		panic(err)
	}

	server := &Server{
		db: liveDB,
	}
	graphqlSchema := schemabuilder.MustBuildSchema(server)

	http.Handle("/graphql", graphql.Handler(graphqlSchema))
	if err := http.ListenAndServe(":3030", nil); err != nil {
		panic(err)
	}
}
<commit_msg>example: inline two fields functions<commit_after>package main

import (
	"context"
	"errors"
	"net/http"

	"github.com/bradfitz/slice"
	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
	"github.com/samsarahq/thunder/livesql"
	"github.com/samsarahq/thunder/sqlgen"
)

var reactionTypes = map[string]bool{
	":)": true,
	":(": true,
}

type Message struct {
	Id   int64 `sql:",primary" graphql:",key"`
	Text string
}

type ReactionInstance struct {
	Id        int64 `sql:",primary"`
	MessageId int64
	Reaction  string
}

type Reaction struct {
	Reaction string `graphql:",key"`
	Count    int
}

type Server struct {
	db *livesql.LiveDB
}

type Query struct{}

func (s *Server) Query() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Query{},
	}
	spec.FieldFunc("messages", func(ctx context.Context) ([]*Message, error) {
		var result []*Message
		if err := s.db.Query(ctx, &result, nil, nil); err != nil {
			return nil, err
		}
		return result, nil
	})
	return spec
}

type Mutation struct{}

func (s *Server) Mutation() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Mutation{},
	}
	spec.FieldFunc("addMessage", func(ctx context.Context, args struct{ Text string }) error {
		_, err := s.db.InsertRow(ctx, &Message{Text: args.Text})
		return err
	})
	spec.FieldFunc("deleteMessage", func(ctx context.Context, args struct{ Id int64 }) error {
		return s.db.DeleteRow(ctx, &Message{Id: args.Id})
	})
	spec.FieldFunc("addReaction", func(ctx context.Context, args struct {
		MessageId int64
		Reaction  string
	}) error {
		if _, ok := reactionTypes[args.Reaction]; !ok {
			return errors.New("reaction not allowed")
		}
		_, err := s.db.InsertRow(ctx, &ReactionInstance{MessageId: args.MessageId, Reaction: args.Reaction})
		return err
	})
	return spec
}

func (s *Server) Message() schemabuilder.Spec {
	spec := schemabuilder.Spec{
		Type: Message{},
	}
	spec.FieldFunc("reactions", func(ctx context.Context, m *Message) ([]*Reaction, error) {
		reactions := make(map[string]*Reaction)
		for reactionType := range reactionTypes {
			reactions[reactionType] = &Reaction{
				Reaction: reactionType,
			}
		}

		var instances []*ReactionInstance
		if err := s.db.Query(ctx, &instances, sqlgen.Filter{"message_id": m.Id}, nil); err != nil {
			return nil, err
		}
		for _, instance := range instances {
			reactions[instance.Reaction].Count++
		}

		var result []*Reaction
		for _, reaction := range reactions {
			result = append(result, reaction)
		}
		slice.Sort(result, func(a, b int) bool { return result[a].Reaction < result[b].Reaction })

		return result, nil
	})
	return spec
}

func main() {
	sqlgenSchema := sqlgen.NewSchema()
	sqlgenSchema.MustRegisterType("messages", sqlgen.AutoIncrement, Message{})
	sqlgenSchema.MustRegisterType("reaction_instances", sqlgen.AutoIncrement, ReactionInstance{})

	liveDB, err := livesql.Open("localhost", 3307, "root", "", "chat", sqlgenSchema)
	if err != nil {
		panic(err)
	}

	server := &Server{
		db: liveDB,
	}
	graphqlSchema := schemabuilder.MustBuildSchema(server)

	http.Handle("/graphql", graphql.Handler(graphqlSchema))
	if err := http.ListenAndServe(":3030", nil); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"

	_ "net/http/pprof"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/http3"
	"github.com/lucas-clemente/quic-go/integrationtests/tools/testserver"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/quictrace"
)

type binds []string

func (b binds) String() string {
	return strings.Join(b, ",")
}

func (b *binds) Set(v string) error {
	*b = strings.Split(v, ",")
	return nil
}

// Size is needed by the /demo/upload handler to determine the size of the uploaded file
type Size interface {
	Size() int64
}

var tracer quictrace.Tracer

func init() {
	tracer = quictrace.NewTracer()
}

func exportTraces() error {
	traces := tracer.GetAllTraces()
	if len(traces) != 1 {
		return errors.New("expected exactly one trace")
	}
	for _, trace := range traces {
		f, err := os.Create("trace.qtr")
		if err != nil {
			return err
		}
		if _, err := f.Write(trace); err != nil {
			return err
		}
		f.Close()
		fmt.Println("Wrote trace to", f.Name())
	}
	return nil
}

type tracingHandler struct {
	handler http.Handler
}

var _ http.Handler = &tracingHandler{}

func (h *tracingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.handler.ServeHTTP(w, r)
	if err := exportTraces(); err != nil {
		panic(err)
	}
}

func setupHandler(www string, trace bool) http.Handler {
	mux := http.NewServeMux()

	mux.Handle("/", http.FileServer(http.Dir(www)))
	mux.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) {
		// Small 40x40 png
		w.Write([]byte{
			0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
			0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28,
			0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00,
			0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb,
			0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18,
			0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00,
			0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
		})
	})

	mux.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "")
		for i := 0; i < 200; i++ {
			fmt.Fprintf(w, `<img src="/demo/tile?cachebust=%d">`, i)
		}
		io.WriteString(w, "")
	})

	mux.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("error reading body while handling /echo: %s\n", err.Error())
		}
		w.Write(body)
	})

	// accept file uploads and return the MD5 of the uploaded file
	// maximum accepted file size is 1 GB
	mux.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			err := r.ParseMultipartForm(1 << 30) // 1 GB
			if err == nil {
				var file multipart.File
				file, _, err = r.FormFile("uploadfile")
				if err == nil {
					var size int64
					if sizeInterface, ok := file.(Size); ok {
						size = sizeInterface.Size()
						b := make([]byte, size)
						file.Read(b)
						md5 := md5.Sum(b)
						fmt.Fprintf(w, "%x", md5)
						return
					}
					err = errors.New("couldn't get uploaded file size")
				}
			}
			if err != nil {
				utils.DefaultLogger.Infof("Error receiving upload: %#v", err)
			}
		}
		io.WriteString(w, `<form action="/demo/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="uploadfile">

				<input type="submit">
			</form>`)
	})

	mux.HandleFunc("/dynamic/", func(w http.ResponseWriter, r *http.Request) {
		const maxSize = 1 << 30 // 1 GB
		num, err := strconv.ParseInt(strings.ReplaceAll(r.RequestURI, "/dynamic/", ""), 10, 64)
		if err != nil || num <= 0 || num > maxSize {
			w.WriteHeader(400)
			return
		}
		w.Write(testserver.GeneratePRData(int(num)))
	})

	if !trace {
		return mux
	}
	return &tracingHandler{handler: mux}
}

func main() {
	// defer profile.Start().Stop()
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	// runtime.SetBlockProfileRate(1)

	verbose := flag.Bool("v", false, "verbose")
	bs := binds{}
	flag.Var(&bs, "bind", "bind to")
	www := flag.String("www", "/var/www", "www data")
	tcp := flag.Bool("tcp", false, "also listen on TCP")
	trace := flag.Bool("trace", false, "enable quic-trace")
	flag.Parse()

	logger := utils.DefaultLogger

	if *verbose {
		logger.SetLogLevel(utils.LogLevelDebug)
	} else {
		logger.SetLogLevel(utils.LogLevelInfo)
	}
	logger.SetLogTimeFormat("")

	if len(bs) == 0 {
		bs = binds{"localhost:6121"}
	}

	handler := setupHandler(*www, *trace)
	var quicConf *quic.Config
	if *trace {
		quicConf = &quic.Config{QuicTracer: tracer}
	}

	var wg sync.WaitGroup
	wg.Add(len(bs))
	for _, b := range bs {
		bCap := b
		go func() {
			var err error
			if *tcp {
				certFile, keyFile := testdata.GetCertificatePaths()
				err = http3.ListenAndServe(bCap, certFile, keyFile, nil)
			} else {
				server := http3.Server{
					Server:     &http.Server{Handler: handler, Addr: bCap},
					QuicConfig: quicConf,
				}
				err = server.ListenAndServeTLS(testdata.GetCertificatePaths())
			}
			if err != nil {
				fmt.Println(err)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<commit_msg>make example server conform with the GET /xxx format used for interop<commit_after>package main

import (
	"crypto/md5"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"

	_ "net/http/pprof"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/http3"
	"github.com/lucas-clemente/quic-go/integrationtests/tools/testserver"
	"github.com/lucas-clemente/quic-go/internal/testdata"
	"github.com/lucas-clemente/quic-go/internal/utils"
	"github.com/lucas-clemente/quic-go/quictrace"
)

type binds []string

func (b binds) String() string {
	return strings.Join(b, ",")
}

func (b *binds) Set(v string) error {
	*b = strings.Split(v, ",")
	return nil
}

// Size is needed by the /demo/upload handler to determine the size of the uploaded file
type Size interface {
	Size() int64
}

var tracer quictrace.Tracer

func init() {
	tracer = quictrace.NewTracer()
}

func exportTraces() error {
	traces := tracer.GetAllTraces()
	if len(traces) != 1 {
		return errors.New("expected exactly one trace")
	}
	for _, trace := range traces {
		f, err := os.Create("trace.qtr")
		if err != nil {
			return err
		}
		if _, err := f.Write(trace); err != nil {
			return err
		}
		f.Close()
		fmt.Println("Wrote trace to", f.Name())
	}
	return nil
}

type tracingHandler struct {
	handler http.Handler
}

var _ http.Handler = &tracingHandler{}

func (h *tracingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.handler.ServeHTTP(w, r)
	if err := exportTraces(); err != nil {
		panic(err)
	}
}

func setupHandler(www string, trace bool) http.Handler {
	mux := http.NewServeMux()

	if len(www) > 0 {
		mux.Handle("/", http.FileServer(http.Dir(www)))
	} else {
		mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			fmt.Printf("%#v\n", r)
			const maxSize = 1 << 30 // 1 GB
			num, err := strconv.ParseInt(strings.ReplaceAll(r.RequestURI, "/", ""), 10, 64)
			if err != nil || num <= 0 || num > maxSize {
				w.WriteHeader(400)
				return
			}
			w.Write(testserver.GeneratePRData(int(num)))
		})
	}

	mux.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) {
		// Small 40x40 png
		w.Write([]byte{
			0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
			0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28,
			0x01, 0x03, 0x00, 0x00, 0x00, 0xb6, 0x30, 0x2a, 0x2e, 0x00, 0x00, 0x00,
			0x03, 0x50, 0x4c, 0x54, 0x45, 0x5a, 0xc3, 0x5a, 0xad, 0x38, 0xaa, 0xdb,
			0x00, 0x00, 0x00, 0x0b, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0x63, 0x18,
			0x61, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe2, 0xb8, 0x75, 0x22, 0x00,
			0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
		})
	})

	mux.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "")
		for i := 0; i < 200; i++ {
			fmt.Fprintf(w, `<img src="/demo/tile?cachebust=%d">`, i)
		}
		io.WriteString(w, "")
	})

	mux.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("error reading body while handling /echo: %s\n", err.Error())
		}
		w.Write(body)
	})

	// accept file uploads and return the MD5 of the uploaded file
	// maximum accepted file size is 1 GB
	mux.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			err := r.ParseMultipartForm(1 << 30) // 1 GB
			if err == nil {
				var file multipart.File
				file, _, err = r.FormFile("uploadfile")
				if err == nil {
					var size int64
					if sizeInterface, ok := file.(Size); ok {
						size = sizeInterface.Size()
						b := make([]byte, size)
						file.Read(b)
						md5 := md5.Sum(b)
						fmt.Fprintf(w, "%x", md5)
						return
					}
					err = errors.New("couldn't get uploaded file size")
				}
			}
			if err != nil {
				utils.DefaultLogger.Infof("Error receiving upload: %#v", err)
			}
		}
		io.WriteString(w, `<form action="/demo/upload" method="post" enctype="multipart/form-data">
				<input type="file" name="uploadfile">

				<input type="submit">
			</form>`)
	})

	if !trace {
		return mux
	}
	return &tracingHandler{handler: mux}
}

func main() {
	// defer profile.Start().Stop()
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	// runtime.SetBlockProfileRate(1)

	verbose := flag.Bool("v", false, "verbose")
	bs := binds{}
	flag.Var(&bs, "bind", "bind to")
	www := flag.String("www", "", "www data")
	tcp := flag.Bool("tcp", false, "also listen on TCP")
	trace := flag.Bool("trace", false, "enable quic-trace")
	flag.Parse()

	logger := utils.DefaultLogger

	if *verbose {
		logger.SetLogLevel(utils.LogLevelDebug)
	} else {
		logger.SetLogLevel(utils.LogLevelInfo)
	}
	logger.SetLogTimeFormat("")

	if len(bs) == 0 {
		bs = binds{"localhost:6121"}
	}

	handler := setupHandler(*www, *trace)
	var quicConf *quic.Config
	if *trace {
		quicConf = &quic.Config{QuicTracer: tracer}
	}

	var wg sync.WaitGroup
	wg.Add(len(bs))
	for _, b := range bs {
		bCap := b
		go func() {
			var err error
			if *tcp {
				certFile, keyFile := testdata.GetCertificatePaths()
				err = http3.ListenAndServe(bCap, certFile, keyFile, nil)
			} else {
				server := http3.Server{
					Server:     &http.Server{Handler: handler, Addr: bCap},
					QuicConfig: quicConf,
				}
				err = server.ListenAndServeTLS(testdata.GetCertificatePaths())
			}
			if err != nil {
				fmt.Println(err)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<|endoftext|>