<commit_before>package aws

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/xmetrics"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sns/snsiface"
)

type AWSConfig struct {
	AccessKey string    `json:"accessKey"`
	SecretKey string    `json:"secretKey"`
	Env       string    `json:"env"`
	Sns       SNSConfig `json:"sns"`
}

type SNSConfig struct {
	Protocol string `json:"protocol"`
	Region   string `json:"region"`
	TopicArn string `json:"topicArn"`
	UrlPath  string `json:"urlPath"` //uri path to register mux
}

type SNSServer struct {
	Config          AWSConfig
	subscriptionArn atomic.Value
	SVC     snsiface.SNSAPI
	SelfUrl *url.URL
	SNSValidator
	notificationData chan string

	errorLog log.Logger
	debugLog log.Logger
	metrics  Metrics
}

// Notifier interface implements the various notification server functionalities
// like Subscribe, Unsubscribe, Publish, NotificationHandler
type Notifier interface {
	Initialize(*mux.Router, *url.URL, http.Handler, log.Logger, func() time.Time)
	PrepareAndStart()
	Subscribe()
	PublishMessage(string)
	Unsubscribe(string)
	NotificationHandle(http.ResponseWriter, *http.Request) []byte
	ValidateSubscriptionArn(string) bool
}

// NewSNSServer creates SNSServer instance using viper config
func NewSNSServer(v *viper.Viper) (ss *SNSServer, err error) {

	var cfg *AWSConfig
	if cfg, err = NewAWSConfig(v); err != nil {
		return nil, err
	}

	cred := credentials.NewStaticCredentials(cfg.AccessKey, cfg.SecretKey, "")

	sess, aws_err := session.NewSession(&aws.Config{
		Region:      aws.String(cfg.Sns.Region),
		Credentials: cred,
	})
	if aws_err != nil {
		return nil, aws_err
	}

	svc := sns.New(sess)
	// Initialize the server
	ss = &SNSServer{
		Config: *cfg,
		SVC:    svc,
	}

	ss.SNSValidator = NewSNSValidator()

	return ss, nil
}

// NewNotifier creates Notifier instance using the viper config
func NewNotifier(v *viper.Viper) (Notifier, error) {
	return NewSNSServer(v)
}

// Initialize initializes the SNSServer fields
// selfURL represents the webhook server URL &url.URL{Scheme:secure,Host:fqdn+port,Path:urlPath}
// handler is the webhook handler to update webhooks @monitor
// SNS POST Notification handler will directly update webhooks list
func (ss *SNSServer) Initialize(rtr *mux.Router, selfUrl *url.URL, handler http.Handler,
	logger log.Logger, registry *xmetrics.Registry, now func() time.Time) {

	if rtr == nil {
		//creating new mux router
		rtr = mux.NewRouter()
	}

	if now == nil {
		now = time.Now
	}

	// Set webhook url path to SNS UrlPath
	// Add unix timestamp to the path to generate unique subArn each time
	var urlPath string
	if strings.HasSuffix(ss.Config.Sns.UrlPath, "/") {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, now().Unix())
	} else {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, "/", now().Unix())
	}

	if selfUrl != nil {
		ss.SelfUrl = selfUrl
		ss.SelfUrl.Path = urlPath
	} else {
		// Test selfurl http://host:port/path
		ss.SelfUrl = &url.URL{
			Scheme: "http",
			Host:   "host:port",
			Path:   urlPath,
		}
	}
	ss.notificationData = make(chan string, 10)

	// set up logger
	if logger == nil {
		logger = logging.DefaultLogger()
	}

	ss.errorLog = logging.Error(logger)
	ss.debugLog = logging.Debug(logger)

	if registry != nil {
		ss.metrics = AddMetrics(*registry)
	} else {
		var empty []Metric
		o := &xmetrics.Options{}
		registry, err := &xmetrics.NewRegistry(o, empty...)
		if err != nil {
			ss.errorLog.Log(logging.MessageKey(), "failed to create default registry", "error", err)
		}
		ss.metrics = AddMetrics(*registry)
	}

	ss.debugLog.Log("selfURL", ss.SelfUrl.String(), "protocol", ss.SelfUrl.Scheme)

	// Set various SNS POST routes
	ss.SetSNSRoutes(urlPath, rtr, handler)

}

// Prepare the SNSServer to receive Notifications
// This better be called after the endpoint http server is started
// and ready to receive AWS SNS POST messages
// subscribe to the SNS topic
func (ss *SNSServer) PrepareAndStart() {

	ss.Subscribe()
}

// Validate that SubscriptionArn received in AWS request matches the cached config data
func (ss *SNSServer) ValidateSubscriptionArn(reqSubscriptionArn string) bool {

	if ss.subscriptionArn.Load() == nil {
		ss.errorLog.Log(logging.MessageKey(), "SNS subscriptionArn is nil")
		return false
	} else if strings.EqualFold(reqSubscriptionArn, ss.subscriptionArn.Load().(string)) {
		return true
	} else {
		ss.errorLog.Log(
			logging.MessageKey(), "SNS Invalid subscription",
			"reqSubscriptionArn", reqSubscriptionArn,
			"cfg", ss.subscriptionArn.Load().(string),
		)
		return false
	}
}

// helper function to report the list size value
func (ss *SNSServer) ReportListSize(size int) {
	ss.metrics.ListSize.Set(float64(size))
}

// helper function to get the right subscription attempts counter to increment
func (ss *SNSServer) SNSSubscriptionAttemptCounter(code int) metrics.Counter {
	if code == -1 {
		return ss.metrics.SNSSubscribeAttempt.With("code", "failure")
	}

	return ss.metrics.SNSSubscribeAttempt.With("code", "okay")
}

// helper function to get the right notification received counter to increment
func (ss *SNSServer) SNSNotificationReceivedCounter(code int) metrics.Counter {
	if code == -1 {
		return ss.metrics.SNSNotificationReceived.With("code", "failure")
	}

	s := strconv.Itoa(code)
	return ss.metrics.SNSNotificationReceived.With("code", s)
}

<commit_msg>more build error fixes<commit_after>package aws

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/xmetrics"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sns/snsiface"
)

type AWSConfig struct {
	AccessKey string    `json:"accessKey"`
	SecretKey string    `json:"secretKey"`
	Env       string    `json:"env"`
	Sns       SNSConfig `json:"sns"`
}

type SNSConfig struct {
	Protocol string `json:"protocol"`
	Region   string `json:"region"`
	TopicArn string `json:"topicArn"`
	UrlPath  string `json:"urlPath"` //uri path to register mux
}

type SNSServer struct {
	Config          AWSConfig
	subscriptionArn atomic.Value
	SVC     snsiface.SNSAPI
	SelfUrl *url.URL
	SNSValidator
	notificationData chan string

	errorLog log.Logger
	debugLog log.Logger
	metrics  Metrics
}

// Notifier interface implements the various notification server functionalities
// like Subscribe, Unsubscribe, Publish, NotificationHandler
type Notifier interface {
	Initialize(*mux.Router, *url.URL, http.Handler, log.Logger, func() time.Time)
	PrepareAndStart()
	Subscribe()
	PublishMessage(string)
	Unsubscribe(string)
	NotificationHandle(http.ResponseWriter, *http.Request) []byte
	ValidateSubscriptionArn(string) bool
}

// NewSNSServer creates SNSServer instance using viper config
func NewSNSServer(v *viper.Viper) (ss *SNSServer, err error) {

	var cfg *AWSConfig
	if cfg, err = NewAWSConfig(v); err != nil {
		return nil, err
	}

	cred := credentials.NewStaticCredentials(cfg.AccessKey, cfg.SecretKey, "")

	sess, aws_err := session.NewSession(&aws.Config{
		Region:      aws.String(cfg.Sns.Region),
		Credentials: cred,
	})
	if aws_err != nil {
		return nil, aws_err
	}

	svc := sns.New(sess)
	// Initialize the server
	ss = &SNSServer{
		Config: *cfg,
		SVC:    svc,
	}

	ss.SNSValidator = NewSNSValidator()

	return ss, nil
}

// NewNotifier creates Notifier instance using the viper config
func NewNotifier(v *viper.Viper) (Notifier, error) {
	return NewSNSServer(v)
}

// Initialize initializes the SNSServer fields
// selfURL represents the webhook server URL &url.URL{Scheme:secure,Host:fqdn+port,Path:urlPath}
// handler is the webhook handler to update webhooks @monitor
// SNS POST Notification handler will directly update webhooks list
func (ss *SNSServer) Initialize(rtr *mux.Router, selfUrl *url.URL, handler http.Handler,
	logger log.Logger, registry *xmetrics.Registry, now func() time.Time) {

	if rtr == nil {
		//creating new mux router
		rtr = mux.NewRouter()
	}

	if now == nil {
		now = time.Now
	}

	// Set webhook url path to SNS UrlPath
	// Add unix timestamp to the path to generate unique subArn each time
	var urlPath string
	if strings.HasSuffix(ss.Config.Sns.UrlPath, "/") {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, now().Unix())
	} else {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, "/", now().Unix())
	}

	if selfUrl != nil {
		ss.SelfUrl = selfUrl
		ss.SelfUrl.Path = urlPath
	} else {
		// Test selfurl http://host:port/path
		ss.SelfUrl = &url.URL{
			Scheme: "http",
			Host:   "host:port",
			Path:   urlPath,
		}
	}
	ss.notificationData = make(chan string, 10)

	// set up logger
	if logger == nil {
		logger = logging.DefaultLogger()
	}

	ss.errorLog = logging.Error(logger)
	ss.debugLog = logging.Debug(logger)

	if registry != nil {
		ss.metrics = AddMetrics(*registry)
	} else {
		o := &xmetrics.Options{}
		registry, err := xmetrics.NewRegistry(o)
		if err != nil {
			ss.errorLog.Log(logging.MessageKey(), "failed to create default registry", "error", err)
		}
		ss.metrics = AddMetrics(&registry)
	}

	ss.debugLog.Log("selfURL", ss.SelfUrl.String(), "protocol", ss.SelfUrl.Scheme)

	// Set various SNS POST routes
	ss.SetSNSRoutes(urlPath, rtr, handler)

}

// Prepare the SNSServer to receive Notifications
// This better be called after the endpoint http server is started
// and ready to receive AWS SNS POST messages
// subscribe to the SNS topic
func (ss *SNSServer) PrepareAndStart() {

	ss.Subscribe()
}

// Validate that SubscriptionArn received in AWS request matches the cached config data
func (ss *SNSServer) ValidateSubscriptionArn(reqSubscriptionArn string) bool {

	if ss.subscriptionArn.Load() == nil {
		ss.errorLog.Log(logging.MessageKey(), "SNS subscriptionArn is nil")
		return false
	} else if strings.EqualFold(reqSubscriptionArn, ss.subscriptionArn.Load().(string)) {
		return true
	} else {
		ss.errorLog.Log(
			logging.MessageKey(), "SNS Invalid subscription",
			"reqSubscriptionArn", reqSubscriptionArn,
			"cfg", ss.subscriptionArn.Load().(string),
		)
		return false
	}
}

// helper function to report the list size value
func (ss *SNSServer) ReportListSize(size int) {
	ss.metrics.ListSize.Set(float64(size))
}

// helper function to get the right subscription attempts counter to increment
func (ss *SNSServer) SNSSubscriptionAttemptCounter(code int) metrics.Counter {
	if code == -1 {
		return ss.metrics.SNSSubscribeAttempt.With("code", "failure")
	}

	return ss.metrics.SNSSubscribeAttempt.With("code", "okay")
}

// helper function to get the right notification received counter to increment
func (ss *SNSServer) SNSNotificationReceivedCounter(code int) metrics.Counter {
	if code == -1 {
		return ss.metrics.SNSNotificationReceived.With("code", "failure")
	}

	s := strconv.Itoa(code)
	return ss.metrics.SNSNotificationReceived.With("code", s)
}

<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The exec package runs external commands.
package exec

import (
	"os"
	"strconv"
)

// Arguments to Run.
const (
	DevNull = iota
	PassThrough
	Pipe
	MergeWithStdout
)

// A Cmd represents a running command.
// Stdin, Stdout, and Stderr are Files representing pipes
// connected to the running command's standard input, output, and error,
// or else nil, depending on the arguments to Run.
// Process represents the underlying operating system process.
type Cmd struct {
	Stdin   *os.File
	Stdout  *os.File
	Stderr  *os.File
	Process *os.Process
}

// PathError records the name of a binary that was not
// found on the current $PATH.
type PathError struct {
	Name string
}

func (e *PathError) String() string {
	return "command " + strconv.Quote(e.Name) + " not found in $PATH"
}

// Given mode (DevNull, etc), return file for child
// and file to record in Cmd structure.
func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
	switch mode {
	case DevNull:
		rw := os.O_WRONLY
		if fd == 0 {
			rw = os.O_RDONLY
		}
		f, err := os.Open(os.DevNull, rw, 0)
		return f, nil, err
	case PassThrough:
		switch fd {
		case 0:
			return os.Stdin, nil, nil
		case 1:
			return os.Stdout, nil, nil
		case 2:
			return os.Stderr, nil, nil
		}
	case Pipe:
		r, w, err := os.Pipe()
		if err != nil {
			return nil, nil, err
		}
		if fd == 0 {
			return r, w, nil
		}
		return w, r, nil
	}
	return nil, nil, os.EINVAL
}

// Run starts the named binary running with
// arguments argv and environment envv.
// It returns a pointer to a new Cmd representing
// the command or an error.
//
// The parameters stdin, stdout, and stderr
// specify how to handle standard input, output, and error.
// The choices are DevNull (connect to /dev/null),
// PassThrough (connect to the current process's standard stream),
// Pipe (connect to an operating system pipe), and
// MergeWithStdout (only for standard error; use the same
// file descriptor as was used for standard output).
// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
// of the returned Cmd is the other end of the pipe.
// Otherwise the field in Cmd is nil.
func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
	c = new(Cmd)
	var fd [3]*os.File

	if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
		goto Error
	}
	if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
		goto Error
	}
	if stderr == MergeWithStdout {
		fd[2] = fd[1]
	} else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
		goto Error
	}

	// Run command.
	c.Process, err = os.StartProcess(name, argv, &os.ProcAttr{Dir: dir, Files: fd[:], Env: envv})
	if err != nil {
		goto Error
	}
	if fd[0] != os.Stdin {
		fd[0].Close()
	}
	if fd[1] != os.Stdout {
		fd[1].Close()
	}
	if fd[2] != os.Stderr && fd[2] != fd[1] {
		fd[2].Close()
	}
	return c, nil

Error:
	if fd[0] != os.Stdin && fd[0] != nil {
		fd[0].Close()
	}
	if fd[1] != os.Stdout && fd[1] != nil {
		fd[1].Close()
	}
	if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
		fd[2].Close()
	}
	if c.Stdin != nil {
		c.Stdin.Close()
	}
	if c.Stdout != nil {
		c.Stdout.Close()
	}
	if c.Stderr != nil {
		c.Stderr.Close()
	}
	if c.Process != nil {
		c.Process.Release()
	}
	return nil, err
}

// Wait waits for the running command c,
// returning the Waitmsg returned when the process exits.
// The options are passed to the process's Wait method.
// Setting options to 0 waits for c to exit;
// other options cause Wait to return for other
// process events; see package os for details.
func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
	if c.Process == nil {
		return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
	}
	w, err := c.Process.Wait(options)
	if w != nil && (w.Exited() || w.Signaled()) {
		c.Process.Release()
		c.Process = nil
	}
	return w, err
}

// Close waits for the running command c to exit,
// if it hasn't already, and then closes the non-nil file descriptors
// c.Stdin, c.Stdout, and c.Stderr.
func (c *Cmd) Close() os.Error {
	if c.Process != nil {
		// Loop on interrupt, but
		// ignore other errors -- maybe
		// caller has already waited for pid.
		_, err := c.Wait(0)
		for err == os.EINTR {
			_, err = c.Wait(0)
		}
	}

	// Close the FDs that are still open.
	var err os.Error
	if c.Stdin != nil && c.Stdin.Fd() >= 0 {
		if err1 := c.Stdin.Close(); err1 != nil {
			err = err1
		}
	}
	if c.Stdout != nil && c.Stdout.Fd() >= 0 {
		if err1 := c.Stdout.Close(); err1 != nil && err != nil {
			err = err1
		}
	}
	if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
		if err1 := c.Stderr.Close(); err1 != nil && err != nil {
			err = err1
		}
	}
	return err
}
<commit_msg>exec: document dir option for Run<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The exec package runs external commands.
package exec

import (
	"os"
	"strconv"
)

// Arguments to Run.
const (
	DevNull = iota
	PassThrough
	Pipe
	MergeWithStdout
)

// A Cmd represents a running command.
// Stdin, Stdout, and Stderr are Files representing pipes
// connected to the running command's standard input, output, and error,
// or else nil, depending on the arguments to Run.
// Process represents the underlying operating system process.
type Cmd struct {
	Stdin   *os.File
	Stdout  *os.File
	Stderr  *os.File
	Process *os.Process
}

// PathError records the name of a binary that was not
// found on the current $PATH.
type PathError struct {
	Name string
}

func (e *PathError) String() string {
	return "command " + strconv.Quote(e.Name) + " not found in $PATH"
}

// Given mode (DevNull, etc), return file for child
// and file to record in Cmd structure.
func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
	switch mode {
	case DevNull:
		rw := os.O_WRONLY
		if fd == 0 {
			rw = os.O_RDONLY
		}
		f, err := os.Open(os.DevNull, rw, 0)
		return f, nil, err
	case PassThrough:
		switch fd {
		case 0:
			return os.Stdin, nil, nil
		case 1:
			return os.Stdout, nil, nil
		case 2:
			return os.Stderr, nil, nil
		}
	case Pipe:
		r, w, err := os.Pipe()
		if err != nil {
			return nil, nil, err
		}
		if fd == 0 {
			return r, w, nil
		}
		return w, r, nil
	}
	return nil, nil, os.EINVAL
}

// Run starts the named binary running with
// arguments argv and environment envv.
// If the dir argument is not empty, the child changes
// into the directory before executing the binary.
// It returns a pointer to a new Cmd representing
// the command or an error.
//
// The arguments stdin, stdout, and stderr
// specify how to handle standard input, output, and error.
// The choices are DevNull (connect to /dev/null),
// PassThrough (connect to the current process's standard stream),
// Pipe (connect to an operating system pipe), and
// MergeWithStdout (only for standard error; use the same
// file descriptor as was used for standard output).
// If an argument is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
// of the returned Cmd is the other end of the pipe.
// Otherwise the field in Cmd is nil.
func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
	c = new(Cmd)
	var fd [3]*os.File

	if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
		goto Error
	}
	if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
		goto Error
	}
	if stderr == MergeWithStdout {
		fd[2] = fd[1]
	} else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
		goto Error
	}

	// Run command.
	c.Process, err = os.StartProcess(name, argv, &os.ProcAttr{Dir: dir, Files: fd[:], Env: envv})
	if err != nil {
		goto Error
	}
	if fd[0] != os.Stdin {
		fd[0].Close()
	}
	if fd[1] != os.Stdout {
		fd[1].Close()
	}
	if fd[2] != os.Stderr && fd[2] != fd[1] {
		fd[2].Close()
	}
	return c, nil

Error:
	if fd[0] != os.Stdin && fd[0] != nil {
		fd[0].Close()
	}
	if fd[1] != os.Stdout && fd[1] != nil {
		fd[1].Close()
	}
	if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
		fd[2].Close()
	}
	if c.Stdin != nil {
		c.Stdin.Close()
	}
	if c.Stdout != nil {
		c.Stdout.Close()
	}
	if c.Stderr != nil {
		c.Stderr.Close()
	}
	if c.Process != nil {
		c.Process.Release()
	}
	return nil, err
}

// Wait waits for the running command c,
// returning the Waitmsg returned when the process exits.
// The options are passed to the process's Wait method.
// Setting options to 0 waits for c to exit;
// other options cause Wait to return for other
// process events; see package os for details.
func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
	if c.Process == nil {
		return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
	}
	w, err := c.Process.Wait(options)
	if w != nil && (w.Exited() || w.Signaled()) {
		c.Process.Release()
		c.Process = nil
	}
	return w, err
}

// Close waits for the running command c to exit,
// if it hasn't already, and then closes the non-nil file descriptors
// c.Stdin, c.Stdout, and c.Stderr.
func (c *Cmd) Close() os.Error {
	if c.Process != nil {
		// Loop on interrupt, but
		// ignore other errors -- maybe
		// caller has already waited for pid.
		_, err := c.Wait(0)
		for err == os.EINTR {
			_, err = c.Wait(0)
		}
	}

	// Close the FDs that are still open.
	var err os.Error
	if c.Stdin != nil && c.Stdin.Fd() >= 0 {
		if err1 := c.Stdin.Close(); err1 != nil {
			err = err1
		}
	}
	if c.Stdout != nil && c.Stdout.Fd() >= 0 {
		if err1 := c.Stdout.Close(); err1 != nil && err != nil {
			err = err1
		}
	}
	if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
		if err1 := c.Stderr.Close(); err1 != nil && err != nil {
			err = err1
		}
	}
	return err
}
<|endoftext|>


<commit_before>package gommit

var appVersion = "2.1.2"

// GetVersion return app version
func GetVersion() string {
	return "v" + appVersion
}
<commit_msg>feat(version) : 2.1.3<commit_after>package gommit

var appVersion = "2.1.3"

// GetVersion return app version
func GetVersion() string {
	return "v" + appVersion
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/glendc/cgreader"
	"math"
	"strings"
)

type Station struct {
	name                string
	longitude, latitude float64
}

type Destination struct {
	hash uint32
	cost float64
}

var hashMap map[uint32]string
var identifierMap map[string]uint32

func GetInput(input <-chan string) string {
	line := <-input
	return string(line[9:])
}

func ToFloat(str string) (x float64) {
	fmt.Sscanf(str, "%f", &x)
	return
}

func GetCost(lo_a, lo_b, la_a, la_b float64) float64 {
	x, y := (lo_b-lo_a)*math.Cos((la_a+la_b)/2), la_b-la_a
	return x*x + y*y
}

var minCost float64 = math.MaxFloat64
var routes map[uint32][]Destination
var finalHash, startHash uint32
var finalRoute []uint32

func TravelRecursive(cost float64, route []uint32) {
	for _, destination := range routes[route[len(route)-1]] {
		if cost += destination.cost; cost < minCost {
			if destination.hash == finalHash {
				minCost = cost
				finalRoute = append(route, destination.hash)
			} else {
				isOK := true
				for _, stop := range route {
					if destination.hash == stop {
						isOK = false
						break
					}
				}
				if isOK {
					TravelRecursive(cost, append(route, destination.hash))
				}
			}
		}
	}
}

func main() {
	cgreader.RunAndValidateManualPrograms(
		cgreader.GetFileList("../../input/tan_network_%d.txt", 6),
		cgreader.GetFileList("../../output/tan_network_%d.txt", 6),
		true,
		func(input <-chan string, output chan string) {
			// this block could be ommited when solo-running
			minCost = math.MaxFloat64
			routes, finalRoute = nil, nil

			start, stop := GetInput(input), GetInput(input)
			hashMap = make(map[uint32]string)
			identifierMap = make(map[string]uint32)

			var ns, nr uint32
			fmt.Sscanf(<-input, "%d", &ns)
			stations := make(map[uint32]Station)
			for i := uint32(0); i < ns; i++ {
				station := GetInput(input)
				info := strings.Split(station, ",")
				hashMap[i] = info[0]
				identifierMap[info[0]] = i
				stations[i] = Station{
					info[1][1 : len(info[1])-1],
					ToFloat(info[3]),
					ToFloat(info[4])}
			}

			startHash, finalHash = identifierMap[start], identifierMap[stop]

			if startHash == finalHash {
				output <- stations[startHash].name
				return
			}

			fmt.Sscanf(<-input, "%d", &nr)
			routes = make(map[uint32][]Destination)
			for i := uint32(0); i < nr; i++ {
				route := GetInput(input)
				ra, ro := string(route[:4]), string(route[14:])
				ha, ho := identifierMap[ra], identifierMap[ro]

				a, b := stations[ha], stations[ho]
				cost := GetCost(
					a.latitude, b.latitude,
					a.longitude, b.longitude)

				routes[ha] = append(routes[ha], Destination{ho, cost})
			}

			TravelRecursive(0, append(make([]uint32, 0), startHash))

			if finalRoute == nil {
				output <- "IMPOSSIBLE"
			} else {
				for _, hash := range finalRoute {
					output <- stations[hash].name
				}
			}
		})
}
<commit_msg>performance fix<commit_after>package main

import (
	"fmt"
	"github.com/glendc/cgreader"
	"math"
	"strings"
)

type Station struct {
	name                string
	longitude, latitude float64
}

type Destination struct {
	hash uint32
	cost uint16
}

var hashMap map[uint32]string
var identifierMap map[string]uint32

func GetInput(input <-chan string) string {
	line := <-input
	return string(line[9:])
}

func ToFloat(str string) (x float64) {
	fmt.Sscanf(str, "%f", &x)
	return
}

func GetCost(lo_a, lo_b, la_a, la_b float64) uint16 {
	x, y := (lo_b-lo_a)*math.Cos((la_a+la_b)/2), la_b-la_a
	return uint16((x*x + y*y) * 100000.0)
}

var minCost uint16 = math.MaxUint16
var routes map[uint32][]Destination
var finalHash, startHash uint32
var finalRoute []uint32

func TravelRecursive(cost uint16, route []uint32) {
	for _, destination := range routes[route[len(route)-1]] {
		if cost += destination.cost; cost < minCost {
			if destination.hash == finalHash {
				minCost = cost
				finalRoute = append(route, destination.hash)
			} else {
				isOK := true
				for _, stop := range route {
					if destination.hash == stop {
						isOK = false
						break
					}
				}
				if isOK {
					TravelRecursive(cost, append(route, destination.hash))
				}
			}
		}
	}
}

func main() {
	cgreader.RunAndValidateManualPrograms(
		cgreader.GetFileList("../../input/tan_network_%d.txt", 6),
		cgreader.GetFileList("../../output/tan_network_%d.txt", 6),
		true,
		func(input <-chan string, output chan string) {
			// this block could be ommited when solo-running
			minCost = math.MaxUint16
			routes, finalRoute = nil, nil

			start, stop := GetInput(input), GetInput(input)
			hashMap = make(map[uint32]string)
			identifierMap = make(map[string]uint32)

			var ns, nr uint32
			fmt.Sscanf(<-input, "%d", &ns)
			stations := make(map[uint32]Station)
			for i := uint32(0); i < ns; i++ {
				station := GetInput(input)
				info := strings.Split(station, ",")
				hashMap[i] = info[0]
				identifierMap[info[0]] = i
				stations[i] = Station{
					info[1][1 : len(info[1])-1],
					ToFloat(info[3]),
					ToFloat(info[4])}
			}

			startHash, finalHash = identifierMap[start], identifierMap[stop]

			if startHash == finalHash {
				output <- stations[startHash].name
				return
			}

			fmt.Sscanf(<-input, "%d", &nr)
			routes = make(map[uint32][]Destination)
			for i := uint32(0); i < nr; i++ {
				route := GetInput(input)
				ra, ro := string(route[:4]), string(route[14:])
				ha, ho := identifierMap[ra], identifierMap[ro]

				a, b := stations[ha], stations[ho]
				cost := GetCost(
					a.latitude, b.latitude,
					a.longitude, b.longitude)

				routes[ha] = append(routes[ha], Destination{ho, cost})
			}

			TravelRecursive(0, append(make([]uint32, 0), startHash))

			if finalRoute == nil {
				output <- "IMPOSSIBLE"
			} else {
				for _, hash := range finalRoute {
					output <- stations[hash].name
				}
			}
		})
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package json

import (
	"bytes"
	"math"
	"reflect"
	"testing"
	"unicode"
)

type Optionals struct {
	Sr string `json:"sr"`
	So string `json:"so,omitempty"`
	Sw string `json:"-"`

	Ir int `json:"omitempty"` // actually named omitempty, not an option
	Io int `json:"io,omitempty"`

	Slr []string `json:"slr,random"`
	Slo []string `json:"slo,omitempty"`

	Mr map[string]interface{} `json:"mr"`
	Mo map[string]interface{} `json:",omitempty"`
}

var optionalsExpected = `{
 "sr": "",
 "omitempty": 0,
 "slr": null,
 "mr": {}
}`

func TestOmitEmpty(t *testing.T) {
	var o Optionals
	o.Sw = "something"
	o.Mr = map[string]interface{}{}
	o.Mo = map[string]interface{}{}

	got, err := MarshalIndent(&o, "", " ")
	if err != nil {
		t.Fatal(err)
	}
	if got := string(got); got != optionalsExpected {
		t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
	}
}

type StringTag struct {
	BoolStr bool   `json:",string"`
	IntStr  int64  `json:",string"`
	StrStr  string `json:",string"`
}

var stringTagExpected = `{
 "BoolStr": "true",
 "IntStr": "42",
 "StrStr": "\"xzbit\""
}`

func TestStringTag(t *testing.T) {
	var s StringTag
	s.BoolStr = true
	s.IntStr = 42
	s.StrStr = "xzbit"
	got, err := MarshalIndent(&s, "", " ")
	if err != nil {
		t.Fatal(err)
	}
	if got := string(got); got != stringTagExpected {
		t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
	}

	// Verify that it round-trips.
	var s2 StringTag
	err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
	if err != nil {
		t.Fatalf("Decode: %v", err)
	}
	if !reflect.DeepEqual(s, s2) {
		t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
	}
}

// byte slices are special even if they're renamed types.
type renamedByte byte
type renamedByteSlice []byte
type renamedRenamedByteSlice []renamedByte

func TestEncodeRenamedByteSlice(t *testing.T) {
	s := renamedByteSlice("abc")
	result, err := Marshal(s)
	if err != nil {
		t.Fatal(err)
	}
	expect := `"YWJj"`
	if string(result) != expect {
		t.Errorf(" got %s want %s", result, expect)
	}
	r := renamedRenamedByteSlice("abc")
	result, err = Marshal(r)
	if err != nil {
		t.Fatal(err)
	}
	if string(result) != expect {
		t.Errorf(" got %s want %s", result, expect)
	}
}

var unsupportedValues = []interface{}{
	math.NaN(),
	math.Inf(-1),
	math.Inf(1),
}

func TestUnsupportedValues(t *testing.T) {
	for _, v := range unsupportedValues {
		if _, err := Marshal(v); err != nil {
			if _, ok := err.(*UnsupportedValueError); !ok {
				t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
			}
		} else {
			t.Errorf("for %v, expected error", v)
		}
	}
}

// Ref has Marshaler and Unmarshaler methods with pointer receiver.
type Ref int

func (*Ref) MarshalJSON() ([]byte, error) {
	return []byte(`"ref"`), nil
}

func (r *Ref) UnmarshalJSON([]byte) error {
	*r = 12
	return nil
}

// Val has Marshaler methods with value receiver.
type Val int

func (Val) MarshalJSON() ([]byte, error) {
	return []byte(`"val"`), nil
}

// RefText has Marshaler and Unmarshaler methods with pointer receiver.
type RefText int

func (*RefText) MarshalText() ([]byte, error) {
	return []byte(`"ref"`), nil
}

func (r *RefText) UnmarshalText([]byte) error {
	*r = 13
	return nil
}

// ValText has Marshaler methods with value receiver.
type ValText int

func (ValText) MarshalText() ([]byte, error) {
	return []byte(`"val"`), nil
}

func TestRefValMarshal(t *testing.T) {
	var s = struct {
		R0 Ref
		R1 *Ref
		R2 RefText
		R3 *RefText
		V0 Val
		V1 *Val
		V2 ValText
		V3 *ValText
	}{
		R0: 12,
		R1: new(Ref),
		R2: 14,
		R3: new(RefText),
		V0: 13,
		V1: new(Val),
		V2: 15,
		V3: new(ValText),
	}
	const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
	b, err := Marshal(&s)
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

// C implements Marshaler and returns unescaped JSON.
type C int

func (C) MarshalJSON() ([]byte, error) {
	return []byte(`"<&>"`), nil
}

// CText implements Marshaler and returns unescaped text.
type CText int

func (CText) MarshalText() ([]byte, error) {
	return []byte(`"<&>"`), nil
}

func TestMarshalerEscaping(t *testing.T) {
	var c C
	want := `"\u003c\u0026\u003e"`
	b, err := Marshal(c)
	if err != nil {
		t.Fatalf("Marshal(c): %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("Marshal(c) = %#q, want %#q", got, want)
	}

	var ct CText
	want = `"\"\u003c\u0026\u003e\""`
	b, err = Marshal(ct)
	if err != nil {
		t.Fatalf("Marshal(ct): %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
	}
}

type IntType int

type MyStruct struct {
	IntType
}

func TestAnonymousNonstruct(t *testing.T) {
	var i IntType = 11
	a := MyStruct{i}
	const want = `{"IntType":11}`

	b, err := Marshal(a)
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

type BugA struct {
	S string
}

type BugB struct {
	BugA
	S string
}

type BugC struct {
	S string
}

// Legal Go: We never use the repeated embedded field (S).
type BugX struct {
	A int
	BugA
	BugB
}

// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
	v := BugB{
		BugA{"A"},
		"B",
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{"S":"B"}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
	// Now check that the duplicate field, S, does not appear.
	x := BugX{
		A: 23,
	}
	b, err = Marshal(x)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want = `{"A":23}`
	got = string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

type BugD struct { // Same as BugA after tagging.
	XXX string `json:"S"`
}

// BugD's tagged S field should dominate BugA's.
type BugY struct {
	BugA
	BugD
}

// Test that a field with a tag dominates untagged fields.
func TestTaggedFieldDominates(t *testing.T) {
	v := BugY{
		BugA{"BugA"},
		BugD{"BugD"},
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{"S":"BugD"}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

// There are no tags here, so S should not appear.
type BugZ struct {
	BugA
	BugC
	BugY // Contains a tagged S field through BugD; should not dominate.
}

func TestDuplicatedFieldDisappears(t *testing.T) {
	v := BugZ{
		BugA{"BugA"},
		BugC{"BugC"},
		BugY{
			BugA{"nested BugA"},
			BugD{"nested BugD"},
		},
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

func TestStringBytes(t *testing.T) {
	// Test that encodeState.stringBytes and encodeState.string use the same encoding.
	es := &encodeState{}
	var r []rune
	for i := '\u0000'; i <= unicode.MaxRune; i++ {
		r = append(r, i)
	}
	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
	_, err := es.string(s)
	if err != nil {
		t.Fatal(err)
	}

	esBytes := &encodeState{}
	_, err = esBytes.stringBytes([]byte(s))
	if err != nil {
		t.Fatal(err)
	}

	enc := es.Buffer.String()
	encBytes := esBytes.Buffer.String()
	if enc != encBytes {
		i := 0
		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
			i++
		}
		enc = enc[i:]
		encBytes = encBytes[i:]
		i = 0
		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
			i++
		}
		enc = enc[:len(enc)-i]
		encBytes = encBytes[:len(encBytes)-i]

		if len(enc) > 20 {
			enc = enc[:20] + "..."
		}
		if len(encBytes) > 20 {
			encBytes = encBytes[:20] + "..."
		}

		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
	}
}

func TestIssue6458(t *testing.T) {
	type Foo struct {
		M RawMessage
	}
	x := Foo{RawMessage(`"foo"`)}

	b, err := Marshal(&x)
	if err != nil {
		t.Fatal(err)
	}
	if want := `{"M":"foo"}`; string(b) != want {
		t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
	}

	b, err = Marshal(x)
	if err != nil {
		t.Fatal(err)
	}

	if want := `{"M":"ImZvbyI="}`; string(b) != want {
		t.Errorf("Marshal(x) = %#q; want %#q", b, want)
	}
}
<commit_msg>encoding/json: add test for HTMLEscape<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package json

import (
	"bytes"
	"math"
	"reflect"
	"testing"
	"unicode"
)

type Optionals struct {
	Sr string `json:"sr"`
	So string `json:"so,omitempty"`
	Sw string `json:"-"`

	Ir int `json:"omitempty"` // actually named omitempty, not an option
	Io int `json:"io,omitempty"`

	Slr []string `json:"slr,random"`
	Slo []string `json:"slo,omitempty"`

	Mr map[string]interface{} `json:"mr"`
	Mo map[string]interface{} `json:",omitempty"`
}

var optionalsExpected = `{
 "sr": "",
 "omitempty": 0,
 "slr": null,
 "mr": {}
}`

func TestOmitEmpty(t *testing.T) {
	var o Optionals
	o.Sw = "something"
	o.Mr = map[string]interface{}{}
	o.Mo = map[string]interface{}{}

	got, err := MarshalIndent(&o, "", " ")
	if err != nil {
		t.Fatal(err)
	}
	if got := string(got); got != optionalsExpected {
		t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
	}
}

type StringTag struct {
	BoolStr bool   `json:",string"`
	IntStr  int64  `json:",string"`
	StrStr  string `json:",string"`
}

var stringTagExpected = `{
 "BoolStr": "true",
 "IntStr": "42",
 "StrStr": "\"xzbit\""
}`

func TestStringTag(t *testing.T) {
	var s StringTag
	s.BoolStr = true
	s.IntStr = 42
	s.StrStr = "xzbit"
	got, err := MarshalIndent(&s, "", " ")
	if err != nil {
		t.Fatal(err)
	}
	if got := string(got); got != stringTagExpected {
		t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
	}

	// Verify that it round-trips.
	var s2 StringTag
	err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
	if err != nil {
		t.Fatalf("Decode: %v", err)
	}
	if !reflect.DeepEqual(s, s2) {
		t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
	}
}

// byte slices are special even if they're renamed types.
type renamedByte byte
type renamedByteSlice []byte
type renamedRenamedByteSlice []renamedByte

func TestEncodeRenamedByteSlice(t *testing.T) {
	s := renamedByteSlice("abc")
	result, err := Marshal(s)
	if err != nil {
		t.Fatal(err)
	}
	expect := `"YWJj"`
	if string(result) != expect {
		t.Errorf(" got %s want %s", result, expect)
	}
	r := renamedRenamedByteSlice("abc")
	result, err = Marshal(r)
	if err != nil {
		t.Fatal(err)
	}
	if string(result) != expect {
		t.Errorf(" got %s want %s", result, expect)
	}
}

var unsupportedValues = []interface{}{
	math.NaN(),
	math.Inf(-1),
	math.Inf(1),
}

func TestUnsupportedValues(t *testing.T) {
	for _, v := range unsupportedValues {
		if _, err := Marshal(v); err != nil {
			if _, ok := err.(*UnsupportedValueError); !ok {
				t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
			}
		} else {
			t.Errorf("for %v, expected error", v)
		}
	}
}

// Ref has Marshaler and Unmarshaler methods with pointer receiver.
type Ref int

func (*Ref) MarshalJSON() ([]byte, error) {
	return []byte(`"ref"`), nil
}

func (r *Ref) UnmarshalJSON([]byte) error {
	*r = 12
	return nil
}

// Val has Marshaler methods with value receiver.
type Val int

func (Val) MarshalJSON() ([]byte, error) {
	return []byte(`"val"`), nil
}

// RefText has Marshaler and Unmarshaler methods with pointer receiver.
type RefText int

func (*RefText) MarshalText() ([]byte, error) {
	return []byte(`"ref"`), nil
}

func (r *RefText) UnmarshalText([]byte) error {
	*r = 13
	return nil
}

// ValText has Marshaler methods with value receiver.
type ValText int

func (ValText) MarshalText() ([]byte, error) {
	return []byte(`"val"`), nil
}

func TestRefValMarshal(t *testing.T) {
	var s = struct {
		R0 Ref
		R1 *Ref
		R2 RefText
		R3 *RefText
		V0 Val
		V1 *Val
		V2 ValText
		V3 *ValText
	}{
		R0: 12,
		R1: new(Ref),
		R2: 14,
		R3: new(RefText),
		V0: 13,
		V1: new(Val),
		V2: 15,
		V3: new(ValText),
	}
	const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
	b, err := Marshal(&s)
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

// C implements Marshaler and returns unescaped JSON.
type C int

func (C) MarshalJSON() ([]byte, error) {
	return []byte(`"<&>"`), nil
}

// CText implements Marshaler and returns unescaped text.
type CText int

func (CText) MarshalText() ([]byte, error) {
	return []byte(`"<&>"`), nil
}

func TestMarshalerEscaping(t *testing.T) {
	var c C
	want := `"\u003c\u0026\u003e"`
	b, err := Marshal(c)
	if err != nil {
		t.Fatalf("Marshal(c): %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("Marshal(c) = %#q, want %#q", got, want)
	}

	var ct CText
	want = `"\"\u003c\u0026\u003e\""`
	b, err = Marshal(ct)
	if err != nil {
		t.Fatalf("Marshal(ct): %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
	}
}

type IntType int

type MyStruct struct {
	IntType
}

func TestAnonymousNonstruct(t *testing.T) {
	var i IntType = 11
	a := MyStruct{i}
	const want = `{"IntType":11}`

	b, err := Marshal(a)
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}
	if got := string(b); got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

type BugA struct {
	S string
}

type BugB struct {
	BugA
	S string
}

type BugC struct {
	S string
}

// Legal Go: We never use the repeated embedded field (S).
type BugX struct {
	A int
	BugA
	BugB
}

// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
	v := BugB{
		BugA{"A"},
		"B",
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{"S":"B"}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
	// Now check that the duplicate field, S, does not appear.
	x := BugX{
		A: 23,
	}
	b, err = Marshal(x)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want = `{"A":23}`
	got = string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

type BugD struct { // Same as BugA after tagging.
	XXX string `json:"S"`
}

// BugD's tagged S field should dominate BugA's.
type BugY struct {
	BugA
	BugD
}

// Test that a field with a tag dominates untagged fields.
func TestTaggedFieldDominates(t *testing.T) {
	v := BugY{
		BugA{"BugA"},
		BugD{"BugD"},
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{"S":"BugD"}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

// There are no tags here, so S should not appear.
type BugZ struct {
	BugA
	BugC
	BugY // Contains a tagged S field through BugD; should not dominate.
}

func TestDuplicatedFieldDisappears(t *testing.T) {
	v := BugZ{
		BugA{"BugA"},
		BugC{"BugC"},
		BugY{
			BugA{"nested BugA"},
			BugD{"nested BugD"},
		},
	}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal("Marshal:", err)
	}
	want := `{}`
	got := string(b)
	if got != want {
		t.Fatalf("Marshal: got %s want %s", got, want)
	}
}

func TestStringBytes(t *testing.T) {
	// Test that encodeState.stringBytes and encodeState.string use the same encoding.
	es := &encodeState{}
	var r []rune
	for i := '\u0000'; i <= unicode.MaxRune; i++ {
		r = append(r, i)
	}
	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
	_, err := es.string(s)
	if err != nil {
		t.Fatal(err)
	}

	esBytes := &encodeState{}
	_, err = esBytes.stringBytes([]byte(s))
	if err != nil {
		t.Fatal(err)
	}

	enc := es.Buffer.String()
	encBytes := esBytes.Buffer.String()
	if enc != encBytes {
		i := 0
		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
			i++
		}
		enc = enc[i:]
		encBytes = encBytes[i:]
		i = 0
		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
			i++
		}
		enc = enc[:len(enc)-i]
		encBytes = encBytes[:len(encBytes)-i]

		if len(enc) > 20 {
			enc = enc[:20] + "..."
		}
		if len(encBytes) > 20 {
			encBytes = encBytes[:20] + "..."
		}

		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
	}
}

func TestIssue6458(t *testing.T) {
	type Foo struct {
		M RawMessage
	}
	x := Foo{RawMessage(`"foo"`)}

	b, err := Marshal(&x)
	if err != nil {
		t.Fatal(err)
	}
	if want := `{"M":"foo"}`; string(b) != want {
		t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
	}

	b, err = Marshal(x)
	if err != nil {
		t.Fatal(err)
	}

	if want := `{"M":"ImZvbyI="}`; string(b) != want {
		t.Errorf("Marshal(x) = %#q; want %#q", b, want)
	}
}

func TestHTMLEscape(t *testing.T) {
	var b, want bytes.Buffer
	m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
	want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
	HTMLEscape(&b, []byte(m))
	if !bytes.Equal(b.Bytes(), want.Bytes()) {
		t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package html

import (
	"fmt"
)

// context describes the state an HTML parser must be in when it reaches the
// portion of HTML produced by evaluating a particular template node.
//
// The zero value of type context is the start context for a template that
// produces an HTML fragment as defined at
// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
// where the context element is null.
type context struct {
	state   state
	delim   delim
	urlPart urlPart
	jsCtx   jsCtx
	attr    attr
	element element
	err     *Error
}

// eq returns whether two contexts are equal.
func (c context) eq(d context) bool {
	return c.state == d.state &&
		c.delim == d.delim &&
		c.urlPart == d.urlPart &&
		c.jsCtx == d.jsCtx &&
		c.attr == d.attr &&
		c.element == d.element &&
		c.err == d.err
}

// mangle produces an identifier that includes a suffix that distinguishes it
// from template names mangled with different contexts.
func (c context) mangle(templateName string) string {
	// The mangled name for the default context is the input templateName.
	if c.state == stateText {
		return templateName
	}
	s := templateName + "$htmltemplate_" + c.state.String()
	if c.delim != 0 {
		s += "_" + c.delim.String()
	}
	if c.urlPart != 0 {
		s += "_" + c.urlPart.String()
	}
	if c.jsCtx != 0 {
		s += "_" + c.jsCtx.String()
	}
	if c.attr != 0 {
		s += "_" + c.attr.String()
	}
	if c.element != 0 {
		s += "_" + c.element.String()
	}
	return s
}

// state describes a high-level HTML parser state.
//
// It bounds the top of the element stack, and by extension the HTML insertion
// mode, but also contains state that does not correspond to anything in the
// HTML5 parsing algorithm because a single token production in the HTML
// grammar may contain embedded actions in a template. For instance, the quoted
// HTML attribute produced by
//

// is a single token in HTML's grammar but in a template spans several nodes.
type state uint8

const (
	// stateText is parsed character data. An HTML parser is in
	// this state when its parse position is outside an HTML tag,
	// directive, comment, and special element body.
	stateText state = iota
	// stateTag occurs before an HTML attribute or the end of a tag.
	stateTag
	// stateAttrName occurs inside an attribute name.
	// It occurs between the ^'s in ` ^name^ = value`.
	stateAttrName
	// stateAfterName occurs after an attr name has ended but before any
	// equals sign. It occurs between the ^'s in ` name^ ^= value`.
	stateAfterName
	// stateBeforeValue occurs after the equals sign but before the value.
	// It occurs between the ^'s in ` name =^ ^value`.
	stateBeforeValue
	// stateHTMLCmt occurs inside an .
	stateHTMLCmt
	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
	// as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
	stateRCDATA
	// stateAttr occurs inside an HTML attribute whose content is text.
	stateAttr
	// stateURL occurs inside an HTML attribute whose content is a URL.
	stateURL
	// stateJS occurs inside an event handler or script element.
	stateJS
	// stateJSDqStr occurs inside a JavaScript double quoted string.
	stateJSDqStr
	// stateJSSqStr occurs inside a JavaScript single quoted string.
	stateJSSqStr
	// stateJSRegexp occurs inside a JavaScript regexp literal.
	stateJSRegexp
	// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
	stateJSBlockCmt
	// stateJSLineCmt occurs inside a JavaScript // line comment.
	stateJSLineCmt
	// stateCSS occurs inside a


<commit_before>package songplayer

import (
	"fmt"
	"github.com/DexterLB/mpvipc"
	"gitlab.transip.us/swiltink/go-MusicBot/meta"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"
)

var youtubeURLRegex, _ = regexp.Compile(`^(https?://)?(www\.)?(youtube\.com|youtu\.?be)/.+$`)

type YoutubePlayer struct {
	mpvBinPath   string
	mpvInputPath string

	mpvProcess   *exec.Cmd
	mpvIsRunning bool
	mpvConn      *mpvipc.Connection
	ytService    *meta.YouTube
	mpvMutex     sync.Mutex
}

func NewYoutubePlayer(mpvBinPath, mpvInputPath string) (player *YoutubePlayer, err error) {
	player = &YoutubePlayer{
		mpvBinPath:   mpvBinPath,
		mpvInputPath: mpvInputPath,
		mpvIsRunning: false,
		ytService:    meta.NewYoutubeService(),
	}

	err = player.init()
	return
}

func (p *YoutubePlayer) init() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	fi, err := os.Stat(p.mpvInputPath)
	if err == nil && !fi.IsDir() {
		fmt.Printf("[YoutubePlayer] Removing existing MPV control node on %s\n", p.mpvInputPath)
		err = os.Remove(p.mpvInputPath)
		if err != nil {
			err = fmt.Errorf("[YoutubePlayer] Error removing existing input %s: %v", p.mpvInputPath, err)
			return
		}
	}

	err = p.startMpv()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error starting mpv: %v ", err)
		return
	}

	// Give MPV a second or so to start and create the input socket
	time.Sleep(time.Second)

	fmt.Printf("[YoutubePlayer] Opening mpv ipc connection on %s\n", p.mpvInputPath)
	p.mpvConn = mpvipc.NewConnection(p.mpvInputPath)
	err = p.mpvConn.Open()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error opening IPC connection on %s: %v ", p.mpvInputPath, err)
		return
	}
	return
}

func (p *YoutubePlayer) startMpv() (err error) {
	fmt.Printf("[YoutubePlayer] Starting MPV %s with control %s in idle mode\n", p.mpvBinPath, p.mpvInputPath)

	command := exec.Command(p.mpvBinPath, "--no-video", "--idle", "--input-ipc-server="+p.mpvInputPath)
	p.mpvProcess = command

	err = command.Start()
	p.mpvIsRunning = err == nil

	if err != nil {
		return
	}

	go func() {
		err := command.Wait()

		fmt.Printf("[YoutubePlayer] mpv has quit: %v\n", err)

		p.mpvMutex.Lock()
		p.mpvIsRunning = false
		p.mpvProcess = nil
		p.mpvMutex.Unlock()
	}()
	return
}

func (p *YoutubePlayer) checkRunning() (err error) {
	if p.mpvIsRunning && p.mpvProcess != nil {
		return
	}
	fmt.Print("[YoutubePlayer] mpv is not running, restarting mpv\n")
	err = p.init()
	return
}

func (p *YoutubePlayer) Name() (name string) {
	return "Youtube"
}

func (p *YoutubePlayer) CanPlay(url string) (canPlay bool) {
	return youtubeURLRegex.MatchString(url)
}

func (p *YoutubePlayer) GetSongs(url string) (songs []Playable, err error) {
	lowerURL := strings.ToLower(url)
	if strings.Contains(lowerURL, "player") || strings.Contains(lowerURL, "list=") {
		var metaDatas []meta.Meta
		metaDatas, err = p.ytService.GetMetasForPlaylistURL(url)
		if err == nil {
			for _, metaData := range metaDatas {
				songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
			}
			return
		}
		// On error, fall back to single add
	}

	metaData, err := p.ytService.GetMetaForURL(url)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error getting meta data: %v", err)
		return
	}
	songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	return
}

func (p *YoutubePlayer) SearchSongs(searchStr string, limit int) (songs []Playable, err error) {
	metaDatas, err := p.ytService.SearchForMetas(searchStr, limit)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error searching meta data: %v", err)
		return
	}

	for _, metaData := range metaDatas {
		songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	}
	return
}

func (p *YoutubePlayer) Play(url string) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.stop()
	if err != nil {
		return
	}

	_, err = p.mpvConn.Call("loadfile", url, "replace")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending loadfile command: %v", err)
		return
	}

	// Listen for events to find out when the file was actually downloaded from YouTube.
	events := make(chan *mpvipc.Event)
	stop := make(chan struct{})
	p.mpvConn.ListenForEvents(events, stop)
	for {
		event := <-events
		if event.Name == "file-loaded" {
			break
		}
	}
	// Stop listening to events again
	stop <- struct{}{}

	return
}

func (p *YoutubePlayer) Seek(positionSeconds int) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("time-pos", positionSeconds)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending time-pos property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Pause(pauseState bool) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("pause", pauseState)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending pause state property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Stop() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	return p.stop()
}

func (p *YoutubePlayer) stop() (err error) {
	err = p.checkRunning()
	if err != nil {
		return
	}

	_, err = p.mpvConn.Call("stop")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending stop command: %v", err)
	}
	return
}
<commit_msg>Fix the load listener<commit_after>package songplayer

import (
	"fmt"
	"github.com/DexterLB/mpvipc"
	"github.com/vansante/go-event-emitter"
	"gitlab.transip.us/swiltink/go-MusicBot/meta"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"
)

var youtubeURLRegex, _ = regexp.Compile(`^(https?://)?(www\.)?(youtube\.com|youtu\.?be)/.+$`)

type YoutubePlayer struct {
	mpvBinPath   string
	mpvInputPath string

	mpvProcess   *exec.Cmd
	mpvIsRunning bool
	mpvConn      *mpvipc.Connection
	ytService    *meta.YouTube
	mpvMutex     sync.Mutex
	mpvEvents    *eventemitter.Emitter
}

func NewYoutubePlayer(mpvBinPath, mpvInputPath string) (player *YoutubePlayer, err error) {
	player = &YoutubePlayer{
		mpvBinPath:   mpvBinPath,
		mpvInputPath: mpvInputPath,
		mpvIsRunning: false,
		ytService:    meta.NewYoutubeService(),
		mpvEvents:    eventemitter.NewEmitter(),
	}

	err = player.init()
	return
}

func (p *YoutubePlayer) init() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	fi, err := os.Stat(p.mpvInputPath)
	if err == nil && !fi.IsDir() {
		fmt.Printf("[YoutubePlayer] Removing existing MPV control node on %s\n", p.mpvInputPath)
		err = os.Remove(p.mpvInputPath)
		if err != nil {
			err = fmt.Errorf("[YoutubePlayer] Error removing existing input %s: %v", p.mpvInputPath, err)
			return
		}
	}

	err = p.startMpv()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error starting mpv: %v ", err)
		return
	}

	// Give MPV a second or so to start and create the input socket
	time.Sleep(time.Second)

	fmt.Printf("[YoutubePlayer] Opening mpv ipc connection on %s\n", p.mpvInputPath)
	p.mpvConn = mpvipc.NewConnection(p.mpvInputPath)
	err = p.mpvConn.Open()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error opening IPC connection on %s: %v ", p.mpvInputPath, err)
		return
	}

	go func() {
		events, stopListening := p.mpvConn.NewEventListener()
		for event := range events {
			p.mpvEvents.EmitEvent(event.Name, event)
		}
		stopListening <- struct{}{}
	}()

	return
}

func (p *YoutubePlayer) startMpv() (err error) {
	fmt.Printf("[YoutubePlayer] Starting MPV %s with control %s in idle mode\n", p.mpvBinPath, p.mpvInputPath)

	command := exec.Command(p.mpvBinPath, "--no-video", "--idle", "--input-ipc-server="+p.mpvInputPath)
	p.mpvProcess = command

	err = command.Start()
	p.mpvIsRunning = err == nil

	if err != nil {
		return
	}

	go func() {
		err := command.Wait()

		fmt.Printf("[YoutubePlayer] mpv has quit: %v\n", err)

		p.mpvMutex.Lock()
		p.mpvIsRunning = false
		p.mpvProcess = nil
		p.mpvMutex.Unlock()
	}()
	return
}

func (p *YoutubePlayer) checkRunning() (err error) {
	if p.mpvIsRunning && p.mpvProcess != nil {
		return
	}
	fmt.Print("[YoutubePlayer] mpv is not running, restarting mpv\n")
	err = p.init()
	return
}

func (p *YoutubePlayer) Name() (name string) {
	return "Youtube"
}

func (p *YoutubePlayer) CanPlay(url string) (canPlay bool) {
	return youtubeURLRegex.MatchString(url)
}

func (p *YoutubePlayer) GetSongs(url string) (songs []Playable, err error) {
	lowerURL := strings.ToLower(url)
	if strings.Contains(lowerURL, "player") || strings.Contains(lowerURL, "list=") {
		var metaDatas []meta.Meta
		metaDatas, err = p.ytService.GetMetasForPlaylistURL(url)
		if err == nil {
			for _, metaData := range metaDatas {
				songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
			}
			return
		}
		// On error, fall back to single add
	}

	metaData, err := p.ytService.GetMetaForURL(url)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error getting meta data: %v", err)
		return
	}
	songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	return
}

func (p *YoutubePlayer) SearchSongs(searchStr string, limit int) (songs []Playable, err error) {
	metaDatas, err := p.ytService.SearchForMetas(searchStr, limit)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error searching meta data: %v", err)
		return
	}

	for _, metaData := range metaDatas {
		songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	}
	return
}

func (p *YoutubePlayer) Play(url string) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.stop()
	if err != nil {
		return
	}

	waitForLoad := make(chan int)
	p.mpvEvents.ListenOnce("file-loaded", func(arguments ...interface{}) {
		waitForLoad <- 1
	})

	// Start an event listener to wait for the file to load.
	_, err = p.mpvConn.Call("loadfile", url, "replace")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending loadfile command: %v", err)
		return
	}
	<- waitForLoad

	return
}

func (p *YoutubePlayer) Seek(positionSeconds int) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("time-pos", positionSeconds)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending time-pos property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Pause(pauseState bool) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("pause", pauseState)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending pause state property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Stop() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	return p.stop()
}

func (p *YoutubePlayer) stop() (err error) {
	err = p.checkRunning()
	if err != nil {
		return
	}

	_, err = p.mpvConn.Call("stop")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending stop command: %v", err)
	}
	return
}
<|endoftext|>


<commit_before>package songplayer

import (
	"fmt"
	"github.com/DexterLB/mpvipc"
	"gitlab.transip.us/swiltink/go-MusicBot/meta"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
)

var youtubeURLRegex, _ = regexp.Compile(`^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$`)

type YoutubePlayer struct {
	mpvBinPath   string
	mpvInputPath string

	mpvProcess   *exec.Cmd
	mpvIsRunning bool
	mpvConn      *mpvipc.Connection
	ytService    *meta.YouTube
	mpvMutex     sync.Mutex
}

func NewYoutubePlayer(mpvBinPath, mpvInputPath string) (player *YoutubePlayer, err error) {
	player = &YoutubePlayer{
		mpvBinPath:   mpvBinPath,
		mpvInputPath: mpvInputPath,
		mpvIsRunning: false,
		ytService:    meta.NewYoutubeService(),
	}

	err = player.init()
	return
}

func (p *YoutubePlayer) init() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	fi, err := os.Stat(p.mpvInputPath)
	if err == nil && !fi.IsDir() {
		fmt.Printf("[YoutubePlayer] Removing existing MPV control node on %s\n", p.mpvInputPath)
		err = os.Remove(p.mpvInputPath)
		if err != nil {
			err = fmt.Errorf("[YoutubePlayer] Error removing existing input %s: %v", p.mpvInputPath, err)
			return
		}
	}

	err = p.startMpv()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error starting mpv: %v ", err)
		return
	}

	fmt.Printf("[YoutubePlayer] Opening mpv ipc connection on %s\n", p.mpvInputPath)
	p.mpvConn = mpvipc.NewConnection(p.mpvInputPath)
	err = p.mpvConn.Open()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error opening IPC connection on %s: %v ", p.mpvInputPath, err)
		return
	}
	return
}

func (p *YoutubePlayer) startMpv() (err error) {
	fmt.Printf("[YoutubePlayer] Starting MPV %s with control %s in idle mode\n", p.mpvBinPath, p.mpvInputPath)

	command := exec.Command(p.mpvBinPath, "--no-video", "--idle", "--input-ipc-server="+p.mpvInputPath)
	p.mpvProcess = command

	err = command.Start()
	p.mpvIsRunning = err == nil

	if err != nil {
		return
	}

	go func() {
		err := command.Wait()
		if err != nil {
			fmt.Printf("[YoutubePlayer] Error while waiting for mpv: %v\n", err)
			return
		}
		fmt.Print("[YoutubePlayer] mpv has quit\n")
		p.mpvMutex.Lock()
		p.mpvIsRunning = false
		p.mpvProcess = nil
		p.mpvMutex.Unlock()
	}()
	return
}

func (p *YoutubePlayer) checkRunning() (err error) {
	if p.mpvIsRunning && p.mpvProcess != nil {
		return
	}
	fmt.Print("[YoutubePlayer] mpv is not running, restarting mpv\n")
	err = p.init()
	return
}

func (p *YoutubePlayer) Name() (name string) {
	return "Youtube"
}

func (p *YoutubePlayer) CanPlay(url string) (canPlay bool) {
	return youtubeURLRegex.MatchString(url)
}

func (p *YoutubePlayer) GetSongs(url string) (songs []Playable, err error) {
	lowerURL := strings.ToLower(url)
	if strings.Contains(lowerURL, "player") || strings.Contains(lowerURL, "list=") {
		var metaDatas []meta.Meta
		metaDatas, err = p.ytService.GetMetasForPlaylistURL(url)
		if err == nil {
			for _, metaData := range metaDatas {
				songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
			}
			return
		}
		// On error, fall back to single add
	}

	metaData, err := p.ytService.GetMetaForURL(url)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error getting meta data: %v", err)
		return
	}
	songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	return
}

func (p *YoutubePlayer) SearchSongs(searchStr string, limit int) (songs []Playable, err error) {
	metaDatas, err := p.ytService.SearchForMetas(searchStr, limit)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error searching meta data: %v", err)
		return
	}

	for _, metaData := range metaDatas {
		songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	}
	return
}

func (p *YoutubePlayer) Play(url string) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.stop()
	if err != nil {
		return
	}
	_, err = p.mpvConn.Call("loadfile", "\""+url+"\"", "replace")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending loadfile command: %v", err)
		return
	}
	return
}

func (p *YoutubePlayer) Pause(pauseState bool) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("pause", pauseState)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending pause state property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Stop() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	return p.stop()
}

func (p *YoutubePlayer) stop() (err error) {
	err = p.checkRunning()
	if err != nil {
		return
	}

	_, err = p.mpvConn.Call("stop")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending stop command: %v", err)
	}
	return
}
<commit_msg>Add a little waiting time<commit_after>package songplayer

import (
	"fmt"
	"github.com/DexterLB/mpvipc"
	"gitlab.transip.us/swiltink/go-MusicBot/meta"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"
)

var youtubeURLRegex, _ = regexp.Compile(`^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$`)

type YoutubePlayer struct {
	mpvBinPath   string
	mpvInputPath string

	mpvProcess   *exec.Cmd
	mpvIsRunning bool
	mpvConn      *mpvipc.Connection
	ytService    *meta.YouTube
	mpvMutex     sync.Mutex
}

func NewYoutubePlayer(mpvBinPath, mpvInputPath string) (player *YoutubePlayer, err error) {
	player = &YoutubePlayer{
		mpvBinPath:   mpvBinPath,
		mpvInputPath: mpvInputPath,
		mpvIsRunning: false,
		ytService:    meta.NewYoutubeService(),
	}

	err = player.init()
	return
}

func (p *YoutubePlayer) init() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	fi, err := os.Stat(p.mpvInputPath)
	if err == nil && !fi.IsDir() {
		fmt.Printf("[YoutubePlayer] Removing existing MPV control node on %s\n", p.mpvInputPath)
		err = os.Remove(p.mpvInputPath)
		if err != nil {
			err = fmt.Errorf("[YoutubePlayer] Error removing existing input %s: %v", p.mpvInputPath, err)
			return
		}
	}

	err = p.startMpv()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error starting mpv: %v ", err)
		return
	}

	// Give MPV a second or so to start and create the input socket
	time.Sleep(time.Second)

	fmt.Printf("[YoutubePlayer] Opening mpv ipc connection on %s\n", p.mpvInputPath)
	p.mpvConn = mpvipc.NewConnection(p.mpvInputPath)
	err = p.mpvConn.Open()
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error opening IPC connection on %s: %v ", p.mpvInputPath, err)
		return
	}
	return
}

func (p *YoutubePlayer) startMpv() (err error) {
	fmt.Printf("[YoutubePlayer] Starting MPV %s with control %s in idle mode\n", p.mpvBinPath, p.mpvInputPath)

	command := exec.Command(p.mpvBinPath, "--no-video", "--idle", "--input-ipc-server="+p.mpvInputPath)
	p.mpvProcess = command

	err = command.Start()
	p.mpvIsRunning = err == nil

	if err != nil {
		return
	}

	go func() {
		err := command.Wait()
		if err != nil {
			fmt.Printf("[YoutubePlayer] Error while waiting for mpv: %v\n", err)
			return
		}
		fmt.Print("[YoutubePlayer] mpv has quit\n")
		p.mpvMutex.Lock()
		p.mpvIsRunning = false
		p.mpvProcess = nil
		p.mpvMutex.Unlock()
	}()
	return
}

func (p *YoutubePlayer) checkRunning() (err error) {
	if p.mpvIsRunning && p.mpvProcess != nil {
		return
	}
	fmt.Print("[YoutubePlayer] mpv is not running, restarting mpv\n")
	err = p.init()
	return
}

func (p *YoutubePlayer) Name() (name string) {
	return "Youtube"
}

func (p *YoutubePlayer) CanPlay(url string) (canPlay bool) {
	return youtubeURLRegex.MatchString(url)
}

func (p *YoutubePlayer) GetSongs(url string) (songs []Playable, err error) {
	lowerURL := strings.ToLower(url)
	if strings.Contains(lowerURL, "player") || strings.Contains(lowerURL, "list=") {
		var metaDatas []meta.Meta
		metaDatas, err = p.ytService.GetMetasForPlaylistURL(url)
		if err == nil {
			for _, metaData := range metaDatas {
				songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
			}
			return
		}
		// On error, fall back to single add
	}

	metaData, err := p.ytService.GetMetaForURL(url)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error getting meta data: %v", err)
		return
	}
	songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	return
}

func (p *YoutubePlayer) SearchSongs(searchStr string, limit int) (songs []Playable, err error) {
	metaDatas, err := p.ytService.SearchForMetas(searchStr, limit)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error searching meta data: %v", err)
		return
	}

	for _, metaData := range metaDatas {
		songs = append(songs, NewSong(metaData.Title, metaData.Duration, metaData.Source))
	}
	return
}

func (p *YoutubePlayer) Play(url string) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.stop()
	if err != nil {
		return
	}
	_, err = p.mpvConn.Call("loadfile", "\""+url+"\"", "replace")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending loadfile command: %v", err)
		return
	}
	return
}

func (p *YoutubePlayer) Pause(pauseState bool) (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	err = p.checkRunning()
	if err != nil {
		return
	}

	err = p.mpvConn.Set("pause", pauseState)
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending pause state property: %v", err)
	}
	return
}

func (p *YoutubePlayer) Stop() (err error) {
	p.mpvMutex.Lock()
	defer p.mpvMutex.Unlock()

	return p.stop()
}

func (p *YoutubePlayer) stop() (err error) {
	err = p.checkRunning()
	if err != nil {
		return
	}

	_, err = p.mpvConn.Call("stop")
	if err != nil {
		err = fmt.Errorf("[YoutubePlayer] Error sending stop command: %v", err)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/binary"
    "errors"
    "flag"
    "fmt"
    ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
    "io"
    "log"
    "math/rand"
    "net"
    "os"
    "path"
    "strconv"
    "strings"
    "time"
)

var debug ss.DebugLog

var (
    errAddrType      = errors.New("socks addr type not supported")
    errVer           = errors.New("socks version not supported")
    errMethod        = errors.New("socks only support 1 method now")
    errAuthExtraData = errors.New("socks authentication get extra data")
    errReqExtraData  = errors.New("socks request get extra data")
    errCmd           = errors.New("socks command not supported")
)

const (
    socksVer5       = 5
    socksCmdConnect = 1
)

func init() {
    rand.Seed(time.Now().Unix())
}

func handShake(conn net.Conn) (err error) {
    const (
        idVer     = 0
        idNmethod = 1
    )
    // version identification and method selection message in theory can have
    // at most 256 methods, plus version and nmethod field in total 258 bytes
    // the current rfc defines only 3 authentication methods (plus 2 reserved),
    // so it won't be such long in practice

    buf := make([]byte, 258)

    var n int
    // make sure we get the nmethod field
    if n, err = io.ReadAtLeast(conn, buf, idNmethod+1); err != nil {
        return
    }
    if buf[idVer] != socksVer5 {
        return errVer
    }
    nmethod := int(buf[idNmethod])
    msgLen := nmethod + 2
    if n == msgLen { // handshake done, common case
        // do nothing, jump directly to send confirmation
    } else if n < msgLen { // has more methods to read, rare case
        if _, err = io.ReadFull(conn, buf[n:msgLen]); err != nil {
            return
        }
    } else { // error, should not get extra data
        return errAuthExtraData
    }
    // send confirmation: version 5, no authentication required
    _, err = conn.Write([]byte{socksVer5, 0})
    return
}

func getRequest(conn net.Conn) (rawaddr []byte, host string, err error) {
    const (
        idVer   = 0
        idCmd   = 1
        idType  = 3 // address type index
        idIP0   = 4 // ip addres start index
        idDmLen = 4 // domain address length index
        idDm0   = 5 // domain address start index

        typeIPv4 = 1 // type is ipv4 address
        typeDm   = 3 // type is domain address
        typeIPv6 = 4 // type is ipv6 address

        lenIPv4   = 3 + 1 + net.IPv4len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv4 + 2port
        lenIPv6   = 3 + 1 + net.IPv6len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv6 + 2port
        lenDmBase = 3 + 1 + 1 + 2           // 3 + 1addrType + 1addrLen + 2port, plus addrLen
    )
    // refer to getRequest in server.go for why set buffer size to 263
    buf := make([]byte, 263)
    var n int
    // read till we get possible domain length field
    if n, err = io.ReadAtLeast(conn, buf, idDmLen+1); err != nil {
        return
    }
    // check version and cmd
    if buf[idVer] != socksVer5 {
        err = errVer
        return
    }
    if buf[idCmd] != socksCmdConnect {
        err = errCmd
        return
    }

    reqLen := -1
    switch buf[idType] {
    case typeIPv4:
        reqLen = lenIPv4
    case typeIPv6:
        reqLen = lenIPv6
    case typeDm:
        reqLen = int(buf[idDmLen]) + lenDmBase
    default:
        err = errAddrType
        return
    }

    if n == reqLen {
        // common case, do nothing
    } else if n < reqLen { // rare case
        if _, err = io.ReadFull(conn, buf[n:reqLen]); err != nil {
            return
        }
    } else {
        err = errReqExtraData
        return
    }

    rawaddr = buf[idType:reqLen]

    if debug {
        switch buf[idType] {
        case typeIPv4:
            host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
        case typeIPv6:
            host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
        case typeDm:
            host = string(buf[idDm0 : idDm0+buf[idDmLen]])
        }
        port := binary.BigEndian.Uint16(buf[reqLen-2 : reqLen])
        host = net.JoinHostPort(host, strconv.Itoa(int(port)))
    }

    return
}

type User struct {
    Name     string
    Password string
}

type ServerCipher struct {
    user   User
    server string
    cipher *ss.Cipher
}

var servers struct {
    srvCipher []*ServerCipher
    failCnt   []int // failed connection count
}

func extractUser(data string) (user User) {
    pack := strings.Split(data, ":")
    if len(pack) == 2 {
        user = User{pack[0], pack[1]}
    } else {
        user = User{pack[0], pack[0]}
    }
    return
}

func parseServerConfig(config *ss.Config) {
    hasPort := func(s string) bool {
        _, port, err := net.SplitHostPort(s)
        if err != nil {
            return false
        }
        return port != ""
    }

    if len(config.ServerPassword) == 0 {
        // only one encryption table
        user := extractUser(config.Password)
        cipher, err := ss.NewCipher(config.Method, user.Password)
        if err != nil {
            log.Fatal("Failed generating ciphers:", err)
        }
        srvPort := strconv.Itoa(config.ServerPort)
        srvArr := config.GetServerArray()
        n := len(srvArr)
        servers.srvCipher = make([]*ServerCipher, n)

        for i, s := range srvArr {
            if hasPort(s) {
                log.Println("ignore server_port option for server", s)
                servers.srvCipher[i] = &ServerCipher{user, s, cipher}
            } else {
                servers.srvCipher[i] = &ServerCipher{user, net.JoinHostPort(s, srvPort), cipher}
            }
        }
    } else {
        // multiple servers
        n := len(config.ServerPassword)
        servers.srvCipher = make([]*ServerCipher, n)

        cipherCache := make(map[string]*ss.Cipher)
        i := 0
        for _, serverInfo := range config.ServerPassword {
            if len(serverInfo) < 2 || len(serverInfo) > 3 {
                log.Fatalf("server %v syntax error\n", serverInfo)
            }
            server := serverInfo[0]
            passwd := serverInfo[1]
            encmethod := ""
            if len(serverInfo) == 3 {
                encmethod = serverInfo[2]
            }
            if !hasPort(server) {
                log.Fatalf("no port for server %s\n", server)
            }
            user := extractUser(passwd)
            cipher, ok := cipherCache[user.Password]
            if !ok {
                var err error
                cipher, err = ss.NewCipher(encmethod, user.Password)
                if err != nil {
                    log.Fatal("Failed generating ciphers:", err)
                }
                cipherCache[user.Password] = cipher
            }
            servers.srvCipher[i] = &ServerCipher{user, server, cipher}
            i++
        }
    }
    servers.failCnt = make([]int, len(servers.srvCipher))
    for _, se := range servers.srvCipher {
        log.Println("available remote server", se.server)
    }
    return
}

func DialWithRawAddr(rawaddr []byte, user User, server string, cipher *ss.Cipher) (remote *ss.Conn, err error) {
    conn, err := net.Dial("tcp", server)
    if err != nil {
        return nil, err
    }
    buf := make([]byte, 2)
    buf[0] = 1
    buf[1] = byte(len(user.Name))
    if _, err = conn.Write(buf); err != nil {
        conn.Close()
        return nil, err
    }
    if _, err = conn.Write([]byte(user.Name)); err != nil {
        conn.Close()
        return nil, err
    }
    remote = ss.NewConn(conn, cipher)
    if _, err = remote.Write(rawaddr); err != nil {
        remote.Close()
        return nil, err
    }
    return
}

func connectToServer(serverId int, rawaddr []byte, addr string) (remote *ss.Conn, err error) {
    se := servers.srvCipher[serverId]
    remote, err = DialWithRawAddr(rawaddr, se.user, se.server, se.cipher.Copy())
    if err != nil {
        log.Println("error connecting to shadowsocks server:", err)
        const maxFailCnt = 30
        if servers.failCnt[serverId] < maxFailCnt {
            servers.failCnt[serverId]++
        }
        return nil, err
    }
    debug.Printf("connected to %s via %s\n", addr, se.server)
    servers.failCnt[serverId] = 0
    return
}

// Connection to the server in the order specified in the config. On
// connection failure, try the next server. A failed server will be tried with
// some probability according to its fail count, so we can discover recovered
// servers.
func createServerConn(rawaddr []byte, addr string) (remote *ss.Conn, err error) {
    const baseFailCnt = 20
    n := len(servers.srvCipher)
    skipped := make([]int, 0)
    for i := 0; i < n; i++ {
        // skip failed server, but try it with some probability
        if servers.failCnt[i] > 0 && rand.Intn(servers.failCnt[i]+baseFailCnt) != 0 {
            skipped = append(skipped, i)
            continue
        }
        remote, err = connectToServer(i, rawaddr, addr)
        if err == nil {
            return
        }
    }
    // last resort, try skipped servers, not likely to succeed
    for _, i := range skipped {
        remote, err = connectToServer(i, rawaddr, addr)
        if err == nil {
            return
        }
    }
    return nil, err
}

func handleConnection(conn net.Conn) {
    if debug {
        debug.Printf("socks connect from %s\n", conn.RemoteAddr().String())
    }
    closed := false
    defer func() {
        if !closed {
            conn.Close()
        }
    }()

    var err error = nil
    if err = handShake(conn); err != nil {
        log.Println("socks handshake:", err)
        return
    }
    rawaddr, addr, err := getRequest(conn)
    if err != nil {
        log.Println("error getting request:", err)
        return
    }
    // Sending connection established message immediately to client.
    // This some round trip time for creating socks connection with the client.
    // But if connection failed, the client will get connection reset error.
    _, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
    if err != nil {
        debug.Println("send connection confirmation:", err)
        return
    }

    remote, err := createServerConn(rawaddr, addr)
    if err != nil {
        if len(servers.srvCipher) > 1 {
            log.Println("Failed connect to all avaiable shadowsocks server")
        }
        return
    }
    defer func() {
        if !closed {
            remote.Close()
        }
    }()

    go ss.PipeThenClose(conn, remote)
    ss.PipeThenClose(remote, conn)
    closed = true
    debug.Println("closed connection to", addr)
}

func run(listenAddr string) {
    ln, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("starting local socks5 server at %v ...\n", listenAddr)
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Println("accept:", err)
            continue
        }
        go handleConnection(conn)
    }
}

func enoughOptions(config *ss.Config) bool {
    return config.Server != nil && config.ServerPort != 0 &&
        config.LocalPort != 0 && config.Password != ""
}

func main() {
    log.SetOutput(os.Stdout)

    var configFile, cmdServer, cmdLocal string
    var cmdConfig ss.Config
    var printVer bool

    flag.BoolVar(&printVer, "version", false, "print version")
    flag.StringVar(&configFile, "c", "config.json", "specify config file")
    flag.StringVar(&cmdServer, "s", "", "server address")
    flag.StringVar(&cmdLocal, "b", "", "local address, listen only to this address if specified")
    flag.StringVar(&cmdConfig.Password, "k", "", "password")
    flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port")
    flag.IntVar(&cmdConfig.LocalPort, "l", 0, "local socks5 proxy port")
    flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, use empty string or rc4")
    flag.BoolVar((*bool)(&debug), "d", false, "print debug message")

    flag.Parse()

    if printVer {
        ss.PrintVersion()
        os.Exit(0)
    }

    cmdConfig.Server = cmdServer
    ss.SetDebug(debug)

    exists, err := ss.IsFileExists(configFile)
    // If no config file in current directory, try search it in the binary directory
    // Note there's no portable way to detect the binary directory.
    binDir := path.Dir(os.Args[0])
    if (!exists || err != nil) && binDir != "" && binDir != "." {
        oldConfig := configFile
        configFile = path.Join(binDir, "config.json")
        log.Printf("%s not found, try config file %s\n", oldConfig, configFile)
    }

    config, err := ss.ParseConfig(configFile)
    if err != nil {
        config = &cmdConfig
        if !os.IsNotExist(err) {
            fmt.Fprintf(os.Stderr, "error reading %s: %v\n", configFile, err)
            os.Exit(1)
        }
    } else {
        ss.UpdateConfig(config, &cmdConfig)
    }

    if len(config.ServerPassword) == 0 {
        if !enoughOptions(config) {
            fmt.Fprintln(os.Stderr, "must specify server address, password and both server/local port")
            os.Exit(1)
        }
    } else {
        if config.Password != "" || config.ServerPort != 0 || config.GetServerArray() != nil {
            fmt.Fprintln(os.Stderr, "given server_password, ignore server, server_port and password option:", config)
        }
        if config.LocalPort == 0 {
            fmt.Fprintln(os.Stderr, "must specify local port")
            os.Exit(1)
        }
    }

    parseServerConfig(config)

    run(cmdLocal + ":" + strconv.Itoa(config.LocalPort))
}
<commit_msg>fixed. compile error<commit_after>package main

import (
    "encoding/binary"
    "errors"
    "flag"
    "fmt"
    ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
    "io"
    "log"
    "math/rand"
    "net"
    "os"
    "path"
    "strconv"
    "strings"
    "time"
)

var debug ss.DebugLog

var (
    errAddrType      = errors.New("socks addr type not supported")
    errVer           = errors.New("socks version not supported")
    errMethod        = errors.New("socks only support 1 method now")
    errAuthExtraData = errors.New("socks authentication get extra data")
    errReqExtraData  = errors.New("socks request get extra data")
    errCmd           = errors.New("socks command not supported")
)

const (
    socksVer5       = 5
    socksCmdConnect = 1
)

func init() {
    rand.Seed(time.Now().Unix())
}

func handShake(conn net.Conn) (err error) {
    const (
        idVer     = 0
        idNmethod = 1
    )
    // version identification and method selection message in theory can have
    // at most 256 methods, plus version and nmethod field in total 258 bytes
    // the current rfc defines only 3 authentication methods (plus 2 reserved),
    // so it won't be such long in practice

    buf := make([]byte, 258)

    var n int
    // make sure we get the nmethod field
    if n, err = io.ReadAtLeast(conn, buf, idNmethod+1); err != nil {
        return
    }
    if buf[idVer] != socksVer5 {
        return errVer
    }
    nmethod := int(buf[idNmethod])
    msgLen := nmethod + 2
    if n == msgLen { // handshake done, common case
        // do nothing, jump directly to send confirmation
    } else if n < msgLen { // has more methods to read, rare case
        if _, err = io.ReadFull(conn, buf[n:msgLen]); err != nil {
            return
        }
    } else { // error, should not get extra data
        return errAuthExtraData
    }
    // send confirmation: version 5, no authentication required
    _, err = conn.Write([]byte{socksVer5, 0})
    return
}

func getRequest(conn net.Conn) (rawaddr []byte, host string, err error) {
    const (
        idVer   = 0
        idCmd   = 1
        idType  = 3 // address type index
        idIP0   = 4 // ip addres start index
        idDmLen = 4 // domain address length index
        idDm0   = 5 // domain address start index

        typeIPv4 = 1 // type is ipv4 address
        typeDm   = 3 // type is domain address
        typeIPv6 = 4 // type is ipv6 address

        lenIPv4   = 3 + 1 + net.IPv4len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv4 + 2port
        lenIPv6   = 3 + 1 + net.IPv6len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv6 + 2port
        lenDmBase = 3 + 1 + 1 + 2           // 3 + 1addrType + 1addrLen + 2port, plus addrLen
    )
    // refer to getRequest in server.go for why set buffer size to 263
    buf := make([]byte, 263)
    var n int
    // read till we get possible domain length field
    if n, err = io.ReadAtLeast(conn, buf, idDmLen+1); err != nil {
        return
    }
    // check version and cmd
    if buf[idVer] != socksVer5 {
        err = errVer
        return
    }
    if buf[idCmd] != socksCmdConnect {
        err = errCmd
        return
    }

    reqLen := -1
    switch buf[idType] {
    case typeIPv4:
        reqLen = lenIPv4
    case typeIPv6:
        reqLen = lenIPv6
    case typeDm:
        reqLen = int(buf[idDmLen]) + lenDmBase
    default:
        err = errAddrType
        return
    }

    if n == reqLen {
        // common case, do nothing
    } else if n < reqLen { // rare case
        if _, err = io.ReadFull(conn, buf[n:reqLen]); err != nil {
            return
        }
    } else {
        err = errReqExtraData
        return
    }

    rawaddr = buf[idType:reqLen]

    if debug {
        switch buf[idType] {
        case typeIPv4:
            host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
        case typeIPv6:
            host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
        case typeDm:
            host = string(buf[idDm0 : idDm0+buf[idDmLen]])
        }
        port := binary.BigEndian.Uint16(buf[reqLen-2 : reqLen])
        host = net.JoinHostPort(host, strconv.Itoa(int(port)))
    }

    return
}

type User struct {
    Name     string
    Password string
}

type ServerCipher struct {
    user   User
    server string
    cipher *ss.Cipher
}

var servers struct {
    srvCipher []*ServerCipher
    failCnt   []int // failed connection count
}

func extractUser(data string) (user User) {
    pack := strings.Split(data, ":")
    if len(pack) == 2 {
        user = User{pack[0], pack[1]}
    } else {
        user = User{pack[0], pack[0]}
    }
    return
}

func parseServerConfig(config *ss.Config) {
    hasPort := func(s string) bool {
        _, port, err := net.SplitHostPort(s)
        if err != nil {
            return false
        }
        return port != ""
    }

    if len(config.ServerPassword) == 0 {
        // only one encryption table
        user := extractUser(config.Password)
        cipher, err := ss.NewCipher(config.Method, user.Password)
        if err != nil {
            log.Fatal("Failed generating ciphers:", err)
        }
        srvPort := strconv.Itoa(config.ServerPort)
        srvArr := config.GetServerArray()
        n := len(srvArr)
        servers.srvCipher = make([]*ServerCipher, n)

        for i, s := range srvArr {
            if hasPort(s) {
                log.Println("ignore server_port option for server", s)
                servers.srvCipher[i] = &ServerCipher{user, s, cipher}
            } else {
                servers.srvCipher[i] = &ServerCipher{user, net.JoinHostPort(s, srvPort), cipher}
            }
        }
    } else {
        // multiple servers
        n := len(config.ServerPassword)
        servers.srvCipher = make([]*ServerCipher, n)

        cipherCache := make(map[string]*ss.Cipher)
        i := 0
        for _, serverInfo := range config.ServerPassword {
            if len(serverInfo) < 2 || len(serverInfo) > 3 {
                log.Fatalf("server %v syntax error\n", serverInfo)
            }
            server := serverInfo[0]
            passwd := serverInfo[1]
            encmethod := ""
            if len(serverInfo) == 3 {
                encmethod = serverInfo[2]
            }
            if !hasPort(server) {
                log.Fatalf("no port for server %s\n", server)
            }
            user := extractUser(passwd)
            cipher, ok := cipherCache[user.Password]
            if !ok {
                var err error
                cipher, err = ss.NewCipher(encmethod, user.Password)
                if err != nil {
                    log.Fatal("Failed generating ciphers:", err)
                }
                cipherCache[user.Password] = cipher
            }
            servers.srvCipher[i] = &ServerCipher{user, server, cipher}
            i++
        }
    }
    servers.failCnt = make([]int, len(servers.srvCipher))
    for _, se := range servers.srvCipher {
        log.Println("available remote server", se.server)
    }
    return
}

func DialWithRawAddr(rawaddr []byte, user User, server string, cipher *ss.Cipher) (remote *ss.Conn, err error) {
    conn, err := net.Dial("tcp", server)
    if err != nil {
        return nil, err
    }
    buf := make([]byte, 2)
    buf[0] = 1
    buf[1] = byte(len(user.Name))
    if _, err = conn.Write(buf); err != nil {
        conn.Close()
        return nil, err
    }
    if _, err = conn.Write([]byte(user.Name)); err != nil {
        conn.Close()
        return nil, err
    }
    remote = ss.NewConn(conn, cipher)
    if _, err = remote.Write(rawaddr); err != nil {
        remote.Close()
        return nil, err
    }
    return
}

func connectToServer(serverId int, rawaddr []byte, addr string) (remote *ss.Conn, err error) {
    se := servers.srvCipher[serverId]
    remote, err = DialWithRawAddr(rawaddr, se.user, se.server, se.cipher.Copy())
    if err != nil {
        log.Println("error connecting to shadowsocks server:", err)
        const maxFailCnt = 30
        if servers.failCnt[serverId] < maxFailCnt {
            servers.failCnt[serverId]++
        }
        return nil, err
    }
    debug.Printf("connected to %s via %s\n", addr, se.server)
    servers.failCnt[serverId] = 0
    return
}

// Connection to the server in the order specified in the config. On
// connection failure, try the next server. A failed server will be tried with
// some probability according to its fail count, so we can discover recovered
// servers.
func createServerConn(rawaddr []byte, addr string) (remote *ss.Conn, err error) {
    const baseFailCnt = 20
    n := len(servers.srvCipher)
    skipped := make([]int, 0)
    for i := 0; i < n; i++ {
        // skip failed server, but try it with some probability
        if servers.failCnt[i] > 0 && rand.Intn(servers.failCnt[i]+baseFailCnt) != 0 {
            skipped = append(skipped, i)
            continue
        }
        remote, err = connectToServer(i, rawaddr, addr)
        if err == nil {
            return
        }
    }
    // last resort, try skipped servers, not likely to succeed
    for _, i := range skipped {
        remote, err = connectToServer(i, rawaddr, addr)
        if err == nil {
            return
        }
    }
    return nil, err
}

func handleConnection(conn net.Conn) {
    if debug {
        debug.Printf("socks connect from %s\n", conn.RemoteAddr().String())
    }
    closed := false
    defer func() {
        if !closed {
            conn.Close()
        }
    }()

    var err error = nil
    if err = handShake(conn); err != nil {
        log.Println("socks handshake:", err)
        return
    }
    rawaddr, addr, err := getRequest(conn)
    if err != nil {
        log.Println("error getting request:", err)
        return
    }
    // Sending connection established message immediately to client.
    // This some round trip time for creating socks connection with the client.
    // But if connection failed, the client will get connection reset error.
    _, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
    if err != nil {
        debug.Println("send connection confirmation:", err)
        return
    }

    remote, err := createServerConn(rawaddr, addr)
    if err != nil {
        if len(servers.srvCipher) > 1 {
            log.Println("Failed connect to all avaiable shadowsocks server")
        }
        return
    }
    defer func() {
        if !closed {
            remote.Close()
        }
    }()

    go ss.PipeThenClose(conn, remote, nil)
    ss.PipeThenClose(remote, conn, nil)
    closed = true
    debug.Println("closed connection to", addr)
}

func run(listenAddr string) {
    ln, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("starting local socks5 server at %v ...\n", listenAddr)
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Println("accept:", err)
            continue
        }
        go handleConnection(conn)
    }
}

func enoughOptions(config *ss.Config) bool {
    return config.Server != nil && config.ServerPort != 0 &&
        config.LocalPort != 0 && config.Password != ""
}

func main() {
    log.SetOutput(os.Stdout)

    var configFile, cmdServer, cmdLocal string
    var cmdConfig ss.Config
    var printVer bool

    flag.BoolVar(&printVer, "version", false, "print version")
    flag.StringVar(&configFile, "c", "config.json", "specify config file")
    flag.StringVar(&cmdServer, "s", "", "server address")
    flag.StringVar(&cmdLocal, "b", "", "local address, listen only to this address if specified")
    flag.StringVar(&cmdConfig.Password, "k", "", "password")
    flag.IntVar(&cmdConfig.ServerPort, "p", 0, "server port")
    flag.IntVar(&cmdConfig.LocalPort, "l", 0, "local socks5 proxy port")
    flag.StringVar(&cmdConfig.Method, "m", "", "encryption method, use empty string or rc4")
    flag.BoolVar((*bool)(&debug), "d", false, "print debug message")

    flag.Parse()

    if printVer {
        ss.PrintVersion()
        os.Exit(0)
    }

    cmdConfig.Server = cmdServer
    ss.SetDebug(debug)

    exists, err := ss.IsFileExists(configFile)
    // If no config file in current directory, try search it in the binary directory
    // Note there's no portable way to detect the binary directory.
    binDir := path.Dir(os.Args[0])
    if (!exists || err != nil) && binDir != "" && binDir != "." {
        oldConfig := configFile
        configFile = path.Join(binDir, "config.json")
        log.Printf("%s not found, try config file %s\n", oldConfig, configFile)
    }

    config, err := ss.ParseConfig(configFile)
    if err != nil {
        config = &cmdConfig
        if !os.IsNotExist(err) {
            fmt.Fprintf(os.Stderr, "error reading %s: %v\n", configFile, err)
            os.Exit(1)
        }
    } else {
        ss.UpdateConfig(config, &cmdConfig)
    }

    if len(config.ServerPassword) == 0 {
        if !enoughOptions(config) {
            fmt.Fprintln(os.Stderr, "must specify server address, password and both server/local port")
            os.Exit(1)
        }
    } else {
        if config.Password != "" || config.ServerPort != 0 || config.GetServerArray() != nil {
            fmt.Fprintln(os.Stderr, "given server_password, ignore server, server_port and password option:", config)
        }
        if config.LocalPort == 0 {
            fmt.Fprintln(os.Stderr, "must specify local port")
            os.Exit(1)
        }
    }

    parseServerConfig(config)

    run(cmdLocal + ":" + strconv.Itoa(config.LocalPort))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	exif "github.com/garyhouston/exif44"
	tiff "github.com/garyhouston/tiff66"
	"log"
	"os"
)

// Recursively print an IFD node, its subIFDs, and next IFD.
func printTree(format exif.FileFormat, node *tiff.IFDNode, maxLen uint32) {
	fmt.Println()
	fields := node.Fields
	space := node.GetSpace()
	fmt.Printf("%s IFD with %d ", space.Name(), len(fields))
	if len(fields) != 1 {
		fmt.Println("entries:")
	} else {
		fmt.Println("entry:")
	}
	order := node.Order
	names := exif.TagNameMap(space)
	for i := 0; i < len(fields); i++ {
		fields[i].Print(order, names, maxLen)
	}
	for i := 0; i < len(node.SubIFDs); i++ {
		printTree(format, node.SubIFDs[i].Node, maxLen)
	}
	if format == exif.FileJPEG && node.Next != nil {
		printTree(format, node.Next, maxLen)
	}
}

// Exif handler.
type readExif struct {
	maxLen uint32
}

func (readExif readExif) ReadExif(format exif.FileFormat, imageIdx uint32, exif exif.Exif) error {
	if imageIdx > 0 {
		fmt.Println()
		fmt.Println("== Processing Image ", imageIdx+1, "==")
	}
	printTree(format, exif.TIFF, readExif.maxLen)
	return nil
}

// Read and print all the IFDs of a TIFF file, or Exif segment of a
// JPEG file, including any private IFDs that can be detected.
func main() {
	var maxLen uint
	flag.UintVar(&maxLen, "m", 20, "maximum values to print or 0 for no limit")
	flag.Parse()
	if flag.NArg() != 1 {
		fmt.Printf("Usage: %s [-m max values] file\n", os.Args[0])
		return
	}
	var control exif.ReadControl
	control.ReadExif = readExif{maxLen: uint32(maxLen)}
	if err := exif.ReadFile(flag.Arg(0), control); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Print more information when files have errors.<commit_after>package main

import (
	"flag"
	"fmt"
	exif "github.com/garyhouston/exif44"
	tiff "github.com/garyhouston/tiff66"
	"log"
	"os"
)

// Recursively print an IFD node, its subIFDs, and next IFD.
func printTree(format exif.FileFormat, node *tiff.IFDNode, maxLen uint32) {
	fmt.Println()
	fields := node.Fields
	space := node.GetSpace()
	fmt.Printf("%s IFD with %d ", space.Name(), len(fields))
	if len(fields) != 1 {
		fmt.Println("entries:")
	} else {
		fmt.Println("entry:")
	}
	order := node.Order
	names := exif.TagNameMap(space)
	for i := 0; i < len(fields); i++ {
		fields[i].Print(order, names, maxLen)
	}
	for i := 0; i < len(node.SubIFDs); i++ {
		printTree(format, node.SubIFDs[i].Node, maxLen)
	}
	if format == exif.FileJPEG && node.Next != nil {
		printTree(format, node.Next, maxLen)
	}
}

// Exif handler.
type readExif struct {
	maxLen uint32
}

func (readExif readExif) ReadExif(format exif.FileFormat, imageIdx uint32, exif exif.Exif, err error) error {
	if imageIdx > 0 {
		fmt.Println()
		fmt.Println("== Processing Image ", imageIdx+1, "==")
	}
	printTree(format, exif.TIFF, readExif.maxLen)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	return nil
}

// Read and print all the IFDs of a TIFF file, or Exif segment of a
// JPEG file, including any private IFDs that can be detected.
func main() {
	var maxLen uint
	flag.UintVar(&maxLen, "m", 20, "maximum values to print or 0 for no limit")
	flag.Parse()
	if flag.NArg() != 1 {
		fmt.Printf("Usage: %s [-m max values] file\n", os.Args[0])
		return
	}
	var control exif.ReadControl
	control.ReadExif = readExif{maxLen: uint32(maxLen)}
	if err := exif.ReadFile(flag.Arg(0), control); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>