<commit_before>// Copyright (c) 2015 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 hyperbahn

import (
	"errors"
	"net"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/json"
	"github.com/uber/tchannel-go/testutils"
)

func TestAdvertiseFailed(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hostPort string) {
		serverCh := testutils.NewServer(t, nil)
		defer serverCh.Close()

		client, err := NewClient(serverCh, configFor(hostPort), nil)
		require.NoError(t, err, "NewClient")
		defer client.Close()
		assert.Error(t, client.Advertise(), "Advertise without handler should fail")
	})
}

func TestInitialAdvertiseFailedRetry(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hyperbahnHostPort string) {
		count := 0
		adHandler := func(ctx json.Context, req *AdRequest) (*AdResponse, error) {
			count++
			return nil, tchannel.ErrServerBusy
		}
		json.Register(hypCh, json.Handlers{"ad": adHandler}, nil)

		ch := testutils.NewServer(t, nil)
		client, err := NewClient(ch, configFor(hyperbahnHostPort), nil)
		assert.NoError(t, err, "hyperbahn NewClient failed")
		defer client.Close()

		assert.Error(t, client.Advertise(), "Advertise should not succeed")
		assert.Equal(t, 5, count, "adHandler not retried correct number of times")
	})
}

func TestNotListeningChannel(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hyperbahnHostPort string) {
		adHandler := func(ctx json.Context, req *AdRequest) (*AdResponse, error) {
			return &AdResponse{1}, nil
		}
		json.Register(hypCh, json.Handlers{"ad": adHandler}, nil)

		ch := testutils.NewClient(t, nil)
		client, err := NewClient(ch, configFor(hyperbahnHostPort), nil)
		assert.NoError(t, err, "hyperbahn NewClient failed")
		defer client.Close()

		assert.Equal(t, errEphemeralPeer, client.Advertise(), "Advertise without Listen should fail")
	})
}

type retryTest struct {
	// channel used to control the response to an 'ad' call.
	respCh chan int
	// reqCh contains the AdRequests sent to the adHandler.
	reqCh chan *AdRequest

	// sleep stub channels.
	sleepArgs  <-chan time.Duration
	sleepBlock chan<- struct{}
	sleepClose func()

	ch     *tchannel.Channel
	client *Client
	mock   mock.Mock
}

func (r *retryTest) On(event Event) {
	r.mock.Called(event)
}
func (r *retryTest) OnError(err error) {
	r.mock.Called(err)
}

func (r *retryTest) adHandler(ctx json.Context, req *AdRequest) (*AdResponse, error) {
	r.reqCh <- req
	v := <-r.respCh
	if v == 0 {
		return nil, errors.New("failed")
	}
	return &AdResponse{v}, nil
}

func (r *retryTest) setup() {
	r.respCh = make(chan int, 1)
	r.reqCh = make(chan *AdRequest, 1)
	r.sleepArgs, r.sleepBlock, r.sleepClose = testutils.SleepStub(&timeSleep)
}

func (r *retryTest) setAdvertiseSuccess() {
	r.respCh <- 1
}

func (r *retryTest) setAdvertiseFailure() {
	r.respCh <- 0
}

func runRetryTest(t *testing.T, f func(r *retryTest)) {
	r := &retryTest{}
	defer testutils.SetTimeout(t, time.Second)()
	r.setup()
	defer testutils.ResetSleepStub(&timeSleep)

	withSetup(t, func(hypCh *tchannel.Channel, hostPort string) {
		json.Register(hypCh, json.Handlers{"ad": r.adHandler}, nil)

		serverCh := testutils.NewServer(t, &testutils.ChannelOpts{ServiceName: "my-client"})
		defer serverCh.Close()

		var err error
		r.ch = serverCh
		r.client, err = NewClient(serverCh, configFor(hostPort), &ClientOptions{
			Handler:      r,
			FailStrategy: FailStrategyIgnore,
		})
		require.NoError(t, err, "NewClient")
		defer r.client.Close()
		f(r)
		r.mock.AssertExpectations(t)
	})
}

func TestAdvertiseSuccess(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 10 /* successful retries */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())

		// Verify that the arguments passed to 'ad' are correct.
		expectedRequest := &AdRequest{[]service{{Name: "my-client", Cost: 0}}}
		require.Equal(t, expectedRequest, <-r.reqCh)

		// Verify readvertise happen after sleeping for ~advertiseInterval.
		r.mock.On("On", Readvertised).Return().Times(10)
		for i := 0; i < 10; i++ {
			s1 := <-r.sleepArgs
			checkAdvertiseInterval(t, s1)
			r.sleepBlock <- struct{}{}

			r.setAdvertiseSuccess()
			require.Equal(t, expectedRequest, <-r.reqCh)
		}

		// Block till the last advertise completes.
		<-r.sleepArgs
	})
}

func TestMutlipleAdvertise(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 10 /* successful retries */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()

		sc2, sc3 := r.ch.GetSubChannel("svc-2"), r.ch.GetSubChannel("svc-3")
		require.NoError(t, r.client.Advertise(sc2, sc3))

		// Verify that the arguments passed to 'ad' are correct.
		expectedRequest := &AdRequest{[]service{
			{Name: "my-client", Cost: 0},
			{Name: "svc-2", Cost: 0},
			{Name: "svc-3", Cost: 0},
		}}
		require.Equal(t, expectedRequest, <-r.reqCh)

		// Verify readvertise happen after sleeping for ~advertiseInterval.
		r.mock.On("On", Readvertised).Return().Times(10)
		for i := 0; i < 10; i++ {
			s1 := <-r.sleepArgs
			checkAdvertiseInterval(t, s1)
			r.sleepBlock <- struct{}{}

			r.setAdvertiseSuccess()
			require.Equal(t, expectedRequest, <-r.reqCh)
		}

		// Block till the last advertise completes.
		<-r.sleepArgs
	})
}

var advertiseErr = json.ErrApplication{"type": "error", "message": "failed"}

func TestRetryTemporaryFailure(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 3 /* fail */ + 10 /* successful */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())
		<-r.reqCh

		s1 := <-r.sleepArgs
		checkAdvertiseInterval(t, s1)

		// When registrations fail, it retries after a short connection and triggers OnError.
		r.mock.On("OnError", ErrAdvertiseFailed{true, advertiseErr}).Return(nil).Times(3)
		for i := 0; i < 3; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseFailure()

			s1 := <-r.sleepArgs
			<-r.reqCh
			checkRetryInterval(t, s1, i+1 /* retryNum */)
		}

		// If the retry suceeds, then it goes back to normal.
		r.mock.On("On", Readvertised).Return().Times(10)
		// Verify re-registrations continue as usual when it succeeds.
		for i := 0; i < 10; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseSuccess()

			s1 := <-r.sleepArgs
			<-r.reqCh
			checkAdvertiseInterval(t, s1)
		}
	})
}

func TestRetryFailure(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + maxAdvertiseFailures /* fail */)
		r.mock.On("On", Advertised).Return().Once()

		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())
		<-r.reqCh

		s1 := <-r.sleepArgs
		checkAdvertiseInterval(t, s1)

		// When retries fail maxRegistrationFailures times, we receive:
		// maxRegistrationFailures - 1 OnError WithRetry=True
		// 1 OnError WithRetry=False
		noRetryFail := make(chan struct{})
		r.mock.On("OnError", ErrAdvertiseFailed{true, advertiseErr}).
			Return(nil).Times(maxAdvertiseFailures - 1)
		r.mock.On("OnError", ErrAdvertiseFailed{false, advertiseErr}).
			Return(nil).Run(func(_ mock.Arguments) {
			noRetryFail <- struct{}{}
		}).Once()
		for i := 0; i < maxAdvertiseFailures-1; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseFailure()
			<-r.reqCh

			s1 := <-r.sleepArgs
			checkRetryInterval(t, s1, i+1 /* retryNum */)
		}

		r.sleepClose()
		r.respCh <- 0
		<-r.reqCh

		// Wait for the handler to be called and the mock expectation to be recorded.
		<-noRetryFail

		select {
		case req := <-r.reqCh:
			t.Errorf("No Advertise calls should be made after failure, got %+v", req)
		default:
		}
	})
}

func checkAdvertiseInterval(t *testing.T, sleptFor time.Duration) {
	assert.True(t, sleptFor >= advertiseInterval,
		"advertise interval should be > advertiseInterval")
	assert.True(t, sleptFor < advertiseInterval+advertiseFuzzInterval,
		"advertise interval should be < advertiseInterval + advertiseFuzzInterval")
}

func checkRetryInterval(t *testing.T, sleptFor time.Duration, retryNum int) {
	maxRetryInterval := advertiseRetryInterval * time.Duration(1<<uint8(retryNum))
	assert.True(t, sleptFor < maxRetryInterval,
		"retry #%v slept for %v, should sleep for less than %v", retryNum, sleptFor, maxRetryInterval)
}

func configFor(node string) Configuration {
	return Configuration{
		InitialNodes: []string{node},
	}
}

func withSetup(t *testing.T, f func(ch *tchannel.Channel, hostPort string)) {
	serverCh, err := tchannel.NewChannel(hyperbahnServiceName, nil)
	require.NoError(t, err)
	defer serverCh.Close()
	listener, err := net.Listen("tcp", ":0")
	require.NoError(t, err)
	serverCh.Serve(listener)

	f(serverCh, listener.Addr().String())
	serverCh.Close()
}
<commit_msg>Ignore expected "registration failed" logs in Hyperbahn tests<commit_after>// Copyright (c) 2015 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 hyperbahn

import (
	"errors"
	"net"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/json"
	"github.com/uber/tchannel-go/testutils"
)

func TestAdvertiseFailed(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hostPort string) {
		serverCh := testutils.NewServer(t, nil)
		defer serverCh.Close()

		client, err := NewClient(serverCh, configFor(hostPort), nil)
		require.NoError(t, err, "NewClient")
		defer client.Close()
		assert.Error(t, client.Advertise(), "Advertise without handler should fail")
	})
}

func TestInitialAdvertiseFailedRetry(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hyperbahnHostPort string) {
		count := 0
		adHandler := func(ctx json.Context, req *AdRequest) (*AdResponse, error) {
			count++
			return nil, tchannel.ErrServerBusy
		}
		json.Register(hypCh, json.Handlers{"ad": adHandler}, nil)

		ch := testutils.NewServer(t, nil)
		client, err := NewClient(ch, configFor(hyperbahnHostPort), nil)
		assert.NoError(t, err, "hyperbahn NewClient failed")
		defer client.Close()

		assert.Error(t, client.Advertise(), "Advertise should not succeed")
		assert.Equal(t, 5, count, "adHandler not retried correct number of times")
	})
}

func TestNotListeningChannel(t *testing.T) {
	withSetup(t, func(hypCh *tchannel.Channel, hyperbahnHostPort string) {
		adHandler := func(ctx json.Context, req *AdRequest) (*AdResponse, error) {
			return &AdResponse{1}, nil
		}
		json.Register(hypCh, json.Handlers{"ad": adHandler}, nil)

		ch := testutils.NewClient(t, nil)
		client, err := NewClient(ch, configFor(hyperbahnHostPort), nil)
		assert.NoError(t, err, "hyperbahn NewClient failed")
		defer client.Close()

		assert.Equal(t, errEphemeralPeer, client.Advertise(), "Advertise without Listen should fail")
	})
}

type retryTest struct {
	// channel used to control the response to an 'ad' call.
	respCh chan int
	// reqCh contains the AdRequests sent to the adHandler.
	reqCh chan *AdRequest

	// sleep stub channels.
	sleepArgs  <-chan time.Duration
	sleepBlock chan<- struct{}
	sleepClose func()

	ch     *tchannel.Channel
	client *Client
	mock   mock.Mock
}

func (r *retryTest) On(event Event) {
	r.mock.Called(event)
}
func (r *retryTest) OnError(err error) {
	r.mock.Called(err)
}

func (r *retryTest) adHandler(ctx json.Context, req *AdRequest) (*AdResponse, error) {
	r.reqCh <- req
	v := <-r.respCh
	if v == 0 {
		return nil, errors.New("failed")
	}
	return &AdResponse{v}, nil
}

func (r *retryTest) setup() {
	r.respCh = make(chan int, 1)
	r.reqCh = make(chan *AdRequest, 1)
	r.sleepArgs, r.sleepBlock, r.sleepClose = testutils.SleepStub(&timeSleep)
}

func (r *retryTest) setAdvertiseSuccess() {
	r.respCh <- 1
}

func (r *retryTest) setAdvertiseFailure() {
	r.respCh <- 0
}

func runRetryTest(t *testing.T, f func(r *retryTest)) {
	r := &retryTest{}
	defer testutils.SetTimeout(t, time.Second)()
	r.setup()
	defer testutils.ResetSleepStub(&timeSleep)

	withSetup(t, func(hypCh *tchannel.Channel, hostPort string) {
		json.Register(hypCh, json.Handlers{"ad": r.adHandler}, nil)

		// Advertise failures cause warning log messages.
		opts := testutils.NewOpts().
			SetServiceName("my-client").
			AddLogFilter("Hyperbahn client registration failed", 10)
		serverCh := testutils.NewServer(t, opts)
		defer serverCh.Close()

		var err error
		r.ch = serverCh
		r.client, err = NewClient(serverCh, configFor(hostPort), &ClientOptions{
			Handler:      r,
			FailStrategy: FailStrategyIgnore,
		})
		require.NoError(t, err, "NewClient")
		defer r.client.Close()
		f(r)
		r.mock.AssertExpectations(t)
	})
}

func TestAdvertiseSuccess(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 10 /* successful retries */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())

		// Verify that the arguments passed to 'ad' are correct.
		expectedRequest := &AdRequest{[]service{{Name: "my-client", Cost: 0}}}
		require.Equal(t, expectedRequest, <-r.reqCh)

		// Verify readvertise happen after sleeping for ~advertiseInterval.
		r.mock.On("On", Readvertised).Return().Times(10)
		for i := 0; i < 10; i++ {
			s1 := <-r.sleepArgs
			checkAdvertiseInterval(t, s1)
			r.sleepBlock <- struct{}{}

			r.setAdvertiseSuccess()
			require.Equal(t, expectedRequest, <-r.reqCh)
		}

		// Block till the last advertise completes.
		<-r.sleepArgs
	})
}

func TestMutlipleAdvertise(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 10 /* successful retries */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()

		sc2, sc3 := r.ch.GetSubChannel("svc-2"), r.ch.GetSubChannel("svc-3")
		require.NoError(t, r.client.Advertise(sc2, sc3))

		// Verify that the arguments passed to 'ad' are correct.
		expectedRequest := &AdRequest{[]service{
			{Name: "my-client", Cost: 0},
			{Name: "svc-2", Cost: 0},
			{Name: "svc-3", Cost: 0},
		}}
		require.Equal(t, expectedRequest, <-r.reqCh)

		// Verify readvertise happen after sleeping for ~advertiseInterval.
		r.mock.On("On", Readvertised).Return().Times(10)
		for i := 0; i < 10; i++ {
			s1 := <-r.sleepArgs
			checkAdvertiseInterval(t, s1)
			r.sleepBlock <- struct{}{}

			r.setAdvertiseSuccess()
			require.Equal(t, expectedRequest, <-r.reqCh)
		}

		// Block till the last advertise completes.
		<-r.sleepArgs
	})
}

var advertiseErr = json.ErrApplication{"type": "error", "message": "failed"}

func TestRetryTemporaryFailure(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + 3 /* fail */ + 10 /* successful */)
		r.mock.On("On", Advertised).Return().Once()
		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())
		<-r.reqCh

		s1 := <-r.sleepArgs
		checkAdvertiseInterval(t, s1)

		// When registrations fail, it retries after a short connection and triggers OnError.
		r.mock.On("OnError", ErrAdvertiseFailed{true, advertiseErr}).Return(nil).Times(3)
		for i := 0; i < 3; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseFailure()

			s1 := <-r.sleepArgs
			<-r.reqCh
			checkRetryInterval(t, s1, i+1 /* retryNum */)
		}

		// If the retry suceeds, then it goes back to normal.
		r.mock.On("On", Readvertised).Return().Times(10)
		// Verify re-registrations continue as usual when it succeeds.
		for i := 0; i < 10; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseSuccess()

			s1 := <-r.sleepArgs
			<-r.reqCh
			checkAdvertiseInterval(t, s1)
		}
	})
}

func TestRetryFailure(t *testing.T) {
	runRetryTest(t, func(r *retryTest) {
		r.mock.On("On", SendAdvertise).Return().
			Times(1 /* initial */ + maxAdvertiseFailures /* fail */)
		r.mock.On("On", Advertised).Return().Once()

		r.setAdvertiseSuccess()
		require.NoError(t, r.client.Advertise())
		<-r.reqCh

		s1 := <-r.sleepArgs
		checkAdvertiseInterval(t, s1)

		// When retries fail maxRegistrationFailures times, we receive:
		// maxRegistrationFailures - 1 OnError WithRetry=True
		// 1 OnError WithRetry=False
		noRetryFail := make(chan struct{})
		r.mock.On("OnError", ErrAdvertiseFailed{true, advertiseErr}).
			Return(nil).Times(maxAdvertiseFailures - 1)
		r.mock.On("OnError", ErrAdvertiseFailed{false, advertiseErr}).
			Return(nil).Run(func(_ mock.Arguments) {
			noRetryFail <- struct{}{}
		}).Once()
		for i := 0; i < maxAdvertiseFailures-1; i++ {
			r.sleepBlock <- struct{}{}
			r.setAdvertiseFailure()
			<-r.reqCh

			s1 := <-r.sleepArgs
			checkRetryInterval(t, s1, i+1 /* retryNum */)
		}

		r.sleepClose()
		r.respCh <- 0
		<-r.reqCh

		// Wait for the handler to be called and the mock expectation to be recorded.
		<-noRetryFail

		select {
		case req := <-r.reqCh:
			t.Errorf("No Advertise calls should be made after failure, got %+v", req)
		default:
		}
	})
}

func checkAdvertiseInterval(t *testing.T, sleptFor time.Duration) {
	assert.True(t, sleptFor >= advertiseInterval,
		"advertise interval should be > advertiseInterval")
	assert.True(t, sleptFor < advertiseInterval+advertiseFuzzInterval,
		"advertise interval should be < advertiseInterval + advertiseFuzzInterval")
}

func checkRetryInterval(t *testing.T, sleptFor time.Duration, retryNum int) {
	maxRetryInterval := advertiseRetryInterval * time.Duration(1<<uint8(retryNum))
	assert.True(t, sleptFor < maxRetryInterval,
		"retry #%v slept for %v, should sleep for less than %v", retryNum, sleptFor, maxRetryInterval)
}

func configFor(node string) Configuration {
	return Configuration{
		InitialNodes: []string{node},
	}
}

func withSetup(t *testing.T, f func(ch *tchannel.Channel, hostPort string)) {
	serverCh, err := tchannel.NewChannel(hyperbahnServiceName, nil)
	require.NoError(t, err)
	defer serverCh.Close()
	listener, err := net.Listen("tcp", ":0")
	require.NoError(t, err)
	serverCh.Serve(listener)

	f(serverCh, listener.Addr().String())
	serverCh.Close()
}
<|endoftext|>


<commit_before>package postbird

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"reflect"

	"github.com/googollee/go-socket.io"
)

// Info struct
// PostBird 에서 사용될 값들
type Info struct {
	BindPort      uint
	BindAddress   string
	RemotePort    uint
	RemoteAddress string
	Mode          uint
	Protocol      uint
}

type Client struct {
	Socket     socketio.Socket
	Connection net.Conn
	ClientID   string
}

type CallEvent struct {
}

const DefaultPort uint = 8787                   // Default Bind Port
const DefaultBindAddress string = "127.0.0.1"   // Default Bind Address
const DefaultRemoteAddress string = "127.0.0.1" // Defualt Server Address
const DefaultProtocol uint = SocketIO

const (
	ServerMode = 0
	ClientMode = 1
)

const (
	TCP      = 0
	SocketIO = 1
)

var info Info
var ServerConnection net.Conn

var isConnected bool
var Clients []Client = make([]Client, 5)

// funcs map
// 원격에서 호출가능한 함수들을 등록해놓은 map
// RegisterFunc 함수로 이 맵에 등록한다
var funcs map[string]interface{} = make(map[string]interface{})

// SetBindAddress func
// StartServer로 ServerMode 로 실행할때 바인드될 아이피 주소. ""로 설정하면 모든 NIC에 바인딩된다.
// 이 함수를 호출하지 않으면 DefaultBindAddress인 127.0.0.1로 바인딩된다.
func SetBindAddress(BindAddress string) {
	info.BindAddress = BindAddress
}

// SetBindPort func
// StartServer로 ServerMode 로 실행할때 바인드될 포트 번호.
// 이 함수를 호출하지 않으면 DefaultPortd인 8787로 바인딩된다.
func SetBindPort(BindPort uint) {
	info.BindPort = BindPort
}

// SetRemoteAddress func
//
func SetRemoteAddress(ServerAddress string) {
	info.RemoteAddress = ServerAddress
}

func SetRemotePort(ServerPort uint) {
	info.RemotePort = ServerPort
}

func SetProtocol(Protocol uint) {
	info.Protocol = Protocol
}

func init() {

	if info.BindAddress == "" {
		info.BindAddress = DefaultBindAddress
	}

	if info.BindPort == 0 {
		info.BindPort = DefaultPort
	}

	if info.RemoteAddress == "" {
		info.RemoteAddress = DefaultRemoteAddress
	}

	if info.RemotePort == 0 {
		info.RemotePort = DefaultPort
	}

	if info.Protocol == 0 {
		info.Protocol = DefaultProtocol
	}

}

// RegisterFunc func
// CallLocalFunc 함수에 의해 실행될 수 있는, 즉 원격에서 호출가능한 함수를 등록하는 함수
// funcs 맵에 등록되며 이 함수에 등록되지 않은 함수는 원격에서 호출할 수 없다.
func RegisterFunc(FuncName string, Function interface{}) {
	funcs[FuncName] = Function
}

// StartServer func
// 프로그램을 서버역할로 사용하려면 이 함수를 호출해서 tcp 서버를 시작하면 된다.
// 시작되면 Binder 함수를 비동기로 호출하여 비동기로 tcp Listen
// 이 함수가 호출되면 무조건 Mode가 ServerMode 로 바뀐다
func StartServer(Protocol uint) {
	info.Mode = ServerMode
	info.Protocol = Protocol

	switch Protocol {
	case 0:
		go Binder(info.BindAddress, info.BindPort)
	case 1:
		go Listener(info.BindAddress, info.BindPort)
	default:
		log.Println("Protocol not match. 0 for TCP, 1 for Socket.io.")
	}

}

// Listener func
// ServerMode 일때 tcp대신 socket.io 사용
func Listener(BindAddr string, Port uint) {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		Clients = append(Clients, Client{so, nil, so.Id()})

		so.On("call", func(FunctionName string, args ...string) {
			go CallLocalFunc(FunctionName, args)
		})

		var i int

		so.On("disconnection", func() {
			for i = 0; i < len(Clients); i++ {
				if so.Id() == Clients[i].ClientID {
					break
				}
			}

			if !(i > len(Clients)) {
				copy(Clients[i:], Clients[i+1:])
				Clients[len(Clients)-1] = Client{}
				Clients = Clients[:len(Clients)-1]
			}

		})
	})

	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	http.ListenAndServe(BindAddr+":"+string(Port), nil)
}

// Binder func
// ServerMode일때 main func
func Binder(BindAddr string, Port uint) {
	ln, err := net.Listen("tcp", BindAddr+":"+string(Port)) // 전달받은 BindAddr:Port 에 TCP로 바인딩
	if err != nil {
		log.Println(err)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		defer conn.Close()

		ClientId := RandStringRunes(17)
		Clients = append(Clients, Client{nil, conn, ClientId})

		go requestHandler(conn)
	}
}

// requestHandler func
// tcp 연결되었을때 request 핸들러
func requestHandler(c net.Conn) {
	encoder := json.NewEncoder(c)
	decoder := json.NewDecoder(c)

	readFully(c)
}

func ConnectToRemote() {
	client, err := net.Dial("tcp", info.RemoteAddress+":"+string(info.RemotePort))
	if err != nil {
		fmt.Println(err)
		return
	}
	ServerConnection = client
}

// CallLocalFunc func
// RegisterFunc 로 등록된 함수가 원격에서 함수를 호출했을때
// 이함수를 통해 실행된다
func CallLocalFunc(name string, params ...interface{}) (result []reflect.Value, err error) {
	f := reflect.ValueOf(funcs[name])
	if len(params) != f.Type().NumIn() {
		err = errors.New("The number of params is not adapted.")
		return
	}
	in := make([]reflect.Value, len(params))
	for k, param := range params {
		in[k] = reflect.ValueOf(param)
	}
	result = f.Call(in)
	return
}

// CallRemoteFunc func
// 연결된 (서버)의 함수를 호출하고 싶을때 사용하는 함수
// json형식으로 변환해서 tcp로 서버에 전달.
func CallRemoteFunc(FunctionName string, args ...interface{}) {
	if Clients[0].ClientID != "" {
		switch info.Protocol {
		case TCP:
			for i := 0; i < len(Clients); i++ {
				Clients[i].Connection.Write(b)
			}
			break
		case SocketIO:
			break
		default:
			log.Fatal("Protocol Type not match")

		}
	}
}

func readFully(conn net.Conn) ([]byte, error) {
	result := bytes.NewBuffer(nil)
	var buf [512]byte
	for {
		n, err := conn.Read(buf[0:])
		result.Write(buf[0:n])
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
	}
	return result.Bytes(), nil
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

// RandStringRunes func
// 랜덤 문자열 생성 함수
func RandStringRunes(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}
<commit_msg>some changes<commit_after>package postbird

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"net/http"
	"reflect"
	"time"

	"github.com/googollee/go-socket.io"
)

// Info struct
// PostBird 에서 사용될 값들
type Info struct {
	BindPort      uint
	BindAddress   string
	RemotePort    uint
	RemoteAddress string
	Mode          uint
	Protocol      uint
}

type Client struct {
	Socket     socketio.Socket
	Connection net.Conn
	ClientID   string
}

type Any interface{}

type CallEvent struct {
	FunctionName string
	Params       []Any
}

const DefaultPort uint = 8787                   // Default Bind Port
const DefaultBindAddress string = "127.0.0.1"   // Default Bind Address
const DefaultRemoteAddress string = "127.0.0.1" // Defualt Server Address
const DefaultProtocol uint = SocketIO

const (
	ServerMode = 0
	ClientMode = 1
)

const (
	TCP      = 0
	SocketIO = 1
)

var info Info
var ServerConnection net.Conn

var isConnected bool
var Clients []Client = make([]Client, 5)

// funcs map
// 원격에서 호출가능한 함수들을 등록해놓은 map
// RegisterFunc 함수로 이 맵에 등록한다
var funcs map[string]interface{} = make(map[string]interface{})

// SetBindAddress func
// StartServer로 ServerMode 로 실행할때 바인드될 아이피 주소. ""로 설정하면 모든 NIC에 바인딩된다.
// 이 함수를 호출하지 않으면 DefaultBindAddress인 127.0.0.1로 바인딩된다.
func SetBindAddress(BindAddress string) {
	info.BindAddress = BindAddress
}

// SetBindPort func
// StartServer로 ServerMode 로 실행할때 바인드될 포트 번호.
// 이 함수를 호출하지 않으면 DefaultPortd인 8787로 바인딩된다.
func SetBindPort(BindPort uint) {
	info.BindPort = BindPort
}

// SetRemoteAddress func
//
func SetRemoteAddress(ServerAddress string) {
	info.RemoteAddress = ServerAddress
}

func SetRemotePort(ServerPort uint) {
	info.RemotePort = ServerPort
}

func SetProtocol(Protocol uint) {
	info.Protocol = Protocol
}

func init() {

	if info.BindAddress == "" {
		info.BindAddress = DefaultBindAddress
	}

	if info.BindPort == 0 {
		info.BindPort = DefaultPort
	}

	if info.RemoteAddress == "" {
		info.RemoteAddress = DefaultRemoteAddress
	}

	if info.RemotePort == 0 {
		info.RemotePort = DefaultPort
	}

	if info.Protocol == 0 {
		info.Protocol = DefaultProtocol
	}

}

// RegisterFunc func
// CallLocalFunc 함수에 의해 실행될 수 있는, 즉 원격에서 호출가능한 함수를 등록하는 함수
// funcs 맵에 등록되며 이 함수에 등록되지 않은 함수는 원격에서 호출할 수 없다.
func RegisterFunc(FuncName string, Function interface{}) {
	funcs[FuncName] = Function
}

// StartServer func
// 프로그램을 서버역할로 사용하려면 이 함수를 호출해서 tcp 서버를 시작하면 된다.
// 시작되면 Binder 함수를 비동기로 호출하여 비동기로 tcp Listen
// 이 함수가 호출되면 무조건 Mode가 ServerMode 로 바뀐다
func StartServer(Protocol uint) {
	info.Mode = ServerMode
	info.Protocol = Protocol

	switch Protocol {
	case 0:
		go Binder(info.BindAddress, info.BindPort)
	case 1:
		go Listener(info.BindAddress, info.BindPort)
	default:
		log.Println("Protocol not match. 0 for TCP, 1 for Socket.io.")
	}

}

// Listener func
// ServerMode 일때 tcp대신 socket.io 사용
func Listener(BindAddr string, Port uint) {
	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	server.On("connection", func(so socketio.Socket) {
		Clients = append(Clients, Client{so, nil, so.Id()})

		so.On("call", func(FunctionName string, args ...string) {
			go CallLocalFunc(FunctionName, args)
		})

		var i int

		so.On("disconnection", func() {
			for i = 0; i < len(Clients); i++ {
				if so.Id() == Clients[i].ClientID {
					break
				}
			}

			if !(i > len(Clients)) {
				copy(Clients[i:], Clients[i+1:])
				Clients[len(Clients)-1] = Client{}
				Clients = Clients[:len(Clients)-1]
			}

		})
	})

	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	http.ListenAndServe(BindAddr+":"+string(Port), nil)
}

// Binder func
// ServerMode일때 main func
func Binder(BindAddr string, Port uint) {
	ln, err := net.Listen("tcp", BindAddr+":"+string(Port)) // 전달받은 BindAddr:Port 에 TCP로 바인딩
	if err != nil {
		log.Println(err)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		defer conn.Close()

		rand.Seed(time.Now().UnixNano())

		ClientId := RandStringRunes(17)
		Clients = append(Clients, Client{nil, conn, ClientId})

		go requestHandler(conn)
	}
}

// requestHandler func
// tcp 연결되었을때 request 핸들러
func requestHandler(c net.Conn) {
	readFully(c)
}

func ConnectToRemote() {
	client, err := net.Dial("tcp", info.RemoteAddress+":"+string(info.RemotePort))
	if err != nil {
		fmt.Println(err)
		return
	}
	ServerConnection = client
}

// CallLocalFunc func
// RegisterFunc 로 등록된 함수가 원격에서 함수를 호출했을때
// 이함수를 통해 실행된다
func CallLocalFunc(name string, params ...Any) (result []reflect.Value, err error) {
	f := reflect.ValueOf(funcs[name])
	if len(params) != f.Type().NumIn() {
		err = errors.New("The number of params is not adapted.")
		return
	}
	in := make([]reflect.Value, len(params))
	for k, param := range params {
		in[k] = reflect.ValueOf(param)
	}
	result = f.Call(in)
	return
}

// CallRemoteFunc func
// 연결된 (서버)의 함수를 호출하고 싶을때 사용하는 함수
// json형식으로 변환해서 tcp로 서버에 전달.
func CallRemoteFunc(FunctionName string, args ...Any) {
	var i int

	if Clients[0].ClientID != "" {
		switch info.Protocol {
		case TCP:
			Event := CallEvent{FunctionName, args}
			/*
				tmpStr := "{\"funcname\":\"" + FunctionName + "\"" + "\"args\":["
				for i = 0; i < len(args)-1; i++ {
					switch args[i].(type) {
					case string:
						tmpStr += "\"" + args[i].(string) + "\","
						break
					default:
						tmpStr += args[i].(string) + ","
					}
				}

				switch args[i].(type) {
				case string:
					tmpStr += "\"" + args[i].(string) + "\""
					break
				default:
					tmpStr += args[i].(string)
				}

				tmpStr += "]}"
			*/
			call, _ := json.Marshal(Event)

			for i = 0; i < len(Clients); i++ {
				Clients[i].Connection.Write(call)
			}
			break
		case SocketIO:
			break
		default:
			log.Fatal("Protocol Type not match")

		}
	}
}

func readFully(conn net.Conn) ([]byte, error) {
	result := bytes.NewBuffer(nil)
	var buf [512]byte
	for {
		n, err := conn.Read(buf[0:])
		result.Write(buf[0:n])
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
	}
	return result.Bytes(), nil
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

// RandStringRunes func
// 랜덤 문자열 생성 함수
func RandStringRunes(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}
<|endoftext|>


<commit_before>package videobox

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

	"github.com/pkg/errors"
)

// VideoAnalysis describes the results of a video processing operation.
type VideoAnalysis struct {
	// Ready indicates whether the results are ready or not.
	Ready   bool     `json:"ready"`
	Facebox *Facebox `json:"facebox,omitempty"`
	Tagbox  *Tagbox  `json:"tagbox,omitempty"`
	Nudebox *Nudebox `json:"nudebox,omitempty"`
}

// Facebox holds box specific results.
type Facebox struct {
	Faces      []Item `json:"faces"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Tagbox holds box specific results.
type Tagbox struct {
	Tags       []Item `json:"tags"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Nudebox holds box specific results.
type Nudebox struct {
	Nudity     []Item `json:"nudity"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Item describes a single entity that was discovered at
// one or many instances throughout the video.
type Item struct {
	// Key is a string describing the item.
	// For Facebox it will be the name.
	// For Tagbox it will be the tag.
	// For Nudebox it will be a description of the nudity detected.
	Key string `json:"key"`
	// Instances holds the time and frame ranges where this Item
	// appears in the video.
	Instances []Range `json:"instances"`
}

// Range describes a period of time within the video.
type Range struct {
	// Start is the start frame.
	Start int `json:"start"`
	// End is the end frame.
	End int `json:"end"`
	// StartMS is the start time in milliseconds.
	StartMS int `json:"start_ms"`
	// EndMS is the end time in milliseconds.
	EndMS int `json:"end_ms"`
}

// Results gets the results of a video processing operation.
// This should be called after the Video.Status is StatusCompleted.
func (c *Client) Results(id string) (*VideoAnalysis, error) {
	u, err := url.Parse(c.addr + "/videobox/results/" + id)
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}
	var results VideoAnalysis
	if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
		return nil, err
	}
	return &results, nil
}
<commit_msg>Added Confidence field<commit_after>package videobox

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

	"github.com/pkg/errors"
)

// VideoAnalysis describes the results of a video processing operation.
type VideoAnalysis struct {
	// Ready indicates whether the results are ready or not.
	Ready   bool     `json:"ready"`
	Facebox *Facebox `json:"facebox,omitempty"`
	Tagbox  *Tagbox  `json:"tagbox,omitempty"`
	Nudebox *Nudebox `json:"nudebox,omitempty"`
}

// Facebox holds box specific results.
type Facebox struct {
	Faces      []Item `json:"faces"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Tagbox holds box specific results.
type Tagbox struct {
	Tags       []Item `json:"tags"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Nudebox holds box specific results.
type Nudebox struct {
	Nudity     []Item `json:"nudity"`
	ErrorCount int    `json:"errorsCount"`
	LastErr    string `json:"lastError,omitempty"`
}

// Item describes a single entity that was discovered at
// one or many instances throughout the video.
type Item struct {
	// Key is a string describing the item.
	// For Facebox it will be the name.
	// For Tagbox it will be the tag.
	// For Nudebox it will be a description of the nudity detected.
	Key string `json:"key"`
	// Instances holds the time and frame ranges where this Item
	// appears in the video.
	Instances []Range `json:"instances"`
}

// Range describes a period of time within the video.
type Range struct {
	// Start is the start frame.
	Start int `json:"start"`
	// End is the end frame.
	End int `json:"end"`
	// StartMS is the start time in milliseconds.
	StartMS int `json:"start_ms"`
	// EndMS is the end time in milliseconds.
	EndMS int `json:"end_ms"`
	// Confidence is the maximum confidence of any instance in this
	// range.
	Confidence float64 `json:"confidence,omitempty"`
}

// Results gets the results of a video processing operation.
// This should be called after the Video.Status is StatusCompleted.
func (c *Client) Results(id string) (*VideoAnalysis, error) {
	u, err := url.Parse(c.addr + "/videobox/results/" + id)
	if err != nil {
		return nil, err
	}
	if !u.IsAbs() {
		return nil, errors.New("box address must be absolute")
	}
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/json; charset=utf-8")
	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}
	var results VideoAnalysis
	if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
		return nil, err
	}
	return &results, nil
}
<|endoftext|>


<commit_before>package server

import (
	"testing"

	"github.com/garyburd/redigo/redis"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/Vladimiroff/vec2d"

	"warcluster/entities"
	"warcluster/entities/db"
)

var gophie entities.Player = entities.Player{
	Username:       "gophie",
	Color:          entities.Color{22, 22, 22},
	TwitterID:      "gophie92",
	HomePlanet:     "planet.GOP6720",
	ScreenSize:     []uint16{1, 1},
	ScreenPosition: &vec2d.Vector{2, 2},
}

var panda entities.Player = entities.Player{
	Username:       "panda",
	Color:          entities.Color{22, 22, 22},
	TwitterID:      "panda13",
	HomePlanet:     "planet.PAN6720",
	ScreenSize:     []uint16{1, 1},
	ScreenPosition: &vec2d.Vector{2, 2},
}

var client Client = Client{
	Session:        new(testSession),
	Player:         &gophie,
}

var planet1 entities.Planet = entities.Planet{
	Name:           "GOP6720",
	Position:       &vec2d.Vector{2, 2},
	IsHome:         true,
	Owner:          "gophie",
}

var planet2 entities.Planet = entities.Planet{
	Name:           "GOP6724",
	Position:       &vec2d.Vector{4, 4},
	IsHome:         false,
	Owner:          "gophie",
}

var planet3 entities.Planet = entities.Planet{
	Name:           "PAN6720",
	Position:       &vec2d.Vector{10, 10},
	IsHome:         true,
	Owner:          "panda",
}

type ResponseTestSuite struct {
	suite.Suite
	conn    redis.Conn
	request *Request
}

func (suite *ResponseTestSuite) SetupTest() {
	suite.conn = db.Pool.Get()
	suite.conn.Do("FLUSHDB")
	entities.Save(&planet1)
	entities.Save(&planet2)
	entities.Save(&planet3)
	entities.Save(&gophie)
	entities.Save(&panda)

	suite.request = new(Request)
	suite.request.Command = "start_mission"
	suite.request.StartPlanet = "planet.GOP6720"
	suite.request.EndPlanet = "planet.PAN6720"
	suite.request.Position = vec2d.New(2.0, 4.0)
	suite.request.Resolution = []uint16{1920, 1080}
	suite.request.Fleet = 32
	suite.request.Username = "panda"
	suite.request.TwitterID = "panda13"
	suite.request.Fraction = 4
	suite.request.SunTextureId = 0
	suite.request.Client = &client
	suite.request.Type = "spy"
}

func (suite *ResponseTestSuite) TestParseActionWithoutStartPlanet() {
	suite.request.StartPlanet = ""

	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)

	suite.request.StartPlanet = planet1.Name
}

func (suite *ResponseTestSuite) TestParseActionWithoutEndPlanet() {
	suite.request.EndPlanet = ""

	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)

	suite.request.EndPlanet = planet3.Name
}

func (suite *ResponseTestSuite) TestParseActionFromForeignPlanet() {
	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)
}

func TestResponseTestSuite(t *testing.T) {
	suite.Run(t, new(ResponseTestSuite))
}
<commit_msg>Add more tests for response functionality<commit_after>package server

import (
	"testing"

	"github.com/garyburd/redigo/redis"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/Vladimiroff/vec2d"

	"warcluster/entities"
	"warcluster/entities/db"
)

var gophie entities.Player = entities.Player{
	Username:       "gophie",
	Color:          entities.Color{22, 22, 22},
	TwitterID:      "gophie92",
	HomePlanet:     "planet.GOP6720",
	ScreenSize:     []uint16{1, 1},
	ScreenPosition: &vec2d.Vector{2, 2},
}

var panda entities.Player = entities.Player{
	Username:       "panda",
	Color:          entities.Color{22, 22, 22},
	TwitterID:      "panda13",
	HomePlanet:     "planet.PAN6720",
	ScreenSize:     []uint16{1, 1},
	ScreenPosition: &vec2d.Vector{2, 2},
}

var client Client = Client{
	Session:        new(testSession),
	Player:         &gophie,
}

var planet1 entities.Planet = entities.Planet{
	Name:           "GOP6720",
	Position:       &vec2d.Vector{2, 2},
	IsHome:         true,
	Owner:          "gophie",
}

var planet2 entities.Planet = entities.Planet{
	Name:           "GOP6724",
	Position:       &vec2d.Vector{4, 4},
	IsHome:         false,
	Owner:          "gophie",
}

var planet3 entities.Planet = entities.Planet{
	Name:           "PAN6720",
	Position:       &vec2d.Vector{10, 10},
	IsHome:         true,
	Owner:          "panda",
}

type ResponseTestSuite struct {
	suite.Suite
	conn    redis.Conn
	request *Request
}

func (suite *ResponseTestSuite) SetupTest() {
	suite.conn = db.Pool.Get()
	suite.conn.Do("FLUSHDB")
	entities.Save(&planet1)
	entities.Save(&planet2)
	entities.Save(&planet3)
	entities.Save(&gophie)
	entities.Save(&panda)

	suite.request = new(Request)
	suite.request.Command = "start_mission"
	suite.request.StartPlanet = "planet.GOP6720"
	suite.request.EndPlanet = "planet.PAN6720"
	suite.request.Position = vec2d.New(2.0, 4.0)
	suite.request.Resolution = []uint16{1920, 1080}
	suite.request.Fleet = 32
	suite.request.Username = "gophie"
	suite.request.TwitterID = "gophie92"
	suite.request.Fraction = 4
	suite.request.SunTextureId = 0
	suite.request.Client = &client
	suite.request.Type = "Spy"
}

func (suite *ResponseTestSuite) TestParseActionWithoutStartPlanet() {
	suite.request.StartPlanet = ""

	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)
}

func (suite *ResponseTestSuite) TestParseActionWithoutEndPlanet() {
	suite.request.EndPlanet = ""

	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)
}

func (suite *ResponseTestSuite) TestParseActionWithDifferentTypes() {
	err := parseAction(suite.request)
	assert.Nil(suite.T(), err)

	suite.request.Type = "Attack"
	err = parseAction(suite.request)
	assert.Nil(suite.T(), err)

	suite.request.Type = "Supply"
	err = parseAction(suite.request)
	assert.Nil(suite.T(), err)

	suite.request.Type = "Panda"
	err = parseAction(suite.request)
	assert.NotNil(suite.T(), err)
}

func (suite *ResponseTestSuite) TestParseActionFromForeignPlanet() {
	suite.request.StartPlanet, suite.request.EndPlanet = suite.request.EndPlanet, suite.request.StartPlanet
	err := parseAction(suite.request)

	assert.NotNil(suite.T(), err)
}

func (suite *ResponseTestSuite) TestParseStartMission() {
	err := parseAction(suite.request)

	assert.Nil(suite.T(), err)
}

func TestResponseTestSuite(t *testing.T) {
	suite.Run(t, new(ResponseTestSuite))
}
<|endoftext|>


<commit_before>// Opcodes from opcodes.h
package vm

const (
	// Instruction opcodes for compiled code

	POP_TOP     = 1
	ROT_TWO     = 2
	ROT_THREE   = 3
	DUP_TOP     = 4
	DUP_TOP_TWO = 5
	NOP         = 9

	UNARY_POSITIVE = 10
	UNARY_NEGATIVE = 11
	UNARY_NOT      = 12

	UNARY_INVERT = 15

	BINARY_POWER = 19

	BINARY_MULTIPLY = 20

	BINARY_MODULO        = 22
	BINARY_ADD           = 23
	BINARY_SUBTRACT      = 24
	BINARY_SUBSCR        = 25
	BINARY_FLOOR_DIVIDE  = 26
	BINARY_TRUE_DIVIDE   = 27
	INPLACE_FLOOR_DIVIDE = 28
	INPLACE_TRUE_DIVIDE  = 29

	STORE_MAP        = 54
	INPLACE_ADD      = 55
	INPLACE_SUBTRACT = 56
	INPLACE_MULTIPLY = 57

	INPLACE_MODULO = 59
	STORE_SUBSCR   = 60
	DELETE_SUBSCR  = 61

	BINARY_LSHIFT    = 62
	BINARY_RSHIFT    = 63
	BINARY_AND       = 64
	BINARY_XOR       = 65
	BINARY_OR        = 66
	INPLACE_POWER    = 67
	GET_ITER         = 68
	STORE_LOCALS     = 69
	PRINT_EXPR       = 70
	LOAD_BUILD_CLASS = 71
	YIELD_FROM       = 72

	INPLACE_LSHIFT = 75
	INPLACE_RSHIFT = 76
	INPLACE_AND    = 77
	INPLACE_XOR    = 78
	INPLACE_OR     = 79
	BREAK_LOOP     = 80
	WITH_CLEANUP   = 81

	RETURN_VALUE = 83
	IMPORT_STAR  = 84

	YIELD_VALUE = 86
	POP_BLOCK   = 87
	END_FINALLY = 88
	POP_EXCEPT  = 89

	HAVE_ARGUMENT = 90 // Opcodes from here have an argument:

	STORE_NAME      = 90 // Index in name list
	DELETE_NAME     = 91 // ""
	UNPACK_SEQUENCE = 92 // Number of sequence items
	FOR_ITER        = 93
	UNPACK_EX       = 94 // Num items before variable part + (Num items after variable part << 8)

	STORE_ATTR    = 95 // Index in name list
	DELETE_ATTR   = 96 // ""
	STORE_GLOBAL  = 97 // ""
	DELETE_GLOBAL = 98 // ""

	LOAD_CONST  = 100 // Index in const list
	LOAD_NAME   = 101 // Index in name list
	BUILD_TUPLE = 102 // Number of tuple items
	BUILD_LIST  = 103 // Number of list items
	BUILD_SET   = 104 // Number of set items
	BUILD_MAP   = 105 // Always zero for now
	LOAD_ATTR   = 106 // Index in name list
	COMPARE_OP  = 107 // Comparison operator
	IMPORT_NAME = 108 // Index in name list
	IMPORT_FROM = 109 // Index in name list

	JUMP_FORWARD         = 110 // Number of bytes to skip
	JUMP_IF_FALSE_OR_POP = 111 // Target byte offset from beginning of code
	JUMP_IF_TRUE_OR_POP  = 112 // ""
	JUMP_ABSOLUTE        = 113 // ""
	POP_JUMP_IF_FALSE    = 114 // ""
	POP_JUMP_IF_TRUE     = 115 // ""

	LOAD_GLOBAL = 116 // Index in name list

	CONTINUE_LOOP = 119 // Start of loop (absolute)
	SETUP_LOOP    = 120 // Target address (relative)
	SETUP_EXCEPT  = 121 // ""
	SETUP_FINALLY = 122 // ""

	LOAD_FAST   = 124 // Local variable number
	STORE_FAST  = 125 // Local variable number
	DELETE_FAST = 126 // Local variable number

	RAISE_VARARGS = 130 // Number of raise arguments (1, 2 or 3)
	// CALL_FUNCTION_XXX opcodes defined below depend on this definition
	CALL_FUNCTION = 131 // #args + (#kwargs<<8)
	MAKE_FUNCTION = 132 // #defaults + #kwdefaults<<8 + #annotations<<16
	BUILD_SLICE   = 133 // Number of items

	MAKE_CLOSURE = 134 // same as MAKE_FUNCTION
	LOAD_CLOSURE = 135 // Load free variable from closure
	LOAD_DEREF   = 136 // Load and dereference from closure cell
	STORE_DEREF  = 137 // Store into cell
	DELETE_DEREF = 138 // Delete closure cell

	// The next 3 opcodes must be contiguous and satisfy
	// (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1
	CALL_FUNCTION_VAR    = 140 // #args + (#kwargs<<8)
	CALL_FUNCTION_KW     = 141 // #args + (#kwargs<<8)
	CALL_FUNCTION_VAR_KW = 142 // #args + (#kwargs<<8)

	SETUP_WITH = 143

	// Support for opargs more than 16 bits long
	EXTENDED_ARG = 144

	LIST_APPEND = 145
	SET_ADD     = 146
	MAP_ADD     = 147

	// LOAD_CLASSDEREF = 148 // New in Pytohon 3.4

	// EXCEPT_HANDLER is a special, implicit block type which is
	// created when entering an except handler. It is not an
	// opcode but we define it here as we want it to be available
	// to both frameobject.c and ceval.c, while remaining private.
	EXCEPT_HANDLER = 255
)

// Turn a name into an opcode
var NameToOpCode = map[string]byte{
	"POP_TOP":              1,
	"ROT_TWO":              2,
	"ROT_THREE":            3,
	"DUP_TOP":              4,
	"DUP_TOP_TWO":          5,
	"NOP":                  9,
	"UNARY_POSITIVE":       10,
	"UNARY_NEGATIVE":       11,
	"UNARY_NOT":            12,
	"UNARY_INVERT":         15,
	"BINARY_POWER":         19,
	"BINARY_MULTIPLY":      20,
	"BINARY_MODULO":        22,
	"BINARY_ADD":           23,
	"BINARY_SUBTRACT":      24,
	"BINARY_SUBSCR":        25,
	"BINARY_FLOOR_DIVIDE":  26,
	"BINARY_TRUE_DIVIDE":   27,
	"INPLACE_FLOOR_DIVIDE": 28,
	"INPLACE_TRUE_DIVIDE":  29,
	"STORE_MAP":            54,
	"INPLACE_ADD":          55,
	"INPLACE_SUBTRACT":     56,
	"INPLACE_MULTIPLY":     57,
	"INPLACE_MODULO":       59,
	"STORE_SUBSCR":         60,
	"DELETE_SUBSCR":        61,
	"BINARY_LSHIFT":        62,
	"BINARY_RSHIFT":        63,
	"BINARY_AND":           64,
	"BINARY_XOR":           65,
	"BINARY_OR":            66,
	"INPLACE_POWER":        67,
	"GET_ITER":             68,
	"STORE_LOCALS":         69,
	"PRINT_EXPR":           70,
	"LOAD_BUILD_CLASS":     71,
	"YIELD_FROM":           72,
	"INPLACE_LSHIFT":       75,
	"INPLACE_RSHIFT":       76,
	"INPLACE_AND":          77,
	"INPLACE_XOR":          78,
	"INPLACE_OR":           79,
	"BREAK_LOOP":           80,
	"WITH_CLEANUP":         81,
	"RETURN_VALUE":         83,
	"IMPORT_STAR":          84,
	"YIELD_VALUE":          86,
	"POP_BLOCK":            87,
	"END_FINALLY":          88,
	"POP_EXCEPT":           89,
	"STORE_NAME":           90,
	"DELETE_NAME":          91,
	"UNPACK_SEQUENCE":      92,
	"FOR_ITER":             93,
	"UNPACK_EX":            94,
	"STORE_ATTR":           95,
	"DELETE_ATTR":          96,
	"STORE_GLOBAL":         97,
	"DELETE_GLOBAL":        98,
	"LOAD_CONST":           100,
	"LOAD_NAME":            101,
	"BUILD_TUPLE":          102,
	"BUILD_LIST":           103,
	"BUILD_SET":            104,
	"BUILD_MAP":            105,
	"LOAD_ATTR":            106,
	"COMPARE_OP":           107,
	"IMPORT_NAME":          108,
	"IMPORT_FROM":          109,
	"JUMP_FORWARD":         110,
	"JUMP_IF_FALSE_OR_POP": 111,
	"JUMP_IF_TRUE_OR_POP":  112,
	"JUMP_ABSOLUTE":        113,
	"POP_JUMP_IF_FALSE":    114,
	"POP_JUMP_IF_TRUE":     115,
	"LOAD_GLOBAL":          116,
	"CONTINUE_LOOP":        119,
	"SETUP_LOOP":           120,
	"SETUP_EXCEPT":         121,
	"SETUP_FINALLY":        122,
	"LOAD_FAST":            124,
	"STORE_FAST":           125,
	"DELETE_FAST":          126,
	"RAISE_VARARGS":        130,
	"CALL_FUNCTION":        131,
	"MAKE_FUNCTION":        132,
	"BUILD_SLICE":          133,
	"MAKE_CLOSURE":         134,
	"LOAD_CLOSURE":         135,
	"LOAD_DEREF":           136,
	"STORE_DEREF":          137,
	"DELETE_DEREF":         138,
	"CALL_FUNCTION_VAR":    140,
	"CALL_FUNCTION_KW":     141,
	"CALL_FUNCTION_VAR_KW": 142,
	"SETUP_WITH":           143,
	"EXTENDED_ARG":         144,
	"LIST_APPEND":          145,
	"SET_ADD":              146,
	"MAP_ADD":              147,
	"LOAD_CLASSDEREF":      148,
}

var OpCodeToName map[byte]string

func init() {
	OpCodeToName = make(map[byte]string, len(NameToOpCode))
	for name, opcode := range NameToOpCode {
		OpCodeToName[opcode] = name
	}
}

// Rich comparison opcodes
const (
	PyCmp_LT = iota
	PyCmp_LE
	PyCmp_EQ
	PyCmp_NE
	PyCmp_GT
	PyCmp_GE
	PyCmp_IN
	PyCmp_NOT_IN
	PyCmp_IS
	PyCmp_IS_NOT
	PyCmp_EXC_MATCH
	PyCmp_BAD
)

// If op has an argument
func HAS_ARG(op byte) bool {
	return op >= HAVE_ARGUMENT
}
<commit_msg>Fix typo in comment<commit_after>// Opcodes from opcodes.h
package vm

const (
	// Instruction opcodes for compiled code

	POP_TOP     = 1
	ROT_TWO     = 2
	ROT_THREE   = 3
	DUP_TOP     = 4
	DUP_TOP_TWO = 5
	NOP         = 9

	UNARY_POSITIVE = 10
	UNARY_NEGATIVE = 11
	UNARY_NOT      = 12

	UNARY_INVERT = 15

	BINARY_POWER = 19

	BINARY_MULTIPLY = 20

	BINARY_MODULO        = 22
	BINARY_ADD           = 23
	BINARY_SUBTRACT      = 24
	BINARY_SUBSCR        = 25
	BINARY_FLOOR_DIVIDE  = 26
	BINARY_TRUE_DIVIDE   = 27
	INPLACE_FLOOR_DIVIDE = 28
	INPLACE_TRUE_DIVIDE  = 29

	STORE_MAP        = 54
	INPLACE_ADD      = 55
	INPLACE_SUBTRACT = 56
	INPLACE_MULTIPLY = 57

	INPLACE_MODULO = 59
	STORE_SUBSCR   = 60
	DELETE_SUBSCR  = 61

	BINARY_LSHIFT    = 62
	BINARY_RSHIFT    = 63
	BINARY_AND       = 64
	BINARY_XOR       = 65
	BINARY_OR        = 66
	INPLACE_POWER    = 67
	GET_ITER         = 68
	STORE_LOCALS     = 69
	PRINT_EXPR       = 70
	LOAD_BUILD_CLASS = 71
	YIELD_FROM       = 72

	INPLACE_LSHIFT = 75
	INPLACE_RSHIFT = 76
	INPLACE_AND    = 77
	INPLACE_XOR    = 78
	INPLACE_OR     = 79
	BREAK_LOOP     = 80
	WITH_CLEANUP   = 81

	RETURN_VALUE = 83
	IMPORT_STAR  = 84

	YIELD_VALUE = 86
	POP_BLOCK   = 87
	END_FINALLY = 88
	POP_EXCEPT  = 89

	HAVE_ARGUMENT = 90 // Opcodes from here have an argument:

	STORE_NAME      = 90 // Index in name list
	DELETE_NAME     = 91 // ""
	UNPACK_SEQUENCE = 92 // Number of sequence items
	FOR_ITER        = 93
	UNPACK_EX       = 94 // Num items before variable part + (Num items after variable part << 8)

	STORE_ATTR    = 95 // Index in name list
	DELETE_ATTR   = 96 // ""
	STORE_GLOBAL  = 97 // ""
	DELETE_GLOBAL = 98 // ""

	LOAD_CONST  = 100 // Index in const list
	LOAD_NAME   = 101 // Index in name list
	BUILD_TUPLE = 102 // Number of tuple items
	BUILD_LIST  = 103 // Number of list items
	BUILD_SET   = 104 // Number of set items
	BUILD_MAP   = 105 // Always zero for now
	LOAD_ATTR   = 106 // Index in name list
	COMPARE_OP  = 107 // Comparison operator
	IMPORT_NAME = 108 // Index in name list
	IMPORT_FROM = 109 // Index in name list

	JUMP_FORWARD         = 110 // Number of bytes to skip
	JUMP_IF_FALSE_OR_POP = 111 // Target byte offset from beginning of code
	JUMP_IF_TRUE_OR_POP  = 112 // ""
	JUMP_ABSOLUTE        = 113 // ""
	POP_JUMP_IF_FALSE    = 114 // ""
	POP_JUMP_IF_TRUE     = 115 // ""

	LOAD_GLOBAL = 116 // Index in name list

	CONTINUE_LOOP = 119 // Start of loop (absolute)
	SETUP_LOOP    = 120 // Target address (relative)
	SETUP_EXCEPT  = 121 // ""
	SETUP_FINALLY = 122 // ""

	LOAD_FAST   = 124 // Local variable number
	STORE_FAST  = 125 // Local variable number
	DELETE_FAST = 126 // Local variable number

	RAISE_VARARGS = 130 // Number of raise arguments (1, 2 or 3)
	// CALL_FUNCTION_XXX opcodes defined below depend on this definition
	CALL_FUNCTION = 131 // #args + (#kwargs<<8)
	MAKE_FUNCTION = 132 // #defaults + #kwdefaults<<8 + #annotations<<16
	BUILD_SLICE   = 133 // Number of items

	MAKE_CLOSURE = 134 // same as MAKE_FUNCTION
	LOAD_CLOSURE = 135 // Load free variable from closure
	LOAD_DEREF   = 136 // Load and dereference from closure cell
	STORE_DEREF  = 137 // Store into cell
	DELETE_DEREF = 138 // Delete closure cell

	// The next 3 opcodes must be contiguous and satisfy
	// (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1
	CALL_FUNCTION_VAR    = 140 // #args + (#kwargs<<8)
	CALL_FUNCTION_KW     = 141 // #args + (#kwargs<<8)
	CALL_FUNCTION_VAR_KW = 142 // #args + (#kwargs<<8)

	SETUP_WITH = 143

	// Support for opargs more than 16 bits long
	EXTENDED_ARG = 144

	LIST_APPEND = 145
	SET_ADD     = 146
	MAP_ADD     = 147

	// LOAD_CLASSDEREF = 148 // New in Python 3.4

	// EXCEPT_HANDLER is a special, implicit block type which is
	// created when entering an except handler. It is not an
	// opcode but we define it here as we want it to be available
	// to both frameobject.c and ceval.c, while remaining private.
	EXCEPT_HANDLER = 255
)

// Turn a name into an opcode
var NameToOpCode = map[string]byte{
	"POP_TOP":              1,
	"ROT_TWO":              2,
	"ROT_THREE":            3,
	"DUP_TOP":              4,
	"DUP_TOP_TWO":          5,
	"NOP":                  9,
	"UNARY_POSITIVE":       10,
	"UNARY_NEGATIVE":       11,
	"UNARY_NOT":            12,
	"UNARY_INVERT":         15,
	"BINARY_POWER":         19,
	"BINARY_MULTIPLY":      20,
	"BINARY_MODULO":        22,
	"BINARY_ADD":           23,
	"BINARY_SUBTRACT":      24,
	"BINARY_SUBSCR":        25,
	"BINARY_FLOOR_DIVIDE":  26,
	"BINARY_TRUE_DIVIDE":   27,
	"INPLACE_FLOOR_DIVIDE": 28,
	"INPLACE_TRUE_DIVIDE":  29,
	"STORE_MAP":            54,
	"INPLACE_ADD":          55,
	"INPLACE_SUBTRACT":     56,
	"INPLACE_MULTIPLY":     57,
	"INPLACE_MODULO":       59,
	"STORE_SUBSCR":         60,
	"DELETE_SUBSCR":        61,
	"BINARY_LSHIFT":        62,
	"BINARY_RSHIFT":        63,
	"BINARY_AND":           64,
	"BINARY_XOR":           65,
	"BINARY_OR":            66,
	"INPLACE_POWER":        67,
	"GET_ITER":             68,
	"STORE_LOCALS":         69,
	"PRINT_EXPR":           70,
	"LOAD_BUILD_CLASS":     71,
	"YIELD_FROM":           72,
	"INPLACE_LSHIFT":       75,
	"INPLACE_RSHIFT":       76,
	"INPLACE_AND":          77,
	"INPLACE_XOR":          78,
	"INPLACE_OR":           79,
	"BREAK_LOOP":           80,
	"WITH_CLEANUP":         81,
	"RETURN_VALUE":         83,
	"IMPORT_STAR":          84,
	"YIELD_VALUE":          86,
	"POP_BLOCK":            87,
	"END_FINALLY":          88,
	"POP_EXCEPT":           89,
	"STORE_NAME":           90,
	"DELETE_NAME":          91,
	"UNPACK_SEQUENCE":      92,
	"FOR_ITER":             93,
	"UNPACK_EX":            94,
	"STORE_ATTR":           95,
	"DELETE_ATTR":          96,
	"STORE_GLOBAL":         97,
	"DELETE_GLOBAL":        98,
	"LOAD_CONST":           100,
	"LOAD_NAME":            101,
	"BUILD_TUPLE":          102,
	"BUILD_LIST":           103,
	"BUILD_SET":            104,
	"BUILD_MAP":            105,
	"LOAD_ATTR":            106,
	"COMPARE_OP":           107,
	"IMPORT_NAME":          108,
	"IMPORT_FROM":          109,
	"JUMP_FORWARD":         110,
	"JUMP_IF_FALSE_OR_POP": 111,
	"JUMP_IF_TRUE_OR_POP":  112,
	"JUMP_ABSOLUTE":        113,
	"POP_JUMP_IF_FALSE":    114,
	"POP_JUMP_IF_TRUE":     115,
	"LOAD_GLOBAL":          116,
	"CONTINUE_LOOP":        119,
	"SETUP_LOOP":           120,
	"SETUP_EXCEPT":         121,
	"SETUP_FINALLY":        122,
	"LOAD_FAST":            124,
	"STORE_FAST":           125,
	"DELETE_FAST":          126,
	"RAISE_VARARGS":        130,
	"CALL_FUNCTION":        131,
	"MAKE_FUNCTION":        132,
	"BUILD_SLICE":          133,
	"MAKE_CLOSURE":         134,
	"LOAD_CLOSURE":         135,
	"LOAD_DEREF":           136,
	"STORE_DEREF":          137,
	"DELETE_DEREF":         138,
	"CALL_FUNCTION_VAR":    140,
	"CALL_FUNCTION_KW":     141,
	"CALL_FUNCTION_VAR_KW": 142,
	"SETUP_WITH":           143,
	"EXTENDED_ARG":         144,
	"LIST_APPEND":          145,
	"SET_ADD":              146,
	"MAP_ADD":              147,
	"LOAD_CLASSDEREF":      148,
}

var OpCodeToName map[byte]string

func init() {
	OpCodeToName = make(map[byte]string, len(NameToOpCode))
	for name, opcode := range NameToOpCode {
		OpCodeToName[opcode] = name
	}
}

// Rich comparison opcodes
const (
	PyCmp_LT = iota
	PyCmp_LE
	PyCmp_EQ
	PyCmp_NE
	PyCmp_GT
	PyCmp_GE
	PyCmp_IN
	PyCmp_NOT_IN
	PyCmp_IS
	PyCmp_IS_NOT
	PyCmp_EXC_MATCH
	PyCmp_BAD
)

// If op has an argument
func HAS_ARG(op byte) bool {
	return op >= HAVE_ARGUMENT
}
<|endoftext|>


<commit_before>//+build ignore

// This small web app is used to redirect from the old taskfile.org domain
// to the new taskfile.dev without breaking CIs that uses cURL to download
// "/install.sh" without the -L flag (which follow redirects).

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/install.sh" {
			println("Dumping install.sh")

			w.Write(installShContent)
			return
		}

		println("Redirecting to taskfile.dev")

		w.Header().Set("Location", "https://taskfile.dev")
		w.WriteHeader(301)
	})

	println("Listening :8080")

	panic(http.ListenAndServe(":8080", nil))
}

var installShContent = []byte(`#!/bin/sh
set -e
# Code generated by godownloader on 2018-04-07T17:47:38Z. DO NOT EDIT.
#

usage() {
  this=$1
  cat <<EOF
$this: download go binaries for go-task/task

Usage: $this [-b] bindir [-d] [tag]
  -b sets bindir or installation directory, Defaults to ./bin
  -d turns on debug logging
   [tag] is a tag from
   https://github.com/go-task/task/releases
   If tag is missing, then the latest will be used.

 Generated by godownloader
  https://github.com/goreleaser/godownloader

EOF
  exit 2
}

parse_args() {
  #BINDIR is ./bin unless set be ENV
  # over-ridden by flag below

  BINDIR=${BINDIR:-./bin}
  while getopts "b:dh?" arg; do
    case "$arg" in
      b) BINDIR="$OPTARG" ;;
      d) log_set_priority 10 ;;
      h | \?) usage "$0" ;;
    esac
  done
  shift $((OPTIND - 1))
  TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
  tmpdir=$(mktmpdir)
  log_debug "downloading files into ${tmpdir}"
  http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
  http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
  hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
  srcdir="${tmpdir}"
  (cd "${tmpdir}" && untar "${TARBALL}")
  install -d "${BINDIR}"
  for binexe in "task" ; do
    if [ "$OS" = "windows" ]; then
      binexe="${binexe}.exe"
    fi
    install "${srcdir}/${binexe}" "${BINDIR}/"
    log_info "installed ${BINDIR}/${binexe}"
  done
}
is_supported_platform() {
  platform=$1
  found=1
  case "$platform" in
    windows/386) found=0 ;;
    windows/amd64) found=0 ;;
    darwin/386) found=0 ;;
    darwin/amd64) found=0 ;;
    linux/386) found=0 ;;
    linux/amd64) found=0 ;;
  esac
  case "$platform" in
    darwin/386) found=1 ;;
  esac
  return $found
}
check_platform() {
  if is_supported_platform "$PLATFORM"; then
    # optional logging goes here
    true
  else
    log_crit "platform $PLATFORM is not supported.  Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
    exit 1
  fi
}
tag_to_version() {
  if [ -z "${TAG}" ]; then
    log_info "checking GitHub for latest tag"
  else
    log_info "checking GitHub for tag '${TAG}'"
  fi
  REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
  if test -z "$REALTAG"; then
    log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
    exit 1
  fi
  # if version starts with 'v', remove it
  TAG="$REALTAG"
  VERSION=${TAG#v}
}
adjust_format() {
  # change format (tar.gz or zip) based on ARCH
  case ${ARCH} in
    windows) FORMAT=zip ;;
  esac
  true
}
adjust_os() {
  # adjust archive name based on OS
  true
}
adjust_arch() {
  # adjust archive name based on ARCH
  true
}

cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
  command -v "$1" >/dev/null
}
echoerr() {
  echo "$@" 1>&2
}
log_prefix() {
  echo "$0"
}
_logp=6
log_set_priority() {
  _logp="$1"
}
log_priority() {
  if test -z "$1"; then
    echo "$_logp"
    return
  fi
  [ "$1" -le "$_logp" ]
}
log_tag() {
  case $1 in
    0) echo "emerg" ;;
    1) echo "alert" ;;
    2) echo "crit" ;;
    3) echo "err" ;;
    4) echo "warning" ;;
    5) echo "notice" ;;
    6) echo "info" ;;
    7) echo "debug" ;;
    *) echo "$1" ;;
  esac
}
log_debug() {
  log_priority 7 || return 0
  echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
  log_priority 6 || return 0
  echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
  log_priority 3 || return 0
  echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
  log_priority 2 || return 0
  echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
  os=$(uname -s | tr '[:upper:]' '[:lower:]')
  case "$os" in
    msys_nt) os="windows" ;;
  esac
  echo "$os"
}
uname_arch() {
  arch=$(uname -m)
  case $arch in
    x86_64) arch="amd64" ;;
    x86) arch="386" ;;
    i686) arch="386" ;;
    i386) arch="386" ;;
    aarch64) arch="arm64" ;;
    armv5*) arch="arm5" ;;
    armv6*) arch="arm6" ;;
    armv7*) arch="arm7" ;;
  esac
  echo ${arch}
}
uname_os_check() {
  os=$(uname_os)
  case "$os" in
    darwin) return 0 ;;
    dragonfly) return 0 ;;
    freebsd) return 0 ;;
    linux) return 0 ;;
    android) return 0 ;;
    nacl) return 0 ;;
    netbsd) return 0 ;;
    openbsd) return 0 ;;
    plan9) return 0 ;;
    solaris) return 0 ;;
    windows) return 0 ;;
  esac
  log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
  return 1
}
uname_arch_check() {
  arch=$(uname_arch)
  case "$arch" in
    386) return 0 ;;
    amd64) return 0 ;;
    arm64) return 0 ;;
    armv5) return 0 ;;
    armv6) return 0 ;;
    armv7) return 0 ;;
    ppc64) return 0 ;;
    ppc64le) return 0 ;;
    mips) return 0 ;;
    mipsle) return 0 ;;
    mips64) return 0 ;;
    mips64le) return 0 ;;
    s390x) return 0 ;;
    amd64p32) return 0 ;;
  esac
  log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value.  Please file bug report at https://github.com/client9/shlib"
  return 1
}
untar() {
  tarball=$1
  case "${tarball}" in
    *.tar.gz | *.tgz) tar -xzf "${tarball}" ;;
    *.tar) tar -xf "${tarball}" ;;
    *.zip) unzip "${tarball}" ;;
    *)
      log_err "untar unknown archive format for ${tarball}"
      return 1
      ;;
  esac
}
mktmpdir() {
  test -z "$TMPDIR" && TMPDIR="$(mktemp -d)"
  mkdir -p "${TMPDIR}"
  echo "${TMPDIR}"
}
http_download_curl() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
  else
    code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
  fi
  if [ "$code" != "200" ]; then
    log_debug "http_download_curl received HTTP status $code"
    return 1
  fi
  return 0
}
http_download_wget() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    wget -q -O "$local_file" "$source_url"
  else
    wget -q --header "$header" -O "$local_file" "$source_url"
  fi
}
http_download() {
  log_debug "http_download $2"
  if is_command curl; then
    http_download_curl "$@"
    return
  elif is_command wget; then
    http_download_wget "$@"
    return
  fi
  log_crit "http_download unable to find wget or curl"
  return 1
}
http_copy() {
  tmp=$(mktemp)
  http_download "${tmp}" "$1" "$2" || return 1
  body=$(cat "$tmp")
  rm -f "${tmp}"
  echo "$body"
}
github_release() {
  owner_repo=$1
  version=$2
  test -z "$version" && version="latest"
  giturl="https://github.com/${owner_repo}/releases/${version}"
  json=$(http_copy "$giturl" "Accept:application/json")
  test -z "$json" && return 1
  version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
  test -z "$version" && return 1
  echo "$version"
}
hash_sha256() {
  TARGET=${1:-/dev/stdin}
  if is_command gsha256sum; then
    hash=$(gsha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command sha256sum; then
    hash=$(sha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command shasum; then
    hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command openssl; then
    hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f a
  else
    log_crit "hash_sha256 unable to find command to compute sha-256 hash"
    return 1
  fi
}
hash_sha256_verify() {
  TARGET=$1
  checksums=$2
  if [ -z "$checksums" ]; then
    log_err "hash_sha256_verify checksum file not specified in arg2"
    return 1
  fi
  BASENAME=${TARGET##*/}
  want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
  if [ -z "$want" ]; then
    log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
    return 1
  fi
  got=$(hash_sha256 "$TARGET")
  if [ "$want" != "$got" ]; then
    log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
    return 1
  fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF

PROJECT_NAME="task"
OWNER=go-task
REPO="task"
BINARY=task
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"

# use in logging routines
log_prefix() {
	echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download

uname_os_check "$OS"
uname_arch_check "$ARCH"

parse_args "$@"

check_platform

tag_to_version

adjust_format

adjust_os

adjust_arch

log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"

NAME=${BINARY}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=task_checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}

execute
`)
<commit_msg>Small fix to redirector<commit_after>// This small web app is used to redirect from the old taskfile.org domain
// to the new taskfile.dev without breaking CIs that uses cURL to download
// "/install.sh" without the -L flag (which follow redirects).

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/install.sh" {
			println("Dumping install.sh")

			w.Write(installShContent)
			return
		}

		println("Redirecting to https://taskfile.dev" + r.URL.Path)

		w.Header().Set("Location", "https://taskfile.dev"+r.URL.Path)
		w.WriteHeader(301)
	})

	println("Listening :8080")

	panic(http.ListenAndServe(":8080", nil))
}

var installShContent = []byte(`#!/bin/sh
set -e
# Code generated by godownloader on 2018-04-07T17:47:38Z. DO NOT EDIT.
#

usage() {
  this=$1
  cat <<EOF
$this: download go binaries for go-task/task

Usage: $this [-b] bindir [-d] [tag]
  -b sets bindir or installation directory, Defaults to ./bin
  -d turns on debug logging
   [tag] is a tag from
   https://github.com/go-task/task/releases
   If tag is missing, then the latest will be used.

 Generated by godownloader
  https://github.com/goreleaser/godownloader

EOF
  exit 2
}

parse_args() {
  #BINDIR is ./bin unless set be ENV
  # over-ridden by flag below

  BINDIR=${BINDIR:-./bin}
  while getopts "b:dh?" arg; do
    case "$arg" in
      b) BINDIR="$OPTARG" ;;
      d) log_set_priority 10 ;;
      h | \?) usage "$0" ;;
    esac
  done
  shift $((OPTIND - 1))
  TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
  tmpdir=$(mktmpdir)
  log_debug "downloading files into ${tmpdir}"
  http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
  http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
  hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
  srcdir="${tmpdir}"
  (cd "${tmpdir}" && untar "${TARBALL}")
  install -d "${BINDIR}"
  for binexe in "task" ; do
    if [ "$OS" = "windows" ]; then
      binexe="${binexe}.exe"
    fi
    install "${srcdir}/${binexe}" "${BINDIR}/"
    log_info "installed ${BINDIR}/${binexe}"
  done
}
is_supported_platform() {
  platform=$1
  found=1
  case "$platform" in
    windows/386) found=0 ;;
    windows/amd64) found=0 ;;
    darwin/386) found=0 ;;
    darwin/amd64) found=0 ;;
    linux/386) found=0 ;;
    linux/amd64) found=0 ;;
  esac
  case "$platform" in
    darwin/386) found=1 ;;
  esac
  return $found
}
check_platform() {
  if is_supported_platform "$PLATFORM"; then
    # optional logging goes here
    true
  else
    log_crit "platform $PLATFORM is not supported.  Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
    exit 1
  fi
}
tag_to_version() {
  if [ -z "${TAG}" ]; then
    log_info "checking GitHub for latest tag"
  else
    log_info "checking GitHub for tag '${TAG}'"
  fi
  REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
  if test -z "$REALTAG"; then
    log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
    exit 1
  fi
  # if version starts with 'v', remove it
  TAG="$REALTAG"
  VERSION=${TAG#v}
}
adjust_format() {
  # change format (tar.gz or zip) based on ARCH
  case ${ARCH} in
    windows) FORMAT=zip ;;
  esac
  true
}
adjust_os() {
  # adjust archive name based on OS
  true
}
adjust_arch() {
  # adjust archive name based on ARCH
  true
}

cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
  command -v "$1" >/dev/null
}
echoerr() {
  echo "$@" 1>&2
}
log_prefix() {
  echo "$0"
}
_logp=6
log_set_priority() {
  _logp="$1"
}
log_priority() {
  if test -z "$1"; then
    echo "$_logp"
    return
  fi
  [ "$1" -le "$_logp" ]
}
log_tag() {
  case $1 in
    0) echo "emerg" ;;
    1) echo "alert" ;;
    2) echo "crit" ;;
    3) echo "err" ;;
    4) echo "warning" ;;
    5) echo "notice" ;;
    6) echo "info" ;;
    7) echo "debug" ;;
    *) echo "$1" ;;
  esac
}
log_debug() {
  log_priority 7 || return 0
  echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
  log_priority 6 || return 0
  echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
  log_priority 3 || return 0
  echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
  log_priority 2 || return 0
  echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
  os=$(uname -s | tr '[:upper:]' '[:lower:]')
  case "$os" in
    msys_nt) os="windows" ;;
  esac
  echo "$os"
}
uname_arch() {
  arch=$(uname -m)
  case $arch in
    x86_64) arch="amd64" ;;
    x86) arch="386" ;;
    i686) arch="386" ;;
    i386) arch="386" ;;
    aarch64) arch="arm64" ;;
    armv5*) arch="arm5" ;;
    armv6*) arch="arm6" ;;
    armv7*) arch="arm7" ;;
  esac
  echo ${arch}
}
uname_os_check() {
  os=$(uname_os)
  case "$os" in
    darwin) return 0 ;;
    dragonfly) return 0 ;;
    freebsd) return 0 ;;
    linux) return 0 ;;
    android) return 0 ;;
    nacl) return 0 ;;
    netbsd) return 0 ;;
    openbsd) return 0 ;;
    plan9) return 0 ;;
    solaris) return 0 ;;
    windows) return 0 ;;
  esac
  log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
  return 1
}
uname_arch_check() {
  arch=$(uname_arch)
  case "$arch" in
    386) return 0 ;;
    amd64) return 0 ;;
    arm64) return 0 ;;
    armv5) return 0 ;;
    armv6) return 0 ;;
    armv7) return 0 ;;
    ppc64) return 0 ;;
    ppc64le) return 0 ;;
    mips) return 0 ;;
    mipsle) return 0 ;;
    mips64) return 0 ;;
    mips64le) return 0 ;;
    s390x) return 0 ;;
    amd64p32) return 0 ;;
  esac
  log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value.  Please file bug report at https://github.com/client9/shlib"
  return 1
}
untar() {
  tarball=$1
  case "${tarball}" in
    *.tar.gz | *.tgz) tar -xzf "${tarball}" ;;
    *.tar) tar -xf "${tarball}" ;;
    *.zip) unzip "${tarball}" ;;
    *)
      log_err "untar unknown archive format for ${tarball}"
      return 1
      ;;
  esac
}
mktmpdir() {
  test -z "$TMPDIR" && TMPDIR="$(mktemp -d)"
  mkdir -p "${TMPDIR}"
  echo "${TMPDIR}"
}
http_download_curl() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
  else
    code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
  fi
  if [ "$code" != "200" ]; then
    log_debug "http_download_curl received HTTP status $code"
    return 1
  fi
  return 0
}
http_download_wget() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    wget -q -O "$local_file" "$source_url"
  else
    wget -q --header "$header" -O "$local_file" "$source_url"
  fi
}
http_download() {
  log_debug "http_download $2"
  if is_command curl; then
    http_download_curl "$@"
    return
  elif is_command wget; then
    http_download_wget "$@"
    return
  fi
  log_crit "http_download unable to find wget or curl"
  return 1
}
http_copy() {
  tmp=$(mktemp)
  http_download "${tmp}" "$1" "$2" || return 1
  body=$(cat "$tmp")
  rm -f "${tmp}"
  echo "$body"
}
github_release() {
  owner_repo=$1
  version=$2
  test -z "$version" && version="latest"
  giturl="https://github.com/${owner_repo}/releases/${version}"
  json=$(http_copy "$giturl" "Accept:application/json")
  test -z "$json" && return 1
  version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
  test -z "$version" && return 1
  echo "$version"
}
hash_sha256() {
  TARGET=${1:-/dev/stdin}
  if is_command gsha256sum; then
    hash=$(gsha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command sha256sum; then
    hash=$(sha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command shasum; then
    hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command openssl; then
    hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f a
  else
    log_crit "hash_sha256 unable to find command to compute sha-256 hash"
    return 1
  fi
}
hash_sha256_verify() {
  TARGET=$1
  checksums=$2
  if [ -z "$checksums" ]; then
    log_err "hash_sha256_verify checksum file not specified in arg2"
    return 1
  fi
  BASENAME=${TARGET##*/}
  want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
  if [ -z "$want" ]; then
    log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
    return 1
  fi
  got=$(hash_sha256 "$TARGET")
  if [ "$want" != "$got" ]; then
    log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
    return 1
  fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF

PROJECT_NAME="task"
OWNER=go-task
REPO="task"
BINARY=task
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"

# use in logging routines
log_prefix() {
	echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download

uname_os_check "$OS"
uname_arch_check "$ARCH"

parse_args "$@"

check_platform

tag_to_version

adjust_format

adjust_os

adjust_arch

log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"

NAME=${BINARY}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=task_checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}

execute
`)
<|endoftext|>


<commit_before>// +build appengine js nacl

package isatty

// IsTerminal returns true if the file descriptor is terminal which
// is always false on js and appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
	return false
}

// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
	return false
}
<commit_msg>add wasm target to others<commit_after>// +build appengine js nacl wasm

package isatty

// IsTerminal returns true if the file descriptor is terminal which
// is always false on js and appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
	return false
}

// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
	return false
}
<|endoftext|>


<commit_before>package eventmaster

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(*Event) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) UpdateTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) DeleteTopic(string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	rows, err := p.db.Query("SELECT dc_id, dc from event_dc")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var dcs []DC

	var dc_id, dc string
	for rows.Next() {
		err = rows.Scan(&dc_id, &dc)
		if err != nil {
			return nil, err
		}
		dcs = append(dcs, DC{
			ID:   dc_id,
			Name: dc,
		})
	}
	return dcs, nil
}

func (p *PostgresStore) AddDC(dc DC) error {
	stmt, err := p.db.Prepare("INSERT INTO event_dc (dc_id, dc) VALUES ($1, $2)")
	if err != nil {
		return errors.Wrap(err, "Failed preparing insert DC statement")
	}
	_, err = stmt.Exec(dc.ID, dc.Name)
	if err != nil {
		return err
	}

	return nil
}

func (p *PostgresStore) UpdateDC(string, string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) CloseSession() {
	p.db.Close()
}
<commit_msg>Implement UpdateDC<commit_after>package eventmaster

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(*Event) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) UpdateTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) DeleteTopic(string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	rows, err := p.db.Query("SELECT dc_id, dc from event_dc")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var dcs []DC

	var dc_id, dc string
	for rows.Next() {
		err = rows.Scan(&dc_id, &dc)
		if err != nil {
			return nil, err
		}
		dcs = append(dcs, DC{
			ID:   dc_id,
			Name: dc,
		})
	}
	return dcs, nil
}

func (p *PostgresStore) AddDC(dc DC) error {
	stmt, err := p.db.Prepare("INSERT INTO event_dc (dc_id, dc) VALUES ($1, $2)")
	if err != nil {
		return errors.Wrap(err, "Failed preparing insert DC statement")
	}
	_, err = stmt.Exec(dc.ID, dc.Name)
	if err != nil {
		return err
	}

	return nil
}

func (p *PostgresStore) UpdateDC(id string, newName string) error {
	_, err := p.db.Exec("UPDATE event_dc SET dc=$1 WHERE dc_id=$2", newName, id)
	return err
}

func (p *PostgresStore) CloseSession() {
	p.db.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/DimShadoWWW/power-pg/proxy"
	"github.com/parnurzeal/gorequest"
)

var (
	localHost     = flag.String("l", ":9876", "Endereço e porta do listener local")
	remoteHost    = flag.String("r", "localhost:5432", "Endereço e porta do servidor PostgreSQL")
	remoteService = flag.String("s", "", "http://localhost:8080/query")
	messages      = []string{}
)

func main() {
	flag.Parse()
	msgs := make(chan string)
	msgCh := make(chan proxy.Pkg)
	msgOut := make(chan string)
	if *remoteService != "" {
		go func() {
			time.Sleep(time.Second * 3)
			inFile, _ := os.Open("canales_list.txt")
			defer inFile.Close()
			scanner := bufio.NewScanner(inFile)
			scanner.Split(bufio.ScanLines)

			for scanner.Scan() {
				time.Sleep(time.Second * 1)
				messages = []string{}
				fmt.Println(scanner.Text())
				msgOut <- fmt.Sprintf("# %s\n", scanner.Text())
				_, _, errs := gorequest.New().Get(fmt.Sprintf("%s%s", *remoteService, scanner.Text())).End()
				if errs != nil {
					log.Fatalf("log failed: %v", errs)
				}
			}
			log.Println("done")
			os.Exit(0)
		}()
	}

	go func() {
		f, err := os.OpenFile("/all.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		for msg := range msgs {
			// fmt.Println(msg)
			_, err := f.WriteString(fmt.Sprintf("%s\n", msg))
			if err != nil {
				log.Fatalf("log failed: %v", err)
			}
		}
	}()

	go func() {
		f, err := os.OpenFile("/report.md", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		for msg := range msgOut {
			fmt.Println(msg)
			_, err := f.WriteString(fmt.Sprintf("%s\n", msg))
			if err != nil {
				log.Fatalf("log failed: %v", err)
			}
		}
	}()

	go func() {
		temp := ""
		for msg := range msgCh {
			if msg.Type == 'P' {
				if strings.Contains(string(msg.Content), "$1") {
					selectIdx := strings.Index(string(msg.Content), string([]byte{83, 69, 76, 69, 67, 84, 32}))
					if selectIdx == -1 {
						selectIdx = 0
					}
					sepIdx := strings.Index(string(msg.Content), string([]byte{0, 1, 0, 0}))
					if sepIdx == -1 {
						sepIdx = len(msg.Content) - 4
					}

					temp = string(bytes.Trim(msg.Content[selectIdx:sepIdx], "\x00"))
					fmt.Printf("SEP index ----->%v\n", sepIdx)
					fmt.Printf("SEP len   ----->%v\n", len(msg.Content))
					fmt.Printf("SEP CONT  ----->%v\n", msg.Content)
				} else {
					temp = ""
					selectIdx := strings.Index(string(msg.Content), string([]byte{83, 69, 76, 69, 67, 84, 32}))
					if selectIdx == -1 {
						selectIdx = 0
					}
					sepIdx := strings.Index(string(msg.Content), string([]byte{0, 0, 1, 0, 0}))
					if sepIdx == -1 || sepIdx+5 > len(msg.Content) {
						sepIdx := strings.Index(string(msg.Content), string([]byte{0, 1, 0, 0}))
						if sepIdx == -1 || sepIdx+4 > len(msg.Content) {
							sepIdx = len(msg.Content) - 4
						} else {
							sepIdx = len(msg.Content) - 1
						}
					}
					if sepIdx == -1 {
						sepIdx = len(msg.Content)
					}
					if selectIdx == -1 {
						selectIdx = 0
					}

					fmt.Printf("SEP index ----->%v\n", sepIdx)
					fmt.Printf("SEP len   ----->%v\n", len(msg.Content))
					fmt.Printf("SEP CONT  ----->%v\n", msg.Content)
					messages = append(messages, string(bytes.Trim(msg.Content[selectIdx:sepIdx], "\x00")))
				}
			} else {
				if msg.Type == 'B' && len(msg.Content) > 28 && temp != "" {
					idxPdo := strings.Index(string(msg.Content), "pdo_stmt_")

					if idxPdo != -1 {
						var newMsg proxy.ReadBuf
						// B type allways ends with 0100
						fmt.Printf("msg.Content   ----->%#v\n", msg.Content)
						newMsg = msg.Content[idxPdo+22 : len(msg.Content)-4]
						fmt.Printf("1 newMsg   ----->%#v\n", newMsg)
						totalVar := newMsg.Int16()

						vars := make(map[int]string)
						var varsIdx []int
						for i := 0; i < totalVar; i++ {
							fmt.Printf("2 newMsg   ----->%#v\n", newMsg)
							// varLen := newMsg.Int32()
							aa := newMsg.Next(4)
							fmt.Printf("aa   -----> %#v\n", aa)
							fmt.Printf("aa bits ----->%8b\n", aa[len(aa)-1])
							varLen := int(binary.LittleEndian.Uint32(aa))
							fmt.Printf("varLen ----->%v\n", varLen)
							fmt.Printf("newMsg   ----->%#v\n", newMsg)
							vars[i] = string(newMsg.Next(varLen))
							fmt.Printf("vars   ----->%#v\n", vars)
							varsIdx = append(varsIdx, i)
							fmt.Printf("varIdx  ----->%#v\n", varsIdx)
						}
						sort.Sort(sort.Reverse(sort.IntSlice(varsIdx)))
						for _, k := range varsIdx {
							messages = append(messages, strings.Replace(temp, fmt.Sprintf("$%d", k+1), fmt.Sprintf("'%s'", string(newMsg[k+1])), -1))
						}
					} else {
						messages = append(messages, string(msg.Content[29:len(msg.Content)-4]))
					}

				}
				temp = ""
			}
			fmt.Printf("---------->%v\n", messages)
			fmt.Printf("---------->%#v\n", messages)
			for k, v := range messages {
				msgOut <- fmt.Sprintf("%d. %s\n", k+1, v)
			}
		}
	}()

	proxy.Start(localHost, remoteHost, getQueryModificada, msgs, msgCh)
}

func getQueryModificada(queryOriginal string) string {
	// log.Println("aa")
	// if queryOriginal[:5] != "power" {
	// 	return queryOriginal
	// }

	// log.Println(queryOriginal)
	fmt.Println(queryOriginal)
	return queryOriginal
}
<commit_msg>Update<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/DimShadoWWW/power-pg/proxy"
	"github.com/parnurzeal/gorequest"
)

var (
	localHost     = flag.String("l", ":9876", "Endereço e porta do listener local")
	remoteHost    = flag.String("r", "localhost:5432", "Endereço e porta do servidor PostgreSQL")
	remoteService = flag.String("s", "", "http://localhost:8080/query")
	messages      = []string{}
)

func main() {
	flag.Parse()
	msgs := make(chan string)
	msgCh := make(chan proxy.Pkg)
	msgOut := make(chan string)
	if *remoteService != "" {
		go func() {
			time.Sleep(time.Second * 3)
			inFile, _ := os.Open("canales_list.txt")
			defer inFile.Close()
			scanner := bufio.NewScanner(inFile)
			scanner.Split(bufio.ScanLines)

			for scanner.Scan() {
				time.Sleep(time.Second * 1)
				messages = []string{}
				fmt.Println(scanner.Text())
				msgOut <- fmt.Sprintf("# %s\n", scanner.Text())
				_, _, errs := gorequest.New().Get(fmt.Sprintf("%s%s", *remoteService, scanner.Text())).End()
				if errs != nil {
					log.Fatalf("log failed: %v", errs)
				}
			}
			log.Println("done")
			os.Exit(0)
		}()
	}

	go func() {
		f, err := os.OpenFile("/all.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		for msg := range msgs {
			// fmt.Println(msg)
			_, err := f.WriteString(fmt.Sprintf("%s\n", msg))
			if err != nil {
				log.Fatalf("log failed: %v", err)
			}
		}
	}()

	go func() {
		f, err := os.OpenFile("/report.md", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		for msg := range msgOut {
			fmt.Println(msg)
			_, err := f.WriteString(fmt.Sprintf("%s\n", msg))
			if err != nil {
				log.Fatalf("log failed: %v", err)
			}
		}
	}()

	go func() {
		temp := ""
		for msg := range msgCh {
			if msg.Type == 'P' {
				if strings.Contains(string(msg.Content), "$1") {
					selectIdx := strings.Index(string(msg.Content), string([]byte{83, 69, 76, 69, 67, 84, 32}))
					if selectIdx == -1 {
						selectIdx = 0
					}
					sepIdx := strings.Index(string(msg.Content), string([]byte{0, 1, 0, 0}))
					if sepIdx == -1 {
						sepIdx = len(msg.Content) - 4
					}

					temp = string(bytes.Trim(msg.Content[selectIdx:sepIdx], "\x00"))
					fmt.Printf("SEP index ----->%v\n", sepIdx)
					fmt.Printf("SEP len   ----->%v\n", len(msg.Content))
					fmt.Printf("SEP CONT  ----->%v\n", msg.Content)
				} else {
					temp = ""
					selectIdx := strings.Index(string(msg.Content), string([]byte{83, 69, 76, 69, 67, 84, 32}))
					if selectIdx == -1 {
						selectIdx = 0
					}
					sepIdx := strings.Index(string(msg.Content), string([]byte{0, 0, 1, 0, 0}))
					if sepIdx == -1 || sepIdx+5 > len(msg.Content) {
						sepIdx := strings.Index(string(msg.Content), string([]byte{0, 1, 0, 0}))
						if sepIdx == -1 || sepIdx+4 > len(msg.Content) {
							sepIdx = len(msg.Content) - 4
						} else {
							sepIdx = len(msg.Content) - 1
						}
					}
					if sepIdx == -1 {
						sepIdx = len(msg.Content)
					}
					if selectIdx == -1 {
						selectIdx = 0
					}

					fmt.Printf("SEP index ----->%v\n", sepIdx)
					fmt.Printf("SEP len   ----->%v\n", len(msg.Content))
					fmt.Printf("SEP CONT  ----->%v\n", msg.Content)
					messages = append(messages, string(bytes.Trim(msg.Content[selectIdx:sepIdx], "\x00")))
				}
			} else {
				if msg.Type == 'B' && len(msg.Content) > 28 && temp != "" {
					idxPdo := strings.Index(string(msg.Content), "pdo_stmt_")

					if idxPdo != -1 {
						var newMsg proxy.ReadBuf
						// B type allways ends with 0100
						fmt.Printf("msg.Content   ----->%#v\n", msg.Content)
						newMsg = msg.Content[idxPdo+22 : len(msg.Content)-4]
						fmt.Printf("1 newMsg   ----->%#v\n", newMsg)
						totalVar := newMsg.Int16()

						vars := make(map[int]string)
						var varsIdx []int
						for i := 0; i < totalVar; i++ {
							fmt.Printf("2 newMsg   ----->%#v\n", newMsg)
							// varLen := newMsg.Int32()
							aa := newMsg.Next(4)
							fmt.Printf("aa   -----> %#v\n", aa)
							fmt.Printf("aa bits ----->%8b\n", aa[len(aa)-1])
							varLen := int(binary.BigEndian.Uint32(aa))
							fmt.Printf("varLen ----->%v\n", varLen)
							fmt.Printf("newMsg   ----->%#v\n", newMsg)
							vars[i] = string(newMsg.Next(varLen))
							fmt.Printf("vars   ----->%#v\n", vars)
							varsIdx = append(varsIdx, i)
							fmt.Printf("varIdx  ----->%#v\n", varsIdx)
						}
						sort.Sort(sort.Reverse(sort.IntSlice(varsIdx)))
						for _, k := range varsIdx {
							messages = append(messages, strings.Replace(temp, fmt.Sprintf("$%d", k+1), fmt.Sprintf("'%s'", string(newMsg[k+1])), -1))
						}
					} else {
						messages = append(messages, string(msg.Content[29:len(msg.Content)-4]))
					}

				}
				temp = ""
			}
			fmt.Printf("---------->%v\n", messages)
			fmt.Printf("---------->%#v\n", messages)
			for k, v := range messages {
				msgOut <- fmt.Sprintf("%d. %s\n", k+1, v)
			}
		}
	}()

	proxy.Start(localHost, remoteHost, getQueryModificada, msgs, msgCh)
}

func getQueryModificada(queryOriginal string) string {
	// log.Println("aa")
	// if queryOriginal[:5] != "power" {
	// 	return queryOriginal
	// }

	// log.Println(queryOriginal)
	fmt.Println(queryOriginal)
	return queryOriginal
}
<|endoftext|>