<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state_test

import (
	"github.com/juju/errors"
	"github.com/juju/names"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
)

type EnvironSuite struct {
	ConnSuite
}

var _ = gc.Suite(&EnvironSuite{})

func (s *EnvironSuite) TestEnvironment(c *gc.C) {
	env, err := s.State.Environment()
	c.Assert(err, jc.IsNil)

	expectedTag := names.NewEnvironTag(env.UUID())
	c.Assert(env.Tag(), gc.Equals, expectedTag)
	c.Assert(env.ServerTag(), gc.Equals, expectedTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

func (s *EnvironSuite) TestNewEnvironment(c *gc.C) {
	cfg, uuid := s.createTestEnvConfig(c)
	owner := names.NewUserTag("test@remote")

	env, st, err := s.State.NewEnvironment(cfg, owner)
	c.Assert(err, jc.IsNil)
	defer st.Close()

	envTag := names.NewEnvironTag(uuid)
	assertEnvMatches := func(env *state.Environment) {
		c.Assert(env.UUID(), gc.Equals, envTag.Id())
		c.Assert(env.Tag(), gc.Equals, envTag)
		c.Assert(env.ServerTag(), gc.Equals, s.envTag)
		c.Assert(env.Owner(), gc.Equals, owner)
		c.Assert(env.Name(), gc.Equals, "testing")
		c.Assert(env.Life(), gc.Equals, state.Alive)
	}
	assertEnvMatches(env)

	// Since the environ tag for the State connection is different,
	// asking for this environment through FindEntity returns a not found error.
	env, err = s.State.GetEnvironment(envTag)
	c.Assert(err, jc.IsNil)
	assertEnvMatches(env)

	env, err = st.Environment()
	c.Assert(err, jc.IsNil)
	assertEnvMatches(env)

	_, err = s.State.FindEntity(envTag)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	entity, err := st.FindEntity(envTag)
	c.Assert(err, jc.IsNil)
	c.Assert(entity.Tag(), gc.Equals, envTag)

	// Ensure the environment is functional by adding a machine
	_, err = st.AddMachine("quantal", state.JobManageEnviron)
	c.Assert(err, jc.IsNil)
}

func (s *EnvironSuite) TestStateServerEnvironment(c *gc.C) {
	env, err := s.State.StateServerEnvironment()
	c.Assert(err, jc.IsNil)

	expectedTag := names.NewEnvironTag(env.UUID())
	c.Assert(env.Tag(), gc.Equals, expectedTag)
	c.Assert(env.ServerTag(), gc.Equals, expectedTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

func (s *EnvironSuite) TestStateServerEnvironmentAccessibleFromOtherEnvironments(c *gc.C) {
	cfg, _ := s.createTestEnvConfig(c)
	_, st, err := s.State.NewEnvironment(cfg, names.NewUserTag("test@remote"))
	defer st.Close()

	env, err := st.StateServerEnvironment()
	c.Assert(err, jc.IsNil)
	c.Assert(env.Tag(), gc.Equals, s.envTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

// createTestEnvConfig use the existing State's config to create a new
// environment config for testing.
func (s *EnvironSuite) createTestEnvConfig(c *gc.C) (*config.Config, string) {
	uuid, err := utils.NewUUID()
	c.Assert(err, jc.IsNil)
	uuidStr := uuid.String()

	cfg, err := s.State.EnvironConfig()
	c.Assert(err, jc.IsNil)
	cfg, err = cfg.Apply(map[string]interface{}{
		"name": "testing",
		"uuid": uuidStr,
	})
	c.Assert(err, jc.IsNil)
	return cfg, uuidStr
}
<commit_msg>state: cleaner env config generation in EnvironSuite<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state_test

import (
	"github.com/juju/errors"
	"github.com/juju/names"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/testing"
)

type EnvironSuite struct {
	ConnSuite
}

var _ = gc.Suite(&EnvironSuite{})

func (s *EnvironSuite) TestEnvironment(c *gc.C) {
	env, err := s.State.Environment()
	c.Assert(err, jc.IsNil)

	expectedTag := names.NewEnvironTag(env.UUID())
	c.Assert(env.Tag(), gc.Equals, expectedTag)
	c.Assert(env.ServerTag(), gc.Equals, expectedTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

func (s *EnvironSuite) TestNewEnvironment(c *gc.C) {
	cfg, uuid := s.createTestEnvConfig(c)
	owner := names.NewUserTag("test@remote")

	env, st, err := s.State.NewEnvironment(cfg, owner)
	c.Assert(err, jc.IsNil)
	defer st.Close()

	envTag := names.NewEnvironTag(uuid)
	assertEnvMatches := func(env *state.Environment) {
		c.Assert(env.UUID(), gc.Equals, envTag.Id())
		c.Assert(env.Tag(), gc.Equals, envTag)
		c.Assert(env.ServerTag(), gc.Equals, s.envTag)
		c.Assert(env.Owner(), gc.Equals, owner)
		c.Assert(env.Name(), gc.Equals, "testing")
		c.Assert(env.Life(), gc.Equals, state.Alive)
	}
	assertEnvMatches(env)

	// Since the environ tag for the State connection is different,
	// asking for this environment through FindEntity returns a not found error.
	env, err = s.State.GetEnvironment(envTag)
	c.Assert(err, jc.IsNil)
	assertEnvMatches(env)

	env, err = st.Environment()
	c.Assert(err, jc.IsNil)
	assertEnvMatches(env)

	_, err = s.State.FindEntity(envTag)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	entity, err := st.FindEntity(envTag)
	c.Assert(err, jc.IsNil)
	c.Assert(entity.Tag(), gc.Equals, envTag)

	// Ensure the environment is functional by adding a machine
	_, err = st.AddMachine("quantal", state.JobManageEnviron)
	c.Assert(err, jc.IsNil)
}

func (s *EnvironSuite) TestStateServerEnvironment(c *gc.C) {
	env, err := s.State.StateServerEnvironment()
	c.Assert(err, jc.IsNil)

	expectedTag := names.NewEnvironTag(env.UUID())
	c.Assert(env.Tag(), gc.Equals, expectedTag)
	c.Assert(env.ServerTag(), gc.Equals, expectedTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

func (s *EnvironSuite) TestStateServerEnvironmentAccessibleFromOtherEnvironments(c *gc.C) {
	cfg, _ := s.createTestEnvConfig(c)
	_, st, err := s.State.NewEnvironment(cfg, names.NewUserTag("test@remote"))
	defer st.Close()

	env, err := st.StateServerEnvironment()
	c.Assert(err, jc.IsNil)
	c.Assert(env.Tag(), gc.Equals, s.envTag)
	c.Assert(env.Name(), gc.Equals, "testenv")
	c.Assert(env.Owner(), gc.Equals, s.owner)
	c.Assert(env.Life(), gc.Equals, state.Alive)

	testAnnotator(c, func() (state.Annotator, error) {
		return env, nil
	})
}

// createTestEnvConfig returns a new environment config and its UUID for testing.
func (s *EnvironSuite) createTestEnvConfig(c *gc.C) (*config.Config, string) {
	uuid, err := utils.NewUUID()
	c.Assert(err, gc.IsNil)
	return testing.CustomEnvironConfig(c, testing.Attrs{
		"name": "testing",
		"uuid": uuid.String(),
	}), uuid.String()
}
<|endoftext|>


<commit_before>package webhook

// DockerHubPayload is the data structure which holds
// the form in which request bodies are expected to be in
// when Docker hub invokes the webhook from a build trigger.
type DockerHubPayload struct {
	PushData    *DockerHubPushData   `json:"push_data"`
	CallbackURL string               `json:"callback_url"`
	Repository  *DockerHubRepository `json:"repository"`
}

// DockerHubPushData holds information specific to the push event
// from a Docker hub trigger.
type DockerHubPushData struct {
	PushedAt int64    `json:"pushed_at"`
	Images   []string `json:"images"`
	Tag      string   `json:"tag"`
	Pusher   string   `json:"pusher"`
}

// DockerHubRepository provides that data structure for all information about the docker
// repository the build occured for.
type DockerHubRepository struct {
	CommentCount    string  `json:"comment_count"`
	DateCreated     float64 `json:"date_created"`
	Description     string  `json:"description"`
	Dockerfile      string  `json:"dockerfile"`
	FullDescription string  `json:"full_description"`
	IsOfficial      bool    `json:"is_official"`
	IsPrivate       bool    `json:"is_private"`
	IsTrusted       bool    `json:"is_trusted"`
	Name            string  `json:"name"`
	Namespace       string  `json:"namespace"`
	Owner           string  `json:"owner"`
	RepoName        string  `json:"repo_name"`
	RepoURL         string  `json:"repo_url"`
	StarCount       int64   `json:"star_count"`
	Status          string  `json:"status"`
}
<commit_msg>Corrected field types for repo info sent by dockerhub.<commit_after>package webhook

// DockerHubPayload is the data structure which holds
// the form in which request bodies are expected to be in
// when Docker hub invokes the webhook from a build trigger.
type DockerHubPayload struct {
	PushData    *DockerHubPushData   `json:"push_data"`
	CallbackURL string               `json:"callback_url"`
	Repository  *DockerHubRepository `json:"repository"`
}

// DockerHubPushData holds information specific to the push event
// from a Docker hub trigger.
type DockerHubPushData struct {
	PushedAt int64    `json:"pushed_at"`
	Images   []string `json:"images"`
	Tag      string   `json:"tag"`
	Pusher   string   `json:"pusher"`
}

// DockerHubRepository provides that data structure for all information about the docker
// repository the build occured for.
type DockerHubRepository struct {
	CommentCount    int64  `json:"comment_count"`
	DateCreated     int64  `json:"date_created"`
	Description     string `json:"description"`
	Dockerfile      string `json:"dockerfile"`
	FullDescription string `json:"full_description"`
	IsOfficial      bool   `json:"is_official"`
	IsPrivate       bool   `json:"is_private"`
	IsTrusted       bool   `json:"is_trusted"`
	Name            string `json:"name"`
	Namespace       string `json:"namespace"`
	Owner           string `json:"owner"`
	RepoName        string `json:"repo_name"`
	RepoURL         string `json:"repo_url"`
	StarCount       int64  `json:"star_count"`
	Status          string `json:"status"`
}
<|endoftext|>


<commit_before>// +build docker

package dock

import (
	"fmt"
	"math/rand"
	"net"
	"runtime"
	"strconv"
	"testing"
	"time"

	"github.com/fsouza/go-dockerclient"
)

var (
	Address = `unix:///var/run/docker.sock`
)

type Config struct {
	docker.Config
}

type fullConfig struct {
	docker.Config
	docker.HostConfig
}

func run(t testing.TB, conf fullConfig) (addr string, closer func()) {
	if testing.Short() {
		t.SkipNow()
	}
	cli, err := docker.NewClient(Address)
	if err != nil {
		t.Fatal(err)
	}
	cont, err := cli.CreateContainer(docker.CreateContainerOptions{
		Config:     &conf.Config,
		HostConfig: &conf.HostConfig,
	})
	if err != nil {
		t.Skip(err)
	}

	closer = func() {
		cli.RemoveContainer(docker.RemoveContainerOptions{
			ID:    cont.ID,
			Force: true,
		})
	}

	if err := cli.StartContainer(cont.ID, &conf.HostConfig); err != nil {
		closer()
		t.Skip(err)
	}

	info, err := cli.InspectContainer(cont.ID)
	if err != nil {
		closer()
		t.Skip(err)
	}
	addr = info.NetworkSettings.IPAddress
	return
}

func randPort() int {
	const (
		min = 10000
		max = 30000
	)
	for {
		port := min + rand.Intn(max-min)
		c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", localhost, port), time.Second)
		if c != nil {
			c.Close()
		}
		if err != nil {
			// TODO: check for a specific error
			return port
		}
	}
}

const localhost = "127.0.0.1"

func RunAndWait(t testing.TB, conf Config, port string, check func(string) bool) (addr string, closer func()) {
	fconf := fullConfig{Config: conf.Config}
	if runtime.GOOS != "linux" {
		lport := strconv.Itoa(randPort())
		// nothing except Linux runs Docker natively,
		// so we randomize the port and expose it on Docker VM
		fconf.PortBindings = map[docker.Port][]docker.PortBinding{
			docker.Port(port + "/tcp"): {{
				HostIP:   localhost,
				HostPort: lport,
			}},
		}
		port = lport
	}
	addr, closer = run(t, fconf)
	if runtime.GOOS != "linux" {
		// VM ports are automatically exposed on localhost
		addr = localhost
	}
	addr += ":" + port
	if check == nil {
		check = waitPort
	}
	ok := false
	for i := 0; i < 10 && !ok; i++ {
		ok = check(addr)
		if !ok {
			time.Sleep(time.Second * 2)
		}
	}
	if !ok {
		closer()
		t.Fatal("Container check fails.")
	}
	return addr, closer
}

const wait = time.Second * 5

func waitPort(addr string) bool {
	start := time.Now()
	c, err := net.DialTimeout("tcp", addr, wait)
	if err == nil {
		c.Close()
	} else if dt := time.Since(start); dt < wait {
		time.Sleep(wait - dt)
	}
	return err == nil
}
<commit_msg>pull image from remote repository if there is not image at local machine<commit_after>// +build docker

package dock

import (
	"fmt"
	"math/rand"
	"net"
	"runtime"
	"strconv"
	"testing"
	"time"

	"github.com/fsouza/go-dockerclient"
)

var (
	Address = `unix:///var/run/docker.sock`
)

type Config struct {
	docker.Config
}

type fullConfig struct {
	docker.Config
	docker.HostConfig
}

func run(t testing.TB, conf fullConfig) (addr string, closer func()) {
	if testing.Short() {
		t.SkipNow()
	}
	cli, err := docker.NewClient(Address)
	if err != nil {
		t.Fatal(err)
	}

	// If there is not relevant image at local, pull image from remote repository.
	if err := cli.PullImage(
		docker.PullImageOptions{
			Repository: conf.Image,
		},
		docker.AuthConfiguration{},
	); err != nil {
		// If pull image fail, skip the test.
		t.Skip(err)
	}

	cont, err := cli.CreateContainer(docker.CreateContainerOptions{
		Config:     &conf.Config,
		HostConfig: &conf.HostConfig,
	})
	if err != nil {
		t.Skip(err)
	}

	closer = func() {
		cli.RemoveContainer(docker.RemoveContainerOptions{
			ID:    cont.ID,
			Force: true,
		})
	}

	if err := cli.StartContainer(cont.ID, &conf.HostConfig); err != nil {
		closer()
		t.Skip(err)
	}

	info, err := cli.InspectContainer(cont.ID)
	if err != nil {
		closer()
		t.Skip(err)
	}
	addr = info.NetworkSettings.IPAddress
	return
}

func randPort() int {
	const (
		min = 10000
		max = 30000
	)
	for {
		port := min + rand.Intn(max-min)
		c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", localhost, port), time.Second)
		if c != nil {
			c.Close()
		}
		if err != nil {
			// TODO: check for a specific error
			return port
		}
	}
}

const localhost = "127.0.0.1"

func RunAndWait(t testing.TB, conf Config, port string, check func(string) bool) (addr string, closer func()) {
	fconf := fullConfig{Config: conf.Config}
	if runtime.GOOS != "linux" {
		lport := strconv.Itoa(randPort())
		// nothing except Linux runs Docker natively,
		// so we randomize the port and expose it on Docker VM
		fconf.PortBindings = map[docker.Port][]docker.PortBinding{
			docker.Port(port + "/tcp"): {{
				HostIP:   localhost,
				HostPort: lport,
			}},
		}
		port = lport
	}
	addr, closer = run(t, fconf)
	if runtime.GOOS != "linux" {
		// VM ports are automatically exposed on localhost
		addr = localhost
	}
	addr += ":" + port
	if check == nil {
		check = waitPort
	}
	ok := false
	for i := 0; i < 10 && !ok; i++ {
		ok = check(addr)
		if !ok {
			time.Sleep(time.Second * 2)
		}
	}
	if !ok {
		closer()
		t.Fatal("Container check fails.")
	}
	return addr, closer
}

const wait = time.Second * 5

func waitPort(addr string) bool {
	start := time.Now()
	c, err := net.DialTimeout("tcp", addr, wait)
	if err == nil {
		c.Close()
	} else if dt := time.Since(start); dt < wait {
		time.Sleep(wait - dt)
	}
	return err == nil
}
<|endoftext|>


<commit_before>package hmac

import (
	"crypto/sha1"
	"hash"
	"sync"
)

func setZeroes(b []byte) {
	for i := range b {
		b[i] = 0
	}
}

func (h *hmac) resetTo(key []byte) {
	h.outer.Reset()
	h.inner.Reset()
	setZeroes(h.ipad)
	setZeroes(h.opad)
	if len(key) > h.blocksize {
		// If key is too big, hash it.
		h.outer.Write(key)
		key = h.outer.Sum(nil)
	}
	copy(h.ipad, key)
	copy(h.opad, key)
	for i := range h.ipad {
		h.ipad[i] ^= 0x36
	}
	for i := range h.opad {
		h.opad[i] ^= 0x5c
	}
	h.inner.Write(h.ipad)
}

var hmacSHA1Pool = &sync.Pool{
	New: func() interface{} {
		h := New(sha1.New, make([]byte, sha1.BlockSize))
		return h
	},
}

// AcquireSHA1 returns new HMAC from pool.
func AcquireSHA1(key []byte) hash.Hash {
	h := hmacSHA1Pool.Get().(*hmac)
	h.resetTo(key)
	return h
}

// PutSHA1 puts h to pool.
func PutSHA1(h hash.Hash) {
	hm := h.(*hmac)
	hmacSHA1Pool.Put(hm)
}
<commit_msg>hmac: add comment for setZeroes<commit_after>package hmac

import (
	"crypto/sha1"
	"hash"
	"sync"
)

// setZeroes sets all bytes from b to zeroes.
//
// See https://github.com/golang/go/issues/5373
func setZeroes(b []byte) {
	for i := range b {
		b[i] = 0
	}
}

func (h *hmac) resetTo(key []byte) {
	h.outer.Reset()
	h.inner.Reset()
	setZeroes(h.ipad)
	setZeroes(h.opad)
	if len(key) > h.blocksize {
		// If key is too big, hash it.
		h.outer.Write(key)
		key = h.outer.Sum(nil)
	}
	copy(h.ipad, key)
	copy(h.opad, key)
	for i := range h.ipad {
		h.ipad[i] ^= 0x36
	}
	for i := range h.opad {
		h.opad[i] ^= 0x5c
	}
	h.inner.Write(h.ipad)
}

var hmacSHA1Pool = &sync.Pool{
	New: func() interface{} {
		h := New(sha1.New, make([]byte, sha1.BlockSize))
		return h
	},
}

// AcquireSHA1 returns new HMAC from pool.
func AcquireSHA1(key []byte) hash.Hash {
	h := hmacSHA1Pool.Get().(*hmac)
	h.resetTo(key)
	return h
}

// PutSHA1 puts h to pool.
func PutSHA1(h hash.Hash) {
	hm := h.(*hmac)
	hmacSHA1Pool.Put(hm)
}
<|endoftext|>


<commit_before>package peer

import (
	"math"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/bitfield"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/mse"
	"github.com/cenkalti/rain/internal/peerconn"
	"github.com/cenkalti/rain/internal/peerconn/peerreader"
	"github.com/cenkalti/rain/internal/peerconn/peerwriter"
	"github.com/cenkalti/rain/internal/peerprotocol"
	"github.com/cenkalti/rain/internal/peersource"
	"github.com/cenkalti/rain/internal/pieceset"
	"github.com/rcrowley/go-metrics"
)

type Peer struct {
	*peerconn.Conn

	ConnectedAt time.Time

	Source peersource.Source

	Bitfield    *bitfield.Bitfield
	AllowedFast pieceset.PieceSet

	ID                [20]byte
	ExtensionsEnabled bool
	FastEnabled       bool
	DHTEnabled        bool
	EncryptionCipher  mse.CryptoMethod

	ClientInterested bool
	ClientChoking    bool
	PeerInterested   bool
	PeerChoking      bool

	OptimisticUnchoked bool

	// Snubbed means peer is sending pieces too slow.
	Snubbed bool

	Downloading bool

	downloadSpeed metrics.EWMA
	uploadSpeed   metrics.EWMA

	// Messages received while we don't have info yet are saved here.
	Messages []interface{}

	ExtensionHandshake *peerprotocol.ExtensionHandshakeMessage

	PEX *pex

	snubTimeout time.Duration
	snubTimer   *time.Timer

	closeC chan struct{}
	doneC  chan struct{}
}

type Message struct {
	*Peer
	Message interface{}
}

type PieceMessage struct {
	*Peer
	Piece peerreader.Piece
}

func New(conn net.Conn, source peersource.Source, id [20]byte, extensions [8]byte, cipher mse.CryptoMethod, pieceReadTimeout, snubTimeout time.Duration, maxRequestsIn int) *Peer {
	bf, _ := bitfield.NewBytes(extensions[:], 64)
	fastEnabled := bf.Test(61)
	extensionsEnabled := bf.Test(43)
	dhtEnabled := bf.Test(63)

	t := time.NewTimer(math.MaxInt64)
	t.Stop()
	return &Peer{
		Conn:              peerconn.New(conn, newPeerLogger(source, conn), pieceReadTimeout, maxRequestsIn, fastEnabled),
		Source:            source,
		ConnectedAt:       time.Now(),
		ID:                id,
		ClientChoking:     true,
		PeerChoking:       true,
		ExtensionsEnabled: extensionsEnabled,
		FastEnabled:       fastEnabled,
		DHTEnabled:        dhtEnabled,
		EncryptionCipher:  cipher,
		snubTimeout:       snubTimeout,
		snubTimer:         t,
		closeC:            make(chan struct{}),
		doneC:             make(chan struct{}),
		downloadSpeed:     metrics.NewEWMA1(),
		uploadSpeed:       metrics.NewEWMA1(),
	}
}

func newPeerLogger(src peersource.Source, conn net.Conn) logger.Logger {
	if src == peersource.Incoming {
		return logger.New("peer <- " + conn.RemoteAddr().String())
	}
	return logger.New("peer -> " + conn.RemoteAddr().String())
}

func (p *Peer) Close() {
	p.snubTimer.Stop()
	if p.PEX != nil {
		p.PEX.close()
	}
	close(p.closeC)
	p.Conn.Close()
	<-p.doneC
}

func (p *Peer) Done() chan struct{} {
	return p.doneC
}

func (p *Peer) Run(messages chan Message, pieces chan interface{}, snubbed, disconnect chan *Peer) {
	defer close(p.doneC)
	go p.Conn.Run()

	speedTicker := time.NewTicker(5 * time.Second)
	defer speedTicker.Stop()

	for {
		select {
		case pm, ok := <-p.Conn.Messages():
			if !ok {
				select {
				case disconnect <- p:
				case <-p.closeC:
				}
				return
			}
			if m, ok := pm.(peerreader.Piece); ok {
				p.downloadSpeed.Update(int64(len(m.Buffer.Data)))
				select {
				case pieces <- PieceMessage{Peer: p, Piece: m}:
				case <-p.closeC:
					return
				}
			} else {
				if m, ok := pm.(peerwriter.BlockUploaded); ok {
					p.uploadSpeed.Update(int64(m.Length))
				}
				select {
				case messages <- Message{Peer: p, Message: pm}:
				case <-p.closeC:
					return
				}
			}
		case <-p.snubTimer.C:
			select {
			case snubbed <- p:
			case <-p.closeC:
				return
			}
		case <-speedTicker.C:
			p.downloadSpeed.Tick()
			p.uploadSpeed.Tick()
		case <-p.closeC:
			return
		}
	}
}

func (p *Peer) StartPEX(initialPeers map[*Peer]struct{}) {
	if p.PEX == nil {
		p.PEX = newPEX(p.Conn, p.ExtensionHandshake.M[peerprotocol.ExtensionKeyPEX], initialPeers)
		go p.PEX.run()
	}
}

func (p *Peer) ResetSnubTimer() {
	p.snubTimer.Reset(p.snubTimeout)
}

func (p *Peer) StopSnubTimer() {
	p.snubTimer.Stop()
}

func (p *Peer) DownloadSpeed() uint {
	return uint(p.downloadSpeed.Rate())
}

func (p *Peer) UploadSpeed() uint {
	return uint(p.uploadSpeed.Rate())
}

func (p *Peer) Choke() {
	p.ClientChoking = true
	p.SendMessage(peerprotocol.ChokeMessage{})
}

func (p *Peer) Unchoke() {
	p.ClientChoking = false
	p.SendMessage(peerprotocol.UnchokeMessage{})
}

func (p *Peer) Choking() bool {
	return p.ClientChoking
}

func (p *Peer) Interested() bool {
	return p.PeerInterested
}

func (p *Peer) Optimistic() bool {
	return p.OptimisticUnchoked
}

func (p *Peer) SetOptimistic(value bool) {
	p.OptimisticUnchoked = value
}

func (p *Peer) MetadataSize() uint32 {
	return uint32(p.ExtensionHandshake.MetadataSize)
}

func (p *Peer) RequestMetadataPiece(index uint32) {
	p.SendMessage(peerprotocol.ExtensionMessage{
		ExtendedMessageID: p.ExtensionHandshake.M[peerprotocol.ExtensionKeyMetadata],
		Payload: peerprotocol.ExtensionMetadataMessage{
			Type:  peerprotocol.ExtensionMetadataMessageTypeRequest,
			Piece: index,
		},
	})
}

func (p *Peer) RequestPiece(index, begin, length uint32) {
	msg := peerprotocol.RequestMessage{Index: index, Begin: begin, Length: length}
	p.SendMessage(msg)
}

func (p *Peer) CancelPiece(index, begin, length uint32) {
	msg := peerprotocol.CancelMessage{RequestMessage: peerprotocol.RequestMessage{Index: index, Begin: begin, Length: length}}
	p.SendMessage(msg)
}

func (p *Peer) EnabledFast() bool {
	return p.FastEnabled
}

func (p *Peer) Client() string {
	if p.ExtensionHandshake == nil {
		return ""
	}
	if p.ExtensionHandshake.V != "" {
		return p.ExtensionHandshake.V
	}
	return asciify(clientID(string(p.ID[:])))
}
<commit_msg>asciify extended client name<commit_after>package peer

import (
	"math"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/bitfield"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/mse"
	"github.com/cenkalti/rain/internal/peerconn"
	"github.com/cenkalti/rain/internal/peerconn/peerreader"
	"github.com/cenkalti/rain/internal/peerconn/peerwriter"
	"github.com/cenkalti/rain/internal/peerprotocol"
	"github.com/cenkalti/rain/internal/peersource"
	"github.com/cenkalti/rain/internal/pieceset"
	"github.com/rcrowley/go-metrics"
)

type Peer struct {
	*peerconn.Conn

	ConnectedAt time.Time

	Source peersource.Source

	Bitfield    *bitfield.Bitfield
	AllowedFast pieceset.PieceSet

	ID                [20]byte
	ExtensionsEnabled bool
	FastEnabled       bool
	DHTEnabled        bool
	EncryptionCipher  mse.CryptoMethod

	ClientInterested bool
	ClientChoking    bool
	PeerInterested   bool
	PeerChoking      bool

	OptimisticUnchoked bool

	// Snubbed means peer is sending pieces too slow.
	Snubbed bool

	Downloading bool

	downloadSpeed metrics.EWMA
	uploadSpeed   metrics.EWMA

	// Messages received while we don't have info yet are saved here.
	Messages []interface{}

	ExtensionHandshake *peerprotocol.ExtensionHandshakeMessage

	PEX *pex

	snubTimeout time.Duration
	snubTimer   *time.Timer

	closeC chan struct{}
	doneC  chan struct{}
}

type Message struct {
	*Peer
	Message interface{}
}

type PieceMessage struct {
	*Peer
	Piece peerreader.Piece
}

func New(conn net.Conn, source peersource.Source, id [20]byte, extensions [8]byte, cipher mse.CryptoMethod, pieceReadTimeout, snubTimeout time.Duration, maxRequestsIn int) *Peer {
	bf, _ := bitfield.NewBytes(extensions[:], 64)
	fastEnabled := bf.Test(61)
	extensionsEnabled := bf.Test(43)
	dhtEnabled := bf.Test(63)

	t := time.NewTimer(math.MaxInt64)
	t.Stop()
	return &Peer{
		Conn:              peerconn.New(conn, newPeerLogger(source, conn), pieceReadTimeout, maxRequestsIn, fastEnabled),
		Source:            source,
		ConnectedAt:       time.Now(),
		ID:                id,
		ClientChoking:     true,
		PeerChoking:       true,
		ExtensionsEnabled: extensionsEnabled,
		FastEnabled:       fastEnabled,
		DHTEnabled:        dhtEnabled,
		EncryptionCipher:  cipher,
		snubTimeout:       snubTimeout,
		snubTimer:         t,
		closeC:            make(chan struct{}),
		doneC:             make(chan struct{}),
		downloadSpeed:     metrics.NewEWMA1(),
		uploadSpeed:       metrics.NewEWMA1(),
	}
}

func newPeerLogger(src peersource.Source, conn net.Conn) logger.Logger {
	if src == peersource.Incoming {
		return logger.New("peer <- " + conn.RemoteAddr().String())
	}
	return logger.New("peer -> " + conn.RemoteAddr().String())
}

func (p *Peer) Close() {
	p.snubTimer.Stop()
	if p.PEX != nil {
		p.PEX.close()
	}
	close(p.closeC)
	p.Conn.Close()
	<-p.doneC
}

func (p *Peer) Done() chan struct{} {
	return p.doneC
}

func (p *Peer) Run(messages chan Message, pieces chan interface{}, snubbed, disconnect chan *Peer) {
	defer close(p.doneC)
	go p.Conn.Run()

	speedTicker := time.NewTicker(5 * time.Second)
	defer speedTicker.Stop()

	for {
		select {
		case pm, ok := <-p.Conn.Messages():
			if !ok {
				select {
				case disconnect <- p:
				case <-p.closeC:
				}
				return
			}
			if m, ok := pm.(peerreader.Piece); ok {
				p.downloadSpeed.Update(int64(len(m.Buffer.Data)))
				select {
				case pieces <- PieceMessage{Peer: p, Piece: m}:
				case <-p.closeC:
					return
				}
			} else {
				if m, ok := pm.(peerwriter.BlockUploaded); ok {
					p.uploadSpeed.Update(int64(m.Length))
				}
				select {
				case messages <- Message{Peer: p, Message: pm}:
				case <-p.closeC:
					return
				}
			}
		case <-p.snubTimer.C:
			select {
			case snubbed <- p:
			case <-p.closeC:
				return
			}
		case <-speedTicker.C:
			p.downloadSpeed.Tick()
			p.uploadSpeed.Tick()
		case <-p.closeC:
			return
		}
	}
}

func (p *Peer) StartPEX(initialPeers map[*Peer]struct{}) {
	if p.PEX == nil {
		p.PEX = newPEX(p.Conn, p.ExtensionHandshake.M[peerprotocol.ExtensionKeyPEX], initialPeers)
		go p.PEX.run()
	}
}

func (p *Peer) ResetSnubTimer() {
	p.snubTimer.Reset(p.snubTimeout)
}

func (p *Peer) StopSnubTimer() {
	p.snubTimer.Stop()
}

func (p *Peer) DownloadSpeed() uint {
	return uint(p.downloadSpeed.Rate())
}

func (p *Peer) UploadSpeed() uint {
	return uint(p.uploadSpeed.Rate())
}

func (p *Peer) Choke() {
	p.ClientChoking = true
	p.SendMessage(peerprotocol.ChokeMessage{})
}

func (p *Peer) Unchoke() {
	p.ClientChoking = false
	p.SendMessage(peerprotocol.UnchokeMessage{})
}

func (p *Peer) Choking() bool {
	return p.ClientChoking
}

func (p *Peer) Interested() bool {
	return p.PeerInterested
}

func (p *Peer) Optimistic() bool {
	return p.OptimisticUnchoked
}

func (p *Peer) SetOptimistic(value bool) {
	p.OptimisticUnchoked = value
}

func (p *Peer) MetadataSize() uint32 {
	return uint32(p.ExtensionHandshake.MetadataSize)
}

func (p *Peer) RequestMetadataPiece(index uint32) {
	p.SendMessage(peerprotocol.ExtensionMessage{
		ExtendedMessageID: p.ExtensionHandshake.M[peerprotocol.ExtensionKeyMetadata],
		Payload: peerprotocol.ExtensionMetadataMessage{
			Type:  peerprotocol.ExtensionMetadataMessageTypeRequest,
			Piece: index,
		},
	})
}

func (p *Peer) RequestPiece(index, begin, length uint32) {
	msg := peerprotocol.RequestMessage{Index: index, Begin: begin, Length: length}
	p.SendMessage(msg)
}

func (p *Peer) CancelPiece(index, begin, length uint32) {
	msg := peerprotocol.CancelMessage{RequestMessage: peerprotocol.RequestMessage{Index: index, Begin: begin, Length: length}}
	p.SendMessage(msg)
}

func (p *Peer) EnabledFast() bool {
	return p.FastEnabled
}

func (p *Peer) Client() string {
	if p.ExtensionHandshake == nil {
		return ""
	}
	var client string
	if p.ExtensionHandshake.V != "" {
		client = p.ExtensionHandshake.V
	} else {
		client = clientID(string(p.ID[:]))
	}
	return asciify(client)
}
<|endoftext|>


<commit_before>package decision

import (
	"errors"
	"fmt"
	"math"
	"strings"
	"sync"
	"testing"

	context "context"
	blocks "github.com/ipfs/go-ipfs/blocks"
	blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
	message "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	testutil "github.com/ipfs/go-ipfs/thirdparty/testutil"
	ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore"
	dssync "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore/sync"
	peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer"
)

type peerAndEngine struct {
	Peer   peer.ID
	Engine *Engine
}

func newEngine(ctx context.Context, idStr string) peerAndEngine {
	return peerAndEngine{
		Peer: peer.ID(idStr),
		//Strategy: New(true),
		Engine: NewEngine(ctx,
			blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))),
	}
}

func TestConsistentAccounting(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sender := newEngine(ctx, "Ernie")
	receiver := newEngine(ctx, "Bert")

	// Send messages from Ernie to Bert
	for i := 0; i < 1000; i++ {

		m := message.New(false)
		content := []string{"this", "is", "message", "i"}
		m.AddBlock(blocks.NewBlock([]byte(strings.Join(content, " "))))

		sender.Engine.MessageSent(receiver.Peer, m)
		receiver.Engine.MessageReceived(sender.Peer, m)
	}

	// Ensure sender records the change
	if sender.Engine.numBytesSentTo(receiver.Peer) == 0 {
		t.Fatal("Sent bytes were not recorded")
	}

	// Ensure sender and receiver have the same values
	if sender.Engine.numBytesSentTo(receiver.Peer) != receiver.Engine.numBytesReceivedFrom(sender.Peer) {
		t.Fatal("Inconsistent book-keeping. Strategies don't agree")
	}

	// Ensure sender didn't record receving anything. And that the receiver
	// didn't record sending anything
	if receiver.Engine.numBytesSentTo(sender.Peer) != 0 || sender.Engine.numBytesReceivedFrom(receiver.Peer) != 0 {
		t.Fatal("Bert didn't send bytes to Ernie")
	}
}

func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) {

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sanfrancisco := newEngine(ctx, "sf")
	seattle := newEngine(ctx, "sea")

	m := message.New(true)

	sanfrancisco.Engine.MessageSent(seattle.Peer, m)
	seattle.Engine.MessageReceived(sanfrancisco.Peer, m)

	if seattle.Peer == sanfrancisco.Peer {
		t.Fatal("Sanity Check: Peers have same Key!")
	}

	if !peerIsPartner(seattle.Peer, sanfrancisco.Engine) {
		t.Fatal("Peer wasn't added as a Partner")
	}

	if !peerIsPartner(sanfrancisco.Peer, seattle.Engine) {
		t.Fatal("Peer wasn't added as a Partner")
	}
}

func peerIsPartner(p peer.ID, e *Engine) bool {
	for _, partner := range e.Peers() {
		if partner == p {
			return true
		}
	}
	return false
}

func TestOutboxClosedWhenEngineClosed(t *testing.T) {
	t.SkipNow() // TODO implement *Engine.Close
	e := NewEngine(context.Background(), blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())))
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		for nextEnvelope := range e.Outbox() {
			<-nextEnvelope
		}
		wg.Done()
	}()
	// e.Close()
	wg.Wait()
	if _, ok := <-e.Outbox(); ok {
		t.Fatal("channel should be closed")
	}
}

func TestPartnerWantsThenCancels(t *testing.T) {
	numRounds := 10
	if testing.Short() {
		numRounds = 1
	}
	alphabet := strings.Split("abcdefghijklmnopqrstuvwxyz", "")
	vowels := strings.Split("aeiou", "")

	type testCase [][]string
	testcases := []testCase{
		{
			alphabet, vowels,
		},
		{
			alphabet, stringsComplement(alphabet, vowels),
		},
	}

	bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))
	for _, letter := range alphabet {
		block := blocks.NewBlock([]byte(letter))
		if err := bs.Put(block); err != nil {
			t.Fatal(err)
		}
	}

	for i := 0; i < numRounds; i++ {
		for _, testcase := range testcases {
			set := testcase[0]
			cancels := testcase[1]
			keeps := stringsComplement(set, cancels)

			e := NewEngine(context.Background(), bs)
			partner := testutil.RandPeerIDFatal(t)

			partnerWants(e, set, partner)
			partnerCancels(e, cancels, partner)
			if err := checkHandledInOrder(t, e, keeps); err != nil {
				t.Logf("run #%d of %d", i, numRounds)
				t.Fatal(err)
			}
		}
	}
}

func partnerWants(e *Engine, keys []string, partner peer.ID) {
	add := message.New(false)
	for i, letter := range keys {
		block := blocks.NewBlock([]byte(letter))
		add.AddEntry(block.Cid(), math.MaxInt32-i)
	}
	e.MessageReceived(partner, add)
}

func partnerCancels(e *Engine, keys []string, partner peer.ID) {
	cancels := message.New(false)
	for _, k := range keys {
		block := blocks.NewBlock([]byte(k))
		cancels.Cancel(block.Cid())
	}
	e.MessageReceived(partner, cancels)
}

func checkHandledInOrder(t *testing.T, e *Engine, keys []string) error {
	for _, k := range keys {
		next := <-e.Outbox()
		envelope := <-next
		received := envelope.Block
		expected := blocks.NewBlock([]byte(k))
		if !received.Cid().Equals(expected.Cid()) {
			return errors.New(fmt.Sprintln("received", string(received.RawData()), "expected", string(expected.RawData())))
		}
	}
	return nil
}

func stringsComplement(set, subset []string) []string {
	m := make(map[string]struct{})
	for _, letter := range subset {
		m[letter] = struct{}{}
	}
	var complement []string
	for _, letter := range set {
		if _, exists := m[letter]; !exists {
			complement = append(complement, letter)
		}
	}
	return complement
}
<commit_msg>test for partner removal<commit_after>package decision

import (
	"errors"
	"fmt"
	"math"
	"strings"
	"sync"
	"testing"

	context "context"
	blocks "github.com/ipfs/go-ipfs/blocks"
	blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
	message "github.com/ipfs/go-ipfs/exchange/bitswap/message"
	testutil "github.com/ipfs/go-ipfs/thirdparty/testutil"
	ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore"
	dssync "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore/sync"
	peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer"
)

type peerAndEngine struct {
	Peer   peer.ID
	Engine *Engine
}

func newEngine(ctx context.Context, idStr string) peerAndEngine {
	return peerAndEngine{
		Peer: peer.ID(idStr),
		//Strategy: New(true),
		Engine: NewEngine(ctx,
			blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))),
	}
}

func TestConsistentAccounting(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sender := newEngine(ctx, "Ernie")
	receiver := newEngine(ctx, "Bert")

	// Send messages from Ernie to Bert
	for i := 0; i < 1000; i++ {

		m := message.New(false)
		content := []string{"this", "is", "message", "i"}
		m.AddBlock(blocks.NewBlock([]byte(strings.Join(content, " "))))

		sender.Engine.MessageSent(receiver.Peer, m)
		receiver.Engine.MessageReceived(sender.Peer, m)
	}

	// Ensure sender records the change
	if sender.Engine.numBytesSentTo(receiver.Peer) == 0 {
		t.Fatal("Sent bytes were not recorded")
	}

	// Ensure sender and receiver have the same values
	if sender.Engine.numBytesSentTo(receiver.Peer) != receiver.Engine.numBytesReceivedFrom(sender.Peer) {
		t.Fatal("Inconsistent book-keeping. Strategies don't agree")
	}

	// Ensure sender didn't record receving anything. And that the receiver
	// didn't record sending anything
	if receiver.Engine.numBytesSentTo(sender.Peer) != 0 || sender.Engine.numBytesReceivedFrom(receiver.Peer) != 0 {
		t.Fatal("Bert didn't send bytes to Ernie")
	}
}

func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) {

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sanfrancisco := newEngine(ctx, "sf")
	seattle := newEngine(ctx, "sea")

	m := message.New(true)

	sanfrancisco.Engine.MessageSent(seattle.Peer, m)
	seattle.Engine.MessageReceived(sanfrancisco.Peer, m)

	if seattle.Peer == sanfrancisco.Peer {
		t.Fatal("Sanity Check: Peers have same Key!")
	}

	if !peerIsPartner(seattle.Peer, sanfrancisco.Engine) {
		t.Fatal("Peer wasn't added as a Partner")
	}

	if !peerIsPartner(sanfrancisco.Peer, seattle.Engine) {
		t.Fatal("Peer wasn't added as a Partner")
	}

	seattle.Engine.PeerDisconnected(sanfrancisco.Peer)
	if peerIsPartner(sanfrancisco.Peer, seattle.Engine) {
		t.Fatal("expected peer to be removed")
	}
}

func peerIsPartner(p peer.ID, e *Engine) bool {
	for _, partner := range e.Peers() {
		if partner == p {
			return true
		}
	}
	return false
}

func TestOutboxClosedWhenEngineClosed(t *testing.T) {
	t.SkipNow() // TODO implement *Engine.Close
	e := NewEngine(context.Background(), blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())))
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		for nextEnvelope := range e.Outbox() {
			<-nextEnvelope
		}
		wg.Done()
	}()
	// e.Close()
	wg.Wait()
	if _, ok := <-e.Outbox(); ok {
		t.Fatal("channel should be closed")
	}
}

func TestPartnerWantsThenCancels(t *testing.T) {
	numRounds := 10
	if testing.Short() {
		numRounds = 1
	}
	alphabet := strings.Split("abcdefghijklmnopqrstuvwxyz", "")
	vowels := strings.Split("aeiou", "")

	type testCase [][]string
	testcases := []testCase{
		{
			alphabet, vowels,
		},
		{
			alphabet, stringsComplement(alphabet, vowels),
		},
	}

	bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))
	for _, letter := range alphabet {
		block := blocks.NewBlock([]byte(letter))
		if err := bs.Put(block); err != nil {
			t.Fatal(err)
		}
	}

	for i := 0; i < numRounds; i++ {
		for _, testcase := range testcases {
			set := testcase[0]
			cancels := testcase[1]
			keeps := stringsComplement(set, cancels)

			e := NewEngine(context.Background(), bs)
			partner := testutil.RandPeerIDFatal(t)

			partnerWants(e, set, partner)
			partnerCancels(e, cancels, partner)
			if err := checkHandledInOrder(t, e, keeps); err != nil {
				t.Logf("run #%d of %d", i, numRounds)
				t.Fatal(err)
			}
		}
	}
}

func partnerWants(e *Engine, keys []string, partner peer.ID) {
	add := message.New(false)
	for i, letter := range keys {
		block := blocks.NewBlock([]byte(letter))
		add.AddEntry(block.Cid(), math.MaxInt32-i)
	}
	e.MessageReceived(partner, add)
}

func partnerCancels(e *Engine, keys []string, partner peer.ID) {
	cancels := message.New(false)
	for _, k := range keys {
		block := blocks.NewBlock([]byte(k))
		cancels.Cancel(block.Cid())
	}
	e.MessageReceived(partner, cancels)
}

func checkHandledInOrder(t *testing.T, e *Engine, keys []string) error {
	for _, k := range keys {
		next := <-e.Outbox()
		envelope := <-next
		received := envelope.Block
		expected := blocks.NewBlock([]byte(k))
		if !received.Cid().Equals(expected.Cid()) {
			return errors.New(fmt.Sprintln("received", string(received.RawData()), "expected", string(expected.RawData())))
		}
	}
	return nil
}

func stringsComplement(set, subset []string) []string {
	m := make(map[string]struct{})
	for _, letter := range subset {
		m[letter] = struct{}{}
	}
	var complement []string
	for _, letter := range set {
		if _, exists := m[letter]; !exists {
			complement = append(complement, letter)
		}
	}
	return complement
}
<|endoftext|>


<commit_before>// Package tmpl provides templating utilities for goreleser
package tmpl

import (
	"bytes"
	"text/template"
	"time"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/masterminds/semver"
	"github.com/pkg/errors"
)

// Template holds data that can be applied to a template string
type Template struct {
	fields fields
}

type fields map[string]interface{}

const (
	// general keys
	projectName = "ProjectName"
	version     = "Version"
	tag         = "Tag"
	commit      = "Commit"
	major       = "Major"
	minor       = "Minor"
	patch       = "Patch"
	env         = "Env"
	date        = "Date"
	timestamp   = "Timestamp"

	// artifact-only keys
	os     = "Os"
	arch   = "Arch"
	arm    = "Arm"
	binary = "Binary"
)

// New Template
func New(ctx *context.Context) *Template {
	return &Template{
		fields: fields{
			projectName: ctx.Config.ProjectName,
			version:     ctx.Version,
			tag:         ctx.Git.CurrentTag,
			commit:      ctx.Git.Commit,
			env:         ctx.Env,
			date:        time.Now().UTC().Format(time.RFC3339),
			timestamp:   time.Now().UTC().Unix(),
		},
	}
}

// WithArtifacts populate fields from the artifact and replacements
func (t *Template) WithArtifact(a artifact.Artifact, replacements map[string]string) *Template {
	var binary = a.Extra[binary]
	if binary == "" {
		binary = t.fields[projectName].(string)
	}
	t.fields[os] = replace(replacements, a.Goos)
	t.fields[arch] = replace(replacements, a.Goarch)
	t.fields[arm] = replace(replacements, a.Goarm)
	t.fields[binary] = binary
	return t
}

// Apply applies the given string against the fields stored in the template.
func (t *Template) Apply(s string) (string, error) {
	var out bytes.Buffer
	tmpl, err := template.New("tmpl").
		Option("missingkey=error").
		Funcs(template.FuncMap{
			"time": func(s string) string {
				return time.Now().UTC().Format(s)
			},
		}).
		Parse(s)
	if err != nil {
		return "", err
	}

	sv, err := semver.NewVersion(t.fields[tag].(string))
	if err != nil {
		return "", errors.Wrap(err, "tmpl")
	}
	t.fields[major] = sv.Major()
	t.fields[minor] = sv.Minor()
	t.fields[patch] = sv.Patch()

	err = tmpl.Execute(&out, t.fields)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}
<commit_msg>fix: broken binary name<commit_after>// Package tmpl provides templating utilities for goreleser
package tmpl

import (
	"bytes"
	"text/template"
	"time"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/masterminds/semver"
	"github.com/pkg/errors"
)

// Template holds data that can be applied to a template string
type Template struct {
	fields fields
}

type fields map[string]interface{}

const (
	// general keys
	projectName = "ProjectName"
	version     = "Version"
	tag         = "Tag"
	commit      = "Commit"
	major       = "Major"
	minor       = "Minor"
	patch       = "Patch"
	env         = "Env"
	date        = "Date"
	timestamp   = "Timestamp"

	// artifact-only keys
	os     = "Os"
	arch   = "Arch"
	arm    = "Arm"
	binary = "Binary"
)

// New Template
func New(ctx *context.Context) *Template {
	return &Template{
		fields: fields{
			projectName: ctx.Config.ProjectName,
			version:     ctx.Version,
			tag:         ctx.Git.CurrentTag,
			commit:      ctx.Git.Commit,
			env:         ctx.Env,
			date:        time.Now().UTC().Format(time.RFC3339),
			timestamp:   time.Now().UTC().Unix(),
		},
	}
}

// WithArtifacts populate fields from the artifact and replacements
func (t *Template) WithArtifact(a artifact.Artifact, replacements map[string]string) *Template {
	var bin = a.Extra[binary]
	if bin == "" {
		bin = t.fields[projectName].(string)
	}
	t.fields[os] = replace(replacements, a.Goos)
	t.fields[arch] = replace(replacements, a.Goarch)
	t.fields[arm] = replace(replacements, a.Goarm)
	t.fields[binary] = bin
	return t
}

// Apply applies the given string against the fields stored in the template.
func (t *Template) Apply(s string) (string, error) {
	var out bytes.Buffer
	tmpl, err := template.New("tmpl").
		Option("missingkey=error").
		Funcs(template.FuncMap{
			"time": func(s string) string {
				return time.Now().UTC().Format(s)
			},
		}).
		Parse(s)
	if err != nil {
		return "", err
	}

	sv, err := semver.NewVersion(t.fields[tag].(string))
	if err != nil {
		return "", errors.Wrap(err, "tmpl")
	}
	t.fields[major] = sv.Major()
	t.fields[minor] = sv.Minor()
	t.fields[patch] = sv.Patch()

	err = tmpl.Execute(&out, t.fields)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}
<|endoftext|>


<commit_before>package interpreter

import (
	"bytes"
	"errors"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"../dos"
)

type StatementT struct {
	Argv     []string
	Redirect []*Redirecter
	Term     string
}

var prefix []string = []string{" 0<", " 1>", " 2>"}

var PercentFunc = map[string]func() string{
	"CD": func() string {
		wd, err := os.Getwd()
		if err == nil {
			return wd
		} else {
			return ""
		}
	},
	"ERRORLEVEL": func() string {
		return ErrorLevel
	},
}

var rxUnicode = regexp.MustCompile("^[uU]\\+?([0-9a-fA-F]+)$")

func chomp(buffer *bytes.Buffer) {
	original := buffer.String()
	buffer.Reset()
	var lastchar rune
	for i, ch := range original {
		if i > 0 {
			buffer.WriteRune(lastchar)
		}
		lastchar = ch
	}
}

func dequote(source *bytes.Buffer) string {
	var buffer bytes.Buffer

	lastchar := ' '
	lastquote := '\000'
	for {
		ch, _, err := source.ReadRune()
		if err != nil {
			break
		}
		if ch == '~' && unicode.IsSpace(lastchar) {
			if home := dos.GetHome(); home != "" {
				buffer.WriteString(home)
			} else {
				buffer.WriteRune('~')
			}
			lastchar = '~'
			continue
		}
		if ch == '%' {
			var nameBuf bytes.Buffer
			for {
				ch, _, err = source.ReadRune()
				if err != nil {
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					return buffer.String()
				}
				if ch == '%' {
					nameStr := nameBuf.String()
					value := os.Getenv(nameStr)
					if value != "" {
						buffer.WriteString(value)
					} else if m := rxUnicode.FindStringSubmatch(nameStr); m != nil {
						ucode, _ := strconv.ParseInt(m[1], 16, 32)
						buffer.WriteRune(rune(ucode))
					} else if f, ok := PercentFunc[nameStr]; ok {
						buffer.WriteString(f())
					} else {
						buffer.WriteRune('%')
						buffer.WriteString(nameStr)
						buffer.WriteRune('%')
					}
					break
				}
				if !unicode.IsLower(ch) && !unicode.IsUpper(ch) && !unicode.IsNumber(ch) && ch != '_' {
					source.UnreadRune()
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					break
				}
				nameBuf.WriteRune(ch)
			}
			continue
		}

		if lastquote != '\000' && ch == lastquote {
			lastquote = '\000'
		} else if (ch == '\'' || ch == '"') && lastquote == '\000' {
			lastquote = ch
			if ch == lastchar {
				buffer.WriteRune(ch)
			}
		} else {
			buffer.WriteRune(ch)
		}
		lastchar = ch
	}
	return buffer.String()
}

func terminate(statements *[]StatementT,
	isRedirected *bool,
	redirect *[]*Redirecter,
	buffer *bytes.Buffer,
	argv *[]string,
	term string) {

	var statement1 StatementT
	if buffer.Len() > 0 {
		if *isRedirected && len(*redirect) > 0 {
			(*redirect)[len(*redirect)-1].SetPath(dequote(buffer))
			*isRedirected = false
			statement1.Argv = *argv
		} else {
			statement1.Argv = append(*argv, dequote(buffer))
		}
		buffer.Reset()
	} else if len(*argv) <= 0 {
		return
	} else {
		statement1.Argv = *argv
	}
	statement1.Redirect = *redirect
	*redirect = make([]*Redirecter, 0, 3)
	*argv = make([]string, 0)
	statement1.Term = term
	*statements = append(*statements, statement1)
}

func parse1(text string) ([]StatementT, error) {
	lastquote := '\000'
	statements := make([]StatementT, 0)
	argv := make([]string, 0)
	lastchar := ' '
	var buffer bytes.Buffer
	isNextRedirect := false
	redirect := make([]*Redirecter, 0, 3)

	reader := strings.NewReader(text)
	for reader.Len() > 0 {
		ch, chSize, chErr := reader.ReadRune()
		if chSize <= 0 {
			break
		}
		if chErr != nil {
			return nil, chErr
		}
		if lastquote == '\000' {
			if ch == '"' || ch == '\'' {
				lastquote = ch
			}
		} else if ch == lastquote {
			lastquote = '\000'
		}
		if lastquote != '\000' {
			buffer.WriteRune(ch)
		} else if ch == ' ' {
			if buffer.Len() > 0 {
				if isNextRedirect && len(redirect) > 0 {
					redirect[len(redirect)-1].SetPath(dequote(&buffer))
				} else {
					argv = append(argv, dequote(&buffer))
				}
				buffer.Reset()
				isNextRedirect = false
			}
		} else if lastchar == ' ' && ch == ';' {
			terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, ";")
		} else if ch == '|' {
			if lastchar == '|' {
				statements[len(statements)-1].Term = "||"
			} else {
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "|")
			}
		} else if ch == '&' {
			switch lastchar {
			case '&':
				statements[len(statements)-1].Term = "&&"
			case '|':
				statements[len(statements)-1].Term = "|&"
			case '>':
				// >&[n]
				ch2, ch2siz, ch2err := reader.ReadRune()
				if ch2err != nil {
					return nil, ch2err
				}
				if ch2siz <= 0 {
					return nil, errors.New("Too Near EOF for >&")
				}
				red := redirect[len(redirect)-1]
				switch ch2 {
				case '1':
					red.DupFrom(1)
				case '2':
					red.DupFrom(2)
				default:
					return nil, errors.New("Syntax error after >&")
				}
				isNextRedirect = false
			default:
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "&")
			}
		} else if ch == '>' {
			switch lastchar {
			case '1':
				// 1>
				chomp(&buffer)
				redirect = append(redirect, NewRedirecter(1))
			case '2':
				// 2>
				chomp(&buffer)
				redirect = append(redirect, NewRedirecter(2))
			case '>':
				// >>
				if len(redirect) >= 0 {
					redirect[len(redirect)-1].SetAppend()
				}
			default:
				// >
				redirect = append(redirect, NewRedirecter(1))
			}
			isNextRedirect = true
		} else if ch == '<' {
			redirect = append(redirect, NewRedirecter(0))
			isNextRedirect = true
		} else {
			buffer.WriteRune(ch)
		}
		lastchar = ch
	}
	terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, " ")
	return statements, nil
}

// Make arrays whose elements are pipelines
func parse2(statements []StatementT) [][]StatementT {
	result := make([][]StatementT, 1)
	for _, statement1 := range statements {
		result[len(result)-1] = append(result[len(result)-1], statement1)
		switch statement1.Term {
		case "|", "|&":

		default:
			result = append(result, make([]StatementT, 0))
		}
	}
	if len(result[len(result)-1]) <= 0 {
		result = result[0 : len(result)-1]
	}
	return result
}

func Parse(text string) ([][]StatementT, error) {
	result1, err := parse1(text)
	if err != nil {
		return nil, err
	}
	result2 := parse2(result1)
	return result2, nil
}
<commit_msg>Do not expand %ENV% enclosed with single quotations.<commit_after>package interpreter

import (
	"bytes"
	"errors"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"../dos"
)

type StatementT struct {
	Argv     []string
	Redirect []*Redirecter
	Term     string
}

var prefix []string = []string{" 0<", " 1>", " 2>"}

var PercentFunc = map[string]func() string{
	"CD": func() string {
		wd, err := os.Getwd()
		if err == nil {
			return wd
		} else {
			return ""
		}
	},
	"ERRORLEVEL": func() string {
		return ErrorLevel
	},
}

var rxUnicode = regexp.MustCompile("^[uU]\\+?([0-9a-fA-F]+)$")

func chomp(buffer *bytes.Buffer) {
	original := buffer.String()
	buffer.Reset()
	var lastchar rune
	for i, ch := range original {
		if i > 0 {
			buffer.WriteRune(lastchar)
		}
		lastchar = ch
	}
}

func dequote(source *bytes.Buffer) string {
	var buffer bytes.Buffer

	lastchar := ' '
	lastquote := '\000'
	for {
		ch, _, err := source.ReadRune()
		if err != nil {
			break
		}
		if ch == '~' && unicode.IsSpace(lastchar) {
			if home := dos.GetHome(); home != "" {
				buffer.WriteString(home)
			} else {
				buffer.WriteRune('~')
			}
			lastchar = '~'
			continue
		}
		if ch == '%' && lastquote != '\'' {
			var nameBuf bytes.Buffer
			for {
				ch, _, err = source.ReadRune()
				if err != nil {
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					return buffer.String()
				}
				if ch == '%' {
					nameStr := nameBuf.String()
					value := os.Getenv(nameStr)
					if value != "" {
						buffer.WriteString(value)
					} else if m := rxUnicode.FindStringSubmatch(nameStr); m != nil {
						ucode, _ := strconv.ParseInt(m[1], 16, 32)
						buffer.WriteRune(rune(ucode))
					} else if f, ok := PercentFunc[nameStr]; ok {
						buffer.WriteString(f())
					} else {
						buffer.WriteRune('%')
						buffer.WriteString(nameStr)
						buffer.WriteRune('%')
					}
					break
				}
				if !unicode.IsLower(ch) && !unicode.IsUpper(ch) && !unicode.IsNumber(ch) && ch != '_' {
					source.UnreadRune()
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					break
				}
				nameBuf.WriteRune(ch)
			}
			continue
		}

		if lastquote != '\000' && ch == lastquote {
			lastquote = '\000'
		} else if (ch == '\'' || ch == '"') && lastquote == '\000' {
			lastquote = ch
			if ch == lastchar {
				buffer.WriteRune(ch)
			}
		} else {
			buffer.WriteRune(ch)
		}
		lastchar = ch
	}
	return buffer.String()
}

func terminate(statements *[]StatementT,
	isRedirected *bool,
	redirect *[]*Redirecter,
	buffer *bytes.Buffer,
	argv *[]string,
	term string) {

	var statement1 StatementT
	if buffer.Len() > 0 {
		if *isRedirected && len(*redirect) > 0 {
			(*redirect)[len(*redirect)-1].SetPath(dequote(buffer))
			*isRedirected = false
			statement1.Argv = *argv
		} else {
			statement1.Argv = append(*argv, dequote(buffer))
		}
		buffer.Reset()
	} else if len(*argv) <= 0 {
		return
	} else {
		statement1.Argv = *argv
	}
	statement1.Redirect = *redirect
	*redirect = make([]*Redirecter, 0, 3)
	*argv = make([]string, 0)
	statement1.Term = term
	*statements = append(*statements, statement1)
}

func parse1(text string) ([]StatementT, error) {
	lastquote := '\000'
	statements := make([]StatementT, 0)
	argv := make([]string, 0)
	lastchar := ' '
	var buffer bytes.Buffer
	isNextRedirect := false
	redirect := make([]*Redirecter, 0, 3)

	reader := strings.NewReader(text)
	for reader.Len() > 0 {
		ch, chSize, chErr := reader.ReadRune()
		if chSize <= 0 {
			break
		}
		if chErr != nil {
			return nil, chErr
		}
		if lastquote == '\000' {
			if ch == '"' || ch == '\'' {
				lastquote = ch
			}
		} else if ch == lastquote {
			lastquote = '\000'
		}
		if lastquote != '\000' {
			buffer.WriteRune(ch)
		} else if ch == ' ' {
			if buffer.Len() > 0 {
				if isNextRedirect && len(redirect) > 0 {
					redirect[len(redirect)-1].SetPath(dequote(&buffer))
				} else {
					argv = append(argv, dequote(&buffer))
				}
				buffer.Reset()
				isNextRedirect = false
			}
		} else if lastchar == ' ' && ch == ';' {
			terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, ";")
		} else if ch == '|' {
			if lastchar == '|' {
				statements[len(statements)-1].Term = "||"
			} else {
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "|")
			}
		} else if ch == '&' {
			switch lastchar {
			case '&':
				statements[len(statements)-1].Term = "&&"
			case '|':
				statements[len(statements)-1].Term = "|&"
			case '>':
				// >&[n]
				ch2, ch2siz, ch2err := reader.ReadRune()
				if ch2err != nil {
					return nil, ch2err
				}
				if ch2siz <= 0 {
					return nil, errors.New("Too Near EOF for >&")
				}
				red := redirect[len(redirect)-1]
				switch ch2 {
				case '1':
					red.DupFrom(1)
				case '2':
					red.DupFrom(2)
				default:
					return nil, errors.New("Syntax error after >&")
				}
				isNextRedirect = false
			default:
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "&")
			}
		} else if ch == '>' {
			switch lastchar {
			case '1':
				// 1>
				chomp(&buffer)
				redirect = append(redirect, NewRedirecter(1))
			case '2':
				// 2>
				chomp(&buffer)
				redirect = append(redirect, NewRedirecter(2))
			case '>':
				// >>
				if len(redirect) >= 0 {
					redirect[len(redirect)-1].SetAppend()
				}
			default:
				// >
				redirect = append(redirect, NewRedirecter(1))
			}
			isNextRedirect = true
		} else if ch == '<' {
			redirect = append(redirect, NewRedirecter(0))
			isNextRedirect = true
		} else {
			buffer.WriteRune(ch)
		}
		lastchar = ch
	}
	terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, " ")
	return statements, nil
}

// Make arrays whose elements are pipelines
func parse2(statements []StatementT) [][]StatementT {
	result := make([][]StatementT, 1)
	for _, statement1 := range statements {
		result[len(result)-1] = append(result[len(result)-1], statement1)
		switch statement1.Term {
		case "|", "|&":

		default:
			result = append(result, make([]StatementT, 0))
		}
	}
	if len(result[len(result)-1]) <= 0 {
		result = result[0 : len(result)-1]
	}
	return result
}

func Parse(text string) ([][]StatementT, error) {
	result1, err := parse1(text)
	if err != nil {
		return nil, err
	}
	result2 := parse2(result1)
	return result2, nil
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package prometheusexporter

import (
	"fmt"
	"sort"

	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"

	"go.opentelemetry.io/collector/model/pdata"
)

type collector struct {
	accumulator accumulator
	logger      *zap.Logger

	sendTimestamps bool
	namespace      string
	constLabels    prometheus.Labels
}

func newCollector(config *Config, logger *zap.Logger) *collector {
	return &collector{
		accumulator:    newAccumulator(logger, config.MetricExpiration),
		logger:         logger,
		namespace:      sanitize(config.Namespace),
		sendTimestamps: config.SendTimestamps,
		constLabels:    config.ConstLabels,
	}
}

// Describe is a no-op, because the collector dynamically allocates metrics.
// https://github.com/prometheus/client_golang/blob/v1.9.0/prometheus/collector.go#L28-L40
func (c *collector) Describe(_ chan<- *prometheus.Desc) {}

/*
	Processing
*/
func (c *collector) processMetrics(rm pdata.ResourceMetrics) (n int) {
	return c.accumulator.Accumulate(rm)
}

var errUnknownMetricType = fmt.Errorf("unknown metric type")

func (c *collector) convertMetric(metric pdata.Metric) (prometheus.Metric, error) {
	switch metric.DataType() {
	case pdata.MetricDataTypeGauge:
		return c.convertDoubleGauge(metric)
	case pdata.MetricDataTypeSum:
		return c.convertSum(metric)
	case pdata.MetricDataTypeHistogram:
		return c.convertDoubleHistogram(metric)
	case pdata.MetricDataTypeSummary:
		return c.convertSummary(metric)
	}

	return nil, errUnknownMetricType
}

func metricName(namespace string, metric pdata.Metric) string {
	if namespace != "" {
		return namespace + "_" + sanitize(metric.Name())
	}
	return sanitize(metric.Name())
}

func (c *collector) getMetricMetadata(metric pdata.Metric, labels pdata.StringMap) (*prometheus.Desc, []string) {
	keys := make([]string, 0, labels.Len())
	values := make([]string, 0, labels.Len())

	labels.Range(func(k string, v string) bool {
		keys = append(keys, sanitize(k))
		values = append(values, v)
		return true
	})

	return prometheus.NewDesc(
		metricName(c.namespace, metric),
		metric.Description(),
		keys,
		c.constLabels,
	), values
}

func (c *collector) convertDoubleGauge(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Gauge().DataPoints().At(0)

	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())
	var value float64
	switch ip.Type() {
	case pdata.MetricValueTypeInt:
		value = float64(ip.IntVal())
	case pdata.MetricValueTypeDouble:
		value = ip.DoubleVal()
	}
	m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, value, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertSum(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Sum().DataPoints().At(0)

	metricType := prometheus.GaugeValue
	if metric.Sum().IsMonotonic() {
		metricType = prometheus.CounterValue
	}

	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())
	var value float64
	switch ip.Type() {
	case pdata.MetricValueTypeInt:
		value = float64(ip.IntVal())
	case pdata.MetricValueTypeDouble:
		value = ip.DoubleVal()
	}
	m, err := prometheus.NewConstMetric(desc, metricType, value, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertSummary(metric pdata.Metric) (prometheus.Metric, error) {
	// TODO: In the off chance that we have multiple points
	// within the same metric, how should we handle them?
	point := metric.Summary().DataPoints().At(0)

	quantiles := make(map[float64]float64)
	qv := point.QuantileValues()
	for j := 0; j < qv.Len(); j++ {
		qvj := qv.At(j)
		// There should be EXACTLY one quantile value lest it is an invalid exposition.
		quantiles[qvj.Quantile()] = qvj.Value()
	}

	desc, labelValues := c.getMetricMetadata(metric, point.LabelsMap())
	m, err := prometheus.NewConstSummary(desc, point.Count(), point.Sum(), quantiles, labelValues...)
	if err != nil {
		return nil, err
	}
	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(point.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertDoubleHistogram(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Histogram().DataPoints().At(0)
	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())

	indicesMap := make(map[float64]int)
	buckets := make([]float64, 0, len(ip.BucketCounts()))
	for index, bucket := range ip.ExplicitBounds() {
		if _, added := indicesMap[bucket]; !added {
			indicesMap[bucket] = index
			buckets = append(buckets, bucket)
		}
	}
	sort.Float64s(buckets)

	cumCount := uint64(0)

	points := make(map[float64]uint64)
	for _, bucket := range buckets {
		index := indicesMap[bucket]
		var countPerBucket uint64
		if len(ip.ExplicitBounds()) > 0 && index < len(ip.ExplicitBounds()) {
			countPerBucket = ip.BucketCounts()[index]
		}
		cumCount += countPerBucket
		points[bucket] = cumCount
	}

	m, err := prometheus.NewConstHistogram(desc, ip.Count(), ip.Sum(), points, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

/*
	Reporting
*/
func (c *collector) Collect(ch chan<- prometheus.Metric) {
	c.logger.Debug("collect called")

	inMetrics := c.accumulator.Collect()

	for _, pMetric := range inMetrics {
		m, err := c.convertMetric(pMetric)
		if err != nil {
			c.logger.Error(fmt.Sprintf("failed to convert metric %s: %s", pMetric.Name(), err.Error()))
			continue
		}

		ch <- m
		c.logger.Debug(fmt.Sprintf("metric served: %s", m.Desc().String()))
	}
}
<commit_msg>Simple rename of private func in prometheus exporter (#3715)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package prometheusexporter

import (
	"fmt"
	"sort"

	"github.com/prometheus/client_golang/prometheus"
	"go.uber.org/zap"

	"go.opentelemetry.io/collector/model/pdata"
)

type collector struct {
	accumulator accumulator
	logger      *zap.Logger

	sendTimestamps bool
	namespace      string
	constLabels    prometheus.Labels
}

func newCollector(config *Config, logger *zap.Logger) *collector {
	return &collector{
		accumulator:    newAccumulator(logger, config.MetricExpiration),
		logger:         logger,
		namespace:      sanitize(config.Namespace),
		sendTimestamps: config.SendTimestamps,
		constLabels:    config.ConstLabels,
	}
}

// Describe is a no-op, because the collector dynamically allocates metrics.
// https://github.com/prometheus/client_golang/blob/v1.9.0/prometheus/collector.go#L28-L40
func (c *collector) Describe(_ chan<- *prometheus.Desc) {}

/*
	Processing
*/
func (c *collector) processMetrics(rm pdata.ResourceMetrics) (n int) {
	return c.accumulator.Accumulate(rm)
}

var errUnknownMetricType = fmt.Errorf("unknown metric type")

func (c *collector) convertMetric(metric pdata.Metric) (prometheus.Metric, error) {
	switch metric.DataType() {
	case pdata.MetricDataTypeGauge:
		return c.convertGauge(metric)
	case pdata.MetricDataTypeSum:
		return c.convertSum(metric)
	case pdata.MetricDataTypeHistogram:
		return c.convertDoubleHistogram(metric)
	case pdata.MetricDataTypeSummary:
		return c.convertSummary(metric)
	}

	return nil, errUnknownMetricType
}

func metricName(namespace string, metric pdata.Metric) string {
	if namespace != "" {
		return namespace + "_" + sanitize(metric.Name())
	}
	return sanitize(metric.Name())
}

func (c *collector) getMetricMetadata(metric pdata.Metric, labels pdata.StringMap) (*prometheus.Desc, []string) {
	keys := make([]string, 0, labels.Len())
	values := make([]string, 0, labels.Len())

	labels.Range(func(k string, v string) bool {
		keys = append(keys, sanitize(k))
		values = append(values, v)
		return true
	})

	return prometheus.NewDesc(
		metricName(c.namespace, metric),
		metric.Description(),
		keys,
		c.constLabels,
	), values
}

func (c *collector) convertGauge(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Gauge().DataPoints().At(0)

	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())
	var value float64
	switch ip.Type() {
	case pdata.MetricValueTypeInt:
		value = float64(ip.IntVal())
	case pdata.MetricValueTypeDouble:
		value = ip.DoubleVal()
	}
	m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, value, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertSum(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Sum().DataPoints().At(0)

	metricType := prometheus.GaugeValue
	if metric.Sum().IsMonotonic() {
		metricType = prometheus.CounterValue
	}

	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())
	var value float64
	switch ip.Type() {
	case pdata.MetricValueTypeInt:
		value = float64(ip.IntVal())
	case pdata.MetricValueTypeDouble:
		value = ip.DoubleVal()
	}
	m, err := prometheus.NewConstMetric(desc, metricType, value, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertSummary(metric pdata.Metric) (prometheus.Metric, error) {
	// TODO: In the off chance that we have multiple points
	// within the same metric, how should we handle them?
	point := metric.Summary().DataPoints().At(0)

	quantiles := make(map[float64]float64)
	qv := point.QuantileValues()
	for j := 0; j < qv.Len(); j++ {
		qvj := qv.At(j)
		// There should be EXACTLY one quantile value lest it is an invalid exposition.
		quantiles[qvj.Quantile()] = qvj.Value()
	}

	desc, labelValues := c.getMetricMetadata(metric, point.LabelsMap())
	m, err := prometheus.NewConstSummary(desc, point.Count(), point.Sum(), quantiles, labelValues...)
	if err != nil {
		return nil, err
	}
	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(point.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

func (c *collector) convertDoubleHistogram(metric pdata.Metric) (prometheus.Metric, error) {
	ip := metric.Histogram().DataPoints().At(0)
	desc, labels := c.getMetricMetadata(metric, ip.LabelsMap())

	indicesMap := make(map[float64]int)
	buckets := make([]float64, 0, len(ip.BucketCounts()))
	for index, bucket := range ip.ExplicitBounds() {
		if _, added := indicesMap[bucket]; !added {
			indicesMap[bucket] = index
			buckets = append(buckets, bucket)
		}
	}
	sort.Float64s(buckets)

	cumCount := uint64(0)

	points := make(map[float64]uint64)
	for _, bucket := range buckets {
		index := indicesMap[bucket]
		var countPerBucket uint64
		if len(ip.ExplicitBounds()) > 0 && index < len(ip.ExplicitBounds()) {
			countPerBucket = ip.BucketCounts()[index]
		}
		cumCount += countPerBucket
		points[bucket] = cumCount
	}

	m, err := prometheus.NewConstHistogram(desc, ip.Count(), ip.Sum(), points, labels...)
	if err != nil {
		return nil, err
	}

	if c.sendTimestamps {
		return prometheus.NewMetricWithTimestamp(ip.Timestamp().AsTime(), m), nil
	}
	return m, nil
}

/*
	Reporting
*/
func (c *collector) Collect(ch chan<- prometheus.Metric) {
	c.logger.Debug("collect called")

	inMetrics := c.accumulator.Collect()

	for _, pMetric := range inMetrics {
		m, err := c.convertMetric(pMetric)
		if err != nil {
			c.logger.Error(fmt.Sprintf("failed to convert metric %s: %s", pMetric.Name(), err.Error()))
			continue
		}

		ch <- m
		c.logger.Debug(fmt.Sprintf("metric served: %s", m.Desc().String()))
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"strings"
)

type (
	ViewEventCallback func(v *View)
	ViewEvent         []ViewEventCallback

	QueryContextReturn   int
	QueryContextCallback func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn
	QueryContextEvent    []QueryContextCallback

	WindowEventCallback func(w *Window)
	WindowEvent         []WindowEventCallback
)

const (
	True QueryContextReturn = iota
	False
	Unknown
)

func (ve *ViewEvent) Add(cb ViewEventCallback) {
	*ve = append(*ve, cb)
}

func (ve ViewEvent) Call(v *View) {
	log4go.Finest("ViewEvent")
	for i := range ve {
		ve[i](v)
	}
}

func (qe *QueryContextEvent) Add(cb QueryContextCallback) {
	*qe = append(*qe, cb)
}

func (qe QueryContextEvent) Call(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
	log4go.Fine("Query context: %s, %v, %v, %v", key, operator, operand, match_all)
	for i := range qe {
		r := qe[i](v, key, operator, operand, match_all)
		if r != Unknown {
			return r
		}
	}
	log4go.Fine("Unknown context: %s", key)
	return Unknown
}

func (we *WindowEvent) Add(cb WindowEventCallback) {
	*we = append(*we, cb)
}

func (we WindowEvent) Call(w *Window) {
	log4go.Finest("WindowEvent")
	for i := range we {
		we[i](w)
	}
}

var (
	OnNew               ViewEvent
	OnLoad              ViewEvent
	OnActivated         ViewEvent
	OnDeactivated       ViewEvent
	OnClose             ViewEvent
	OnPreSave           ViewEvent
	OnPostSave          ViewEvent
	OnModified          ViewEvent
	OnSelectionModified ViewEvent

	OnNewWindow    WindowEvent
	OnQueryContext QueryContextEvent
)

func init() {
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		if strings.HasPrefix(key, "setting.") && operator == OpEqual {
			c, ok := v.Settings().Get(key[8:]).(bool)
			if c && ok {
				return True
			}
			return False
		} else if key == "num_selections" {
			opf, _ := operand.(float64)
			op := int(opf)

			switch operator {
			case OpEqual:
				if op == v.Sel().Len() {
					return True
				}
				return False
			case OpNotEqual:
				if op != v.Sel().Len() {
					return True
				}
				return False
			}
		}
		return Unknown
	})
}
<commit_msg>backend: Document events<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"strings"
)

type (
	// An event callback dealing with View events.
	ViewEventCallback func(v *View)
	// A ViewEvent is simply a bunch of ViewEventCallbacks.
	ViewEvent []ViewEventCallback

	// The return value returned from a QueryContextCallback.
	QueryContextReturn int

	// The context is queried when trying to figure out what action should be performed when
	// certain conditions are met.
	//
	// Context is just a string identifier, an optional comparison operator, an optional operand, and an optional
	// match_all boolean. The data of the context is optionally provided together with a key binding and the key's
	// action will only be considered if the context conditions are met.
	//
	// Exactly how these values are interpreted is up to the individual context handlers, which may be fully
	// customized by implementing the callback in a plugin.
	//
	// For instance pressing the key 'j' will have a different meaning when in a VI command mode emulation
	// and when in a VI insert mode emulation. A plugin would then define two key binding entries for 'j',
	// describe the key binding context to be able to discern which action is appropriate when 'j' is then pressed.
	QueryContextCallback func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn

	// A QueryContextEvent is simply a bunch of QueryContextCallbacks.
	QueryContextEvent []QueryContextCallback

	// A WindowEventCallback deals with Window events.
	WindowEventCallback func(w *Window)
	// A WindowEvent is simply a bunch of WindowEventCallbacks.
	WindowEvent []WindowEventCallback
)

const (
	True    QueryContextReturn = iota //< Returned when the context query matches.
	False                             //< Returned when the context query does not match.
	Unknown                           //< Returned when the QueryContextCallback does not know how to deal with the given context.
)

// Add the provided ViewEventCallback to this ViewEvent
// TODO(.): Support removing ViewEventCallbacks?
func (ve *ViewEvent) Add(cb ViewEventCallback) {
	*ve = append(*ve, cb)
}

// Trigger this ViewEvent by calling all the registered callbacks in order of registration.
func (ve ViewEvent) Call(v *View) {
	log4go.Finest("ViewEvent")
	for i := range ve {
		ve[i](v)
	}
}

// Add the provided QueryContextCallback to the QueryContextEvent.
// TODO(.): Support removing QueryContextCallbacks?
func (qe *QueryContextEvent) Add(cb QueryContextCallback) {
	*qe = append(*qe, cb)
}

// Searches for a QueryContextCallback and returns the result of the first callback being able to deal with this
// context, or Unknown if no such callback was found.
func (qe QueryContextEvent) Call(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
	log4go.Fine("Query context: %s, %v, %v, %v", key, operator, operand, match_all)
	for i := range qe {
		r := qe[i](v, key, operator, operand, match_all)
		if r != Unknown {
			return r
		}
	}
	log4go.Fine("Unknown context: %s", key)
	return Unknown
}

// Add the provided WindowEventCallback to this WindowEvent.
// TODO(.): Support removing WindowEventCallbacks?
func (we *WindowEvent) Add(cb WindowEventCallback) {
	*we = append(*we, cb)
}

// Trigger this WindowEvent by callig all the registered callbacks in order of registration.
func (we WindowEvent) Call(w *Window) {
	log4go.Finest("WindowEvent")
	for i := range we {
		we[i](w)
	}
}

var (
	OnNew               ViewEvent //< Called when a new view is created
	OnLoad              ViewEvent //< Called when loading a view's buffer has finished
	OnActivated         ViewEvent //< Called when a view gains input focus.
	OnDeactivated       ViewEvent //< Called when a view loses input focus.
	OnClose             ViewEvent //< Called when a view has been closed.
	OnPreSave           ViewEvent //< Called just before a view's buffer is saved.
	OnPostSave          ViewEvent //< Called after a view's buffer has been saved.
	OnModified          ViewEvent //< Called when the contents of a view's underlying buffer has changed.
	OnSelectionModified ViewEvent //< Called when a view's Selection/cursor has changed.

	OnNewWindow    WindowEvent       //< Called when a new window has been created.
	OnQueryContext QueryContextEvent //< Called when context is being queried.
)

func init() {
	// Register functionality dealing with a couple of built in contexts
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		if strings.HasPrefix(key, "setting.") && operator == OpEqual {
			c, ok := v.Settings().Get(key[8:]).(bool)
			if c && ok {
				return True
			}
			return False
		} else if key == "num_selections" {
			opf, _ := operand.(float64)
			op := int(opf)

			switch operator {
			case OpEqual:
				if op == v.Sel().Len() {
					return True
				}
				return False
			case OpNotEqual:
				if op != v.Sel().Len() {
					return True
				}
				return False
			}
		}
		return Unknown
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"
)

type SettingMessage struct {
	Setting string `json:"setting"`
	Value   bool   `json:"state"`
}

type InfoMessage struct {
	*status
	*settings
}

func statusSender(conn *websocket.Conn) {
	timer := time.NewTicker(1 * time.Second)
	for {
		<-timer.C

		update, _ := json.Marshal(InfoMessage{status: &globalStatus, settings: &globalSettings})
        // TODO: once we switch to hte new WebUI, we will not send settings via websocket
		// update, _ := json.Marshal(&globalStatus)
		_, err := conn.Write(update)

		if err != nil {
			//			log.Printf("Web client disconnected.\n")
			break
		}
	}
}

func handleManagementConnection(conn *websocket.Conn) {
	//	log.Printf("Web client connected.\n")
	go statusSender(conn)

    // TODO: once we have the new WebUI established, the websocket will nolonger receive settings changes
	for {
		var msg SettingMessage
		err := websocket.JSON.Receive(conn, &msg)
		if err == io.EOF {
			break
		} else if err != nil {
			log.Printf("handleManagementConnection: %s\n", err.Error())
		} else {
			if msg.Setting == "UAT_Enabled" {
				globalSettings.UAT_Enabled = msg.Value
			}
			if msg.Setting == "ES_Enabled" {
				globalSettings.ES_Enabled = msg.Value
			}
			if msg.Setting == "GPS_Enabled" {
				globalSettings.GPS_Enabled = msg.Value
			}
			if msg.Setting == "AHRS_Enabled" {
				globalSettings.AHRS_Enabled = msg.Value
			}
			if msg.Setting == "DEBUG" {
				globalSettings.DEBUG = msg.Value
			}

			saveSettings()
		}
	}
}

// AJAX call - /getTraffic. Responds with currently tracked traffic targets.
func handleTrafficRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	/* From JSON package docs:
	"JSON objects only support strings as keys; to encode a Go map type it must be of the form map[string]T (where T is any Go type supported by the json package)."
	*/
	t := make(map[string]TrafficInfo)
	trafficMutex.Lock()
	for icao, traf := range traffic {
		icaoStr := strconv.FormatInt(int64(icao), 16) // Convert to hex.
		t[icaoStr] = traf
	}
	trafficJSON, _ := json.Marshal(&t)
	trafficMutex.Unlock()
	fmt.Fprintf(w, "%s\n", trafficJSON)
}

// AJAX call - /getSituation. Responds with current situation (lat/lon/gdspeed/track/pitch/roll/heading/etc.)
func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	situationJSON, _ := json.Marshal(&mySituation)
	fmt.Fprintf(w, "%s\n", situationJSON)
}

// AJAX call - /getTowers. Responds with all ADS-B ground towers that have sent messages that we were able to parse, along with its stats.
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	towersJSON, _ := json.Marshal(&ADSBTowers)
	fmt.Fprintf(w, "%s\n", towersJSON)
}

// AJAX call - /getSettings. Responds with all stratux.conf data.
func handleSettingsGetRequest(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
	settingsJSON, _ := json.Marshal(&globalSettings)
	fmt.Fprintf(w, "%s\n", settingsJSON)
}

// AJAX call - /setSettings. receives via POST command, any/all stratux.conf data.
func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
    // define header in support of cross-domain AJAX
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
    w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
    w.Header().Set("Content-Type", "application/json")

    // for an OPTION method request, we return header without processing.
    // this insures we are recognized as supporting cross-domain AJAX REST calls
    if (r.Method == "POST") {
        // raw, _ := httputil.DumpRequest(r, true)
        // log.Printf("handleSettingsSetRequest:raw: %s\n", raw)

        decoder := json.NewDecoder(r.Body);
        for {
            var msg map[string]interface{} // support arbitrary JSON

            err := decoder.Decode(&msg)
            if err == io.EOF {
                break
            } else if err != nil {
                log.Printf("handleSettingsSetRequest:error: %s\n", err.Error())
            } else {
                for key, val := range msg {
                    // log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
                    switch key {
                        case "UAT_Enabled":     globalSettings.UAT_Enabled = val.(bool)
                        case "ES_Enabled":      globalSettings.ES_Enabled = val.(bool)
                        case "GPS_Enabled":     globalSettings.GPS_Enabled = val.(bool)
                        case "AHRS_Enabled":    globalSettings.AHRS_Enabled = val.(bool)
                        case "DEBUG":           globalSettings.DEBUG = val.(bool)
                        case "ReplayLog":       globalSettings.ReplayLog = val.(bool)
                        case "PPM":             globalSettings.PPM = int(val.(float64))
                        default:                log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
                    }
                }
                saveSettings()
            }
        }

        // while it may be redundent, we return the latest settings
        settingsJSON, _ := json.Marshal(&globalSettings)
        fmt.Fprintf(w, "%s\n", settingsJSON)
    }
}

func managementInterface() {
	http.Handle("/", http.FileServer(http.Dir("/var/www")))
	http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
	http.HandleFunc("/control",
		func(w http.ResponseWriter, req *http.Request) {
			s := websocket.Server{
				Handler: websocket.Handler(handleManagementConnection)}
			s.ServeHTTP(w, req)
		})

	http.HandleFunc("/getTraffic", handleTrafficRequest)
	http.HandleFunc("/getSituation", handleSituationRequest)
	http.HandleFunc("/getTowers", handleTowersRequest)
	http.HandleFunc("/getSettings", handleSettingsGetRequest)
	http.HandleFunc("/setSettings", handleSettingsSetRequest)

	err := http.ListenAndServe(managementAddr, nil)

	if err != nil {
		log.Printf("managementInterface ListenAndServe: %s\n", err.Error())
	}
}
<commit_msg>gofmt<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"
)

type SettingMessage struct {
	Setting string `json:"setting"`
	Value   bool   `json:"state"`
}

type InfoMessage struct {
	*status
	*settings
}

func statusSender(conn *websocket.Conn) {
	timer := time.NewTicker(1 * time.Second)
	for {
		<-timer.C

		update, _ := json.Marshal(InfoMessage{status: &globalStatus, settings: &globalSettings})
		// TODO: once we switch to hte new WebUI, we will not send settings via websocket
		// update, _ := json.Marshal(&globalStatus)
		_, err := conn.Write(update)

		if err != nil {
			//			log.Printf("Web client disconnected.\n")
			break
		}
	}
}

func handleManagementConnection(conn *websocket.Conn) {
	//	log.Printf("Web client connected.\n")
	go statusSender(conn)

	// TODO: once we have the new WebUI established, the websocket will nolonger receive settings changes
	for {
		var msg SettingMessage
		err := websocket.JSON.Receive(conn, &msg)
		if err == io.EOF {
			break
		} else if err != nil {
			log.Printf("handleManagementConnection: %s\n", err.Error())
		} else {
			if msg.Setting == "UAT_Enabled" {
				globalSettings.UAT_Enabled = msg.Value
			}
			if msg.Setting == "ES_Enabled" {
				globalSettings.ES_Enabled = msg.Value
			}
			if msg.Setting == "GPS_Enabled" {
				globalSettings.GPS_Enabled = msg.Value
			}
			if msg.Setting == "AHRS_Enabled" {
				globalSettings.AHRS_Enabled = msg.Value
			}
			if msg.Setting == "DEBUG" {
				globalSettings.DEBUG = msg.Value
			}

			saveSettings()
		}
	}
}

// AJAX call - /getTraffic. Responds with currently tracked traffic targets.
func handleTrafficRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	/* From JSON package docs:
	"JSON objects only support strings as keys; to encode a Go map type it must be of the form map[string]T (where T is any Go type supported by the json package)."
	*/
	t := make(map[string]TrafficInfo)
	trafficMutex.Lock()
	for icao, traf := range traffic {
		icaoStr := strconv.FormatInt(int64(icao), 16) // Convert to hex.
		t[icaoStr] = traf
	}
	trafficJSON, _ := json.Marshal(&t)
	trafficMutex.Unlock()
	fmt.Fprintf(w, "%s\n", trafficJSON)
}

// AJAX call - /getSituation. Responds with current situation (lat/lon/gdspeed/track/pitch/roll/heading/etc.)
func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	situationJSON, _ := json.Marshal(&mySituation)
	fmt.Fprintf(w, "%s\n", situationJSON)
}

// AJAX call - /getTowers. Responds with all ADS-B ground towers that have sent messages that we were able to parse, along with its stats.
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	towersJSON, _ := json.Marshal(&ADSBTowers)
	fmt.Fprintf(w, "%s\n", towersJSON)
}

// AJAX call - /getSettings. Responds with all stratux.conf data.
func handleSettingsGetRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json")
	settingsJSON, _ := json.Marshal(&globalSettings)
	fmt.Fprintf(w, "%s\n", settingsJSON)
}

// AJAX call - /setSettings. receives via POST command, any/all stratux.conf data.
func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
	// define header in support of cross-domain AJAX
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
	w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
	w.Header().Set("Content-Type", "application/json")

	// for an OPTION method request, we return header without processing.
	// this insures we are recognized as supporting cross-domain AJAX REST calls
	if r.Method == "POST" {
		// raw, _ := httputil.DumpRequest(r, true)
		// log.Printf("handleSettingsSetRequest:raw: %s\n", raw)

		decoder := json.NewDecoder(r.Body)
		for {
			var msg map[string]interface{} // support arbitrary JSON

			err := decoder.Decode(&msg)
			if err == io.EOF {
				break
			} else if err != nil {
				log.Printf("handleSettingsSetRequest:error: %s\n", err.Error())
			} else {
				for key, val := range msg {
					// log.Printf("handleSettingsSetRequest:json: testing for key:%s of type %s\n", key, reflect.TypeOf(val))
					switch key {
					case "UAT_Enabled":
						globalSettings.UAT_Enabled = val.(bool)
					case "ES_Enabled":
						globalSettings.ES_Enabled = val.(bool)
					case "GPS_Enabled":
						globalSettings.GPS_Enabled = val.(bool)
					case "AHRS_Enabled":
						globalSettings.AHRS_Enabled = val.(bool)
					case "DEBUG":
						globalSettings.DEBUG = val.(bool)
					case "ReplayLog":
						globalSettings.ReplayLog = val.(bool)
					case "PPM":
						globalSettings.PPM = int(val.(float64))
					default:
						log.Printf("handleSettingsSetRequest:json: unrecognized key:%s\n", key)
					}
				}
				saveSettings()
			}
		}

		// while it may be redundent, we return the latest settings
		settingsJSON, _ := json.Marshal(&globalSettings)
		fmt.Fprintf(w, "%s\n", settingsJSON)
	}
}

func managementInterface() {
	http.Handle("/", http.FileServer(http.Dir("/var/www")))
	http.Handle("/logs/", http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log"))))
	http.HandleFunc("/control",
		func(w http.ResponseWriter, req *http.Request) {
			s := websocket.Server{
				Handler: websocket.Handler(handleManagementConnection)}
			s.ServeHTTP(w, req)
		})

	http.HandleFunc("/getTraffic", handleTrafficRequest)
	http.HandleFunc("/getSituation", handleSituationRequest)
	http.HandleFunc("/getTowers", handleTowersRequest)
	http.HandleFunc("/getSettings", handleSettingsGetRequest)
	http.HandleFunc("/setSettings", handleSettingsSetRequest)

	err := http.ListenAndServe(managementAddr, nil)

	if err != nil {
		log.Printf("managementInterface ListenAndServe: %s\n", err.Error())
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium 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 (
	"flag"
	"fmt"
	"runtime"
	"testing"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/x/ref"
	"v.io/x/ref/lib/security/securityflag"
	_ "v.io/x/ref/runtime/factories/static"
	"v.io/x/ref/runtime/internal/flow/flowtest"
	fmanager "v.io/x/ref/runtime/internal/flow/manager"
	"v.io/x/ref/runtime/internal/rpc/benchmark/internal"
	"v.io/x/ref/runtime/internal/rpc/stream/manager"
	"v.io/x/ref/test"
	"v.io/x/ref/test/benchmark"
	"v.io/x/ref/test/testutil"
)

const (
	payloadSize = 1000
	chunkCnt    = 10000

	bulkPayloadSize = 1000000

	numCPUs          = 2
	defaultBenchTime = 5 * time.Second
)

var (
	serverEP naming.Endpoint
	ctx      *context.T
)

// Benchmark for measuring RPC connection time including authentication.
//
// rpc.Client doesn't export an interface for closing connection. So we
// use the stream manager directly here.
func benchmarkRPCConnection(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)

	principal := testutil.NewPrincipal("test")
	nctx, _ := v23.WithPrincipal(ctx, principal)

	b.StopTimer()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if ref.RPCTransitionState() >= ref.XServers {
			m := fmanager.New(nctx, naming.FixedRoutingID(0xc), nil)
			b.StartTimer()
			_, err := m.Dial(nctx, serverEP, flowtest.AllowAllPeersAuthorizer{})
			if err != nil {
				ctx.Fatalf("Dial failed: %v", err)
			}
			b.StopTimer()
			// TODO(mattr): close m.
		} else {
			client := manager.InternalNew(ctx, naming.FixedRoutingID(0xc))
			b.StartTimer()
			_, err := client.Dial(nctx, serverEP)
			if err != nil {
				ctx.Fatalf("Dial failed: %v", err)
			}
			b.StopTimer()
			client.Shutdown()
		}
	}
}

// Benchmark for non-streaming RPC.
func benchmarkRPC(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEcho(b, ctx, serverEP.Name(), b.N, payloadSize, benchmark.NewStats(1))
}

// Benchmark for streaming RPC.
func benchmarkStreamingRPC(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEchoStream(b, ctx, serverEP.Name(), b.N, chunkCnt, payloadSize, benchmark.NewStats(1))
}

// Benchmark for measuring throughput in streaming RPC.
func benchmarkStreamingRPCThroughput(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEchoStream(b, ctx, serverEP.Name(), 1, b.N, bulkPayloadSize, benchmark.NewStats(1))
}

func msPerRPC(r testing.BenchmarkResult) float64 {
	return r.T.Seconds() / float64(r.N) * 1000
}

func rpcPerSec(r testing.BenchmarkResult) float64 {
	return float64(r.N) / r.T.Seconds()
}
func mbPerSec(r testing.BenchmarkResult) float64 {
	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
}

func runBenchmarks() {
	r := testing.Benchmark(benchmarkRPCConnection)
	fmt.Printf("RPC Connection\t%.2f ms/rpc\n", msPerRPC(r))

	// Create a connection to exclude the setup time from the following benchmarks.
	internal.CallEcho(&testing.B{}, ctx, serverEP.Name(), 1, 0, benchmark.NewStats(1))

	r = testing.Benchmark(benchmarkRPC)
	fmt.Printf("RPC (echo %vB)\t%.2f ms/rpc (%.2f qps)\n", payloadSize, msPerRPC(r), rpcPerSec(r))

	r = testing.Benchmark(benchmarkStreamingRPC)
	fmt.Printf("RPC Streaming (echo %vB)\t%.2f ms/rpc\n", payloadSize, msPerRPC(r)/chunkCnt)

	r = testing.Benchmark(benchmarkStreamingRPCThroughput)
	fmt.Printf("RPC Streaming Throughput (echo %vMB)\t%.2f MB/s\n", bulkPayloadSize/1e6, mbPerSec(r))
}

func main() {
	// Set the default benchmark time.
	flag.Set("test.benchtime", defaultBenchTime.String())

	var shutdown v23.Shutdown
	ctx, shutdown = test.V23Init()
	defer shutdown()

	ctx, server, err := v23.WithNewServer(ctx, "", internal.NewService(), securityflag.NewAuthorizerOrDie())
	if err != nil {
		ctx.Fatalf("NewServer failed: %v", err)
	}
	serverEP = server.Status().Endpoints[0]

	runBenchmarks()
}
<commit_msg>rpc/benchmark/simple: Correctly close manager so that benchmark can run on mac.<commit_after>// Copyright 2015 The Vanadium 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 (
	"flag"
	"fmt"
	"runtime"
	"testing"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/x/ref"
	"v.io/x/ref/lib/security/securityflag"
	_ "v.io/x/ref/runtime/factories/static"
	"v.io/x/ref/runtime/internal/flow/flowtest"
	fmanager "v.io/x/ref/runtime/internal/flow/manager"
	"v.io/x/ref/runtime/internal/rpc/benchmark/internal"
	"v.io/x/ref/runtime/internal/rpc/stream/manager"
	"v.io/x/ref/test"
	"v.io/x/ref/test/benchmark"
	"v.io/x/ref/test/testutil"
)

const (
	payloadSize = 1000
	chunkCnt    = 10000

	bulkPayloadSize = 1000000

	numCPUs          = 2
	defaultBenchTime = 5 * time.Second
)

var (
	serverEP naming.Endpoint
	ctx      *context.T
)

// Benchmark for measuring RPC connection time including authentication.
//
// rpc.Client doesn't export an interface for closing connection. So we
// use the stream manager directly here.
func benchmarkRPCConnection(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)

	principal := testutil.NewPrincipal("test")
	nctx, _ := v23.WithPrincipal(ctx, principal)

	b.StopTimer()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if ref.RPCTransitionState() >= ref.XServers {
			mctx, cancel := context.WithCancel(nctx)
			m := fmanager.New(mctx, naming.FixedRoutingID(0xc), nil)
			b.StartTimer()
			_, err := m.Dial(mctx, serverEP, flowtest.AllowAllPeersAuthorizer{})
			if err != nil {
				ctx.Fatalf("Dial failed: %v", err)
			}
			b.StopTimer()
			cancel()
			<-m.Closed()
		} else {
			client := manager.InternalNew(ctx, naming.FixedRoutingID(0xc))
			b.StartTimer()
			_, err := client.Dial(nctx, serverEP)
			if err != nil {
				ctx.Fatalf("Dial failed: %v", err)
			}
			b.StopTimer()
			client.Shutdown()
		}
	}
}

// Benchmark for non-streaming RPC.
func benchmarkRPC(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEcho(b, ctx, serverEP.Name(), b.N, payloadSize, benchmark.NewStats(1))
}

// Benchmark for streaming RPC.
func benchmarkStreamingRPC(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEchoStream(b, ctx, serverEP.Name(), b.N, chunkCnt, payloadSize, benchmark.NewStats(1))
}

// Benchmark for measuring throughput in streaming RPC.
func benchmarkStreamingRPCThroughput(b *testing.B) {
	mp := runtime.GOMAXPROCS(numCPUs)
	defer runtime.GOMAXPROCS(mp)
	internal.CallEchoStream(b, ctx, serverEP.Name(), 1, b.N, bulkPayloadSize, benchmark.NewStats(1))
}

func msPerRPC(r testing.BenchmarkResult) float64 {
	return r.T.Seconds() / float64(r.N) * 1000
}

func rpcPerSec(r testing.BenchmarkResult) float64 {
	return float64(r.N) / r.T.Seconds()
}
func mbPerSec(r testing.BenchmarkResult) float64 {
	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
}

func runBenchmarks() {
	r := testing.Benchmark(benchmarkRPCConnection)
	fmt.Printf("RPC Connection\t%.2f ms/rpc\n", msPerRPC(r))

	// Create a connection to exclude the setup time from the following benchmarks.
	internal.CallEcho(&testing.B{}, ctx, serverEP.Name(), 1, 0, benchmark.NewStats(1))

	r = testing.Benchmark(benchmarkRPC)
	fmt.Printf("RPC (echo %vB)\t%.2f ms/rpc (%.2f qps)\n", payloadSize, msPerRPC(r), rpcPerSec(r))

	r = testing.Benchmark(benchmarkStreamingRPC)
	fmt.Printf("RPC Streaming (echo %vB)\t%.2f ms/rpc\n", payloadSize, msPerRPC(r)/chunkCnt)

	r = testing.Benchmark(benchmarkStreamingRPCThroughput)
	fmt.Printf("RPC Streaming Throughput (echo %vMB)\t%.2f MB/s\n", bulkPayloadSize/1e6, mbPerSec(r))
}

func main() {
	// Set the default benchmark time.
	flag.Set("test.benchtime", defaultBenchTime.String())

	var shutdown v23.Shutdown
	ctx, shutdown = test.V23Init()
	defer shutdown()

	ctx, server, err := v23.WithNewServer(ctx, "", internal.NewService(), securityflag.NewAuthorizerOrDie())
	if err != nil {
		ctx.Fatalf("NewServer failed: %v", err)
	}
	serverEP = server.Status().Endpoints[0]

	runBenchmarks()
}
<|endoftext|>