<commit_before>package outputelastic

import (
	"context"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/tsaikd/KDGoLib/errutil"
	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/config/goglog"
	"github.com/tsaikd/gogstash/config/logevent"
	elastic "gopkg.in/olivere/elastic.v5"
)

// ModuleName is the name used in config file
const ModuleName = "elastic"

// OutputConfig holds the configuration json fields and internal objects
type OutputConfig struct {
	config.OutputConfig
	URL          string `json:"url"`           // elastic API entrypoint
	Index        string `json:"index"`         // index name to log
	DocumentType string `json:"document_type"` // type name to log
	DocumentID   string `json:"document_id"`   // id to log, used if you want to control id format

	Sniff bool `json:"sniff"` // find all nodes of your cluster, https://github.com/olivere/elastic/wiki/Sniffing

	// BulkActions specifies when to flush based on the number of actions
	// currently added. Defaults to 1000 and can be set to -1 to be disabled.
	BulkActions int `json:"bulk_actions,omitempty"`

	// BulkSize specifies when to flush based on the size (in bytes) of the actions
	// currently added. Defaults to 5 MB and can be set to -1 to be disabled.
	BulkSize int `json:"bulk_size,omitempty"`

	// BulkFlushInterval specifies when to flush at the end of the given interval.
	// Defaults to 30 seconds. If you want the bulk processor to
	// operate completely asynchronously, set both BulkActions and BulkSize to
	// -1 and set the FlushInterval to a meaningful interval.
	BulkFlushInterval time.Duration `json:"bulk_flush_interval"`

	// ExponentialBackoffInitialTimeout used to set the first/minimal interval in elastic.ExponentialBackoff
	// Defaults to 10s
	ExponentialBackoffInitialTimeout string `json:"exponential_backoff_initial_timeout,omitempty"`
	exponentialBackoffInitialTimeout time.Duration

	// ExponentialBackoffMaxTimeout used to set the maximum wait interval in elastic.ExponentialBackoff
	// Defaults to 5m
	ExponentialBackoffMaxTimeout string `json:"exponential_backoff_max_timeout,omitempty"`
	exponentialBackoffMaxTimeout time.Duration

	client    *elastic.Client        // elastic client instance
	processor *elastic.BulkProcessor // elastic bulk processor
}

// DefaultOutputConfig returns an OutputConfig struct with default values
func DefaultOutputConfig() OutputConfig {
	return OutputConfig{
		OutputConfig: config.OutputConfig{
			CommonConfig: config.CommonConfig{
				Type: ModuleName,
			},
		},
		BulkActions:                      1000,    // 1000 actions
		BulkSize:                         5 << 20, // 5 MB
		BulkFlushInterval:                30 * time.Second,
		ExponentialBackoffInitialTimeout: "10s",
		ExponentialBackoffMaxTimeout:     "5m",
	}
}

// errors
var (
	ErrorCreateClientFailed1 = errutil.NewFactory("create elastic client failed: %q")
)

type errorLogger struct {
	logger logrus.FieldLogger
}

// Printf log format string to error level
func (l *errorLogger) Printf(format string, args ...interface{}) {
	l.logger.Errorf(format, args...)
}

// InitHandler initialize the output plugin
func InitHandler(ctx context.Context, raw *config.ConfigRaw) (config.TypeOutputConfig, error) {
	conf := DefaultOutputConfig()
	err := config.ReflectConfig(raw, &conf)
	if err != nil {
		return nil, err
	}

	// map Printf to error level
	logger := &errorLogger{logger: goglog.Logger}

	if conf.client, err = elastic.NewClient(
		elastic.SetURL(conf.URL),
		elastic.SetSniff(conf.Sniff),
		elastic.SetErrorLog(logger),
	); err != nil {
		return nil, ErrorCreateClientFailed1.New(err, conf.URL)
	}

	conf.exponentialBackoffInitialTimeout, err = time.ParseDuration(conf.ExponentialBackoffInitialTimeout)
	if err != nil {
		return nil, err
	}

	conf.exponentialBackoffMaxTimeout, err = time.ParseDuration(conf.ExponentialBackoffMaxTimeout)
	if err != nil {
		return nil, err
	}

	conf.processor, err = conf.client.BulkProcessor().
		Name("gogstash-output-elastic").
		BulkActions(conf.BulkActions).
		BulkSize(conf.BulkSize).
		FlushInterval(conf.BulkFlushInterval).
		Backoff(elastic.NewExponentialBackoff(conf.exponentialBackoffInitialTimeout, conf.exponentialBackoffMaxTimeout)).
		After(conf.BulkAfter).
		Do(ctx)
	if err != nil {
		return nil, err
	}

	return &conf, nil
}

// BulkAfter execute after a commit to Elasticsearch
func (t *OutputConfig) BulkAfter(executionID int64, requests []elastic.BulkableRequest, response *elastic.BulkResponse, err error) {
	if err == nil && response.Errors {
		// find failed requests, and log it
		for i, item := range response.Items {
			for _, v := range item {
				if v.Error != nil {
					goglog.Logger.Errorf("%s: bulk processor request %s failed: %s", ModuleName, requests[i].String(), v.Error.Reason)
				}
			}
		}
	}
}

// Output event
func (t *OutputConfig) Output(ctx context.Context, event logevent.LogEvent) (err error) {
	index := event.Format(t.Index)
	// elastic index name should be lowercase
	index = strings.ToLower(index)
	doctype := event.Format(t.DocumentType)
	id := event.Format(t.DocumentID)

	indexRequest := elastic.NewBulkIndexRequest().
		Index(index).
		Type(doctype).
		Id(id).
		Doc(event)
	t.processor.Add(indexRequest)

	return
}
<commit_msg>Support multiple elasticsearch endpoints.<commit_after>package outputelastic

import (
	"context"
	"strings"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/tsaikd/KDGoLib/errutil"
	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/config/goglog"
	"github.com/tsaikd/gogstash/config/logevent"
	elastic "gopkg.in/olivere/elastic.v5"
)

// ModuleName is the name used in config file
const ModuleName = "elastic"

// OutputConfig holds the configuration json fields and internal objects
type OutputConfig struct {
	config.OutputConfig
	URL          []string `json:"url"`           // elastic API entrypoints
	Index        string   `json:"index"`         // index name to log
	DocumentType string   `json:"document_type"` // type name to log
	DocumentID   string   `json:"document_id"`   // id to log, used if you want to control id format

	Sniff bool `json:"sniff"` // find all nodes of your cluster, https://github.com/olivere/elastic/wiki/Sniffing

	// BulkActions specifies when to flush based on the number of actions
	// currently added. Defaults to 1000 and can be set to -1 to be disabled.
	BulkActions int `json:"bulk_actions,omitempty"`

	// BulkSize specifies when to flush based on the size (in bytes) of the actions
	// currently added. Defaults to 5 MB and can be set to -1 to be disabled.
	BulkSize int `json:"bulk_size,omitempty"`

	// BulkFlushInterval specifies when to flush at the end of the given interval.
	// Defaults to 30 seconds. If you want the bulk processor to
	// operate completely asynchronously, set both BulkActions and BulkSize to
	// -1 and set the FlushInterval to a meaningful interval.
	BulkFlushInterval time.Duration `json:"bulk_flush_interval"`

	// ExponentialBackoffInitialTimeout used to set the first/minimal interval in elastic.ExponentialBackoff
	// Defaults to 10s
	ExponentialBackoffInitialTimeout string `json:"exponential_backoff_initial_timeout,omitempty"`
	exponentialBackoffInitialTimeout time.Duration

	// ExponentialBackoffMaxTimeout used to set the maximum wait interval in elastic.ExponentialBackoff
	// Defaults to 5m
	ExponentialBackoffMaxTimeout string `json:"exponential_backoff_max_timeout,omitempty"`
	exponentialBackoffMaxTimeout time.Duration

	client    *elastic.Client        // elastic client instance
	processor *elastic.BulkProcessor // elastic bulk processor
}

// DefaultOutputConfig returns an OutputConfig struct with default values
func DefaultOutputConfig() OutputConfig {
	return OutputConfig{
		OutputConfig: config.OutputConfig{
			CommonConfig: config.CommonConfig{
				Type: ModuleName,
			},
		},
		BulkActions:                      1000,    // 1000 actions
		BulkSize:                         5 << 20, // 5 MB
		BulkFlushInterval:                30 * time.Second,
		ExponentialBackoffInitialTimeout: "10s",
		ExponentialBackoffMaxTimeout:     "5m",
	}
}

// errors
var (
	ErrorCreateClientFailed1 = errutil.NewFactory("create elastic client failed: %q")
)

type errorLogger struct {
	logger logrus.FieldLogger
}

// Printf log format string to error level
func (l *errorLogger) Printf(format string, args ...interface{}) {
	l.logger.Errorf(format, args...)
}

// InitHandler initialize the output plugin
func InitHandler(ctx context.Context, raw *config.ConfigRaw) (config.TypeOutputConfig, error) {
	conf := DefaultOutputConfig()
	err := config.ReflectConfig(raw, &conf)
	if err != nil {
		return nil, err
	}

	// map Printf to error level
	logger := &errorLogger{logger: goglog.Logger}

	if conf.client, err = elastic.NewClient(
		elastic.SetURL(conf.URL...),
		elastic.SetSniff(conf.Sniff),
		elastic.SetErrorLog(logger),
	); err != nil {
		return nil, ErrorCreateClientFailed1.New(err, conf.URL)
	}

	conf.exponentialBackoffInitialTimeout, err = time.ParseDuration(conf.ExponentialBackoffInitialTimeout)
	if err != nil {
		return nil, err
	}

	conf.exponentialBackoffMaxTimeout, err = time.ParseDuration(conf.ExponentialBackoffMaxTimeout)
	if err != nil {
		return nil, err
	}

	conf.processor, err = conf.client.BulkProcessor().
		Name("gogstash-output-elastic").
		BulkActions(conf.BulkActions).
		BulkSize(conf.BulkSize).
		FlushInterval(conf.BulkFlushInterval).
		Backoff(elastic.NewExponentialBackoff(conf.exponentialBackoffInitialTimeout, conf.exponentialBackoffMaxTimeout)).
		After(conf.BulkAfter).
		Do(ctx)
	if err != nil {
		return nil, err
	}

	return &conf, nil
}

// BulkAfter execute after a commit to Elasticsearch
func (t *OutputConfig) BulkAfter(executionID int64, requests []elastic.BulkableRequest, response *elastic.BulkResponse, err error) {
	if err == nil && response.Errors {
		// find failed requests, and log it
		for i, item := range response.Items {
			for _, v := range item {
				if v.Error != nil {
					goglog.Logger.Errorf("%s: bulk processor request %s failed: %s", ModuleName, requests[i].String(), v.Error.Reason)
				}
			}
		}
	}
}

// Output event
func (t *OutputConfig) Output(ctx context.Context, event logevent.LogEvent) (err error) {
	index := event.Format(t.Index)
	// elastic index name should be lowercase
	index = strings.ToLower(index)
	doctype := event.Format(t.DocumentType)
	id := event.Format(t.DocumentID)

	indexRequest := elastic.NewBulkIndexRequest().
		Index(index).
		Type(doctype).
		Id(id).
		Doc(event)
	t.processor.Add(indexRequest)

	return
}
<|endoftext|>


<commit_before>package libp2pquic

import (
	"context"
	"crypto/sha256"
	"errors"
	"io"
	"net"

	"golang.org/x/crypto/hkdf"

	logging "github.com/ipfs/go-log"
	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/pnet"
	tpt "github.com/libp2p/go-libp2p-core/transport"
	p2ptls "github.com/libp2p/go-libp2p-tls"
	filter "github.com/libp2p/go-maddr-filter"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	mafmt "github.com/multiformats/go-multiaddr-fmt"
	manet "github.com/multiformats/go-multiaddr-net"
)

var log = logging.Logger("quic-transport")

var quicConfig = &quic.Config{
	MaxIncomingStreams:                    1000,
	MaxIncomingUniStreams:                 -1,             // disable unidirectional streams
	MaxReceiveStreamFlowControlWindow:     10 * (1 << 20), // 10 MB
	MaxReceiveConnectionFlowControlWindow: 15 * (1 << 20), // 15 MB
	AcceptToken: func(clientAddr net.Addr, _ *quic.Token) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
	KeepAlive: true,
}

type connManager struct {
	reuseUDP4 *reuse
	reuseUDP6 *reuse
}

func newConnManager(filters *filter.Filters) (*connManager, error) {
	reuseUDP4, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	reuseUDP6, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	return &connManager{
		reuseUDP4: reuseUDP4,
		reuseUDP6: reuseUDP6,
	}, nil
}

func (c *connManager) getReuse(network string) (*reuse, error) {
	switch network {
	case "udp4":
		return c.reuseUDP4, nil
	case "udp6":
		return c.reuseUDP6, nil
	default:
		return nil, errors.New("invalid network: must be either udp4 or udp6")
	}
}

func (c *connManager) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Listen(network, laddr)
}

func (c *connManager) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Dial(network, raddr)
}

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey     ic.PrivKey
	localPeer   peer.ID
	identity    *p2ptls.Identity
	connManager *connManager
	config      *quic.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Transport, error) {
	if len(psk) > 0 {
		log.Error("QUIC doesn't support private networks yet.")
		return nil, errors.New("QUIC doesn't support private networks yet")
	}
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	identity, err := p2ptls.NewIdentity(key)
	if err != nil {
		return nil, err
	}
	connManager, err := newConnManager(filters)
	if err != nil {
		return nil, err
	}
	config := quicConfig.Clone()
	keyBytes, err := key.Raw()
	if err != nil {
		return nil, err
	}
	keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte("libp2p quic stateless reset key"))
	config.StatelessResetKey = make([]byte, 32)
	if _, err := io.ReadFull(keyReader, config.StatelessResetKey); err != nil {
		return nil, err
	}

	return &transport{
		privKey:     key,
		localPeer:   localPeer,
		identity:    identity,
		connManager: connManager,
		config:      config,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) {
	network, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	addr, err := net.ResolveUDPAddr(network, host)
	if err != nil {
		return nil, err
	}
	remoteMultiaddr, err := toQuicMultiaddr(addr)
	if err != nil {
		return nil, err
	}
	tlsConf, keyCh := t.identity.ConfigForPeer(p)
	pconn, err := t.connManager.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, t.config)
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	// Should be ready by this point, don't block.
	var remotePubKey ic.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}
	if remotePubKey == nil {
		pconn.DecreaseCount()
		return nil, errors.New("go-libp2p-quic-transport BUG: expected remote pub key to be set")
	}
	go func() {
		<-sess.Context().Done()
		pconn.DecreaseCount()
	}()

	localMultiaddr, err := toQuicMultiaddr(pconn.LocalAddr())
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	return &conn{
		sess:            sess,
		transport:       t,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: remoteMultiaddr,
	}, nil
}

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.QUIC.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	lnet, host, err := manet.DialArgs(addr)
	if err != nil {
		return nil, err
	}
	laddr, err := net.ResolveUDPAddr(lnet, host)
	if err != nil {
		return nil, err
	}
	conn, err := t.connManager.Listen(lnet, laddr)
	if err != nil {
		return nil, err
	}
	return newListener(conn, t, t.localPeer, t.privKey, t.identity)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<commit_msg>use minio/sha256-simd instead of standard library SHA256<commit_after>package libp2pquic

import (
	"context"
	"errors"
	"io"
	"net"

	"github.com/minio/sha256-simd"
	"golang.org/x/crypto/hkdf"

	logging "github.com/ipfs/go-log"
	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/pnet"
	tpt "github.com/libp2p/go-libp2p-core/transport"
	p2ptls "github.com/libp2p/go-libp2p-tls"
	filter "github.com/libp2p/go-maddr-filter"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	mafmt "github.com/multiformats/go-multiaddr-fmt"
	manet "github.com/multiformats/go-multiaddr-net"
)

var log = logging.Logger("quic-transport")

var quicConfig = &quic.Config{
	MaxIncomingStreams:                    1000,
	MaxIncomingUniStreams:                 -1,             // disable unidirectional streams
	MaxReceiveStreamFlowControlWindow:     10 * (1 << 20), // 10 MB
	MaxReceiveConnectionFlowControlWindow: 15 * (1 << 20), // 15 MB
	AcceptToken: func(clientAddr net.Addr, _ *quic.Token) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
	KeepAlive: true,
}

type connManager struct {
	reuseUDP4 *reuse
	reuseUDP6 *reuse
}

func newConnManager(filters *filter.Filters) (*connManager, error) {
	reuseUDP4, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	reuseUDP6, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	return &connManager{
		reuseUDP4: reuseUDP4,
		reuseUDP6: reuseUDP6,
	}, nil
}

func (c *connManager) getReuse(network string) (*reuse, error) {
	switch network {
	case "udp4":
		return c.reuseUDP4, nil
	case "udp6":
		return c.reuseUDP6, nil
	default:
		return nil, errors.New("invalid network: must be either udp4 or udp6")
	}
}

func (c *connManager) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Listen(network, laddr)
}

func (c *connManager) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Dial(network, raddr)
}

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey     ic.PrivKey
	localPeer   peer.ID
	identity    *p2ptls.Identity
	connManager *connManager
	config      *quic.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Transport, error) {
	if len(psk) > 0 {
		log.Error("QUIC doesn't support private networks yet.")
		return nil, errors.New("QUIC doesn't support private networks yet")
	}
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	identity, err := p2ptls.NewIdentity(key)
	if err != nil {
		return nil, err
	}
	connManager, err := newConnManager(filters)
	if err != nil {
		return nil, err
	}
	config := quicConfig.Clone()
	keyBytes, err := key.Raw()
	if err != nil {
		return nil, err
	}
	keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte("libp2p quic stateless reset key"))
	config.StatelessResetKey = make([]byte, 32)
	if _, err := io.ReadFull(keyReader, config.StatelessResetKey); err != nil {
		return nil, err
	}

	return &transport{
		privKey:     key,
		localPeer:   localPeer,
		identity:    identity,
		connManager: connManager,
		config:      config,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) {
	network, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	addr, err := net.ResolveUDPAddr(network, host)
	if err != nil {
		return nil, err
	}
	remoteMultiaddr, err := toQuicMultiaddr(addr)
	if err != nil {
		return nil, err
	}
	tlsConf, keyCh := t.identity.ConfigForPeer(p)
	pconn, err := t.connManager.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, t.config)
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	// Should be ready by this point, don't block.
	var remotePubKey ic.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}
	if remotePubKey == nil {
		pconn.DecreaseCount()
		return nil, errors.New("go-libp2p-quic-transport BUG: expected remote pub key to be set")
	}
	go func() {
		<-sess.Context().Done()
		pconn.DecreaseCount()
	}()

	localMultiaddr, err := toQuicMultiaddr(pconn.LocalAddr())
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	return &conn{
		sess:            sess,
		transport:       t,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: remoteMultiaddr,
	}, nil
}

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.QUIC.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	lnet, host, err := manet.DialArgs(addr)
	if err != nil {
		return nil, err
	}
	laddr, err := net.ResolveUDPAddr(lnet, host)
	if err != nil {
		return nil, err
	}
	conn, err := t.connManager.Listen(lnet, laddr)
	if err != nil {
		return nil, err
	}
	return newListener(conn, t, t.localPeer, t.privKey, t.identity)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<|endoftext|>


<commit_before>package js

import (
	"github.com/loadimpact/k6/stats"
	"time"
)

func (a JSAPI) MetricAdd(m *stats.Metric, v float64, tags map[string]string) {
	t := time.Now()
	s := stats.Sample{Metric: m, Time: t, Tags: tags, Value: v}
	a.vu.Samples = append(a.vu.Samples, s)
}
<commit_msg>[fix] Custom metrics deal with ms, not ns<commit_after>package js

import (
	"github.com/loadimpact/k6/stats"
	"time"
)

func (a JSAPI) MetricAdd(m *stats.Metric, v float64, tags map[string]string) {
	t := time.Now()
	if m.Contains == stats.Time {
		v *= 1000
	}
	s := stats.Sample{Metric: m, Time: t, Tags: tags, Value: v}
	a.vu.Samples = append(a.vu.Samples, s)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcCreate,
		Read:   resourceAwsVpcRead,
		Update: resourceAwsVpcUpdate,
		Delete: resourceAwsVpcDelete,

		Schema: map[string]*schema.Schema{
			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)
					_, ipnet, err := net.ParseCIDR(value)

					if err != nil || ipnet == nil || value != ipnet.String() {
						errors = append(errors, fmt.Errorf(
							"%q must contain a valid CIDR", k))
					}
					return
				},
			},

			"instance_tenancy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"enable_dns_hostnames": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_dns_support": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_classiclink": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},

			"main_route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_network_acl_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"dhcp_options_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	instance_tenancy := "default"
	if v, ok := d.GetOk("instance_tenancy"); ok {
		instance_tenancy = v.(string)
	}
	// Create the VPC
	createOpts := &ec2.CreateVpcInput{
		CidrBlock:       aws.String(d.Get("cidr_block").(string)),
		InstanceTenancy: aws.String(instance_tenancy),
	}
	log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
	vpcResp, err := conn.CreateVpc(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating VPC: %s", err)
	}

	// Get the ID and store it
	vpc := vpcResp.Vpc
	d.SetId(*vpc.VpcId)
	log.Printf("[INFO] VPC ID: %s", d.Id())

	// Set partial mode and say that we setup the cidr block
	d.Partial(true)
	d.SetPartial("cidr_block")

	// Wait for the VPC to become available
	log.Printf(
		"[DEBUG] Waiting for VPC (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"available"},
		Refresh: VPCStateRefreshFunc(conn, d.Id()),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for VPC (%s) to become available: %s",
			d.Id(), err)
	}

	// Update our attributes and return
	return resourceAwsVpcUpdate(d, meta)
}

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

	// Refresh the VPC state
	vpcRaw, _, err := VPCStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}
	if vpcRaw == nil {
		d.SetId("")
		return nil
	}

	// VPC stuff
	vpc := vpcRaw.(*ec2.Vpc)
	vpcid := d.Id()
	d.Set("cidr_block", vpc.CidrBlock)
	d.Set("dhcp_options_id", vpc.DhcpOptionsId)

	// Tags
	d.Set("tags", tagsToMap(vpc.Tags))

	// Attributes
	attribute := "enableDnsSupport"
	DescribeAttrOpts := &ec2.DescribeVpcAttributeInput{
		Attribute: aws.String(attribute),
		VpcId:     aws.String(vpcid),
	}
	resp, err := conn.DescribeVpcAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_support", *resp.EnableDnsSupport)
	attribute = "enableDnsHostnames"
	DescribeAttrOpts = &ec2.DescribeVpcAttributeInput{
		Attribute: &attribute,
		VpcId:     &vpcid,
	}
	resp, err = conn.DescribeVpcAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_hostnames", *resp.EnableDnsHostnames)

	DescribeClassiclinkOpts := &ec2.DescribeVpcClassicLinkInput{
		VpcIds: []*string{&vpcid},
	}

	// Classic Link is only available in regions that support EC2 Classic
	respClassiclink, err := conn.DescribeVpcClassicLink(DescribeClassiclinkOpts)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "UnsupportedOperation" {
			log.Printf("[WARN] VPC Classic Link is not supported in this region")
		} else {
			return err
		}
	} else {
		classiclink_enabled := false
		for _, v := range respClassiclink.Vpcs {
			if *v.VpcId == vpcid {
				if v.ClassicLinkEnabled != nil {
					classiclink_enabled = *v.ClassicLinkEnabled
				}
				break
			}
		}
		d.Set("enable_classiclink", classiclink_enabled)
	}

	// Get the main routing table for this VPC
	// Really Ugly need to make this better - rmenn
	filter1 := &ec2.Filter{
		Name:   aws.String("association.main"),
		Values: []*string{aws.String("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeRouteOpts := &ec2.DescribeRouteTablesInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	routeResp, err := conn.DescribeRouteTables(DescribeRouteOpts)
	if err != nil {
		return err
	}
	if v := routeResp.RouteTables; len(v) > 0 {
		d.Set("main_route_table_id", *v[0].RouteTableId)
	}

	resourceAwsVpcSetDefaultNetworkAcl(conn, d)
	resourceAwsVpcSetDefaultSecurityGroup(conn, d)

	return nil
}

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

	// Turn on partial mode
	d.Partial(true)
	vpcid := d.Id()
	if d.HasChange("enable_dns_hostnames") {
		val := d.Get("enable_dns_hostnames").(bool)
		modifyOpts := &ec2.ModifyVpcAttributeInput{
			VpcId: &vpcid,
			EnableDnsHostnames: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if d.HasChange("enable_dns_support") {
		val := d.Get("enable_dns_support").(bool)
		modifyOpts := &ec2.ModifyVpcAttributeInput{
			VpcId: &vpcid,
			EnableDnsSupport: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if d.HasChange("enable_classiclink") {
		val := d.Get("enable_classiclink").(bool)

		if val {
			modifyOpts := &ec2.EnableVpcClassicLinkInput{
				VpcId: &vpcid,
			}
			log.Printf(
				"[INFO] Modifying enable_classiclink vpc attribute for %s: %#v",
				d.Id(), modifyOpts)
			if _, err := conn.EnableVpcClassicLink(modifyOpts); err != nil {
				return err
			}
		} else {
			modifyOpts := &ec2.DisableVpcClassicLinkInput{
				VpcId: &vpcid,
			}
			log.Printf(
				"[INFO] Modifying enable_classiclink vpc attribute for %s: %#v",
				d.Id(), modifyOpts)
			if _, err := conn.DisableVpcClassicLink(modifyOpts); err != nil {
				return err
			}
		}

		d.SetPartial("enable_classiclink")
	}

	if err := setTags(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)
	return resourceAwsVpcRead(d, meta)
}

func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	vpcID := d.Id()
	DeleteVpcOpts := &ec2.DeleteVpcInput{
		VpcId: &vpcID,
	}
	log.Printf("[INFO] Deleting VPC: %s", d.Id())

	return resource.Retry(5*time.Minute, func() error {
		_, err := conn.DeleteVpc(DeleteVpcOpts)
		if err == nil {
			return nil
		}

		ec2err, ok := err.(awserr.Error)
		if !ok {
			return &resource.RetryError{Err: err}
		}

		switch ec2err.Code() {
		case "InvalidVpcID.NotFound":
			return nil
		case "DependencyViolation":
			return err
		}

		return &resource.RetryError{
			Err: fmt.Errorf("Error deleting VPC: %s", err),
		}
	})
}

// VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPC.
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeVpcOpts := &ec2.DescribeVpcsInput{
			VpcIds: []*string{aws.String(id)},
		}
		resp, err := conn.DescribeVpcs(DescribeVpcOpts)
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VPCStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		vpc := resp.Vpcs[0]
		return vpc, *vpc.State, nil
	}
}

func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("default"),
		Values: []*string{aws.String("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeNetworkACLOpts := &ec2.DescribeNetworkAclsInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	networkAclResp, err := conn.DescribeNetworkAcls(DescribeNetworkACLOpts)

	if err != nil {
		return err
	}
	if v := networkAclResp.NetworkAcls; len(v) > 0 {
		d.Set("default_network_acl_id", v[0].NetworkAclId)
	}

	return nil
}

func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("group-name"),
		Values: []*string{aws.String("default")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeSgOpts := &ec2.DescribeSecurityGroupsInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)

	if err != nil {
		return err
	}
	if v := securityGroupResp.SecurityGroups; len(v) > 0 {
		d.Set("default_security_group_id", v[0].GroupId)
	}

	return nil
}
<commit_msg>provider/aws: Change VPC ClassicLink to be computed<commit_after>package aws

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcCreate,
		Read:   resourceAwsVpcRead,
		Update: resourceAwsVpcUpdate,
		Delete: resourceAwsVpcDelete,

		Schema: map[string]*schema.Schema{
			"cidr_block": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)
					_, ipnet, err := net.ParseCIDR(value)

					if err != nil || ipnet == nil || value != ipnet.String() {
						errors = append(errors, fmt.Errorf(
							"%q must contain a valid CIDR", k))
					}
					return
				},
			},

			"instance_tenancy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"enable_dns_hostnames": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_dns_support": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"enable_classiclink": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
			},

			"main_route_table_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_network_acl_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"dhcp_options_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"default_security_group_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	instance_tenancy := "default"
	if v, ok := d.GetOk("instance_tenancy"); ok {
		instance_tenancy = v.(string)
	}
	// Create the VPC
	createOpts := &ec2.CreateVpcInput{
		CidrBlock:       aws.String(d.Get("cidr_block").(string)),
		InstanceTenancy: aws.String(instance_tenancy),
	}
	log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
	vpcResp, err := conn.CreateVpc(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating VPC: %s", err)
	}

	// Get the ID and store it
	vpc := vpcResp.Vpc
	d.SetId(*vpc.VpcId)
	log.Printf("[INFO] VPC ID: %s", d.Id())

	// Set partial mode and say that we setup the cidr block
	d.Partial(true)
	d.SetPartial("cidr_block")

	// Wait for the VPC to become available
	log.Printf(
		"[DEBUG] Waiting for VPC (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"available"},
		Refresh: VPCStateRefreshFunc(conn, d.Id()),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for VPC (%s) to become available: %s",
			d.Id(), err)
	}

	// Update our attributes and return
	return resourceAwsVpcUpdate(d, meta)
}

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

	// Refresh the VPC state
	vpcRaw, _, err := VPCStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}
	if vpcRaw == nil {
		d.SetId("")
		return nil
	}

	// VPC stuff
	vpc := vpcRaw.(*ec2.Vpc)
	vpcid := d.Id()
	d.Set("cidr_block", vpc.CidrBlock)
	d.Set("dhcp_options_id", vpc.DhcpOptionsId)

	// Tags
	d.Set("tags", tagsToMap(vpc.Tags))

	// Attributes
	attribute := "enableDnsSupport"
	DescribeAttrOpts := &ec2.DescribeVpcAttributeInput{
		Attribute: aws.String(attribute),
		VpcId:     aws.String(vpcid),
	}
	resp, err := conn.DescribeVpcAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_support", *resp.EnableDnsSupport)
	attribute = "enableDnsHostnames"
	DescribeAttrOpts = &ec2.DescribeVpcAttributeInput{
		Attribute: &attribute,
		VpcId:     &vpcid,
	}
	resp, err = conn.DescribeVpcAttribute(DescribeAttrOpts)
	if err != nil {
		return err
	}
	d.Set("enable_dns_hostnames", *resp.EnableDnsHostnames)

	DescribeClassiclinkOpts := &ec2.DescribeVpcClassicLinkInput{
		VpcIds: []*string{&vpcid},
	}

	// Classic Link is only available in regions that support EC2 Classic
	respClassiclink, err := conn.DescribeVpcClassicLink(DescribeClassiclinkOpts)
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "UnsupportedOperation" {
			log.Printf("[WARN] VPC Classic Link is not supported in this region")
		} else {
			return err
		}
	} else {
		classiclink_enabled := false
		for _, v := range respClassiclink.Vpcs {
			if *v.VpcId == vpcid {
				if v.ClassicLinkEnabled != nil {
					classiclink_enabled = *v.ClassicLinkEnabled
				}
				break
			}
		}
		d.Set("enable_classiclink", classiclink_enabled)
	}

	// Get the main routing table for this VPC
	// Really Ugly need to make this better - rmenn
	filter1 := &ec2.Filter{
		Name:   aws.String("association.main"),
		Values: []*string{aws.String("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeRouteOpts := &ec2.DescribeRouteTablesInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	routeResp, err := conn.DescribeRouteTables(DescribeRouteOpts)
	if err != nil {
		return err
	}
	if v := routeResp.RouteTables; len(v) > 0 {
		d.Set("main_route_table_id", *v[0].RouteTableId)
	}

	resourceAwsVpcSetDefaultNetworkAcl(conn, d)
	resourceAwsVpcSetDefaultSecurityGroup(conn, d)

	return nil
}

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

	// Turn on partial mode
	d.Partial(true)
	vpcid := d.Id()
	if d.HasChange("enable_dns_hostnames") {
		val := d.Get("enable_dns_hostnames").(bool)
		modifyOpts := &ec2.ModifyVpcAttributeInput{
			VpcId: &vpcid,
			EnableDnsHostnames: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if d.HasChange("enable_dns_support") {
		val := d.Get("enable_dns_support").(bool)
		modifyOpts := &ec2.ModifyVpcAttributeInput{
			VpcId: &vpcid,
			EnableDnsSupport: &ec2.AttributeBooleanValue{
				Value: &val,
			},
		}

		log.Printf(
			"[INFO] Modifying enable_dns_support vpc attribute for %s: %#v",
			d.Id(), modifyOpts)
		if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
			return err
		}

		d.SetPartial("enable_dns_support")
	}

	if d.HasChange("enable_classiclink") {
		val := d.Get("enable_classiclink").(bool)

		if val {
			modifyOpts := &ec2.EnableVpcClassicLinkInput{
				VpcId: &vpcid,
			}
			log.Printf(
				"[INFO] Modifying enable_classiclink vpc attribute for %s: %#v",
				d.Id(), modifyOpts)
			if _, err := conn.EnableVpcClassicLink(modifyOpts); err != nil {
				return err
			}
		} else {
			modifyOpts := &ec2.DisableVpcClassicLinkInput{
				VpcId: &vpcid,
			}
			log.Printf(
				"[INFO] Modifying enable_classiclink vpc attribute for %s: %#v",
				d.Id(), modifyOpts)
			if _, err := conn.DisableVpcClassicLink(modifyOpts); err != nil {
				return err
			}
		}

		d.SetPartial("enable_classiclink")
	}

	if err := setTags(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)
	return resourceAwsVpcRead(d, meta)
}

func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	vpcID := d.Id()
	DeleteVpcOpts := &ec2.DeleteVpcInput{
		VpcId: &vpcID,
	}
	log.Printf("[INFO] Deleting VPC: %s", d.Id())

	return resource.Retry(5*time.Minute, func() error {
		_, err := conn.DeleteVpc(DeleteVpcOpts)
		if err == nil {
			return nil
		}

		ec2err, ok := err.(awserr.Error)
		if !ok {
			return &resource.RetryError{Err: err}
		}

		switch ec2err.Code() {
		case "InvalidVpcID.NotFound":
			return nil
		case "DependencyViolation":
			return err
		}

		return &resource.RetryError{
			Err: fmt.Errorf("Error deleting VPC: %s", err),
		}
	})
}

// VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPC.
func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeVpcOpts := &ec2.DescribeVpcsInput{
			VpcIds: []*string{aws.String(id)},
		}
		resp, err := conn.DescribeVpcs(DescribeVpcOpts)
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VPCStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		vpc := resp.Vpcs[0]
		return vpc, *vpc.State, nil
	}
}

func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("default"),
		Values: []*string{aws.String("true")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeNetworkACLOpts := &ec2.DescribeNetworkAclsInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	networkAclResp, err := conn.DescribeNetworkAcls(DescribeNetworkACLOpts)

	if err != nil {
		return err
	}
	if v := networkAclResp.NetworkAcls; len(v) > 0 {
		d.Set("default_network_acl_id", v[0].NetworkAclId)
	}

	return nil
}

func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error {
	filter1 := &ec2.Filter{
		Name:   aws.String("group-name"),
		Values: []*string{aws.String("default")},
	}
	filter2 := &ec2.Filter{
		Name:   aws.String("vpc-id"),
		Values: []*string{aws.String(d.Id())},
	}
	DescribeSgOpts := &ec2.DescribeSecurityGroupsInput{
		Filters: []*ec2.Filter{filter1, filter2},
	}
	securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts)

	if err != nil {
		return err
	}
	if v := securityGroupResp.SecurityGroups; len(v) > 0 {
		d.Set("default_security_group_id", v[0].GroupId)
	}

	return nil
}
<|endoftext|>


<commit_before>package json

import (
	"bytes"
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/tdewolff/minify/v2"
	"github.com/tdewolff/test"
)

func TestJSON(t *testing.T) {
	jsonTests := []struct {
		json     string
		expected string
	}{
		{"{ \"a\": [1, 2] }", "{\"a\":[1,2]}"},
		{"[{ \"a\": [{\"x\": null}, true] }]", "[{\"a\":[{\"x\":null},true]}]"},
		{"{ \"a\": 1, \"b\": 2 }", "{\"a\":1,\"b\":2}"},
	}

	m := minify.New()
	for _, tt := range jsonTests {
		t.Run(tt.json, func(t *testing.T) {
			r := bytes.NewBufferString(tt.json)
			w := &bytes.Buffer{}
			err := Minify(m, w, r, nil)
			test.Minify(t, tt.json, err, w.String(), tt.expected)
		})
	}
}

func TestReaderErrors(t *testing.T) {
	r := test.NewErrorReader(0)
	w := &bytes.Buffer{}
	m := minify.New()
	err := Minify(m, w, r, nil)
	test.T(t, err, test.ErrPlain, "return error at first read")
}

func TestWriterErrors(t *testing.T) {
	errorTests := []struct {
		json string
		n    []int
	}{
		//01    234  56  78
		{`{"key":[100,200]}`, []int{0, 1, 2, 3, 4, 5, 7, 8}},
	}

	m := minify.New()
	for _, tt := range errorTests {
		for _, n := range tt.n {
			t.Run(fmt.Sprint(tt.json, " ", tt.n), func(t *testing.T) {
				r := bytes.NewBufferString(tt.json)
				w := test.NewErrorWriter(n)
				err := Minify(m, w, r, nil)
				test.T(t, err, test.ErrPlain)
			})
		}
	}
}

////////////////////////////////////////////////////////////////

func ExampleMinify() {
	m := minify.New()
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), Minify)

	if err := m.Minify("application/json", os.Stdout, os.Stdin); err != nil {
		panic(err)
	}
}
<commit_msg>Add empty JSON test<commit_after>package json

import (
	"bytes"
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/tdewolff/minify/v2"
	"github.com/tdewolff/test"
)

func TestJSON(t *testing.T) {
	jsonTests := []struct {
		json     string
		expected string
	}{
		{"", ""},
		{"{ \"a\": [1, 2] }", "{\"a\":[1,2]}"},
		{"[{ \"a\": [{\"x\": null}, true] }]", "[{\"a\":[{\"x\":null},true]}]"},
		{"{ \"a\": 1, \"b\": 2 }", "{\"a\":1,\"b\":2}"},
	}

	m := minify.New()
	for _, tt := range jsonTests {
		t.Run(tt.json, func(t *testing.T) {
			r := bytes.NewBufferString(tt.json)
			w := &bytes.Buffer{}
			err := Minify(m, w, r, nil)
			test.Minify(t, tt.json, err, w.String(), tt.expected)
		})
	}
}

func TestReaderErrors(t *testing.T) {
	r := test.NewErrorReader(0)
	w := &bytes.Buffer{}
	m := minify.New()
	err := Minify(m, w, r, nil)
	test.T(t, err, test.ErrPlain, "return error at first read")
}

func TestWriterErrors(t *testing.T) {
	errorTests := []struct {
		json string
		n    []int
	}{
		//01    234  56  78
		{`{"key":[100,200]}`, []int{0, 1, 2, 3, 4, 5, 7, 8}},
	}

	m := minify.New()
	for _, tt := range errorTests {
		for _, n := range tt.n {
			t.Run(fmt.Sprint(tt.json, " ", tt.n), func(t *testing.T) {
				r := bytes.NewBufferString(tt.json)
				w := test.NewErrorWriter(n)
				err := Minify(m, w, r, nil)
				test.T(t, err, test.ErrPlain)
			})
		}
	}
}

////////////////////////////////////////////////////////////////

func ExampleMinify() {
	m := minify.New()
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), Minify)

	if err := m.Minify("application/json", os.Stdout, os.Stdin); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// packet is a wrapper for GoPacket and sub packages
package packet

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

// TCPFlags holds TCP flags
type TCPFlags struct {
	FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
}

// Packet holds all layers information
type Packet struct {
	EthType    layers.EthernetType
	SrcMAC     net.HardwareAddr
	DstMAC     net.HardwareAddr
	Src        net.IP
	Dst        net.IP
	Proto      layers.IPProtocol
	Flags      TCPFlags
	SrcPort    int
	DstPort    int
	Seq        uint32
	Ack        uint32
	Window     uint16
	Urgent     uint16
	Checksum   uint16
	Payload    string
	DataOffset uint8
}

var (
	device            = "en0"
	snapshotLen int32 = 1024
	promiscuous       = false
	err         error
	timeout     = 100 * time.Nanosecond
	handle      *pcap.Handle
)

// NewPacket creates an empty packet info
func NewPacket() *Packet {
	return &Packet{}
}

// Open is a loop over packets
func (p *Packet) Open() chan *Packet {
	var (
		c    = make(chan *Packet, 1)
		s    = make(chan os.Signal, 1)
		loop = true
	)
	// capture interrupt w/ s channel
	signal.Notify(s, os.Interrupt)

	go func() {
		handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
		if err != nil {
			log.Fatal(err)
		}
		if err := handle.SetBPFFilter(""); err != nil {
			log.Fatal(err)
		}

		defer handle.Close()
		defer close(s)
		defer close(c)

		packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
		for loop {
			packet, err := packetSource.NextPacket()
			if err != nil {
				continue
			}
			select {
			case <-s:
				loop = false
				signal.Stop(s)
			case c <- GetPacketInfo(packet):
			}
		}
	}()
	return c
}

// PrintPretty prints out the captured data
// to the stdout
func (p *Packet) PrintPretty() {
	switch p.EthType {
	case layers.EthernetTypeIPv4:
		p.PrintIPv4()
	case layers.EthernetTypeIPv6:
		println("IPV6")
		p.PrintIPv4()
	case layers.EthernetTypeARP:
		println("ARP")
	default:
		println("unknown")

	}
}

// PrintIPv4 prints IPv4 packets
func (p *Packet) PrintIPv4() {
	switch {
	case p.Proto == layers.IPProtocolTCP:
		log.Printf("IP %s > %s , %s length: %d\n", p.Src, p.Dst, p.Proto, len(p.Payload))
	case p.Proto == layers.IPProtocolUDP:
		log.Printf("IP %s > %s , %s length: %d\n", p.Src, p.Dst, p.Proto, len(p.Payload))
	}
}

// GetPacketInfo -------
func GetPacketInfo(packet gopacket.Packet) *Packet {
	var p Packet
	// Ethernet
	ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
	if ethernetLayer != nil {
		ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
		p.SrcMAC = ethernetPacket.SrcMAC
		p.DstMAC = ethernetPacket.DstMAC
		p.EthType = ethernetPacket.EthernetType
	}
	// IP Address V4
	ipLayer := packet.Layer(layers.LayerTypeIPv4)
	if ipLayer != nil {
		ip, _ := ipLayer.(*layers.IPv4)
		// IP layer variables:
		// Version (Either 4 or 6)
		// IHL (IP Header Length in 32-bit words)
		// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
		// Checksum, SrcIP, DstIP
		p.Src = ip.SrcIP
		p.Dst = ip.DstIP
		p.Proto = ip.Protocol
	}

	// TCP
	tcpLayer := packet.Layer(layers.LayerTypeTCP)
	if tcpLayer != nil {
		tcp, _ := tcpLayer.(*layers.TCP)

		p.Seq = tcp.Seq
		p.Ack = tcp.Ack
		p.Window = tcp.Window
		p.Urgent = tcp.Urgent
		p.Checksum = tcp.Checksum
		p.DataOffset = tcp.DataOffset

		p.Flags.FIN = tcp.FIN
		p.Flags.SYN = tcp.SYN
		p.Flags.RST = tcp.RST
		p.Flags.PSH = tcp.PSH
		p.Flags.ACK = tcp.ACK
		p.Flags.URG = tcp.URG
		p.Flags.ECE = tcp.ECE
		p.Flags.CWR = tcp.CWR
		p.Flags.NS = tcp.NS

		p.SrcPort = int(tcp.SrcPort)
		p.DstPort = int(tcp.DstPort)
	} else {
		// UDP
		udpLayer := packet.Layer(layers.LayerTypeUDP)
		if udpLayer != nil {
			udp, _ := udpLayer.(*layers.UDP)
			p.SrcPort = int(udp.SrcPort)
			p.DstPort = int(udp.DstPort)
		}
	}
	// Iterate over all layers, printing out each layer type
	//fmt.Println("All packet layers:")
	//for _, layer := range packet.Layers() {
	//	fmt.Println("- ", layer.LayerType())
	//}

	// Application
	applicationLayer := packet.ApplicationLayer()
	if applicationLayer != nil {
		p.Payload = string(applicationLayer.Payload())
	}

	// Check for errors
	if err := packet.ErrorLayer(); err != nil {
		fmt.Println("Error decoding some part of the packet:", err)
	}
	return &p
}
<commit_msg>optimized: struct litral<commit_after>// packet is a wrapper for GoPacket and sub packages
package packet

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

// TCPFlags holds TCP flags
type TCPFlags struct {
	FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool
}

// Packet holds all layers information
type Packet struct {
	EthType    layers.EthernetType
	SrcMAC     net.HardwareAddr
	DstMAC     net.HardwareAddr
	Src        net.IP
	Dst        net.IP
	Proto      layers.IPProtocol
	Flags      TCPFlags
	SrcPort    int
	DstPort    int
	Seq        uint32
	Ack        uint32
	Window     uint16
	Urgent     uint16
	Checksum   uint16
	Payload    string
	DataOffset uint8
}

var (
	device            = "en0"
	snapshotLen int32 = 1024
	promiscuous       = false
	err         error
	timeout     = 100 * time.Nanosecond
	handle      *pcap.Handle
)

// NewPacket creates an empty packet info
func NewPacket() *Packet {
	return &Packet{}
}

// Open is a loop over packets
func (p *Packet) Open() chan *Packet {
	var (
		c    = make(chan *Packet, 1)
		s    = make(chan os.Signal, 1)
		loop = true
	)
	// capture interrupt w/ s channel
	signal.Notify(s, os.Interrupt)

	go func() {
		handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
		if err != nil {
			log.Fatal(err)
		}
		if err := handle.SetBPFFilter(""); err != nil {
			log.Fatal(err)
		}

		defer handle.Close()
		defer close(s)
		defer close(c)

		packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
		for loop {
			packet, err := packetSource.NextPacket()
			if err != nil {
				continue
			}
			select {
			case <-s:
				loop = false
				signal.Stop(s)
			case c <- GetPacketInfo(packet):
			}
		}
	}()
	return c
}

// PrintPretty prints out the captured data
// to the stdout
func (p *Packet) PrintPretty() {
	switch p.EthType {
	case layers.EthernetTypeIPv4:
		p.PrintIPv4()
	case layers.EthernetTypeIPv6:
		println("IPV6")
		p.PrintIPv4()
	case layers.EthernetTypeARP:
		println("ARP")
	default:
		println("unknown")

	}
}

// PrintIPv4 prints IPv4 packets
func (p *Packet) PrintIPv4() {
	switch {
	case p.Proto == layers.IPProtocolTCP:
		log.Printf("IP %s > %s , %s length: %d\n", p.Src, p.Dst, p.Proto, len(p.Payload))
	case p.Proto == layers.IPProtocolUDP:
		log.Printf("IP %s > %s , %s length: %d\n", p.Src, p.Dst, p.Proto, len(p.Payload))
	}
}

// GetPacketInfo -------
func GetPacketInfo(packet gopacket.Packet) *Packet {
	var p Packet
	// Ethernet
	ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
	if ethernetLayer != nil {
		ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
		p.SrcMAC = ethernetPacket.SrcMAC
		p.DstMAC = ethernetPacket.DstMAC
		p.EthType = ethernetPacket.EthernetType
	}
	// IP Address V4
	ipLayer := packet.Layer(layers.LayerTypeIPv4)
	if ipLayer != nil {
		ip, _ := ipLayer.(*layers.IPv4)
		// IP layer variables:
		// Version (Either 4 or 6)
		// IHL (IP Header Length in 32-bit words)
		// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
		// Checksum, SrcIP, DstIP
		p.Src = ip.SrcIP
		p.Dst = ip.DstIP
		p.Proto = ip.Protocol
	}

	// TCP
	tcpLayer := packet.Layer(layers.LayerTypeTCP)
	if tcpLayer != nil {
		tcp, _ := tcpLayer.(*layers.TCP)

		p.Flags = TCPFlags{tcp.FIN, tcp.SYN, tcp.RST, tcp.PSH, tcp.ACK, tcp.URG, tcp.ECE, tcp.CWR, tcp.NS}

		p.Seq = tcp.Seq
		p.Ack = tcp.Ack
		p.Window = tcp.Window
		p.Urgent = tcp.Urgent
		p.Checksum = tcp.Checksum
		p.DataOffset = tcp.DataOffset
		p.SrcPort = int(tcp.SrcPort)
		p.DstPort = int(tcp.DstPort)

	} else {
		// UDP
		udpLayer := packet.Layer(layers.LayerTypeUDP)
		if udpLayer != nil {
			udp, _ := udpLayer.(*layers.UDP)
			p.SrcPort = int(udp.SrcPort)
			p.DstPort = int(udp.DstPort)
		}
	}
	// Iterate over all layers, printing out each layer type
	//fmt.Println("All packet layers:")
	//for _, layer := range packet.Layers() {
	//	fmt.Println("- ", layer.LayerType())
	//}

	// Application
	applicationLayer := packet.ApplicationLayer()
	if applicationLayer != nil {
		p.Payload = string(applicationLayer.Payload())
	}

	// Check for errors
	if err := packet.ErrorLayer(); err != nil {
		fmt.Println("Error decoding some part of the packet:", err)
	}
	return &p
}
<|endoftext|>


<commit_before>package action

import (
	"errors"
	"fmt"
	"strings"

	"github.com/gorilla/websocket"
	"github.com/trumae/valente/status"
)

var (
	errNotImplemented = errors.New("Not Implemented!")
)

// Exec execute the js code on WebBrowser
func Exec(ws *websocket.Conn, js string) error {
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Enable the target form field or button.
func Enable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Disable  the target form field or button.
func Disable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Replace target with new content
func Replace(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).replaceWith(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//HTML replace target with new content
func HTML(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).html(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Hide the target
func Hide(ws *websocket.Conn, target string, duration string) error {
	js := fmt.Sprintf("$( \"#%s\" ).hide(\"%s\");", target, duration)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Show the target
func Show(ws *websocket.Conn, target string, duration string) error {
	js := fmt.Sprintf("$( \"#%s\" ).show(\"%s\");", target, duration)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Remove target from the DOM
func Remove(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//InsertTop Insert content at the top of target
func InsertTop(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBottom Insert content at the bottom of target
func InsertBottom(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBefore Insert content at the before of target
func InsertBefore(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertAfter Insert content at the after of target
func InsertAfter(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//Redirect to url
func Redirect(ws *websocket.Conn, url string) error {
	return errNotImplemented
}

//AddClass add a class for an element
func AddClass(ws *websocket.Conn, target, class string) error {
	js := fmt.Sprintf("$('#%s').addClass('%s');", target, class)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//RemoveClass add a class for an element
func RemoveClass(ws *websocket.Conn, target, class string) error {
	js := fmt.Sprintf("$('#%s').removeClass('%s');", target, class)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//Set update a form element (textbox, dropdown, checkbox, etc) to set text value of TargetID.
func Set(ws *websocket.Conn, target, value string) error {
	js := fmt.Sprintf("$('#%s').val('%s');", target, value)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//Get content of form element
func Get(ws *websocket.Conn, target string) (string, error) {
	ret := ""
	js := fmt.Sprintf("ws.send($('#%s').val());", target)
	status.Status.SendedBytes += len(js)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return "", err
	}

	_, bret, err := ws.ReadMessage()
	if err != nil {
		return "", err
	}
	ret = string(bret)
	status.Status.ReceivedBytes += len(ret)

	return ret, nil
}

//Wire bind an action to an event on target
func Wire(ws *websocket.Conn, target, event, act string) error {
	return errNotImplemented
}

//SendEvent send an event to server
func SendEvent(ws *websocket.Conn, event string) error {
	js := fmt.Sprintf("sendEvent('%s');", event)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)

	return nil
}

//Alert show alert message in browser
func Alert(ws *websocket.Conn, message string) error {
	js := fmt.Sprintf("alert('%s');", message)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)

	return nil
}

var (
	//BlockMessage is the message showed in waiting time
	BlockMessage = "
Please, wait...
"
)

//BlockUI block page interaction
func BlockUI(ws *websocket.Conn) {
	Exec(ws, fmt.Sprintf("$.blockUI({ message: '%s' });", BlockMessage))
}

//UnblockUI block page interaction
func UnblockUI(ws *websocket.Conn) {
	Exec(ws, "$.unblockUI();")
}
<commit_msg>Append + Prepend actions<commit_after>package action

import (
	"errors"
	"fmt"
	"strings"

	"github.com/gorilla/websocket"
	"github.com/trumae/valente/status"
)

var (
	errNotImplemented = errors.New("Not Implemented!")
)

// Exec execute the js code on WebBrowser
func Exec(ws *websocket.Conn, js string) error {
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Enable the target form field or button.
func Enable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Disable  the target form field or button.
func Disable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Replace target with new content
func Replace(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).replaceWith(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//HTML replace target with new content
func HTML(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).html(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Hide the target
func Hide(ws *websocket.Conn, target string, duration string) error {
	js := fmt.Sprintf("$( \"#%s\" ).hide(\"%s\");", target, duration)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Show the target
func Show(ws *websocket.Conn, target string, duration string) error {
	js := fmt.Sprintf("$( \"#%s\" ).show(\"%s\");", target, duration)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Remove target from the DOM
func Remove(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Append concate content at target
func Append(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).append(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Prepend concate content at the begin of target
func Prepend(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).prepend(\"%s\");", target, c)

	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return err
}

//Redirect to url
func Redirect(ws *websocket.Conn, url string) error {
	return errNotImplemented
}

//AddClass add a class for an element
func AddClass(ws *websocket.Conn, target, class string) error {
	js := fmt.Sprintf("$('#%s').addClass('%s');", target, class)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//RemoveClass add a class for an element
func RemoveClass(ws *websocket.Conn, target, class string) error {
	js := fmt.Sprintf("$('#%s').removeClass('%s');", target, class)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//Set update a form element (textbox, dropdown, checkbox, etc) to set text value of TargetID.
func Set(ws *websocket.Conn, target, value string) error {
	js := fmt.Sprintf("$('#%s').val('%s');", target, value)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)
	return nil
}

//Get content of form element
func Get(ws *websocket.Conn, target string) (string, error) {
	ret := ""
	js := fmt.Sprintf("ws.send($('#%s').val());", target)
	status.Status.SendedBytes += len(js)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return "", err
	}

	_, bret, err := ws.ReadMessage()
	if err != nil {
		return "", err
	}
	ret = string(bret)
	status.Status.ReceivedBytes += len(ret)

	return ret, nil
}

//Wire bind an action to an event on target
func Wire(ws *websocket.Conn, target, event, act string) error {
	return errNotImplemented
}

//SendEvent send an event to server
func SendEvent(ws *websocket.Conn, event string) error {
	js := fmt.Sprintf("sendEvent('%s');", event)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)

	return nil
}

//Alert show alert message in browser
func Alert(ws *websocket.Conn, message string) error {
	js := fmt.Sprintf("alert('%s');", message)
	err := ws.WriteMessage(websocket.TextMessage, []byte(js))
	if err != nil {
		return err
	}
	status.Status.SendedBytes += len(js)

	return nil
}

var (
	//BlockMessage is the message showed in waiting time
	BlockMessage = "
Please, wait...
"
)

//BlockUI block page interaction
func BlockUI(ws *websocket.Conn) {
	Exec(ws, fmt.Sprintf("$.blockUI({ message: '%s' });", BlockMessage))
}

//UnblockUI block page interaction
func UnblockUI(ws *websocket.Conn) {
	Exec(ws, "$.unblockUI();")
}
<|endoftext|>


<commit_before>// +build !windows

package bind

import (
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"syscall"
)

const tooBigErr = "bind: einhorn@%d not found (einhorn only passed %d fds)"
const bindErr = "bind: could not bind einhorn@%d: not running under einhorn"
const einhornErr = "bind: einhorn environment initialization error"
const ackErr = "bind: error ACKing to einhorn: %v"

var einhornNumFds int

func envInt(val string) (int, error) {
	return strconv.Atoi(os.Getenv(val))
}

// Unfortunately this can't be a normal init function, because their execution
// order is undefined, and we need to run before the init() in bind.go.
func einhornInit() {
	mpid, err := envInt("EINHORN_MASTER_PID")
	if err != nil || mpid != os.Getppid() {
		return
	}

	einhornNumFds, err = envInt("EINHORN_FD_COUNT")
	if err != nil {
		einhornNumFds = 0
		return
	}

	// Prevent einhorn's fds from leaking to our children
	for i := 0; i < einhornNumFds; i++ {
		syscall.CloseOnExec(einhornFdMap(i))
	}
}

func usingEinhorn() bool {
	return einhornNumFds > 0
}

func einhornFdMap(n int) int {
	name := fmt.Sprintf("EINHORN_FD_%d", n)
	fno, err := envInt(name)
	if err != nil {
		log.Fatal(einhornErr)
	}
	return fno
}

func einhornBind(n int) (net.Listener, error) {
	if !usingEinhorn() {
		return nil, fmt.Errorf(bindErr, n)
	}
	if n >= einhornNumFds || n < 0 {
		return nil, fmt.Errorf(tooBigErr, n, einhornNumFds)
	}

	fno := einhornFdMap(n)
	f := os.NewFile(uintptr(fno), fmt.Sprintf("einhorn@%d", n))
	defer f.Close()
	return net.FileListener(f)
}

// Fun story: this is actually YAML, not JSON.
const ackMsg = `{"command":"worker:ack","pid":%d}` + "\n"

func einhornAck() {
	if !usingEinhorn() {
		return
	}
	log.Print("bind: ACKing to einhorn")

	ctl, err := net.Dial("unix", os.Getenv("EINHORN_SOCK_PATH"))
	if err != nil {
		log.Fatalf(ackErr, err)
	}
	defer ctl.Close()

	_, err = fmt.Fprintf(ctl, ackMsg, os.Getpid())
	if err != nil {
		log.Fatalf(ackErr, err)
	}
}
<commit_msg>Add compatibility for YAML in Ruby 1.8<commit_after>// +build !windows

package bind

import (
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"syscall"
)

const tooBigErr = "bind: einhorn@%d not found (einhorn only passed %d fds)"
const bindErr = "bind: could not bind einhorn@%d: not running under einhorn"
const einhornErr = "bind: einhorn environment initialization error"
const ackErr = "bind: error ACKing to einhorn: %v"

var einhornNumFds int

func envInt(val string) (int, error) {
	return strconv.Atoi(os.Getenv(val))
}

// Unfortunately this can't be a normal init function, because their execution
// order is undefined, and we need to run before the init() in bind.go.
func einhornInit() {
	mpid, err := envInt("EINHORN_MASTER_PID")
	if err != nil || mpid != os.Getppid() {
		return
	}

	einhornNumFds, err = envInt("EINHORN_FD_COUNT")
	if err != nil {
		einhornNumFds = 0
		return
	}

	// Prevent einhorn's fds from leaking to our children
	for i := 0; i < einhornNumFds; i++ {
		syscall.CloseOnExec(einhornFdMap(i))
	}
}

func usingEinhorn() bool {
	return einhornNumFds > 0
}

func einhornFdMap(n int) int {
	name := fmt.Sprintf("EINHORN_FD_%d", n)
	fno, err := envInt(name)
	if err != nil {
		log.Fatal(einhornErr)
	}
	return fno
}

func einhornBind(n int) (net.Listener, error) {
	if !usingEinhorn() {
		return nil, fmt.Errorf(bindErr, n)
	}
	if n >= einhornNumFds || n < 0 {
		return nil, fmt.Errorf(tooBigErr, n, einhornNumFds)
	}

	fno := einhornFdMap(n)
	f := os.NewFile(uintptr(fno), fmt.Sprintf("einhorn@%d", n))
	defer f.Close()
	return net.FileListener(f)
}

// Fun story: this is actually YAML, not JSON.
const ackMsg = `{"command": "worker:ack", "pid": %d}` + "\n"

func einhornAck() {
	if !usingEinhorn() {
		return
	}
	log.Print("bind: ACKing to einhorn")

	ctl, err := net.Dial("unix", os.Getenv("EINHORN_SOCK_PATH"))
	if err != nil {
		log.Fatalf(ackErr, err)
	}
	defer ctl.Close()

	_, err = fmt.Fprintf(ctl, ackMsg, os.Getpid())
	if err != nil {
		log.Fatalf(ackErr, err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"log"
	"os"
	"sort"
	"strconv"
)

const _DB_CONFIG_FILENAME = "db_config.SECRET.json"
const QUERY_LIMIT = 100

var noLimitFlag bool

func init() {
	flag.BoolVar(&noLimitFlag, "a", false, "Specify to execute the solves query with no limit.")
}

type dbConfig struct {
	Url, Username, Password, DbName, SolvesTable, SolvesID, SolvesPuzzleID, SolvesTotalTime, SolvesUser string
}

type solve struct {
	puzzleID  int
	totalTime int
}

type userSolvesCollection struct {
	solves []*solve
	max    int
	min    int
}

type puzzle struct {
	id                     int
	userRelativeDifficulty float32
}

type puzzles []puzzle

type byUserRelativeDifficulty struct {
	puzzles
}

func (self puzzles) Len() int {
	return len(self)
}

func (self puzzles) Swap(i, j int) {
	self[i], self[j] = self[j], self[i]
}

func (self byUserRelativeDifficulty) Less(i, j int) bool {
	return self.puzzles[i].userRelativeDifficulty < self.puzzles[j].userRelativeDifficulty
}

func (self *userSolvesCollection) addSolve(solve *solve) {
	self.solves = append(self.solves, solve)
	if len(self.solves) == 1 {
		self.max = solve.totalTime
		self.min = solve.totalTime
	} else {
		if self.max < solve.totalTime {
			self.max = solve.totalTime
		}
		if self.min > solve.totalTime {
			self.min = solve.totalTime
		}
	}
}

func (self *userSolvesCollection) relativeDifficulties() map[int]float32 {
	//Returns a map of puzzle id to relative difficulty, normalized by our max and min.
	avgSolveTimes := make(map[int]float32)
	//Keep track of how many times we've seen each puzzle solved by this user so we can do correct averaging.
	avgSolveTimesCount := make(map[int]int)

	//First, collect the average solve time (in case the same user has solved more than once the same puzzle)

	for _, solve := range self.solves {
		currentAvgSolveTime := avgSolveTimes[solve.puzzleID]

		avgSolveTimes[solve.puzzleID] = (currentAvgSolveTime*float32(avgSolveTimesCount[solve.puzzleID]) + float32(solve.totalTime)) / float32(avgSolveTimesCount[solve.puzzleID]+1)

		avgSolveTimesCount[solve.puzzleID]++
	}

	//Now, relativize all of the scores.

	result := make(map[int]float32)

	for puzzleID, avgSolveTime := range avgSolveTimes {
		result[puzzleID] = (avgSolveTime - float32(self.min)) / float32(self.max-self.min)
	}

	return result
}

func main() {

	flag.Parse()

	file, err := os.Open(_DB_CONFIG_FILENAME)
	if err != nil {
		log.Fatal("Could not find the config file at ", _DB_CONFIG_FILENAME, ". You should copy the SAMPLE one to that filename and configure.")
		os.Exit(1)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	var config dbConfig
	if err := decoder.Decode(&config); err != nil {
		log.Fatal("There was an error parsing JSON from the config file: ", err)
		os.Exit(1)
	}

	db := mysql.New("tcp", "", config.Url, config.Username, config.Password, config.DbName)

	if err := db.Connect(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	var solvesQuery string

	if noLimitFlag {
		fmt.Println("Running without a limit for number of solves to retrieve.")
		solvesQuery = "select %s, %s, %s from %s"
	} else {
		fmt.Println("Running with a limit of ", QUERY_LIMIT, " for number of solves to retrieve.")
		solvesQuery = "select %s, %s, %s from %s limit " + strconv.Itoa(QUERY_LIMIT)
	}

	res, err := db.Start(solvesQuery, config.SolvesUser, config.SolvesPuzzleID, config.SolvesTotalTime, config.SolvesTable)

	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	solvesByUser := make(map[string]*userSolvesCollection)

	var userSolves *userSolvesCollection
	var ok bool
	var i int

	//First, process all user records in the DB to collect all solves by userName.
	for {

		row, _ := res.GetRow()

		if row == nil {
			break
		}

		userSolves, ok = solvesByUser[row.Str(0)]

		if !ok {
			userSolves = new(userSolvesCollection)
			solvesByUser[row.Str(0)] = userSolves
		}

		userSolves.addSolve(&solve{row.Int(1), row.Int(2)})
		i++
	}

	fmt.Println("Processed ", i, " solves by ", len(solvesByUser), " users.")

	//Now get the relative difficulty for each user's puzzles, and collect them.

	relativeDifficultiesByPuzzle := make(map[int][]float32)

	var skippedUsers int

	for _, collection := range solvesByUser {

		if len(collection.solves) < 2 {
			skippedUsers++
			continue
		}

		for puzzleID, relativeDifficulty := range collection.relativeDifficulties() {
			relativeDifficultiesByPuzzle[puzzleID] = append(relativeDifficultiesByPuzzle[puzzleID], relativeDifficulty)
		}

	}

	fmt.Println("Skipped ", skippedUsers, " users because they had only solved one unique puzzle.")

	puzzles := make([]puzzle, len(relativeDifficultiesByPuzzle))

	var index int

	for puzzleID, difficulties := range relativeDifficultiesByPuzzle {
		var sum float32
		for _, difficulty := range difficulties {
			sum += difficulty
		}
		puzzles[index] = puzzle{puzzleID, sum / float32(len(difficulties))}
		index++
	}

	//Sort the puzzles by relative user difficulty
	//We actually don't need the wrapper, since it will modify the underlying slice.
	sort.Sort(byUserRelativeDifficulty{puzzles})
}
<commit_msg>Switch to jsut having an array of solves instead of pointer to solves, since they're only 64 bits and not being used elsewhere anyway.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"log"
	"os"
	"sort"
	"strconv"
)

const _DB_CONFIG_FILENAME = "db_config.SECRET.json"
const QUERY_LIMIT = 100

var noLimitFlag bool

func init() {
	flag.BoolVar(&noLimitFlag, "a", false, "Specify to execute the solves query with no limit.")
}

type dbConfig struct {
	Url, Username, Password, DbName, SolvesTable, SolvesID, SolvesPuzzleID, SolvesTotalTime, SolvesUser string
}

type solve struct {
	puzzleID  int
	totalTime int
}

type userSolvesCollection struct {
	solves []solve
	max    int
	min    int
}

type puzzle struct {
	id                     int
	userRelativeDifficulty float32
}

type puzzles []puzzle

type byUserRelativeDifficulty struct {
	puzzles
}

func (self puzzles) Len() int {
	return len(self)
}

func (self puzzles) Swap(i, j int) {
	self[i], self[j] = self[j], self[i]
}

func (self byUserRelativeDifficulty) Less(i, j int) bool {
	return self.puzzles[i].userRelativeDifficulty < self.puzzles[j].userRelativeDifficulty
}

func (self *userSolvesCollection) addSolve(solve solve) {
	self.solves = append(self.solves, solve)
	if len(self.solves) == 1 {
		self.max = solve.totalTime
		self.min = solve.totalTime
	} else {
		if self.max < solve.totalTime {
			self.max = solve.totalTime
		}
		if self.min > solve.totalTime {
			self.min = solve.totalTime
		}
	}
}

func (self *userSolvesCollection) relativeDifficulties() map[int]float32 {
	//Returns a map of puzzle id to relative difficulty, normalized by our max and min.
	avgSolveTimes := make(map[int]float32)
	//Keep track of how many times we've seen each puzzle solved by this user so we can do correct averaging.
	avgSolveTimesCount := make(map[int]int)

	//First, collect the average solve time (in case the same user has solved more than once the same puzzle)

	for _, solve := range self.solves {
		currentAvgSolveTime := avgSolveTimes[solve.puzzleID]

		avgSolveTimes[solve.puzzleID] = (currentAvgSolveTime*float32(avgSolveTimesCount[solve.puzzleID]) + float32(solve.totalTime)) / float32(avgSolveTimesCount[solve.puzzleID]+1)

		avgSolveTimesCount[solve.puzzleID]++
	}

	//Now, relativize all of the scores.

	result := make(map[int]float32)

	for puzzleID, avgSolveTime := range avgSolveTimes {
		result[puzzleID] = (avgSolveTime - float32(self.min)) / float32(self.max-self.min)
	}

	return result
}

func main() {

	flag.Parse()

	file, err := os.Open(_DB_CONFIG_FILENAME)
	if err != nil {
		log.Fatal("Could not find the config file at ", _DB_CONFIG_FILENAME, ". You should copy the SAMPLE one to that filename and configure.")
		os.Exit(1)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	var config dbConfig
	if err := decoder.Decode(&config); err != nil {
		log.Fatal("There was an error parsing JSON from the config file: ", err)
		os.Exit(1)
	}

	db := mysql.New("tcp", "", config.Url, config.Username, config.Password, config.DbName)

	if err := db.Connect(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	var solvesQuery string

	if noLimitFlag {
		fmt.Println("Running without a limit for number of solves to retrieve.")
		solvesQuery = "select %s, %s, %s from %s"
	} else {
		fmt.Println("Running with a limit of ", QUERY_LIMIT, " for number of solves to retrieve.")
		solvesQuery = "select %s, %s, %s from %s limit " + strconv.Itoa(QUERY_LIMIT)
	}

	res, err := db.Start(solvesQuery, config.SolvesUser, config.SolvesPuzzleID, config.SolvesTotalTime, config.SolvesTable)

	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	solvesByUser := make(map[string]*userSolvesCollection)

	var userSolves *userSolvesCollection
	var ok bool
	var i int

	//First, process all user records in the DB to collect all solves by userName.
	for {

		row, _ := res.GetRow()

		if row == nil {
			break
		}

		userSolves, ok = solvesByUser[row.Str(0)]

		if !ok {
			userSolves = new(userSolvesCollection)
			solvesByUser[row.Str(0)] = userSolves
		}

		userSolves.addSolve(solve{row.Int(1), row.Int(2)})
		i++
	}

	fmt.Println("Processed ", i, " solves by ", len(solvesByUser), " users.")

	//Now get the relative difficulty for each user's puzzles, and collect them.

	relativeDifficultiesByPuzzle := make(map[int][]float32)

	var skippedUsers int

	for _, collection := range solvesByUser {

		if len(collection.solves) < 2 {
			skippedUsers++
			continue
		}

		for puzzleID, relativeDifficulty := range collection.relativeDifficulties() {
			relativeDifficultiesByPuzzle[puzzleID] = append(relativeDifficultiesByPuzzle[puzzleID], relativeDifficulty)
		}

	}

	fmt.Println("Skipped ", skippedUsers, " users because they had only solved one unique puzzle.")

	puzzles := make([]puzzle, len(relativeDifficultiesByPuzzle))

	var index int

	for puzzleID, difficulties := range relativeDifficultiesByPuzzle {
		var sum float32
		for _, difficulty := range difficulties {
			sum += difficulty
		}
		puzzles[index] = puzzle{puzzleID, sum / float32(len(difficulties))}
		index++
	}

	//Sort the puzzles by relative user difficulty
	//We actually don't need the wrapper, since it will modify the underlying slice.
	sort.Sort(byUserRelativeDifficulty{puzzles})
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/sosedoff/musicbot/spotify"
)

func setupCommands(bot *Bot) {
	bot.addCommand("^help$", Help)
	bot.addCommand("^current$", CurrentTrack)
	bot.addCommand("^(next|skip)$", NextTrack)
	bot.addCommand("^pause$", Pause)
	bot.addCommand("^resume$", Resume)
	bot.addCommand("^stop$", Stop)
	bot.addCommand("^play$", Resume)
	bot.addCommand("^play (.*)", Play)
	bot.addCommand("^(tracks|list)$", Tracks)
	bot.addCommand("^clear$", Clear)
	bot.addCommand("^state$", State)
	bot.addCommand("^(vol|volume)$", Volume)
	bot.addCommand("^(vol|volume) (up|down|[0-9]+)$", SetVolume)
}

func Help(bot *Bot, match *Match) {
	bot.Say("Not implemented")
}

func CurrentTrack(bot *Bot, match *Match) {
	track, err := bot.mopidy.CurrentTrack()
	if err != nil {
		bot.Say("Cant get current track")
		return
	}

	if track == nil {
		bot.Say("No current track")
		return
	}

	bot.Say(track.String())
}

func NextTrack(bot *Bot, match *Match) {
	err := bot.mopidy.PlayNextTrack()
	if err != nil {
		bot.Say("Cant play next track")
		return
	}
}

func Pause(bot *Bot, match *Match) {
	err := bot.mopidy.Pause()
	if err != nil {
		bot.Say("Cant pause")
		return
	}
}

func Resume(bot *Bot, match *Match) {
	err := bot.mopidy.Resume()
	if err != nil {
		bot.Say("Cant resume")
		return
	}
}

func Stop(bot *Bot, match *Match) {
	err := bot.mopidy.Stop(true)
	if err != nil {
		bot.Say("Cant stop, wont stop!")
		return
	}
}

func Tracks(bot *Bot, match *Match) {
	current := ""

	track, _ := bot.mopidy.CurrentTrack()
	if track != nil {
		current = track.Uri
	}

	tracks, err := bot.mopidy.Tracks()
	if err != nil {
		bot.Say("Cant get tracks")
		return
	}

	if len(tracks) == 0 {
		bot.Say("Queue is empty")
		return
	}

	lines := make([]string, len(tracks))

	// For now just print 10 tracks. Slack will cut WS if you try to send a lot of data.
	num := len(tracks)
	if num > 10 {
		num = 10
	}

	for i, track := range tracks[0:num] {
		if track.Uri == current {
			lines[i] = fmt.Sprintf("*%d. %s*", i+1, track.String())
		} else {
			lines[i] = fmt.Sprintf("%d. %s", i+1, track.String())
		}
	}

	bot.Say(strings.Join(lines, "\n"))
}

func Clear(bot *Bot, match *Match) {
	err := bot.mopidy.ClearTracklist()
	if err != nil {
		bot.Say("Cant clear queue")
		return
	}

	bot.Say("Queue is cleared")
}

func State(bot *Bot, match *Match) {
	state, err := bot.mopidy.State()
	if err != nil {
		bot.Say("Cant get state")
		return
	}

	bot.Say("Player state: " + state)
}

func Play(bot *Bot, match *Match) {
	query := match.Values[0]

	opts := spotify.SearchOptions{
		Query: query,
		Type:  "track",
		Limit: 10,
	}

	result, err := spotify.Search(opts)
	if err != nil {
		fmt.Println(err)
		bot.Say("_Spotify search failed_")
		return
	}

	if len(result.Tracks.Items) == 0 {
		bot.Say("Nothing found for: " + query)
		return
	}

	err = bot.mopidy.AddSpotifyTracks(result.Tracks.Items)
	if err != nil {
		bot.Say("Cant add tracks to the queue")
		return
	}

	lines := make([]string, len(result.Tracks.Items))
	for i, track := range result.Tracks.Items {
		lines[i] = fmt.Sprintf("%v. %s - %s", i+1, track.Name, track.Album.Name)
	}

	bot.Say("Added tracks:\n" + strings.Join(lines, "\n"))

	state, _ := bot.mopidy.State()
	if state == "stopped" {
		bot.mopidy.Play()
	}
}

func Volume(bot *Bot, match *Match) {
	vol, err := bot.mopidy.Volume()
	if err != nil {
		bot.Say("Cant get volume")
		return
	}

	bot.Say(fmt.Sprintf("Volume: %v%s", vol, "%"))
}

func SetVolume(bot *Bot, match *Match) {
	vol, err := bot.mopidy.Volume()
	if err != nil {
		bot.Say("Cant get volume")
		return
	}

	newvol := match.Values[1]

	switch newvol {
	case "up":
		vol += 10
	case "down":
		vol -= 10
	default:
		vol, err = strconv.Atoi(newvol)
		if err != nil {
			bot.Say("Invalid volume value")
			return
		}
	}

	if vol > 100 || vol < 0 {
		bot.Say("Volume range is 0-100")
		return
	}

	err = bot.mopidy.SetVolume(vol)
	if err != nil {
		bot.Say("Cant change volume")
		return
	}
}
<commit_msg>Flush queue when adding new tracks and player is stopped. Comments.<commit_after>package bot

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/sosedoff/musicbot/spotify"
)

func setupCommands(bot *Bot) {
	bot.addCommand("^help$", Help)
	bot.addCommand("^current$", CurrentTrack)
	bot.addCommand("^(next|skip)$", NextTrack)
	bot.addCommand("^pause$", Pause)
	bot.addCommand("^resume$", Resume)
	bot.addCommand("^stop$", Stop)
	bot.addCommand("^play$", Resume)
	bot.addCommand("^play (.*)", Play)
	bot.addCommand("^(tracks|list)$", Tracks)
	bot.addCommand("^clear$", Clear)
	bot.addCommand("^state$", State)
	bot.addCommand("^(vol|volume)$", Volume)
	bot.addCommand("^(vol|volume) (up|down|[0-9]+)$", SetVolume)
}

func Help(bot *Bot, match *Match) {
	bot.Say("Not implemented")
}

func CurrentTrack(bot *Bot, match *Match) {
	track, err := bot.mopidy.CurrentTrack()
	if err != nil {
		bot.Say("Cant get current track")
		return
	}

	if track == nil {
		bot.Say("No current track")
		return
	}

	bot.Say(track.String())
}

func NextTrack(bot *Bot, match *Match) {
	err := bot.mopidy.PlayNextTrack()
	if err != nil {
		bot.Say("Cant play next track")
		return
	}
}

func Pause(bot *Bot, match *Match) {
	err := bot.mopidy.Pause()
	if err != nil {
		bot.Say("Cant pause")
		return
	}
}

func Resume(bot *Bot, match *Match) {
	err := bot.mopidy.Resume()
	if err != nil {
		bot.Say("Cant resume")
		return
	}
}

func Stop(bot *Bot, match *Match) {
	err := bot.mopidy.Stop(true)
	if err != nil {
		bot.Say("Cant stop, wont stop!")
		return
	}
}

func Tracks(bot *Bot, match *Match) {
	current := ""

	track, _ := bot.mopidy.CurrentTrack()
	if track != nil {
		current = track.Uri
	}

	tracks, err := bot.mopidy.Tracks()
	if err != nil {
		bot.Say("Cant get tracks")
		return
	}

	if len(tracks) == 0 {
		bot.Say("Queue is empty")
		return
	}

	lines := make([]string, len(tracks))

	// For now just print 10 tracks. Slack will cut WS if you try to send a lot of data.
	num := len(tracks)
	if num > 10 {
		num = 10
	}

	for i, track := range tracks[0:num] {
		if track.Uri == current {
			lines[i] = fmt.Sprintf("*%d. %s*", i+1, track.String())
		} else {
			lines[i] = fmt.Sprintf("%d. %s", i+1, track.String())
		}
	}

	bot.Say(strings.Join(lines, "\n"))
}

func Clear(bot *Bot, match *Match) {
	err := bot.mopidy.ClearTracklist()
	if err != nil {
		bot.Say("Cant clear queue")
		return
	}

	bot.Say("Queue is cleared")
}

func State(bot *Bot, match *Match) {
	state, err := bot.mopidy.State()
	if err != nil {
		bot.Say("Cant get state")
		return
	}

	bot.Say("Player state: " + state)
}

func Play(bot *Bot, match *Match) {
	query := match.Values[0]

	opts := spotify.SearchOptions{
		Query: query,
		Type:  "track",
		Limit: 10,
	}

	result, err := spotify.Search(opts)
	if err != nil {
		fmt.Println(err)
		bot.Say("_Spotify search failed_")
		return
	}

	if len(result.Tracks.Items) == 0 {
		bot.Say("Nothing found for: " + query)
		return
	}

	// If player is stopped we should clear old track list so that playback will s
	// start with only new tracks. This is needed to keep the track list small.
	state, _ := bot.mopidy.State()
	if state == "stopped" {
		bot.mopidy.ClearTracklist()
	}

	err = bot.mopidy.AddSpotifyTracks(result.Tracks.Items)
	if err != nil {
		bot.Say("Cant add tracks to the queue")
		return
	}

	// Start playback only if player is stopped.
	state, _ = bot.mopidy.State()
	if state == "stopped" {
		bot.mopidy.Play()
	}

	// Build a string that only includes 10 tracks. Its a dirty hack to make sure
	// that amount of data sent to slack stays low, otherwise slack will terminate
	// websocket connection. TODO: need a better way of handing this.
	lines := make([]string, len(result.Tracks.Items))
	for i, track := range result.Tracks.Items {
		lines[i] = fmt.Sprintf("%v. %s - %s", i+1, track.Name, track.Album.Name)
	}

	bot.Say("Added tracks:\n" + strings.Join(lines, "\n"))
}

func Volume(bot *Bot, match *Match) {
	vol, err := bot.mopidy.Volume()
	if err != nil {
		bot.Say("Cant get volume")
		return
	}

	bot.Say(fmt.Sprintf("Volume: %v%s", vol, "%"))
}

func SetVolume(bot *Bot, match *Match) {
	vol, err := bot.mopidy.Volume()
	if err != nil {
		bot.Say("Cant get volume")
		return
	}

	newvol := match.Values[1]

	switch newvol {
	case "up":
		vol += 10
	case "down":
		vol -= 10
	default:
		vol, err = strconv.Atoi(newvol)
		if err != nil {
			bot.Say("Invalid volume value")
			return
		}
	}

	if vol > 100 || vol < 0 {
		bot.Say("Volume range is 0-100")
		return
	}

	err = bot.mopidy.SetVolume(vol)
	if err != nil {
		bot.Say("Cant change volume")
		return
	}
}
<|endoftext|>