<commit_before>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tlsmux

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"sync"
	"time"

	"go.uber.org/net/metrics"
	yarpctls "go.uber.org/yarpc/api/transport/tls"
	"go.uber.org/zap"
)

var (
	errListenerClosed = errors.New("listener closed")

	// TODO(jronak): below timeouts are experimental, will be tuned after testing.
	_sniffReadTimeout    = time.Second * 10
	_tlsHandshakeTimeout = time.Second * 10
)

// Config describes how listener should be configured.
type Config struct {
	Listener  net.Listener
	TLSConfig *tls.Config

	ServiceName   string
	TransportName string
	Meter         *metrics.Scope
	Logger        *zap.Logger
	Mode          yarpctls.Mode
}

// listener wraps original net listener and it accepts both TLS and non-TLS connections.
type listener struct {
	net.Listener

	tlsConfig *tls.Config
	observer  *observer
	logger    *zap.Logger
	mode      yarpctls.Mode

	closeOnce   sync.Once
	connChan    chan net.Conn
	stopChan    chan struct{}
	stoppedChan chan struct{}
}

// NewListener returns a multiplexed listener which accepts both TLS and
// plaintext connections.
func NewListener(c Config) net.Listener {
	if c.Mode == yarpctls.Disabled {
		return c.Listener
	}

	lis := &listener{
		Listener:    c.Listener,
		tlsConfig:   c.TLSConfig,
		observer:    newObserver(c.Meter, c.Logger, c.ServiceName, c.TransportName, c.Mode),
		logger:      c.Logger,
		connChan:    make(chan net.Conn),
		stoppedChan: make(chan struct{}),
		stopChan:    make(chan struct{}),
		mode:        c.Mode,
	}

	// Starts go routine for the connection server
	go lis.serve()

	return lis
}

// Accept returns multiplexed plaintext connetion.
// After close, returned error is errListenerClosed.
func (l *listener) Accept() (net.Conn, error) {
	select {
	case conn, ok := <-l.connChan:
		if !ok {
			return nil, errListenerClosed
		}
		return conn, nil
	case <-l.stopChan:
		return nil, errListenerClosed
	}
}

// Close closes the listener and waits until the connection server drains
// accepted connections and stops the server.
func (l *listener) Close() error {
	var err error
	l.closeOnce.Do(func() {
		err = l.Listener.Close()
		close(l.stopChan)
		<-l.stoppedChan
	})
	return err
}

// serve starts accepting the connection from the underlying listener and creates a new
// go routine for each connection for async muxing.
func (l *listener) serve() {
	var wg sync.WaitGroup

	defer func() {
		wg.Wait()
		close(l.stoppedChan)
		close(l.connChan)
	}()

	for {
		conn, err := l.Listener.Accept()
		if err != nil {
			return
		}

		wg.Add(1)
		go l.serveConnection(conn, &wg)
	}
}

// serveConnection muxes the given connection and sends muxed connection to the
// connection channel.
func (l *listener) serveConnection(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()

	c, err := l.mux(conn)
	if err != nil {
		conn.Close()
		return
	}

	select {
	case l.connChan <- c:
	case <-l.stopChan:
		conn.Close()
	}
}

// mux accepts both plaintext and tls connection, and returns a plaintext
// connection.
func (l *listener) mux(conn net.Conn) (net.Conn, error) {
	if l.mode == yarpctls.Enforced {
		return l.handleTLSConn(conn)
	}

	c := newConnectionSniffer(conn)
	isTLS, err := matchTLSConnection(c)
	if err != nil {
		l.logger.Error("TLS connection matcher failed", zap.Error(err))
		return nil, err
	}

	if isTLS {
		return l.handleTLSConn(c)
	}

	return l.handlePlaintextConn(c)
}

// handleTLSConn completes the TLS handshake for the given connection and
// returns a TLS server wrapped plaintext connection.
func (l *listener) handleTLSConn(conn net.Conn) (net.Conn, error) {
	ctx, cancel := context.WithTimeout(context.Background(), _tlsHandshakeTimeout)
	defer cancel()

	tlsConn := tls.Server(conn, l.tlsConfig)
	if err := tlsConn.HandshakeContext(ctx); err != nil {
		l.observer.incTLSHandshakeFailures()
		l.logger.Error("TLS handshake failed", zap.Error(err))
		return nil, err
	}

	l.observer.incTLSConnections(tlsConn.ConnectionState().Version)
	return tlsConn, nil
}

func (l *listener) handlePlaintextConn(conn net.Conn) (net.Conn, error) {
	l.observer.incPlaintextConnections()
	return conn, nil
}

func matchTLSConnection(cs *connSniffer) (bool, error) {
	if err := cs.SetReadDeadline(time.Now().Add(_sniffReadTimeout)); err != nil {
		return false, err
	}

	// Reset read deadline after sniffing. See below:
	// https://github.com/golang/go/blob/be0b2a393a5a7297a3c8f42ca7d5ad3e4b15dcbe/src/net/http/server.go#L1887
	defer func() {
		_ = cs.SetReadDeadline(time.Time{})
	}()

	isTLS, err := isTLSClientHelloRecord(cs)
	if err != nil {
		return false, err
	}

	cs.stopSniffing()
	return isTLS, nil
}
<commit_msg>[tlsmux] Update timeouts and context (#2148)<commit_after>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tlsmux

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"sync"
	"time"

	"go.uber.org/net/metrics"
	yarpctls "go.uber.org/yarpc/api/transport/tls"
	"go.uber.org/zap"
)

var (
	errListenerClosed = errors.New("listener closed")

	// Connection has 15s to transmit first 5 bytes for sniffing.
	_sniffReadTimeout = time.Second * 15
	// Handshake timeout set to 120s, see gRPC-go:
	// https://github.com/grpc/grpc-go/blob/fdc5d2f3da856f3cdd3483280ae33da5bee17a93/server.go#L467
	_tlsHandshakeTimeout = time.Second * 120
)

// Config describes how listener should be configured.
type Config struct {
	Listener  net.Listener
	TLSConfig *tls.Config

	ServiceName   string
	TransportName string
	Meter         *metrics.Scope
	Logger        *zap.Logger
	Mode          yarpctls.Mode
}

// listener wraps original net listener and it accepts both TLS and non-TLS connections.
type listener struct {
	net.Listener

	tlsConfig *tls.Config
	observer  *observer
	logger    *zap.Logger
	mode      yarpctls.Mode

	closeOnce   sync.Once
	connChan    chan net.Conn
	stopChan    chan struct{}
	stoppedChan chan struct{}
}

// NewListener returns a multiplexed listener which accepts both TLS and
// plaintext connections.
func NewListener(c Config) net.Listener {
	if c.Mode == yarpctls.Disabled {
		return c.Listener
	}

	lis := &listener{
		Listener:    c.Listener,
		tlsConfig:   c.TLSConfig,
		observer:    newObserver(c.Meter, c.Logger, c.ServiceName, c.TransportName, c.Mode),
		logger:      c.Logger,
		connChan:    make(chan net.Conn),
		stoppedChan: make(chan struct{}),
		stopChan:    make(chan struct{}),
		mode:        c.Mode,
	}

	// Starts go routine for the connection server
	go lis.serve()

	return lis
}

// Accept returns multiplexed plaintext connetion.
// After close, returned error is errListenerClosed.
func (l *listener) Accept() (net.Conn, error) {
	select {
	case conn, ok := <-l.connChan:
		if !ok {
			return nil, errListenerClosed
		}
		return conn, nil
	case <-l.stopChan:
		return nil, errListenerClosed
	}
}

// Close closes the listener and waits until the connection server drains
// accepted connections and stops the server.
func (l *listener) Close() error {
	var err error
	l.closeOnce.Do(func() {
		err = l.Listener.Close()
		close(l.stopChan)
		<-l.stoppedChan
	})
	return err
}

// serve starts accepting the connection from the underlying listener and creates a new
// go routine for each connection for async muxing.
func (l *listener) serve() {
	var wg sync.WaitGroup
	ctx, cancel := context.WithCancel(context.Background())
	defer func() {
		cancel()
		wg.Wait()
		close(l.stoppedChan)
		close(l.connChan)
	}()

	for {
		conn, err := l.Listener.Accept()
		if err != nil {
			return
		}

		wg.Add(1)
		go l.serveConnection(ctx, conn, &wg)
	}
}

// serveConnection muxes the given connection and sends muxed connection to the
// connection channel.
func (l *listener) serveConnection(ctx context.Context, conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()

	c, err := l.mux(ctx, conn)
	if err != nil {
		conn.Close()
		return
	}

	select {
	case l.connChan <- c:
	case <-l.stopChan:
		conn.Close()
	}
}

// mux accepts both plaintext and tls connection, and returns a plaintext
// connection.
func (l *listener) mux(ctx context.Context, conn net.Conn) (net.Conn, error) {
	if l.mode == yarpctls.Enforced {
		return l.handleTLSConn(ctx, conn)
	}

	c := newConnectionSniffer(conn)
	isTLS, err := matchTLSConnection(c)
	if err != nil {
		l.logger.Error("TLS connection matcher failed", zap.Error(err))
		return nil, err
	}

	if isTLS {
		return l.handleTLSConn(ctx, c)
	}

	return l.handlePlaintextConn(c)
}

// handleTLSConn completes the TLS handshake for the given connection and
// returns a TLS server wrapped plaintext connection.
func (l *listener) handleTLSConn(ctx context.Context, conn net.Conn) (net.Conn, error) {
	ctx, cancel := context.WithTimeout(ctx, _tlsHandshakeTimeout)
	defer cancel()

	tlsConn := tls.Server(conn, l.tlsConfig)
	if err := tlsConn.HandshakeContext(ctx); err != nil {
		l.observer.incTLSHandshakeFailures()
		l.logger.Error("TLS handshake failed", zap.Error(err))
		return nil, err
	}

	l.observer.incTLSConnections(tlsConn.ConnectionState().Version)
	return tlsConn, nil
}

func (l *listener) handlePlaintextConn(conn net.Conn) (net.Conn, error) {
	l.observer.incPlaintextConnections()
	return conn, nil
}

func matchTLSConnection(cs *connSniffer) (bool, error) {
	if err := cs.SetReadDeadline(time.Now().Add(_sniffReadTimeout)); err != nil {
		return false, err
	}

	// Reset read deadline after sniffing. See below:
	// https://github.com/golang/go/blob/be0b2a393a5a7297a3c8f42ca7d5ad3e4b15dcbe/src/net/http/server.go#L1887
	defer func() {
		_ = cs.SetReadDeadline(time.Time{})
	}()

	isTLS, err := isTLSClientHelloRecord(cs)
	if err != nil {
		return false, err
	}

	cs.stopSniffing()
	return isTLS, nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2017 All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package consensus

import (
	"github.com/hyperledger/fabric/common/channelconfig"
	"github.com/hyperledger/fabric/common/crypto"
	"github.com/hyperledger/fabric/orderer/common/blockcutter"
	"github.com/hyperledger/fabric/orderer/common/msgprocessor"
	cb "github.com/hyperledger/fabric/protos/common"
)

// Consenter defines the backing ordering mechanism.
type Consenter interface {
	// HandleChain should create and return a reference to a Chain for the given set of resources.
	// It will only be invoked for a given chain once per process.  In general, errors will be treated
	// as irrecoverable and cause system shutdown.  See the description of Chain for more details
	// The second argument to HandleChain is a pointer to the metadata stored on the `ORDERER` slot of
	// the last block committed to the ledger of this Chain.  For a new chain, this metadata will be
	// nil, as this field is not set on the genesis block
	HandleChain(support ConsenterSupport, metadata *cb.Metadata) (Chain, error)
}

// Chain defines a way to inject messages for ordering.
// Note, that in order to allow flexibility in the implementation, it is the responsibility of the implementer
// to take the ordered messages, send them through the blockcutter.Receiver supplied via HandleChain to cut blocks,
// and ultimately write the ledger also supplied via HandleChain.  This design allows for two primary flows
// 1. Messages are ordered into a stream, the stream is cut into blocks, the blocks are committed (solo, kafka)
// 2. Messages are cut into blocks, the blocks are ordered, then the blocks are committed (sbft)
type Chain interface {
	// NOTE: The kafka consenter has not been updated to perform the revalidation
	// checks conditionally.  For now, Order/Configure are essentially Enqueue as before.
	// This does not cause data inconsistency, but it wastes cycles and will be required
	// to properly support the ConfigUpdate concept once introduced
	// Once this is done, the MsgClassification logic in msgprocessor should return error
	// for non ConfigUpdate/Normal msg types

	// Order accepts a message which has been processed at a given configSeq.
	// If the configSeq advances, it is the responsibility of the consenter
	// to revalidate and potentially discard the message
	// The consenter may return an error, indicating the message was not accepted
	Order(env *cb.Envelope, configSeq uint64) error

	// Configure accepts a message which reconfigures the channel and will
	// trigger an update to the configSeq if committed.  The configuration must have
	// been triggered by a ConfigUpdate message. If the config sequence advances,
	// it is the responsibility of the consenter to recompute the resulting config,
	// discarding the message if the reconfiguration is no longer valid.
	// The consenter may return an error, indicating the message was not accepted
	Configure(config *cb.Envelope, configSeq uint64) error

	// WaitReady blocks waiting for consenter to be ready for accepting new messages.
	// This is useful when consenter needs to temporarily block ingress messages so
	// that in-flight messages can be consumed. It could return error if consenter is
	// in erroneous states. If this blocking behavior is not desired, consenter could
	// simply return nil.
	WaitReady() error

	// Errored returns a channel which will close when an error has occurred.
	// This is especially useful for the Deliver client, who must terminate waiting
	// clients when the consenter is not up to date.
	Errored() <-chan struct{}

	// Start should allocate whatever resources are needed for staying up to date with the chain.
	// Typically, this involves creating a thread which reads from the ordering source, passes those
	// messages to a block cutter, and writes the resulting blocks to the ledger.
	Start()

	// Halt frees the resources which were allocated for this Chain.
	Halt()
}

// ConsenterSupport provides the resources available to a Consenter implementation.
type ConsenterSupport interface {
	crypto.LocalSigner
	msgprocessor.Processor

	// BlockCutter returns the block cutting helper for this channel.
	BlockCutter() blockcutter.Receiver

	// SharedConfig provides the shared config from the channel's current config block.
	SharedConfig() channelconfig.Orderer

	// CreateNextBlock takes a list of messages and creates the next block based on the block with highest block number committed to the ledger
	// Note that either WriteBlock or WriteConfigBlock must be called before invoking this method a second time.
	CreateNextBlock(messages []*cb.Envelope) *cb.Block

	// WriteBlock commits a block to the ledger.
	WriteBlock(block *cb.Block, encodedMetadataValue []byte)

	// WriteConfigBlock commits a block to the ledger, and applies the config update inside.
	WriteConfigBlock(block *cb.Block, encodedMetadataValue []byte)

	// Sequence returns the current config squence.
	Sequence() uint64

	// ChainID returns the channel ID this support is associated with.
	ChainID() string

	// Height returns the number of blocks in the chain this channel is associated with.
	Height() uint64
}
<commit_msg>[FAB-8799] Remove Kafka revalidation comment<commit_after>/*
Copyright IBM Corp. 2017 All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package consensus

import (
	"github.com/hyperledger/fabric/common/channelconfig"
	"github.com/hyperledger/fabric/common/crypto"
	"github.com/hyperledger/fabric/orderer/common/blockcutter"
	"github.com/hyperledger/fabric/orderer/common/msgprocessor"
	cb "github.com/hyperledger/fabric/protos/common"
)

// Consenter defines the backing ordering mechanism.
type Consenter interface {
	// HandleChain should create and return a reference to a Chain for the given set of resources.
	// It will only be invoked for a given chain once per process.  In general, errors will be treated
	// as irrecoverable and cause system shutdown.  See the description of Chain for more details
	// The second argument to HandleChain is a pointer to the metadata stored on the `ORDERER` slot of
	// the last block committed to the ledger of this Chain.  For a new chain, this metadata will be
	// nil, as this field is not set on the genesis block
	HandleChain(support ConsenterSupport, metadata *cb.Metadata) (Chain, error)
}

// Chain defines a way to inject messages for ordering.
// Note, that in order to allow flexibility in the implementation, it is the responsibility of the implementer
// to take the ordered messages, send them through the blockcutter.Receiver supplied via HandleChain to cut blocks,
// and ultimately write the ledger also supplied via HandleChain.  This design allows for two primary flows
// 1. Messages are ordered into a stream, the stream is cut into blocks, the blocks are committed (solo, kafka)
// 2. Messages are cut into blocks, the blocks are ordered, then the blocks are committed (sbft)
type Chain interface {
	// Order accepts a message which has been processed at a given configSeq.
	// If the configSeq advances, it is the responsibility of the consenter
	// to revalidate and potentially discard the message
	// The consenter may return an error, indicating the message was not accepted
	Order(env *cb.Envelope, configSeq uint64) error

	// Configure accepts a message which reconfigures the channel and will
	// trigger an update to the configSeq if committed.  The configuration must have
	// been triggered by a ConfigUpdate message. If the config sequence advances,
	// it is the responsibility of the consenter to recompute the resulting config,
	// discarding the message if the reconfiguration is no longer valid.
	// The consenter may return an error, indicating the message was not accepted
	Configure(config *cb.Envelope, configSeq uint64) error

	// WaitReady blocks waiting for consenter to be ready for accepting new messages.
	// This is useful when consenter needs to temporarily block ingress messages so
	// that in-flight messages can be consumed. It could return error if consenter is
	// in erroneous states. If this blocking behavior is not desired, consenter could
	// simply return nil.
	WaitReady() error

	// Errored returns a channel which will close when an error has occurred.
	// This is especially useful for the Deliver client, who must terminate waiting
	// clients when the consenter is not up to date.
	Errored() <-chan struct{}

	// Start should allocate whatever resources are needed for staying up to date with the chain.
	// Typically, this involves creating a thread which reads from the ordering source, passes those
	// messages to a block cutter, and writes the resulting blocks to the ledger.
	Start()

	// Halt frees the resources which were allocated for this Chain.
	Halt()
}

// ConsenterSupport provides the resources available to a Consenter implementation.
type ConsenterSupport interface {
	crypto.LocalSigner
	msgprocessor.Processor

	// BlockCutter returns the block cutting helper for this channel.
	BlockCutter() blockcutter.Receiver

	// SharedConfig provides the shared config from the channel's current config block.
	SharedConfig() channelconfig.Orderer

	// CreateNextBlock takes a list of messages and creates the next block based on the block with highest block number committed to the ledger
	// Note that either WriteBlock or WriteConfigBlock must be called before invoking this method a second time.
	CreateNextBlock(messages []*cb.Envelope) *cb.Block

	// WriteBlock commits a block to the ledger.
	WriteBlock(block *cb.Block, encodedMetadataValue []byte)

	// WriteConfigBlock commits a block to the ledger, and applies the config update inside.
	WriteConfigBlock(block *cb.Block, encodedMetadataValue []byte)

	// Sequence returns the current config squence.
	Sequence() uint64

	// ChainID returns the channel ID this support is associated with.
	ChainID() string

	// Height returns the number of blocks in the chain this channel is associated with.
	Height() uint64
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

                 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package solo

import (
	"testing"
	"time"

	mockconfig "github.com/hyperledger/fabric/common/mocks/config"
	mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter"
	mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain"
	cb "github.com/hyperledger/fabric/protos/common"

	logging "github.com/op/go-logging"
)

func init() {
	logging.SetLevel(logging.DEBUG, "")
}

var testMessage = &cb.Envelope{Payload: []byte("TEST_MESSAGE")}

func syncQueueMessage(msg *cb.Envelope, chain *chain, bc *mockblockcutter.Receiver) {
	chain.Enqueue(msg)
	bc.Block <- struct{}{}
}

type waitableGo struct {
	done chan struct{}
}

func goWithWait(target func()) *waitableGo {
	wg := &waitableGo{
		done: make(chan struct{}),
	}
	go func() {
		target()
		close(wg.done)
	}()
	return wg
}

func TestEmptyBatch(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	bs.Halt()
	select {
	case <-support.Blocks:
		t.Fatalf("Expected no invocations of Append")
	case <-wg.done:
	}
}

func TestBatchTimer(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected a block to be cut because of batch timer expiration but did not")
	}

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Did not create the second batch, indicating that the timer was not appopriately reset")
	}

	bs.Halt()
	select {
	case <-support.Blocks:
		t.Fatalf("Expected no invocations of Append")
	case <-wg.done:
	}
}

func TestBatchTimerHaltOnFilledBatch(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1h")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)

	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	support.BlockCutterVal.CutNext = true
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected a block to be cut because the batch was filled, but did not")
	}

	// Change the batch timeout to be near instant, if the timer was not reset, it will still be waiting an hour
	bs.batchTimeout = time.Millisecond

	support.BlockCutterVal.CutNext = false
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Did not create the second batch, indicating that the old timer was still running")
	}

	bs.Halt()
	select {
	case <-time.After(time.Second):
		t.Fatalf("Should have exited")
	case <-wg.done:
	}
}

func TestConfigStyleMultiBatch(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1h")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	support.BlockCutterVal.IsolatedTx = true
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected two blocks to be cut but never got the first")
	}

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected the config type tx to create two blocks, but only go the first")
	}

	bs.Halt()
	select {
	case <-time.After(time.Second):
		t.Fatalf("Should have exited")
	case <-wg.done:
	}
}
<commit_msg>[FAB-4349] Improve UT coverage of orderer/solo<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

                 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package solo

import (
	"testing"
	"time"

	mockconfig "github.com/hyperledger/fabric/common/mocks/config"
	mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter"
	mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain"
	cb "github.com/hyperledger/fabric/protos/common"

	logging "github.com/op/go-logging"
	"github.com/stretchr/testify/assert"
)

func init() {
	logging.SetLevel(logging.DEBUG, "")
}

var testMessage = &cb.Envelope{Payload: []byte("TEST_MESSAGE")}

func syncQueueMessage(msg *cb.Envelope, chain *chain, bc *mockblockcutter.Receiver) {
	chain.Enqueue(msg)
	bc.Block <- struct{}{}
}

type waitableGo struct {
	done chan struct{}
}

func goWithWait(target func()) *waitableGo {
	wg := &waitableGo{
		done: make(chan struct{}),
	}
	go func() {
		target()
		close(wg.done)
	}()
	return wg
}

// This test checks that if consenter is halted before a timer fires, nothing is actually written.
func TestHaltBeforeTimeout(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	bs.Halt()
	select {
	case <-support.Blocks:
		t.Fatalf("Expected no invocations of Append")
	case <-wg.done:
	}
}

func TestStart(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	close(support.BlockCutterVal.Block)
	bs, _ := New().HandleChain(support, nil)
	bs.Start()
	defer bs.Halt()

	support.BlockCutterVal.CutNext = true
	bs.Enqueue(testMessage)
	select {
	case <-support.Blocks:
	case <-bs.Errored():
		t.Fatalf("Expected not to exit")
	}
}

func TestEnqueueAfterHalt(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	bs.Halt()
	assert.False(t, bs.Enqueue(testMessage), "Enqueue should not be accepted after halt")
	select {
	case <-bs.Errored():
	default:
		t.Fatalf("Expected Errored to be closed by halt")
	}
}

func TestBatchTimer(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected a block to be cut because of batch timer expiration but did not")
	}

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Did not create the second batch, indicating that the timer was not appopriately reset")
	}

	bs.Halt()
	select {
	case <-support.Blocks:
		t.Fatalf("Expected no invocations of Append")
	case <-wg.done:
	}
}

func TestBatchTimerHaltOnFilledBatch(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1h")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)

	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	support.BlockCutterVal.CutNext = true
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected a block to be cut because the batch was filled, but did not")
	}

	// Change the batch timeout to be near instant, if the timer was not reset, it will still be waiting an hour
	bs.batchTimeout = time.Millisecond

	support.BlockCutterVal.CutNext = false
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Did not create the second batch, indicating that the old timer was still running")
	}

	bs.Halt()
	select {
	case <-time.After(time.Second):
		t.Fatalf("Should have exited")
	case <-wg.done:
	}
}

func TestConfigStyleMultiBatch(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1h")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	wg := goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	support.BlockCutterVal.IsolatedTx = true
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected two blocks to be cut but never got the first")
	}

	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected the config type tx to create two blocks, but only go the first")
	}

	bs.Halt()
	select {
	case <-time.After(time.Second):
		t.Fatalf("Should have exited")
	case <-wg.done:
	}
}

// This test checks that solo consenter could recover from an erroneous situation
// where empty batch is cut
func TestRecoverFromError(t *testing.T) {
	batchTimeout, _ := time.ParseDuration("1ms")
	support := &mockmultichain.ConsenterSupport{
		Blocks:          make(chan *cb.Block),
		BlockCutterVal:  mockblockcutter.NewReceiver(),
		SharedConfigVal: &mockconfig.Orderer{BatchTimeoutVal: batchTimeout},
	}
	defer close(support.BlockCutterVal.Block)
	bs := newChain(support)
	_ = goWithWait(bs.main)
	defer bs.Halt()

	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	support.BlockCutterVal.CurBatch = nil

	select {
	case <-support.Blocks:
		t.Fatalf("Expected no invocations of Append")
	case <-time.After(2 * time.Millisecond):
	}

	support.BlockCutterVal.CutNext = true
	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
	select {
	case <-support.Blocks:
	case <-time.After(time.Second):
		t.Fatalf("Expected block to be cut")
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"log"
	"os"

	"golang.org/x/net/context"

	"github.com/codegangsta/cli"
	"github.com/olekukonko/tablewriter"
)

var cmdDomainsDetails = cli.Command{
	Name:  "details",
	Usage: "print domain details",
	Action: func(c *cli.Context) {
		domains, err := client(c).Domains.List(context.Background())
		if err != nil {
			log.Fatal(err)
		}
		table := tablewriter.NewWriter(os.Stdout)
		table.SetHeader([]string{"Domain"})
		for _, domain := range domains {
			table.Append([]string{domain})
		}
		table.Render()
	},
}
<commit_msg>cmd: fix domain details command<commit_after>package cmd

import (
	"encoding/json"
	"fmt"
	"log"

	"golang.org/x/net/context"

	"github.com/codegangsta/cli"
)

var cmdDomainsDetails = cli.Command{
	Name:      "details",
	Usage:     "prints domain details",
	ArgsUsage: "<domain>",
	Action: func(c *cli.Context) {
		if len(c.Args()) != 1 {
			cli.ShowSubcommandHelp(c)
			return
		}
		domain, err := client(c).Domains.Details(context.Background(), c.Args().First())
		if err != nil {
			log.Fatal(err)
		}

		body, err := json.MarshalIndent(domain, "", "  ")
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("%s\n", body)
	},
}
<|endoftext|>


<commit_before>package relay

import (
	"encoding/binary"

	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

// This function cleans up a relay's address set to remove private addresses and curtail
// addrsplosion.
func cleanupAddressSet(pi pstore.PeerInfo) pstore.PeerInfo {
	var public, private []ma.Multiaddr

	for _, a := range pi.Addrs {
		if manet.IsPublicAddr(a) || isDNSAddr(a) {
			public = append(public, a)
			continue
		}

		// discard unroutable addrs
		if manet.IsPrivateAddr(a) {
			private = append(private, a)
		}
	}

	if !hasAddrsplosion(public) {
		return pstore.PeerInfo{ID: pi.ID, Addrs: public}
	}

	addrs := sanitizeAddrsplodedSet(public, private)
	return pstore.PeerInfo{ID: pi.ID, Addrs: addrs}
}

func isDNSAddr(a ma.Multiaddr) bool {
	dnsaddr := false
	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case 54, 55, 56:
			dnsaddr = true
		}

		return false
	})

	return dnsaddr
}

// we have addrsplosion if for some protocol we advertise multiple ports on
// the same base address.
func hasAddrsplosion(addrs []ma.Multiaddr) bool {
	aset := make(map[string]int)

	for _, a := range addrs {
		key, port := addrKeyAndPort(a)
		xport, ok := aset[key]
		if ok && port != xport {
			return true
		}
		aset[key] = port
	}

	return false
}

func addrKeyAndPort(a ma.Multiaddr) (string, int) {
	var (
		key  string
		port int
	)

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case ma.P_TCP, ma.P_UDP:
			port = int(binary.BigEndian.Uint16(c.RawValue()))
			key += "/" + c.Protocol().Name
		default:
			val := c.Value()
			if val == "" {
				val = c.Protocol().Name
			}
			key += "/" + val
		}
		return true
	})

	return key, port
}

// clean up addrsplosion
// the following heuristic is used:
// - for each base address/protocol combination, if there are multiple ports advertised then
//   only accept the default port if present.
//   - If the default port is not present, we check for non-standard ports by tracking
//     private port bindings if present.
//   - If there is no default or private port binding, then we can't infer the correct
//     port and give up and return all addrs (for that base address)
func sanitizeAddrsplodedSet(public, private []ma.Multiaddr) []ma.Multiaddr {
	type portAndAddr struct {
		addr ma.Multiaddr
		port int
	}

	privports := make(map[int]struct{})
	pubaddrs := make(map[string][]portAndAddr)

	for _, a := range private {
		_, port := addrKeyAndPort(a)
		privports[port] = struct{}{}
	}

	for _, a := range public {
		key, port := addrKeyAndPort(a)
		pubaddrs[key] = append(pubaddrs[key], portAndAddr{addr: a, port: port})
	}

	var result []ma.Multiaddr
	for _, pas := range pubaddrs {
		if len(pas) == 1 {
			// it's not addrsploded
			result = append(result, pas[0].addr)
			continue
		}

		haveAddr := false
		for _, pa := range pas {
			if pa.port == 4001 || pa.port == 4002 {
				// it's a default port, use it
				result = append(result, pa.addr)
				haveAddr = true
				continue
			}

			if _, ok := privports[pa.port]; ok {
				// it matches a privately bound port, use it
				result = append(result, pa.addr)
				haveAddr = true
			}
		}

		if !haveAddr {
			// we weren't able to select a port; bite the bullet and use them all
			for _, pa := range pas {
				result = append(result, pa.addr)
			}
		}
	}

	return result
}
<commit_msg>rewrite isDNSAddr to use ma.SplitFirst<commit_after>package relay

import (
	"encoding/binary"

	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

// This function cleans up a relay's address set to remove private addresses and curtail
// addrsplosion.
func cleanupAddressSet(pi pstore.PeerInfo) pstore.PeerInfo {
	var public, private []ma.Multiaddr

	for _, a := range pi.Addrs {
		if manet.IsPublicAddr(a) || isDNSAddr(a) {
			public = append(public, a)
			continue
		}

		// discard unroutable addrs
		if manet.IsPrivateAddr(a) {
			private = append(private, a)
		}
	}

	if !hasAddrsplosion(public) {
		return pstore.PeerInfo{ID: pi.ID, Addrs: public}
	}

	addrs := sanitizeAddrsplodedSet(public, private)
	return pstore.PeerInfo{ID: pi.ID, Addrs: addrs}
}

func isDNSAddr(a ma.Multiaddr) bool {
	if first, _ := ma.SplitFirst(a); first != nil {
		switch first.Protocol().Code {
		case 54, 55, 56:
			return true
		}
	}
	return false
}

// we have addrsplosion if for some protocol we advertise multiple ports on
// the same base address.
func hasAddrsplosion(addrs []ma.Multiaddr) bool {
	aset := make(map[string]int)

	for _, a := range addrs {
		key, port := addrKeyAndPort(a)
		xport, ok := aset[key]
		if ok && port != xport {
			return true
		}
		aset[key] = port
	}

	return false
}

func addrKeyAndPort(a ma.Multiaddr) (string, int) {
	var (
		key  string
		port int
	)

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case ma.P_TCP, ma.P_UDP:
			port = int(binary.BigEndian.Uint16(c.RawValue()))
			key += "/" + c.Protocol().Name
		default:
			val := c.Value()
			if val == "" {
				val = c.Protocol().Name
			}
			key += "/" + val
		}
		return true
	})

	return key, port
}

// clean up addrsplosion
// the following heuristic is used:
// - for each base address/protocol combination, if there are multiple ports advertised then
//   only accept the default port if present.
//   - If the default port is not present, we check for non-standard ports by tracking
//     private port bindings if present.
//   - If there is no default or private port binding, then we can't infer the correct
//     port and give up and return all addrs (for that base address)
func sanitizeAddrsplodedSet(public, private []ma.Multiaddr) []ma.Multiaddr {
	type portAndAddr struct {
		addr ma.Multiaddr
		port int
	}

	privports := make(map[int]struct{})
	pubaddrs := make(map[string][]portAndAddr)

	for _, a := range private {
		_, port := addrKeyAndPort(a)
		privports[port] = struct{}{}
	}

	for _, a := range public {
		key, port := addrKeyAndPort(a)
		pubaddrs[key] = append(pubaddrs[key], portAndAddr{addr: a, port: port})
	}

	var result []ma.Multiaddr
	for _, pas := range pubaddrs {
		if len(pas) == 1 {
			// it's not addrsploded
			result = append(result, pas[0].addr)
			continue
		}

		haveAddr := false
		for _, pa := range pas {
			if pa.port == 4001 || pa.port == 4002 {
				// it's a default port, use it
				result = append(result, pa.addr)
				haveAddr = true
				continue
			}

			if _, ok := privports[pa.port]; ok {
				// it matches a privately bound port, use it
				result = append(result, pa.addr)
				haveAddr = true
			}
		}

		if !haveAddr {
			// we weren't able to select a port; bite the bullet and use them all
			for _, pa := range pas {
				result = append(result, pa.addr)
			}
		}
	}

	return result
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

//inspired by http://www.musicdsp.org/

package echo

import (
    "afp"
    "os"
)

type EchoFilter struct {
    context *afp.Context
    header afp.StreamHeader
    decay float32 //decay factor: between 0 and 1
}

func (self *EchoFilter) GetType() int {
    return afp.PIPE_LINK
}

func NewEchoFilter() afp.Filter {
    return &EchoFilter{}
}

func (self *EchoFilter) Usage() {
    //TODO: add usage
}

func (self *EchoFilter) Init(ctx *afp.Context, args []string) os.Error {
    self.context = ctx
    //TODO: add argument parsing for decay rate
    self.decay = .2
    return nil
}

func (self *EchoFilter) Start() {
    self.header = <-self.context.HeaderSource
    self.context.HeaderSink <- self.header

    buffer := <-self.context.Source
    frameSize := len(buffer)
    //make the buffer 2x the frame size
    buffer = append(buffer, <-self.context.Source...)

    for nextFrame := range self.context.Source {
        for i := 0; i < frameSize; i++ {
            for j := int8(0); j < self.header.Channels; j++ {
                //ECHO, Echo, echo...
                buffer[i+1][j] += buffer[i][j] * self.decay
            }
        }

        self.context.Sink <- buffer[0:frameSize]
        buffer = buffer[frameSize:]
        buffer = append(buffer, nextFrame...)
    }
}

func (self *EchoFilter) Stop() os.Error {
    //TODO
    return nil
}
<commit_msg>Whoops, wouldn't want to forget about the last couple frames, now would we?<commit_after>// Copyright (c) 2010 AFP Authors
// This source code is released under the terms of the
// MIT license. Please see the file LICENSE for license details.

//inspired by http://www.musicdsp.org/

package echo

import (
    "afp"
    "os"
)

type EchoFilter struct {
    context *afp.Context
    header afp.StreamHeader
    decay float32 //decay factor: between 0 and 1
}

func (self *EchoFilter) GetType() int {
    return afp.PIPE_LINK
}

func NewEchoFilter() afp.Filter {
    return &EchoFilter{}
}

func (self *EchoFilter) Usage() {
    //TODO: add usage
}

func (self *EchoFilter) Init(ctx *afp.Context, args []string) os.Error {
    self.context = ctx
    //TODO: add argument parsing for decay rate
    self.decay = .2
    return nil
}

func (self *EchoFilter) Start() {
    self.header = <-self.context.HeaderSource
    self.context.HeaderSink <- self.header

    buffer := <-self.context.Source
    frameSize := len(buffer)
    //make the buffer 2x the frame size
    buffer = append(buffer, <-self.context.Source...)

    for nextFrame := range self.context.Source {
        for i := 0; i < frameSize; i++ {
            for j := int8(0); j < self.header.Channels; j++ {
                //ECHO, Echo, echo...
                //buffer[i+1][j] += buffer[i][j] * self.decay
                //what do we really want to do here?

            }
        }

        self.context.Sink <- buffer[0:frameSize]
        buffer = buffer[frameSize:]
        buffer = append(buffer, nextFrame...)
    }

    //Flush the buffer
    length = len(buffer)
    for i := 0; i < length; i++ {
        //apply echo/reverb

        if i == frameSize {
            self.context.Sink <- buffer[0:frameSize]
            buffer = buffer[frameSize:]
            i = 0
            length -= frameSize
        }
    }
}

func (self *EchoFilter) Stop() os.Error {
    //TODO
    return nil
}
<|endoftext|>


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

package finddecl

import (
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"

	"github.com/visualfc/gotools/command"
)

var Command = &command.Command{
	Run:       runFindDecl,
	UsageLine: "finddecl",
	Short:     "golang finddecl util",
	Long:      `golang finddecl util.`,
}

var (
	filePath string
	fileLine int
)

func init() {
	Command.Flag.StringVar(&filePath, "file", "", "file path")
	Command.Flag.IntVar(&fileLine, "line", -1, "file line")
}

func runFindDecl(cmd *command.Command, args []string) error {
	if len(filePath) == 0 || fileLine == -1 {
		cmd.Usage()
		return os.ErrInvalid
	}
	if !filepath.IsAbs(filePath) {
		dir, err := os.Getwd()
		if err != nil {
			return err
		}
		filePath = filepath.Join(dir, filePath)
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filePath, nil, 0)
	if err != nil {
		return err
	}
	decl := findDecl(fset, f, fileLine)
	if decl == nil {
		fmt.Println("-")
		return errors.New("error find decl")
	}
	printDecl(fset, decl)
	return nil
}

func printDecl(fset *token.FileSet, decl ast.Decl) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		fmt.Println(d.Tok, fset.Position(d.Pos()).Line, fset.Position(d.End()).Line)
	case *ast.FuncDecl:
		fmt.Println(d.Name, fset.Position(d.Pos()).Line, fset.Position(d.End()).Line)
	}
}

func findDecl(fset *token.FileSet, file *ast.File, line int) ast.Decl {
	for _, decl := range file.Decls {
		if line >= fset.Position(decl.Pos()).Line && line <= fset.Position(decl.End()).Line {
			return decl
		}
	}
	return nil
}
<commit_msg>finddecl add func prefix<commit_after>// Copyright 2011-2015 visualfc <visualfc@gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package finddecl

import (
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"

	"github.com/visualfc/gotools/command"
)

var Command = &command.Command{
	Run:       runFindDecl,
	UsageLine: "finddecl",
	Short:     "golang finddecl util",
	Long:      `golang finddecl util.`,
}

var (
	filePath string
	fileLine int
)

func init() {
	Command.Flag.StringVar(&filePath, "file", "", "file path")
	Command.Flag.IntVar(&fileLine, "line", -1, "file line")
}

func runFindDecl(cmd *command.Command, args []string) error {
	if len(filePath) == 0 || fileLine == -1 {
		cmd.Usage()
		return os.ErrInvalid
	}
	if !filepath.IsAbs(filePath) {
		dir, err := os.Getwd()
		if err != nil {
			return err
		}
		filePath = filepath.Join(dir, filePath)
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filePath, nil, 0)
	if err != nil {
		return err
	}
	decl := findDecl(fset, f, fileLine)
	if decl == nil {
		fmt.Println("-")
		return errors.New("error find decl")
	}
	printDecl(fset, decl)
	return nil
}

func printDecl(fset *token.FileSet, decl ast.Decl) {
	switch d := decl.(type) {
	case *ast.GenDecl:
		fmt.Println(d.Tok, fset.Position(d.Pos()).Line, fset.Position(d.End()).Line)
	case *ast.FuncDecl:
		fmt.Println("func", d.Name, fset.Position(d.Pos()).Line, fset.Position(d.End()).Line)
	}
}

func findDecl(fset *token.FileSet, file *ast.File, line int) ast.Decl {
	for _, decl := range file.Decls {
		if line >= fset.Position(decl.Pos()).Line && line <= fset.Position(decl.End()).Line {
			return decl
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

type Direction struct {
	DeltaX    int
	DeltaY    int
	TurnLeft  func() *Direction
	TurnRight func() *Direction
}

type Command struct {
	TurnDirection string
	MoveDistance  int
}

type Vector struct {
	X int
	Y int
}

func (v Vector) String() string {
	return fmt.Sprintf("%d:%d", v.X, v.Y)
}

func ParseInput(input string) *Command {
	input = strings.TrimSpace(input)
	result := &Command{}

	if input[0] == 'L' {
		result.TurnDirection = "left"
	} else {
		result.TurnDirection = "right"
	}

	result.MoveDistance, _ = strconv.Atoi(string(input[1:]))
	return result
}

func GetManhattanDistance(vector1, vector2 Vector) int {
	return int(math.Abs(float64(vector1.X)-float64(vector2.X)) + math.Abs(float64(vector1.Y)-float64(vector2.Y)))
}

func Visited(visitedLocations map[string]Vector, vector Vector) bool {
	var ok bool
	_, ok = visitedLocations[vector.String()]
	return ok
}

func main() {
	var puzzleInput string

	east := &Direction{DeltaX: -1, DeltaY: 0}
	north := &Direction{DeltaX: 0, DeltaY: 1}
	south := &Direction{DeltaX: 0, DeltaY: -1}
	west := &Direction{DeltaX: 1, DeltaY: 0}

	east.TurnLeft = func() *Direction { return north }
	east.TurnRight = func() *Direction { return south }

	north.TurnLeft = func() *Direction { return west }
	north.TurnRight = func() *Direction { return east }

	south.TurnLeft = func() *Direction { return east }
	south.TurnRight = func() *Direction { return west }

	west.TurnLeft = func() *Direction { return south }
	west.TurnRight = func() *Direction { return north }

	puzzleInput = "R8, R4, R4, R8"
	//puzzleInput = "R2, L2, R2, R2, R2"
	//puzzleInput = "L4, R2, R4, L5, L3, L1, R4, R5, R1, R3, L3, L2, L2, R5, R1, L1, L2, R2, R2, L5, R5, R5, L2, R1, R2, L2, L4, L1, R5, R2, R1, R1, L2, L3, R2, L5, L186, L5, L3, R3, L5, R4, R2, L5, R1, R4, L1, L3, R3, R1, L1, R4, R2, L1, L4, R5, L1, R50, L4, R3, R78, R4, R2, L4, R3, L4, R4, L1, R5, L4, R1, L2, R3, L2, R5, R5, L4, L1, L2, R185, L5, R2, R1, L3, R4, L5, R2, R4, L3, R4, L2, L5, R1, R2, L2, L1, L2, R2, L2, R1, L5, L3, L4, L3, L4, L2, L5, L5, R2, L3, L4, R4, R4, R5, L4, L2, R4, L5, R3, R1, L1, R3, L2, R2, R1, R5, L4, R5, L3, R2, R3, R1, R4, L4, R1, R3, L5, L1, L3, R2, R1, R4, L4, R3, L3, R3, R2, L3, L3, R4, L2, R4, L3, L4, R5, R1, L1, R5, R3, R1, R3, R4, L1, R4, R3, R1, L5, L5, L4, R4, R3, L2, R1, R5, L3, R4, R5, L4, L5, R2"

	commands := strings.Split(puzzleInput, ", ")
	parsedCommand := &Command{}

	currentDirection := north
	origin := Vector{X: 0, Y: 0}
	currentPosition := Vector{X: 0, Y: 0}
	visited := make(map[string]Vector)

	nextCommand := ""

	visited[origin.String()] = origin

	for _, nextCommand = range commands {
		fmt.Printf("Next command: %s\n", nextCommand)
		parsedCommand = ParseInput(nextCommand)

		if parsedCommand.TurnDirection == "left" {
			currentDirection = currentDirection.TurnLeft()
		} else {
			currentDirection = currentDirection.TurnRight()
		}

		for dx := 0; dx < parsedCommand.MoveDistance; dx++ {
			currentPosition.X += currentDirection.DeltaX
			currentPosition.Y += currentDirection.DeltaY

			if Visited(visited, currentPosition) {
				break
			}

			visited[currentPosition.String()] = currentPosition
		}
		// currentPosition.X += (currentDirection.DeltaX * parsedCommand.MoveDistance)
		// currentPosition.Y += (currentDirection.DeltaY * parsedCommand.MoveDistance)
	}

	fmt.Printf("We are now %d blocks away from our starting point.\n", GetManhattanDistance(origin, currentPosition))
}
<commit_msg>It works. For some reason the input provided on the site is wrong, and I had to look it up on reddit<commit_after>package main

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

type Direction struct {
	DeltaX    int
	DeltaY    int
	TurnLeft  func() *Direction
	TurnRight func() *Direction
}

type Command struct {
	TurnDirection string
	MoveDistance  int
}

type Vector struct {
	X int
	Y int
}

func (v Vector) String() string {
	return fmt.Sprintf("%d:%d", v.X, v.Y)
}

func ParseInput(input string) *Command {
	input = strings.TrimSpace(input)
	result := &Command{}

	if input[0] == 'L' {
		result.TurnDirection = "left"
	} else {
		result.TurnDirection = "right"
	}

	result.MoveDistance, _ = strconv.Atoi(string(input[1:]))
	return result
}

func GetManhattanDistance(vector1, vector2 Vector) int {
	return int(math.Abs(float64(vector1.X)-float64(vector2.X)) + math.Abs(float64(vector1.Y)-float64(vector2.Y)))
}

func Visited(visitedLocations map[string]Vector, vector Vector) bool {
	var ok bool
	_, ok = visitedLocations[vector.String()]
	return ok
}

func main() {
	var puzzleInput string

	east := &Direction{DeltaX: -1, DeltaY: 0}
	north := &Direction{DeltaX: 0, DeltaY: 1}
	south := &Direction{DeltaX: 0, DeltaY: -1}
	west := &Direction{DeltaX: 1, DeltaY: 0}

	east.TurnLeft = func() *Direction { return north }
	east.TurnRight = func() *Direction { return south }

	north.TurnLeft = func() *Direction { return west }
	north.TurnRight = func() *Direction { return east }

	south.TurnLeft = func() *Direction { return east }
	south.TurnRight = func() *Direction { return west }

	west.TurnLeft = func() *Direction { return south }
	west.TurnRight = func() *Direction { return north }

	//puzzleInput = "R8, R4, R4, R8"
	//puzzleInput = "R2, L2, R2, R2, R2"
	puzzleInput = "R5, L2, L1, R1, R3, R3, L3, R3, R4, L2, R4, L4, R4, R3, L2, L1, L1, R2, R4, R4, L4, R3, L2, R1, L4, R1, R3, L5, L4, L5, R3, L3, L1, L1, R4, R2, R2, L1, L4, R191, R5, L2, R46, R3, L1, R74, L2, R2, R187, R3, R4, R1, L4, L4, L2, R4, L5, R4, R3, L2, L1, R3, R3, R3, R1, R1, L4, R4, R1, R5, R2, R1, R3, L4, L2, L2, R1, L3, R1, R3, L5, L3, R5, R3, R4, L1, R3, R2, R1, R2, L4, L1, L1, R3, L3, R4, L2, L4, L5, L5, L4, R2, R5, L4, R4, L2, R3, L4, L3, L5, R5, L4, L2, R3, R5, R5, L1, L4, R3, L1, R2, L5, L1, R4, L1, R5, R1, L4, L4, L4, R4, R3, L5, R1, L3, R4, R3, L2, L1, R1, R2, R2, R2, L1, L1, L2, L5, L3, L1"

	commands := strings.Split(puzzleInput, ", ")
	parsedCommand := &Command{}

	currentDirection := north
	origin := Vector{X: 0, Y: 0}
	currentPosition := Vector{X: 0, Y: 0}
	visited := make(map[string]Vector)

	nextCommand := ""

	visited[origin.String()] = origin

	for _, nextCommand = range commands {
		parsedCommand = ParseInput(nextCommand)

		if parsedCommand.TurnDirection == "left" {
			currentDirection = currentDirection.TurnLeft()
		} else {
			currentDirection = currentDirection.TurnRight()
		}

		for dx := 0; dx < parsedCommand.MoveDistance; dx++ {
			currentPosition.X += currentDirection.DeltaX
			currentPosition.Y += currentDirection.DeltaY

			if Visited(visited, currentPosition) {
				break
			}

			visited[currentPosition.String()] = currentPosition
		}
	}

	fmt.Printf("We are now %d blocks away from our starting point.\n", GetManhattanDistance(origin, currentPosition))
}
<|endoftext|>


<commit_before>package driver

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/hashicorp/go-version"
	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	cstructs "github.com/hashicorp/nomad/client/driver/structs"
	"github.com/hashicorp/nomad/client/fingerprint"
	"github.com/hashicorp/nomad/helper/args"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

var (
	reRktVersion  = regexp.MustCompile(`rkt version (\d[.\d]+)`)
	reAppcVersion = regexp.MustCompile(`appc version (\d[.\d]+)`)
)

// RktDriver is a driver for running images via Rkt
// We attempt to chose sane defaults for now, with more configuration available
// planned in the future
type RktDriver struct {
	DriverContext
	fingerprint.StaticFingerprinter
}

type RktDriverConfig struct {
	ImageName string   `mapstructure:"image"`
	Args      []string `mapstructure:"args"`
}

// rktHandle is returned from Start/Open as a handle to the PID
type rktHandle struct {
	proc   *os.Process
	image  string
	logger *log.Logger
	waitCh chan *cstructs.WaitResult
	doneCh chan struct{}
}

// rktPID is a struct to map the pid running the process to the vm image on
// disk
type rktPID struct {
	Pid   int
	Image string
}

// NewRktDriver is used to create a new exec driver
func NewRktDriver(ctx *DriverContext) Driver {
	return &RktDriver{DriverContext: *ctx}
}

func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// Only enable if we are root when running on non-windows systems.
	if runtime.GOOS != "windows" && syscall.Geteuid() != 0 {
		d.logger.Printf("[DEBUG] driver.rkt: must run as root user, disabling")
		return false, nil
	}

	outBytes, err := exec.Command("rkt", "version").Output()
	if err != nil {
		return false, nil
	}
	out := strings.TrimSpace(string(outBytes))

	rktMatches := reRktVersion.FindStringSubmatch(out)
	appcMatches := reAppcVersion.FindStringSubmatch(out)
	if len(rktMatches) != 2 || len(appcMatches) != 2 {
		return false, fmt.Errorf("Unable to parse Rkt version string: %#v", rktMatches)
	}

	node.Attributes["driver.rkt"] = "1"
	node.Attributes["driver.rkt.version"] = rktMatches[1]
	node.Attributes["driver.rkt.appc.version"] = appcMatches[1]

	minVersion, _ := version.NewVersion("0.14.0")
	currentVersion, _ := version.NewVersion(node.Attributes["driver.rkt.version"])
	if currentVersion.LessThan(minVersion) {
		// Do not allow rkt < 0.14.0
		d.logger.Printf("[WARN] driver.rkt: please upgrade rkt to a version >= %s", minVersion)
		node.Attributes["driver.rkt"] = "0"
	}
	return true, nil
}

// Run an existing Rkt image.
func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var driverConfig RktDriverConfig
	if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
		return nil, err
	}
	// Validate that the config is valid.
	img := driverConfig.ImageName
	if img == "" {
		return nil, fmt.Errorf("Missing ACI image for rkt")
	}

	// Get the tasks local directory.
	taskName := d.DriverContext.taskName
	taskDir, ok := ctx.AllocDir.TaskDirs[taskName]
	if !ok {
		return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
	}
	taskLocal := filepath.Join(taskDir, allocdir.TaskLocal)

	// Add the given trust prefix
	trustPrefix, trustCmd := task.Config["trust_prefix"]
	if trustCmd {
		var outBuf, errBuf bytes.Buffer
		cmd := exec.Command("rkt", "trust", fmt.Sprintf("--prefix=%s", trustPrefix))
		cmd.Stdout = &outBuf
		cmd.Stderr = &errBuf
		if err := cmd.Run(); err != nil {
			return nil, fmt.Errorf("Error running rkt trust: %s\n\nOutput: %s\n\nError: %s",
				err, outBuf.String(), errBuf.String())
		}
		d.logger.Printf("[DEBUG] driver.rkt: added trust prefix: %q", trustPrefix)
	}

	// Build the command.
	var cmdArgs []string

	// Inject the environment variables.
	envVars := TaskEnvironmentVariables(ctx, task)

	// Clear the task directories as they are not currently supported.
	envVars.ClearTaskLocalDir()
	envVars.ClearAllocDir()

	for k, v := range envVars.Map() {
		cmdArgs = append(cmdArgs, fmt.Sprintf("--set-env=%v=%v", k, v))
	}

	// Disble signature verification if the trust command was not run.
	if !trustCmd {
		cmdArgs = append(cmdArgs, "--insecure-skip-verify")
	}

	// Append the run command.
	cmdArgs = append(cmdArgs, "run", "--mds-register=false", img)

	// Check if the user has overriden the exec command.
	if execCmd, ok := task.Config["command"]; ok {
		cmdArgs = append(cmdArgs, fmt.Sprintf("--exec=%v", execCmd))
	}

	if task.Resources.MemoryMB == 0 {
		return nil, fmt.Errorf("Memory limit cannot be zero")
	}
	if task.Resources.CPU == 0 {
		return nil, fmt.Errorf("CPU limit cannot be zero")
	}

	// Add memory isolator
	cmdArgs = append(cmdArgs, fmt.Sprintf("--memory=%vM", int64(task.Resources.MemoryMB)*1024*1024))

	// Add CPU isolator
	cmdArgs = append(cmdArgs, fmt.Sprintf("--cpu=%vm", int64(task.Resources.CPU)))

	// Add user passed arguments.
	if len(driverConfig.Args) != 0 {
		parsed := args.ParseAndReplace(driverConfig.Args, envVars.Map())

		// Need to start arguments with "--"
		if len(parsed) > 0 {
			cmdArgs = append(cmdArgs, "--")
		}

		for _, arg := range parsed {
			cmdArgs = append(cmdArgs, fmt.Sprintf("%v", arg))
		}
	}

	// Create files to capture stdin and out.
	stdoutFilename := filepath.Join(taskLocal, fmt.Sprintf("%s.stdout", taskName))
	stderrFilename := filepath.Join(taskLocal, fmt.Sprintf("%s.stderr", taskName))

	stdo, err := os.OpenFile(stdoutFilename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("Error opening file to redirect stdout: %v", err)
	}

	stde, err := os.OpenFile(stderrFilename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("Error opening file to redirect stderr: %v", err)
	}

	cmd := exec.Command("rkt", cmdArgs...)
	cmd.Stdout = stdo
	cmd.Stderr = stde

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("Error running rkt: %v", err)
	}

	d.logger.Printf("[DEBUG] driver.rkt: started ACI %q with: %v", img, cmd.Args)
	h := &rktHandle{
		proc:   cmd.Process,
		image:  img,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan *cstructs.WaitResult, 1),
	}
	go h.run()
	return h, nil
}

func (d *RktDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
	// Parse the handle
	pidBytes := []byte(strings.TrimPrefix(handleID, "Rkt:"))
	qpid := &rktPID{}
	if err := json.Unmarshal(pidBytes, qpid); err != nil {
		return nil, fmt.Errorf("failed to parse Rkt handle '%s': %v", handleID, err)
	}

	// Find the process
	proc, err := os.FindProcess(qpid.Pid)
	if proc == nil || err != nil {
		return nil, fmt.Errorf("failed to find Rkt PID %d: %v", qpid.Pid, err)
	}

	// Return a driver handle
	h := &rktHandle{
		proc:   proc,
		image:  qpid.Image,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan *cstructs.WaitResult, 1),
	}

	go h.run()
	return h, nil
}

func (h *rktHandle) ID() string {
	// Return a handle to the PID
	pid := &rktPID{
		Pid:   h.proc.Pid,
		Image: h.image,
	}
	data, err := json.Marshal(pid)
	if err != nil {
		h.logger.Printf("[ERR] driver.rkt: failed to marshal rkt PID to JSON: %s", err)
	}
	return fmt.Sprintf("Rkt:%s", string(data))
}

func (h *rktHandle) WaitCh() chan *cstructs.WaitResult {
	return h.waitCh
}

func (h *rktHandle) Update(task *structs.Task) error {
	// Update is not possible
	return nil
}

// Kill is used to terminate the task. We send an Interrupt
// and then provide a 5 second grace period before doing a Kill.
func (h *rktHandle) Kill() error {
	h.proc.Signal(os.Interrupt)
	select {
	case <-h.doneCh:
		return nil
	case <-time.After(5 * time.Second):
		return h.proc.Kill()
	}
}

func (h *rktHandle) run() {
	ps, err := h.proc.Wait()
	close(h.doneCh)
	code := 0
	if !ps.Success() {
		// TODO: Better exit code parsing.
		code = 1
	}
	h.waitCh <- cstructs.NewWaitResult(code, 0, err)
	close(h.waitCh)
}
<commit_msg>Move constants to the top<commit_after>package driver

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/hashicorp/go-version"
	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	cstructs "github.com/hashicorp/nomad/client/driver/structs"
	"github.com/hashicorp/nomad/client/fingerprint"
	"github.com/hashicorp/nomad/helper/args"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

var (
	reRktVersion  = regexp.MustCompile(`rkt version (\d[.\d]+)`)
	reAppcVersion = regexp.MustCompile(`appc version (\d[.\d]+)`)
)

const (
	// rkt added support for CPU and memory isolators in 0.14.0. We cannot support
	// an earlier version to maintain an uniform interface across all drivers
	minRktVersion    = "0.14.0"
	conversionFactor = 1024 * 1024
)

// RktDriver is a driver for running images via Rkt
// We attempt to chose sane defaults for now, with more configuration available
// planned in the future
type RktDriver struct {
	DriverContext
	fingerprint.StaticFingerprinter
}

type RktDriverConfig struct {
	ImageName string   `mapstructure:"image"`
	Args      []string `mapstructure:"args"`
}

// rktHandle is returned from Start/Open as a handle to the PID
type rktHandle struct {
	proc   *os.Process
	image  string
	logger *log.Logger
	waitCh chan *cstructs.WaitResult
	doneCh chan struct{}
}

// rktPID is a struct to map the pid running the process to the vm image on
// disk
type rktPID struct {
	Pid   int
	Image string
}

// NewRktDriver is used to create a new exec driver
func NewRktDriver(ctx *DriverContext) Driver {
	return &RktDriver{DriverContext: *ctx}
}

func (d *RktDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// Only enable if we are root when running on non-windows systems.
	if runtime.GOOS != "windows" && syscall.Geteuid() != 0 {
		d.logger.Printf("[DEBUG] driver.rkt: must run as root user, disabling")
		return false, nil
	}

	outBytes, err := exec.Command("rkt", "version").Output()
	if err != nil {
		return false, nil
	}
	out := strings.TrimSpace(string(outBytes))

	rktMatches := reRktVersion.FindStringSubmatch(out)
	appcMatches := reAppcVersion.FindStringSubmatch(out)
	if len(rktMatches) != 2 || len(appcMatches) != 2 {
		return false, fmt.Errorf("Unable to parse Rkt version string: %#v", rktMatches)
	}

	node.Attributes["driver.rkt"] = "1"
	node.Attributes["driver.rkt.version"] = rktMatches[1]
	node.Attributes["driver.rkt.appc.version"] = appcMatches[1]

	minVersion, _ := version.NewVersion(minRktVersion)
	currentVersion, _ := version.NewVersion(node.Attributes["driver.rkt.version"])
	if currentVersion.LessThan(minVersion) {
		// Do not allow rkt < 0.14.0
		d.logger.Printf("[WARN] driver.rkt: please upgrade rkt to a version >= %s", minVersion)
		node.Attributes["driver.rkt"] = "0"
	}
	return true, nil
}

// Run an existing Rkt image.
func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var driverConfig RktDriverConfig
	if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
		return nil, err
	}
	// Validate that the config is valid.
	img := driverConfig.ImageName
	if img == "" {
		return nil, fmt.Errorf("Missing ACI image for rkt")
	}

	// Get the tasks local directory.
	taskName := d.DriverContext.taskName
	taskDir, ok := ctx.AllocDir.TaskDirs[taskName]
	if !ok {
		return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
	}
	taskLocal := filepath.Join(taskDir, allocdir.TaskLocal)

	// Add the given trust prefix
	trustPrefix, trustCmd := task.Config["trust_prefix"]
	if trustCmd {
		var outBuf, errBuf bytes.Buffer
		cmd := exec.Command("rkt", "trust", fmt.Sprintf("--prefix=%s", trustPrefix))
		cmd.Stdout = &outBuf
		cmd.Stderr = &errBuf
		if err := cmd.Run(); err != nil {
			return nil, fmt.Errorf("Error running rkt trust: %s\n\nOutput: %s\n\nError: %s",
				err, outBuf.String(), errBuf.String())
		}
		d.logger.Printf("[DEBUG] driver.rkt: added trust prefix: %q", trustPrefix)
	}

	// Build the command.
	var cmdArgs []string

	// Inject the environment variables.
	envVars := TaskEnvironmentVariables(ctx, task)

	// Clear the task directories as they are not currently supported.
	envVars.ClearTaskLocalDir()
	envVars.ClearAllocDir()

	for k, v := range envVars.Map() {
		cmdArgs = append(cmdArgs, fmt.Sprintf("--set-env=%v=%v", k, v))
	}

	// Disble signature verification if the trust command was not run.
	if !trustCmd {
		cmdArgs = append(cmdArgs, "--insecure-skip-verify")
	}

	// Append the run command.
	cmdArgs = append(cmdArgs, "run", "--mds-register=false", img)

	// Check if the user has overriden the exec command.
	if execCmd, ok := task.Config["command"]; ok {
		cmdArgs = append(cmdArgs, fmt.Sprintf("--exec=%v", execCmd))
	}

	if task.Resources.MemoryMB == 0 {
		return nil, fmt.Errorf("Memory limit cannot be zero")
	}
	if task.Resources.CPU == 0 {
		return nil, fmt.Errorf("CPU limit cannot be zero")
	}

	// Add memory isolator
	cmdArgs = append(cmdArgs, fmt.Sprintf("--memory=%vM", int64(task.Resources.MemoryMB)*conversionFactor))

	// Add CPU isolator
	cmdArgs = append(cmdArgs, fmt.Sprintf("--cpu=%vm", int64(task.Resources.CPU)))

	// Add user passed arguments.
	if len(driverConfig.Args) != 0 {
		parsed := args.ParseAndReplace(driverConfig.Args, envVars.Map())

		// Need to start arguments with "--"
		if len(parsed) > 0 {
			cmdArgs = append(cmdArgs, "--")
		}

		for _, arg := range parsed {
			cmdArgs = append(cmdArgs, fmt.Sprintf("%v", arg))
		}
	}

	// Create files to capture stdin and out.
	stdoutFilename := filepath.Join(taskLocal, fmt.Sprintf("%s.stdout", taskName))
	stderrFilename := filepath.Join(taskLocal, fmt.Sprintf("%s.stderr", taskName))

	stdo, err := os.OpenFile(stdoutFilename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("Error opening file to redirect stdout: %v", err)
	}

	stde, err := os.OpenFile(stderrFilename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("Error opening file to redirect stderr: %v", err)
	}

	cmd := exec.Command("rkt", cmdArgs...)
	cmd.Stdout = stdo
	cmd.Stderr = stde

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("Error running rkt: %v", err)
	}

	d.logger.Printf("[DEBUG] driver.rkt: started ACI %q with: %v", img, cmd.Args)
	h := &rktHandle{
		proc:   cmd.Process,
		image:  img,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan *cstructs.WaitResult, 1),
	}
	go h.run()
	return h, nil
}

func (d *RktDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
	// Parse the handle
	pidBytes := []byte(strings.TrimPrefix(handleID, "Rkt:"))
	qpid := &rktPID{}
	if err := json.Unmarshal(pidBytes, qpid); err != nil {
		return nil, fmt.Errorf("failed to parse Rkt handle '%s': %v", handleID, err)
	}

	// Find the process
	proc, err := os.FindProcess(qpid.Pid)
	if proc == nil || err != nil {
		return nil, fmt.Errorf("failed to find Rkt PID %d: %v", qpid.Pid, err)
	}

	// Return a driver handle
	h := &rktHandle{
		proc:   proc,
		image:  qpid.Image,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan *cstructs.WaitResult, 1),
	}

	go h.run()
	return h, nil
}

func (h *rktHandle) ID() string {
	// Return a handle to the PID
	pid := &rktPID{
		Pid:   h.proc.Pid,
		Image: h.image,
	}
	data, err := json.Marshal(pid)
	if err != nil {
		h.logger.Printf("[ERR] driver.rkt: failed to marshal rkt PID to JSON: %s", err)
	}
	return fmt.Sprintf("Rkt:%s", string(data))
}

func (h *rktHandle) WaitCh() chan *cstructs.WaitResult {
	return h.waitCh
}

func (h *rktHandle) Update(task *structs.Task) error {
	// Update is not possible
	return nil
}

// Kill is used to terminate the task. We send an Interrupt
// and then provide a 5 second grace period before doing a Kill.
func (h *rktHandle) Kill() error {
	h.proc.Signal(os.Interrupt)
	select {
	case <-h.doneCh:
		return nil
	case <-time.After(5 * time.Second):
		return h.proc.Kill()
	}
}

func (h *rktHandle) run() {
	ps, err := h.proc.Wait()
	close(h.doneCh)
	code := 0
	if !ps.Success() {
		// TODO: Better exit code parsing.
		code = 1
	}
	h.waitCh <- cstructs.NewWaitResult(code, 0, err)
	close(h.waitCh)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/textproto"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
	"github.com/faiface/pixel/pixelgl"
	"github.com/faiface/pixel/text"
	"golang.org/x/image/colornames"
	"golang.org/x/image/font/basicfont"
)

//Page are settings
type Page struct {
	Channel  string   `json:"channel"`
	Username string   `json:"username"`
	Oauth    string   `json:"oauth"`
	CommandA string   `json:"commandA"`
	CommandB string   `json:"commandB"`
	KeyWorld []string `json:"keyWord"`
}

//Score that is saved
type Score struct {
	A int `json:"a"`
	B int `json:"b"`
}

var i = 0
var j = 0

func (p Page) toString() string {
	return toJSON(p)
}

func toString(s Score) string {
	return toJSON(s)
}

func toJSON(p interface{}) string {
	bytes, err := json.Marshal(p)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	return string(bytes)
}

func getPages() []Page {
	raw, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	var c []Page
	json.Unmarshal(raw, &c)
	return c
}

func getScore() []Score {
	raw, err := ioutil.ReadFile("./score.json")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	var c []Score
	json.Unmarshal(raw, &c)
	return c
}

func countCheers(s2 string, page Page) int {
	result := 0
	for _, keyword := range page.KeyWorld {
		result += countCheersSingle(s2, keyword, page.CommandA, page.CommandB)
	}
	return result
}

func countCheersSingle(s2 string, keyword string, commandA string, commandB string) int {

	s := strings.Replace(" "+s2+" ", " ", "  ", -1)
	r := regexp.MustCompile("\\s(" + keyword + ")(.*?[\\d]+)\\s")
	ff := r.FindAllStringSubmatch(s, 40)
	result := 0
	for _, f := range ff {
		fmt.Println(f)
		// element is the element from someSlice for where we are
		if len(f) == 3 {
			m := f[2]
			i, _ := strconv.ParseInt(m, 0, 64)
			if strings.Contains(s, "#"+commandA) {
				result += int(i)
			} else if strings.Contains(s, "#"+commandB) {
				result += int(i * -1)
			}
		}
	}

	return result
}

func goBotGo(page Page, score Score, win *pixelgl.Window) {
	conn, err := net.Dial("tcp", "irc.chat.twitch.tv:6667")
	if err != nil {
		panic(err)
	}
	conn.Write([]byte("PASS " + page.Oauth + "\r\n"))
	conn.Write([]byte("NICK " + page.Username + "\r\n"))
	conn.Write([]byte("JOIN " + "#" + page.Channel + "\r\n"))
	defer conn.Close()

	tp := textproto.NewReader(bufio.NewReader(conn))
	fmt.Println(strconv.Itoa(score.A))
	fmt.Println(strconv.Itoa(score.B))
	scoreA := score.A
	scoreB := score.B
	i = pink
	j = scoreA

	for !win.Closed() {
		msg, err := tp.ReadLine()
		if err != nil {
			panic(err)
		}
		fmt.Println(msg)
		msgParts := strings.Split(msg, " ")
		if msgParts[0] == "PING" {
			conn.Write([]byte("PONG " + msgParts[1]))
			continue
		}

		splitMessage := strings.Split(strings.ToLower(msg), ":")
		if len(splitMessage) >= 3 {
			if strings.Split(msg, ":")[2] == "!score" {
				outputScore(scoreB, scoreA, conn, score, page)
				continue
			}

			cheer := countCheers(strings.Split(msg, ":")[2], page)
			fmt.Println(strings.Split(msg, ":")[2])
			fmt.Println(cheer)
			if cheer > 0 {
				scoreB += cheer
			} else if cheer < 0 {
				scoreA += cheer * -1
			}

			if cheer != 0 {
				outputScore(scoreB, scoreA, conn, score, page)
				continue
			}
		}
	}
}

func outputScore(pink int, purple int, conn net.Conn, score Score, page Page) {
	pinkString := strconv.Itoa(pink)
	purpleString := strconv.Itoa(purple)
	score.B = pink
	score.A = purple
	json := "[" + toString(score) + "]"
	ioutil.WriteFile("score.json", []byte(json), 0644)
	i = pink
	j = purple
	fmt.Println(" " + page.CommandA + "  : " + pinkString + " " + page.CommandB + " : " + purpleString + "\r\n")
	conn.Write([]byte("PRIVMSG #" + page.Channel + " :" + "Pink: " + pinkString + " Purple: " + purpleString + "\r\n"))
}

func run() {
	cfg := pixelgl.WindowConfig{
		Title:  "Cheer Bot",
		Bounds: pixel.R(0, 0, 600, 175),
		VSync:  true,
	}
	win, err := pixelgl.NewWindow(cfg)
	if err != nil {
		panic(err)
	}

	win.Clear(colornames.Black)

	pages := getPages()
	score := getScore()

	go goBotGo(pages[0], score[0], win)
	runWindow(win)

}

func runWindow(win *pixelgl.Window) {

	for !win.Closed() {
		imd := imdraw.New(nil)
		basicAtlas := text.NewAtlas(basicfont.Face7x13, text.ASCII)
		pinkTXT := text.New(pixel.V(10, 150), basicAtlas)
		fmt.Fprintln(pinkTXT, "PINK")
		purpleTXT := text.New(pixel.V(400, 150), basicAtlas)
		fmt.Fprintln(purpleTXT, "PURPLE")
		if i > 0 || j > 0 {
			totalVotes := float64(i) + float64(j)
			iPercent := float64(i) / totalVotes * 600

			r := float64(iPercent)
			//purple
			imd.Color = pixel.RGB(85.0/256.0, 26.0/256.0, 139.0/256.0)
			imd.Push(pixel.V(0, 0))
			imd.Push(pixel.V(0, 100))
			imd.Push(pixel.V(600, 100))
			imd.Push(pixel.V(600, 0))
			imd.Polygon(0)

			//pink
			imd.Color = pixel.RGB(255.0/256.0, 105.0/256.0, 180.0/256)
			imd.Push(pixel.V(0, 0))
			imd.Push(pixel.V(0, 100))
			imd.Push(pixel.V(r, 100))
			imd.Push(pixel.V(r, 0))
			imd.Polygon(0)
			purpleTXT.Clear()
			pinkTXT.Clear()
			fmt.Fprintln(purpleTXT, strconv.Itoa(j)+" : PURPLE")
			fmt.Fprintln(pinkTXT, "PINK : "+strconv.Itoa(i))
		}
		win.Clear(colornames.Black)
		imd.Draw(win)
		purpleTXT.Draw(win, pixel.IM.Scaled(purpleTXT.Orig, 2))
		pinkTXT.Draw(win, pixel.IM.Scaled(pinkTXT.Orig, 2))
		win.Update()
		time.Sleep(time.Millisecond * 16) //Sleep for a frame
	}
}
func runImage() {
	pixelgl.Run(run)
}

func main() {
	runImage()
}
<commit_msg>More cleaning<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/textproto"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
	"github.com/faiface/pixel/pixelgl"
	"github.com/faiface/pixel/text"
	"golang.org/x/image/colornames"
	"golang.org/x/image/font/basicfont"
)

//Page are settings
type Page struct {
	Channel  string   `json:"channel"`
	Username string   `json:"username"`
	Oauth    string   `json:"oauth"`
	CommandA string   `json:"commandA"`
	CommandB string   `json:"commandB"`
	KeyWorld []string `json:"keyWord"`
}

//Score that is saved
type Score struct {
	A int `json:"a"`
	B int `json:"b"`
}

var i = 0
var j = 0

func (p Page) toString() string {
	return toJSON(p)
}

func toString(s Score) string {
	return toJSON(s)
}

func toJSON(p interface{}) string {
	bytes, err := json.Marshal(p)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	return string(bytes)
}

func getPages() []Page {
	raw, err := ioutil.ReadFile("./settings.json")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	var c []Page
	json.Unmarshal(raw, &c)
	return c
}

func getScore() []Score {
	raw, err := ioutil.ReadFile("./score.json")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	var c []Score
	json.Unmarshal(raw, &c)
	return c
}

func countCheers(s2 string, page Page) int {
	result := 0
	for _, keyword := range page.KeyWorld {
		result += countCheersSingle(s2, keyword, page.CommandA, page.CommandB)
	}
	return result
}

func countCheersSingle(s2 string, keyword string, commandA string, commandB string) int {

	s := strings.Replace(" "+s2+" ", " ", "  ", -1)
	r := regexp.MustCompile("\\s(" + keyword + ")(.*?[\\d]+)\\s")
	ff := r.FindAllStringSubmatch(s, 40)
	result := 0
	for _, f := range ff {
		fmt.Println(f)
		// element is the element from someSlice for where we are
		if len(f) == 3 {
			m := f[2]
			i, _ := strconv.ParseInt(m, 0, 64)
			if strings.Contains(s, "#"+commandA) {
				result += int(i)
			} else if strings.Contains(s, "#"+commandB) {
				result += int(i * -1)
			}
		}
	}

	return result
}

func goBotGo(page Page, score Score, win *pixelgl.Window) {
	conn, err := net.Dial("tcp", "irc.chat.twitch.tv:6667")
	if err != nil {
		panic(err)
	}
	conn.Write([]byte("PASS " + page.Oauth + "\r\n"))
	conn.Write([]byte("NICK " + page.Username + "\r\n"))
	conn.Write([]byte("JOIN " + "#" + page.Channel + "\r\n"))
	defer conn.Close()

	tp := textproto.NewReader(bufio.NewReader(conn))
	fmt.Println(strconv.Itoa(score.A))
	fmt.Println(strconv.Itoa(score.B))
	scoreA := score.A
	scoreB := score.B
	i = pink
	j = scoreA

	for !win.Closed() {
		msg, err := tp.ReadLine()
		if err != nil {
			panic(err)
		}
		fmt.Println(msg)
		msgParts := strings.Split(msg, " ")
		if msgParts[0] == "PING" {
			conn.Write([]byte("PONG " + msgParts[1]))
			continue
		}

		splitMessage := strings.Split(strings.ToLower(msg), ":")
		if len(splitMessage) >= 3 {
			if strings.Split(msg, ":")[2] == "!score" {
				outputScore(scoreB, scoreA, conn, score, page)
				continue
			}

			cheer := countCheers(strings.Split(msg, ":")[2], page)
			fmt.Println(strings.Split(msg, ":")[2])
			fmt.Println(cheer)
			if cheer > 0 {
				scoreB += cheer
			} else if cheer < 0 {
				scoreA += cheer * -1
			}

			if cheer != 0 {
				outputScore(scoreB, scoreA, conn, score, page)
				continue
			}
		}
	}
}

func outputScore(scoreB int, scoreA int, conn net.Conn, score Score, page Page) {
	scoreAString := strconv.Itoa(scoreA)
	scoreBString := strconv.Itoa(scoreA)
	score.B = scoreA
	score.A = scoreA
	json := "[" + toString(score) + "]"
	ioutil.WriteFile("score.json", []byte(json), 0644)
	i = scoreA
	j = scoreA
	fmt.Println(" " + page.CommandA + "  : " + scoreAString + " " + page.CommandB + " : " + scoreBString + "\r\n")
	conn.Write([]byte("PRIVMSG #" + page.Channel + " :" + "Pink: " + scoreAString + " Purple: " + scoreBString + "\r\n"))
}

func run() {
	cfg := pixelgl.WindowConfig{
		Title:  "Cheer Bot",
		Bounds: pixel.R(0, 0, 600, 175),
		VSync:  true,
	}
	win, err := pixelgl.NewWindow(cfg)
	if err != nil {
		panic(err)
	}

	win.Clear(colornames.Black)

	pages := getPages()
	score := getScore()

	go goBotGo(pages[0], score[0], win)
	runWindow(win)

}

func runWindow(win *pixelgl.Window) {

	for !win.Closed() {
		imd := imdraw.New(nil)
		basicAtlas := text.NewAtlas(basicfont.Face7x13, text.ASCII)
		pinkTXT := text.New(pixel.V(10, 150), basicAtlas)
		fmt.Fprintln(pinkTXT, "PINK")
		purpleTXT := text.New(pixel.V(400, 150), basicAtlas)
		fmt.Fprintln(purpleTXT, "PURPLE")
		if i > 0 || j > 0 {
			totalVotes := float64(i) + float64(j)
			iPercent := float64(i) / totalVotes * 600

			r := float64(iPercent)
			//purple
			imd.Color = pixel.RGB(85.0/256.0, 26.0/256.0, 139.0/256.0)
			imd.Push(pixel.V(0, 0))
			imd.Push(pixel.V(0, 100))
			imd.Push(pixel.V(600, 100))
			imd.Push(pixel.V(600, 0))
			imd.Polygon(0)

			//pink
			imd.Color = pixel.RGB(255.0/256.0, 105.0/256.0, 180.0/256)
			imd.Push(pixel.V(0, 0))
			imd.Push(pixel.V(0, 100))
			imd.Push(pixel.V(r, 100))
			imd.Push(pixel.V(r, 0))
			imd.Polygon(0)
			purpleTXT.Clear()
			pinkTXT.Clear()
			fmt.Fprintln(purpleTXT, strconv.Itoa(j)+" : PURPLE")
			fmt.Fprintln(pinkTXT, "PINK : "+strconv.Itoa(i))
		}
		win.Clear(colornames.Black)
		imd.Draw(win)
		purpleTXT.Draw(win, pixel.IM.Scaled(purpleTXT.Orig, 2))
		pinkTXT.Draw(win, pixel.IM.Scaled(pinkTXT.Orig, 2))
		win.Update()
		time.Sleep(time.Millisecond * 16) //Sleep for a frame
	}
}
func runImage() {
	pixelgl.Run(run)
}

func main() {
	runImage()
}
<|endoftext|>