<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	"fmt"
	"reflect"
	"time"

	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	"github.com/TheThingsNetwork/ttn/core/handler/functions"
	"github.com/TheThingsNetwork/ttn/core/types"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/apex/log"
)

// ConvertFieldsUp converts the payload to fields using payload functions
func (h *handler) ConvertFieldsUp(ctx log.Interface, ttnUp *pb_broker.DeduplicatedUplinkMessage, appUp *types.UplinkMessage) error {
	// Find Application
	app, err := h.applications.Get(ttnUp.AppId)
	if err != nil {
		return nil // Do not process if application not found
	}

	functions := &UplinkFunctions{
		Decoder:   app.Decoder,
		Converter: app.Converter,
		Validator: app.Validator,
		Logger:    functions.Ignore,
	}

	fields, valid, err := functions.Process(appUp.PayloadRaw, appUp.FPort)
	if err != nil {
		return nil // Do not set fields if processing failed
	}

	if !valid {
		return errors.NewErrInvalidArgument("Payload", "payload validator function returned false")
	}

	appUp.PayloadFields = fields

	return nil
}

// UplinkFunctions decodes, converts and validates payload using JavaScript functions
type UplinkFunctions struct {
	// Decoder is a JavaScript function that accepts the payload as byte array and
	// returns an object containing the decoded values
	Decoder string
	// Converter is a JavaScript function that accepts the data as decoded by
	// Decoder and returns an object containing the converted values
	Converter string
	// Validator is a JavaScript function that validates the data is converted by
	// Converter and returns a boolean value indicating the validity of the data
	Validator string

	// Logger is the logger that will be used to store logs
	Logger functions.Logger
}

// timeOut is the maximum allowed time a payload function is allowed to run
var timeOut = 100 * time.Millisecond

// Decode decodes the payload using the Decoder function into a map
func (f *UplinkFunctions) Decode(payload []byte, port uint8) (map[string]interface{}, error) {
	if f.Decoder == "" {
		return nil, errors.NewErrInternal("Decoder function not set")
	}

	env := map[string]interface{}{
		"payload": payload,
		"port":    port,
	}
	code := fmt.Sprintf(`
		%s;
		Decoder(payload.slice(0), port);
	`, f.Decoder)

	value, err := functions.RunCode("decoder", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object")
	}

	v, _ := value.Export()
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object")
	}
	return m, nil
}

// Convert converts the values in the specified map to a another map using the
// Converter function. If the Converter function is not set, this function
// returns the data as-is
func (f *UplinkFunctions) Convert(fields map[string]interface{}, port uint8) (map[string]interface{}, error) {
	if f.Converter == "" {
		return fields, nil
	}

	env := map[string]interface{}{
		"fields": fields,
		"port":   port,
	}

	code := fmt.Sprintf(`
		%s;
		Converter(fields, port)
	`, f.Converter)

	value, err := functions.RunCode("converter", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Converter", "does not return an object")
	}

	v, _ := value.Export()
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil, errors.NewErrInvalidArgument("Converter", "does not return an object")
	}

	return m, nil
}

// Validate validates the values in the specified map using the Validator
// function. If the Validator function is not set, this function returns true
func (f *UplinkFunctions) Validate(fields map[string]interface{}, port uint8) (bool, error) {
	if f.Validator == "" {
		return true, nil
	}

	env := map[string]interface{}{
		"fields": fields,
		"port":   port,
	}
	code := fmt.Sprintf(`
		%s;
		Validator(fields, port)
	`, f.Validator)

	value, err := functions.RunCode("valdator", code, env, timeOut, f.Logger)
	if err != nil {
		return false, err
	}

	if !value.IsBoolean() {
		return false, errors.NewErrInvalidArgument("Validator", "does not return a boolean")
	}

	return value.ToBoolean()
}

// Process decodes the specified payload, converts it and test the validity
func (f *UplinkFunctions) Process(payload []byte, port uint8) (map[string]interface{}, bool, error) {
	decoded, err := f.Decode(payload, port)
	if err != nil {
		return nil, false, err
	}

	converted, err := f.Convert(decoded, port)
	if err != nil {
		return nil, false, err
	}

	valid, err := f.Validate(converted, port)
	return converted, valid, err
}

// DownlinkFunctions encodes payload using JavaScript functions
type DownlinkFunctions struct {
	// Encoder is a JavaScript function that accepts the payload as JSON and
	// returns an array of bytes
	Encoder string

	// Logger is the logger that will be used to store logs
	Logger functions.Logger
}

// Encode encodes the map into a byte slice using the encoder payload function
// If no encoder function is set, this function returns an array.
func (f *DownlinkFunctions) Encode(payload map[string]interface{}, port uint8) ([]byte, error) {
	if f.Encoder == "" {
		return nil, errors.NewErrInternal("Encoder function not set")
	}

	env := map[string]interface{}{
		"payload": payload,
		"port":    port,
	}
	code := fmt.Sprintf(`
		%s;
		Encoder(payload, port)
	`, f.Encoder)

	value, err := functions.RunCode("encoder", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Encoder", "does not return an object")
	}

	v, err := value.Export()
	if err != nil {
		return nil, err
	}

	if reflect.TypeOf(v).Kind() != reflect.Slice {
		return nil, errors.NewErrInvalidArgument("Encoder", "does not return an Array")
	}

	s := reflect.ValueOf(v)
	l := s.Len()

	res := make([]byte, l)

	var n int64
	for i := 0; i < l; i++ {
		el := s.Index(i).Interface()

		// type switch does not have fallthrough so we need
		// to check every element individually
		switch t := el.(type) {
		case byte:
			n = int64(t)
		case int:
			n = int64(t)
		case int8:
			n = int64(t)
		case int16:
			n = int64(t)
		case uint16:
			n = int64(t)
		case int32:
			n = int64(t)
		case uint32:
			n = int64(t)
		case int64:
			n = int64(t)
		case uint64:
			n = int64(t)
		case float32:
			n = int64(t)
			if float32(n) != t {
				return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
			}
		case float64:
			n = int64(t)
			if float64(n) != t {
				return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
			}
		default:
			return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
		}

		if n < 0 || n > 255 {
			return nil, errors.NewErrInvalidArgument("Encoder Output", "Numbers in Array should be between 0 and 255")
		}

		res[i] = byte(n)
	}

	return res, nil
}

// Process encode the specified field, converts it into a valid payload
func (f *DownlinkFunctions) Process(payload map[string]interface{}, port uint8) ([]byte, bool, error) {
	encoded, err := f.Encode(payload, port)
	if err != nil {
		return nil, false, err
	}

	return encoded, true, nil
}

// ConvertFieldsDown converts the fields into a payload
func (h *handler) ConvertFieldsDown(ctx log.Interface, appDown *types.DownlinkMessage, ttnDown *pb_broker.DownlinkMessage) error {
	if appDown.PayloadFields == nil {
		return nil
	}

	if appDown.PayloadRaw != nil {
		return errors.NewErrInvalidArgument("Downlink", "Both Fields and Payload provided")
	}

	app, err := h.applications.Get(appDown.AppID)
	if err != nil {
		return nil
	}

	functions := &DownlinkFunctions{
		Encoder: app.Encoder,
		Logger:  functions.Ignore,
	}

	message, _, err := functions.Process(appDown.PayloadFields, appDown.FPort)
	if err != nil {
		return err
	}

	appDown.PayloadRaw = message

	return nil
}
<commit_msg>Check for downlink fields length and return better error if no encoder set<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package handler

import (
	"fmt"
	"reflect"
	"time"

	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	"github.com/TheThingsNetwork/ttn/core/handler/functions"
	"github.com/TheThingsNetwork/ttn/core/types"
	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/apex/log"
)

// ConvertFieldsUp converts the payload to fields using payload functions
func (h *handler) ConvertFieldsUp(ctx log.Interface, ttnUp *pb_broker.DeduplicatedUplinkMessage, appUp *types.UplinkMessage) error {
	// Find Application
	app, err := h.applications.Get(ttnUp.AppId)
	if err != nil {
		return nil // Do not process if application not found
	}

	functions := &UplinkFunctions{
		Decoder:   app.Decoder,
		Converter: app.Converter,
		Validator: app.Validator,
		Logger:    functions.Ignore,
	}

	fields, valid, err := functions.Process(appUp.PayloadRaw, appUp.FPort)
	if err != nil {
		return nil // Do not set fields if processing failed
	}

	if !valid {
		return errors.NewErrInvalidArgument("Payload", "payload validator function returned false")
	}

	appUp.PayloadFields = fields

	return nil
}

// UplinkFunctions decodes, converts and validates payload using JavaScript functions
type UplinkFunctions struct {
	// Decoder is a JavaScript function that accepts the payload as byte array and
	// returns an object containing the decoded values
	Decoder string
	// Converter is a JavaScript function that accepts the data as decoded by
	// Decoder and returns an object containing the converted values
	Converter string
	// Validator is a JavaScript function that validates the data is converted by
	// Converter and returns a boolean value indicating the validity of the data
	Validator string

	// Logger is the logger that will be used to store logs
	Logger functions.Logger
}

// timeOut is the maximum allowed time a payload function is allowed to run
var timeOut = 100 * time.Millisecond

// Decode decodes the payload using the Decoder function into a map
func (f *UplinkFunctions) Decode(payload []byte, port uint8) (map[string]interface{}, error) {
	if f.Decoder == "" {
		return nil, errors.NewErrInternal("Decoder function not set")
	}

	env := map[string]interface{}{
		"payload": payload,
		"port":    port,
	}
	code := fmt.Sprintf(`
		%s;
		Decoder(payload.slice(0), port);
	`, f.Decoder)

	value, err := functions.RunCode("decoder", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object")
	}

	v, _ := value.Export()
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object")
	}
	return m, nil
}

// Convert converts the values in the specified map to a another map using the
// Converter function. If the Converter function is not set, this function
// returns the data as-is
func (f *UplinkFunctions) Convert(fields map[string]interface{}, port uint8) (map[string]interface{}, error) {
	if f.Converter == "" {
		return fields, nil
	}

	env := map[string]interface{}{
		"fields": fields,
		"port":   port,
	}

	code := fmt.Sprintf(`
		%s;
		Converter(fields, port)
	`, f.Converter)

	value, err := functions.RunCode("converter", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Converter", "does not return an object")
	}

	v, _ := value.Export()
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil, errors.NewErrInvalidArgument("Converter", "does not return an object")
	}

	return m, nil
}

// Validate validates the values in the specified map using the Validator
// function. If the Validator function is not set, this function returns true
func (f *UplinkFunctions) Validate(fields map[string]interface{}, port uint8) (bool, error) {
	if f.Validator == "" {
		return true, nil
	}

	env := map[string]interface{}{
		"fields": fields,
		"port":   port,
	}
	code := fmt.Sprintf(`
		%s;
		Validator(fields, port)
	`, f.Validator)

	value, err := functions.RunCode("valdator", code, env, timeOut, f.Logger)
	if err != nil {
		return false, err
	}

	if !value.IsBoolean() {
		return false, errors.NewErrInvalidArgument("Validator", "does not return a boolean")
	}

	return value.ToBoolean()
}

// Process decodes the specified payload, converts it and test the validity
func (f *UplinkFunctions) Process(payload []byte, port uint8) (map[string]interface{}, bool, error) {
	decoded, err := f.Decode(payload, port)
	if err != nil {
		return nil, false, err
	}

	converted, err := f.Convert(decoded, port)
	if err != nil {
		return nil, false, err
	}

	valid, err := f.Validate(converted, port)
	return converted, valid, err
}

// DownlinkFunctions encodes payload using JavaScript functions
type DownlinkFunctions struct {
	// Encoder is a JavaScript function that accepts the payload as JSON and
	// returns an array of bytes
	Encoder string

	// Logger is the logger that will be used to store logs
	Logger functions.Logger
}

// Encode encodes the map into a byte slice using the encoder payload function
// If no encoder function is set, this function returns an array.
func (f *DownlinkFunctions) Encode(payload map[string]interface{}, port uint8) ([]byte, error) {
	if f.Encoder == "" {
		return nil, errors.NewErrInvalidArgument("Downlink Payload", "fields supplied, but no Encoder function set")
	}

	env := map[string]interface{}{
		"payload": payload,
		"port":    port,
	}
	code := fmt.Sprintf(`
		%s;
		Encoder(payload, port)
	`, f.Encoder)

	value, err := functions.RunCode("encoder", code, env, timeOut, f.Logger)
	if err != nil {
		return nil, err
	}

	if !value.IsObject() {
		return nil, errors.NewErrInvalidArgument("Encoder", "does not return an object")
	}

	v, err := value.Export()
	if err != nil {
		return nil, err
	}

	if reflect.TypeOf(v).Kind() != reflect.Slice {
		return nil, errors.NewErrInvalidArgument("Encoder", "does not return an Array")
	}

	s := reflect.ValueOf(v)
	l := s.Len()

	res := make([]byte, l)

	var n int64
	for i := 0; i < l; i++ {
		el := s.Index(i).Interface()

		// type switch does not have fallthrough so we need
		// to check every element individually
		switch t := el.(type) {
		case byte:
			n = int64(t)
		case int:
			n = int64(t)
		case int8:
			n = int64(t)
		case int16:
			n = int64(t)
		case uint16:
			n = int64(t)
		case int32:
			n = int64(t)
		case uint32:
			n = int64(t)
		case int64:
			n = int64(t)
		case uint64:
			n = int64(t)
		case float32:
			n = int64(t)
			if float32(n) != t {
				return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
			}
		case float64:
			n = int64(t)
			if float64(n) != t {
				return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
			}
		default:
			return nil, errors.NewErrInvalidArgument("Encoder", "should return an Array of integer numbers")
		}

		if n < 0 || n > 255 {
			return nil, errors.NewErrInvalidArgument("Encoder Output", "Numbers in Array should be between 0 and 255")
		}

		res[i] = byte(n)
	}

	return res, nil
}

// Process encode the specified field, converts it into a valid payload
func (f *DownlinkFunctions) Process(payload map[string]interface{}, port uint8) ([]byte, bool, error) {
	encoded, err := f.Encode(payload, port)
	if err != nil {
		return nil, false, err
	}

	return encoded, true, nil
}

// ConvertFieldsDown converts the fields into a payload
func (h *handler) ConvertFieldsDown(ctx log.Interface, appDown *types.DownlinkMessage, ttnDown *pb_broker.DownlinkMessage) error {
	if appDown.PayloadFields == nil || len(appDown.PayloadFields) == 0 {
		return nil
	}

	if appDown.PayloadRaw != nil {
		return errors.NewErrInvalidArgument("Downlink", "Both Fields and Payload provided")
	}

	app, err := h.applications.Get(appDown.AppID)
	if err != nil {
		return nil
	}

	functions := &DownlinkFunctions{
		Encoder: app.Encoder,
		Logger:  functions.Ignore,
	}

	message, _, err := functions.Process(appDown.PayloadFields, appDown.FPort)
	if err != nil {
		return err
	}

	appDown.PayloadRaw = message

	return nil
}
<|endoftext|>


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

SPDX-License-Identifier: Apache-2.0
*/

package operations_test

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/hyperledger/fabric-lib-go/healthz"
	"github.com/hyperledger/fabric/common/metrics/disabled"
	"github.com/hyperledger/fabric/common/metrics/prometheus"
	"github.com/hyperledger/fabric/common/metrics/statsd"
	"github.com/hyperledger/fabric/core/operations"
	"github.com/hyperledger/fabric/core/operations/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
)

var _ = Describe("System", func() {
	var (
		fakeLogger *fakes.Logger
		tempDir    string

		client       *http.Client
		unauthClient *http.Client
		options      operations.Options
		system       *operations.System
	)

	BeforeEach(func() {
		var err error
		tempDir, err := ioutil.TempDir("", "opssys")
		Expect(err).NotTo(HaveOccurred())

		generateCertificates(tempDir)
		client = newHTTPClient(tempDir, true)
		unauthClient = newHTTPClient(tempDir, false)

		fakeLogger = &fakes.Logger{}
		options = operations.Options{
			Logger:        fakeLogger,
			ListenAddress: "127.0.0.1:0",
			Metrics: operations.MetricsOptions{
				Provider: "disabled",
			},
			TLS: operations.TLS{
				Enabled:            true,
				CertFile:           filepath.Join(tempDir, "server-cert.pem"),
				KeyFile:            filepath.Join(tempDir, "server-key.pem"),
				ClientCertRequired: false,
				ClientCACertFiles:  []string{filepath.Join(tempDir, "client-ca.pem")},
			},
			Version: "test-version",
		}

		system = operations.NewSystem(options)
	})

	AfterEach(func() {
		os.RemoveAll(tempDir)
		if system != nil {
			system.Stop()
		}
	})

	It("hosts an unsecured endpoint for the version information", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		versionURL := fmt.Sprintf("https://%s/version", system.Addr())
		resp, err := client.Get(versionURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
		resp.Body.Close()
	})

	It("hosts a secure endpoint for logging", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		logspecURL := fmt.Sprintf("https://%s/logspec", system.Addr())
		resp, err := client.Get(logspecURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
		resp.Body.Close()

		resp, err = unauthClient.Get(logspecURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
	})

	Context("when TLS is disabled", func() {
		BeforeEach(func() {
			options.TLS.Enabled = false
			system = operations.NewSystem(options)
		})

		It("hosts an insecure endpoint for logging", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			resp, err := client.Get(fmt.Sprintf("http://%s/logspec", system.Addr()))
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			resp.Body.Close()
		})
	})

	Context("when ClientCertRequired is true", func() {
		BeforeEach(func() {
			options.TLS.ClientCertRequired = true
			system = operations.NewSystem(options)
		})

		It("requires a client cert to connect", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			_, err = unauthClient.Get(fmt.Sprintf("https://%s/healthz", system.Addr()))
			Expect(err).To(MatchError(ContainSubstring("remote error: tls: bad certificate")))
		})
	})

	Context("when listen fails", func() {
		var listener net.Listener

		BeforeEach(func() {
			var err error
			listener, err = net.Listen("tcp", "127.0.0.1:0")
			Expect(err).NotTo(HaveOccurred())

			options.ListenAddress = listener.Addr().String()
			system = operations.NewSystem(options)
		})

		AfterEach(func() {
			listener.Close()
		})

		It("returns an error", func() {
			err := system.Start()
			Expect(err).To(MatchError(ContainSubstring("bind: address already in use")))
		})
	})

	Context("when a bad TLS configuration is provided", func() {
		BeforeEach(func() {
			options.TLS.CertFile = "cert-file-does-not-exist"
			system = operations.NewSystem(options)
		})

		It("returns an error", func() {
			err := system.Start()
			Expect(err).To(MatchError("open cert-file-does-not-exist: no such file or directory"))
		})
	})

	It("proxies Log to the provided logger", func() {
		err := system.Log("key", "value")
		Expect(err).NotTo(HaveOccurred())

		Expect(fakeLogger.WarnCallCount()).To(Equal(1))
		Expect(fakeLogger.WarnArgsForCall(0)).To(Equal([]interface{}{"key", "value"}))
	})

	Context("when a logger is not provided", func() {
		BeforeEach(func() {
			options.Logger = nil
			system = operations.NewSystem(options)
		})

		It("does not panic when logging", func() {
			Expect(func() { system.Log("key", "value") }).NotTo(Panic())
		})

		It("returns nil from Log", func() {
			err := system.Log("key", "value")
			Expect(err).NotTo(HaveOccurred())
		})
	})

	It("hosts a health check endpoint", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		healthy := &fakes.HealthChecker{}
		unhealthy := &fakes.HealthChecker{}
		unhealthy.HealthCheckReturns(errors.New("Unfortunately, I am not feeling well."))

		system.RegisterChecker("healthy", healthy)
		system.RegisterChecker("unhealthy", unhealthy)

		resp, err := client.Get(fmt.Sprintf("https://%s/healthz", system.Addr()))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
		body, err := ioutil.ReadAll(resp.Body)
		Expect(err).NotTo(HaveOccurred())
		resp.Body.Close()

		var healthStatus healthz.HealthStatus
		err = json.Unmarshal(body, &healthStatus)
		Expect(err).NotTo(HaveOccurred())
		Expect(healthStatus.Status).To(Equal(healthz.StatusUnavailable))
		Expect(healthStatus.FailedChecks).To(ConsistOf(healthz.FailedCheck{
			Component: "unhealthy",
			Reason:    "Unfortunately, I am not feeling well.",
		}))
	})

	Context("when the metrics provider is disabled", func() {
		BeforeEach(func() {
			options.Metrics = operations.MetricsOptions{
				Provider: "disabled",
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		It("sets up a disabled provider", func() {
			Expect(system.Provider).To(Equal(&disabled.Provider{}))
		})
	})

	Context("when the metrics provider is prometheus", func() {
		BeforeEach(func() {
			options.Metrics = operations.MetricsOptions{
				Provider: "prometheus",
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		It("sets up prometheus as a provider", func() {
			Expect(system.Provider).To(Equal(&prometheus.Provider{}))
		})

		It("hosts a secure endpoint for metrics", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			metricsURL := fmt.Sprintf("https://%s/metrics", system.Addr())
			resp, err := client.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			body, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			Expect(err).NotTo(HaveOccurred())
			Expect(body).To(ContainSubstring("# TYPE go_gc_duration_seconds summary"))

			resp, err = unauthClient.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
		})

		It("records the fabric version", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			metricsURL := fmt.Sprintf("https://%s/metrics", system.Addr())
			resp, err := client.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			body, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			Expect(err).NotTo(HaveOccurred())
			Expect(string(body)).To(ContainSubstring("# TYPE fabric_version gauge"))
			Expect(string(body)).To(ContainSubstring(`fabric_version{version="test-version"}`))
		})
	})

	Context("when the metrics provider is statsd", func() {
		var listener net.Listener

		BeforeEach(func() {
			var err error
			listener, err = net.Listen("tcp", "127.0.0.1:0")
			Expect(err).NotTo(HaveOccurred())

			options.Metrics = operations.MetricsOptions{
				Provider: "statsd",
				Statsd: &operations.Statsd{
					Network:       "tcp",
					Address:       listener.Addr().String(),
					WriteInterval: 100 * time.Millisecond,
					Prefix:        "prefix",
				},
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		recordStats := func(w io.Writer) {
			defer GinkgoRecover()

			// handle the dial check
			conn, err := listener.Accept()
			if err != nil {
				return
			}
			conn.Close()

			// handle the payload
			conn, err = listener.Accept()
			Expect(err).NotTo(HaveOccurred())
			defer conn.Close()

			conn.SetReadDeadline(time.Now().Add(time.Minute))
			_, err = io.Copy(w, conn)
			if err != nil && err != io.EOF {
				Expect(err).NotTo(HaveOccurred())
			}
		}

		AfterEach(func() {
			listener.Close()
		})

		It("sets up statsd as a provider", func() {
			provider, ok := system.Provider.(*statsd.Provider)
			Expect(ok).To(BeTrue())
			Expect(provider.Statsd).NotTo(BeNil())
		})

		It("emits statsd metrics", func() {
			statsBuffer := gbytes.NewBuffer()
			go recordStats(statsBuffer)

			err := system.Start()
			Expect(err).NotTo(HaveOccurred())
			Eventually(statsBuffer).Should(gbytes.Say(`\Qprefix.go.mem.gc_last_epoch_nanotime:\E`))
		})

		It("emits the fabric version statsd metric", func() {
			statsBuffer := gbytes.NewBuffer()
			go recordStats(statsBuffer)

			err := system.Start()
			Expect(err).NotTo(HaveOccurred())
			Eventually(statsBuffer).Should(gbytes.Say(`\Qprefix.fabric_version.test-version:1.000000|g\E`))
		})

		Context("when checking the network and address fails", func() {
			BeforeEach(func() {
				options.Metrics.Statsd.Network = "bob-the-network"
				system = operations.NewSystem(options)
			})

			It("returns an error", func() {
				err := system.Start()
				Expect(err).To(MatchError(ContainSubstring("bob-the-network")))
			})
		})
	})

	Context("when the metrics provider is unknown", func() {
		BeforeEach(func() {
			options.Metrics.Provider = "something-unknown"
			system = operations.NewSystem(options)
		})

		It("sets up a disabled provider", func() {
			Expect(system.Provider).To(Equal(&disabled.Provider{}))
		})

		It("logs the issue", func() {
			Expect(fakeLogger.WarnfCallCount()).To(Equal(1))
			msg, args := fakeLogger.WarnfArgsForCall(0)
			Expect(msg).To(Equal("Unknown provider type: %s; metrics disabled"))
			Expect(args).To(Equal([]interface{}{"something-unknown"}))
		})
	})

	It("supports ifrit", func() {
		process := ifrit.Invoke(system)
		Eventually(process.Ready()).Should(BeClosed())

		process.Signal(syscall.SIGTERM)
		Eventually(process.Wait()).Should(Receive(BeNil()))
	})

	Context("when start fails and ifrit is used", func() {
		BeforeEach(func() {
			options.TLS.CertFile = "non-existent-file"
			system = operations.NewSystem(options)
		})

		It("does not close the ready chan", func() {
			process := ifrit.Invoke(system)
			Consistently(process.Ready()).ShouldNot(BeClosed())
			Eventually(process.Wait()).Should(Receive(MatchError("open non-existent-file: no such file or directory")))
		})
	})
})
<commit_msg>Fix temporary directory cleanup in core/operations<commit_after>/*
Copyright IBM Corp All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package operations_test

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/hyperledger/fabric-lib-go/healthz"
	"github.com/hyperledger/fabric/common/metrics/disabled"
	"github.com/hyperledger/fabric/common/metrics/prometheus"
	"github.com/hyperledger/fabric/common/metrics/statsd"
	"github.com/hyperledger/fabric/core/operations"
	"github.com/hyperledger/fabric/core/operations/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/tedsuo/ifrit"
)

var _ = Describe("System", func() {
	var (
		fakeLogger *fakes.Logger
		tempDir    string

		client       *http.Client
		unauthClient *http.Client
		options      operations.Options
		system       *operations.System
	)

	BeforeEach(func() {
		var err error
		tempDir, err = ioutil.TempDir("", "opssys")
		Expect(err).NotTo(HaveOccurred())

		generateCertificates(tempDir)
		client = newHTTPClient(tempDir, true)
		unauthClient = newHTTPClient(tempDir, false)

		fakeLogger = &fakes.Logger{}
		options = operations.Options{
			Logger:        fakeLogger,
			ListenAddress: "127.0.0.1:0",
			Metrics: operations.MetricsOptions{
				Provider: "disabled",
			},
			TLS: operations.TLS{
				Enabled:            true,
				CertFile:           filepath.Join(tempDir, "server-cert.pem"),
				KeyFile:            filepath.Join(tempDir, "server-key.pem"),
				ClientCertRequired: false,
				ClientCACertFiles:  []string{filepath.Join(tempDir, "client-ca.pem")},
			},
			Version: "test-version",
		}

		system = operations.NewSystem(options)
	})

	AfterEach(func() {
		os.RemoveAll(tempDir)
		if system != nil {
			system.Stop()
		}
	})

	It("hosts an unsecured endpoint for the version information", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		versionURL := fmt.Sprintf("https://%s/version", system.Addr())
		resp, err := client.Get(versionURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
		resp.Body.Close()
	})

	It("hosts a secure endpoint for logging", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		logspecURL := fmt.Sprintf("https://%s/logspec", system.Addr())
		resp, err := client.Get(logspecURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusOK))
		resp.Body.Close()

		resp, err = unauthClient.Get(logspecURL)
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
	})

	Context("when TLS is disabled", func() {
		BeforeEach(func() {
			options.TLS.Enabled = false
			system = operations.NewSystem(options)
		})

		It("hosts an insecure endpoint for logging", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			resp, err := client.Get(fmt.Sprintf("http://%s/logspec", system.Addr()))
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			resp.Body.Close()
		})
	})

	Context("when ClientCertRequired is true", func() {
		BeforeEach(func() {
			options.TLS.ClientCertRequired = true
			system = operations.NewSystem(options)
		})

		It("requires a client cert to connect", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			_, err = unauthClient.Get(fmt.Sprintf("https://%s/healthz", system.Addr()))
			Expect(err).To(MatchError(ContainSubstring("remote error: tls: bad certificate")))
		})
	})

	Context("when listen fails", func() {
		var listener net.Listener

		BeforeEach(func() {
			var err error
			listener, err = net.Listen("tcp", "127.0.0.1:0")
			Expect(err).NotTo(HaveOccurred())

			options.ListenAddress = listener.Addr().String()
			system = operations.NewSystem(options)
		})

		AfterEach(func() {
			listener.Close()
		})

		It("returns an error", func() {
			err := system.Start()
			Expect(err).To(MatchError(ContainSubstring("bind: address already in use")))
		})
	})

	Context("when a bad TLS configuration is provided", func() {
		BeforeEach(func() {
			options.TLS.CertFile = "cert-file-does-not-exist"
			system = operations.NewSystem(options)
		})

		It("returns an error", func() {
			err := system.Start()
			Expect(err).To(MatchError("open cert-file-does-not-exist: no such file or directory"))
		})
	})

	It("proxies Log to the provided logger", func() {
		err := system.Log("key", "value")
		Expect(err).NotTo(HaveOccurred())

		Expect(fakeLogger.WarnCallCount()).To(Equal(1))
		Expect(fakeLogger.WarnArgsForCall(0)).To(Equal([]interface{}{"key", "value"}))
	})

	Context("when a logger is not provided", func() {
		BeforeEach(func() {
			options.Logger = nil
			system = operations.NewSystem(options)
		})

		It("does not panic when logging", func() {
			Expect(func() { system.Log("key", "value") }).NotTo(Panic())
		})

		It("returns nil from Log", func() {
			err := system.Log("key", "value")
			Expect(err).NotTo(HaveOccurred())
		})
	})

	It("hosts a health check endpoint", func() {
		err := system.Start()
		Expect(err).NotTo(HaveOccurred())

		healthy := &fakes.HealthChecker{}
		unhealthy := &fakes.HealthChecker{}
		unhealthy.HealthCheckReturns(errors.New("Unfortunately, I am not feeling well."))

		system.RegisterChecker("healthy", healthy)
		system.RegisterChecker("unhealthy", unhealthy)

		resp, err := client.Get(fmt.Sprintf("https://%s/healthz", system.Addr()))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
		body, err := ioutil.ReadAll(resp.Body)
		Expect(err).NotTo(HaveOccurred())
		resp.Body.Close()

		var healthStatus healthz.HealthStatus
		err = json.Unmarshal(body, &healthStatus)
		Expect(err).NotTo(HaveOccurred())
		Expect(healthStatus.Status).To(Equal(healthz.StatusUnavailable))
		Expect(healthStatus.FailedChecks).To(ConsistOf(healthz.FailedCheck{
			Component: "unhealthy",
			Reason:    "Unfortunately, I am not feeling well.",
		}))
	})

	Context("when the metrics provider is disabled", func() {
		BeforeEach(func() {
			options.Metrics = operations.MetricsOptions{
				Provider: "disabled",
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		It("sets up a disabled provider", func() {
			Expect(system.Provider).To(Equal(&disabled.Provider{}))
		})
	})

	Context("when the metrics provider is prometheus", func() {
		BeforeEach(func() {
			options.Metrics = operations.MetricsOptions{
				Provider: "prometheus",
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		It("sets up prometheus as a provider", func() {
			Expect(system.Provider).To(Equal(&prometheus.Provider{}))
		})

		It("hosts a secure endpoint for metrics", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			metricsURL := fmt.Sprintf("https://%s/metrics", system.Addr())
			resp, err := client.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			body, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			Expect(err).NotTo(HaveOccurred())
			Expect(body).To(ContainSubstring("# TYPE go_gc_duration_seconds summary"))

			resp, err = unauthClient.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
		})

		It("records the fabric version", func() {
			err := system.Start()
			Expect(err).NotTo(HaveOccurred())

			metricsURL := fmt.Sprintf("https://%s/metrics", system.Addr())
			resp, err := client.Get(metricsURL)
			Expect(err).NotTo(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(http.StatusOK))
			body, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			Expect(err).NotTo(HaveOccurred())
			Expect(string(body)).To(ContainSubstring("# TYPE fabric_version gauge"))
			Expect(string(body)).To(ContainSubstring(`fabric_version{version="test-version"}`))
		})
	})

	Context("when the metrics provider is statsd", func() {
		var listener net.Listener

		BeforeEach(func() {
			var err error
			listener, err = net.Listen("tcp", "127.0.0.1:0")
			Expect(err).NotTo(HaveOccurred())

			options.Metrics = operations.MetricsOptions{
				Provider: "statsd",
				Statsd: &operations.Statsd{
					Network:       "tcp",
					Address:       listener.Addr().String(),
					WriteInterval: 100 * time.Millisecond,
					Prefix:        "prefix",
				},
			}
			system = operations.NewSystem(options)
			Expect(system).NotTo(BeNil())
		})

		recordStats := func(w io.Writer) {
			defer GinkgoRecover()

			// handle the dial check
			conn, err := listener.Accept()
			if err != nil {
				return
			}
			conn.Close()

			// handle the payload
			conn, err = listener.Accept()
			Expect(err).NotTo(HaveOccurred())
			defer conn.Close()

			conn.SetReadDeadline(time.Now().Add(time.Minute))
			_, err = io.Copy(w, conn)
			if err != nil && err != io.EOF {
				Expect(err).NotTo(HaveOccurred())
			}
		}

		AfterEach(func() {
			listener.Close()
		})

		It("sets up statsd as a provider", func() {
			provider, ok := system.Provider.(*statsd.Provider)
			Expect(ok).To(BeTrue())
			Expect(provider.Statsd).NotTo(BeNil())
		})

		It("emits statsd metrics", func() {
			statsBuffer := gbytes.NewBuffer()
			go recordStats(statsBuffer)

			err := system.Start()
			Expect(err).NotTo(HaveOccurred())
			Eventually(statsBuffer).Should(gbytes.Say(`\Qprefix.go.mem.gc_last_epoch_nanotime:\E`))
		})

		It("emits the fabric version statsd metric", func() {
			statsBuffer := gbytes.NewBuffer()
			go recordStats(statsBuffer)

			err := system.Start()
			Expect(err).NotTo(HaveOccurred())
			Eventually(statsBuffer).Should(gbytes.Say(`\Qprefix.fabric_version.test-version:1.000000|g\E`))
		})

		Context("when checking the network and address fails", func() {
			BeforeEach(func() {
				options.Metrics.Statsd.Network = "bob-the-network"
				system = operations.NewSystem(options)
			})

			It("returns an error", func() {
				err := system.Start()
				Expect(err).To(MatchError(ContainSubstring("bob-the-network")))
			})
		})
	})

	Context("when the metrics provider is unknown", func() {
		BeforeEach(func() {
			options.Metrics.Provider = "something-unknown"
			system = operations.NewSystem(options)
		})

		It("sets up a disabled provider", func() {
			Expect(system.Provider).To(Equal(&disabled.Provider{}))
		})

		It("logs the issue", func() {
			Expect(fakeLogger.WarnfCallCount()).To(Equal(1))
			msg, args := fakeLogger.WarnfArgsForCall(0)
			Expect(msg).To(Equal("Unknown provider type: %s; metrics disabled"))
			Expect(args).To(Equal([]interface{}{"something-unknown"}))
		})
	})

	It("supports ifrit", func() {
		process := ifrit.Invoke(system)
		Eventually(process.Ready()).Should(BeClosed())

		process.Signal(syscall.SIGTERM)
		Eventually(process.Wait()).Should(Receive(BeNil()))
	})

	Context("when start fails and ifrit is used", func() {
		BeforeEach(func() {
			options.TLS.CertFile = "non-existent-file"
			system = operations.NewSystem(options)
		})

		It("does not close the ready chan", func() {
			process := ifrit.Invoke(system)
			Consistently(process.Ready()).ShouldNot(BeClosed())
			Eventually(process.Wait()).Should(Receive(MatchError("open non-existent-file: no such file or directory")))
		})
	})
})
<|endoftext|>


<commit_before>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package types

// GatewayMetadata contains metadata for each gateway that received a message
type GatewayMetadata struct {
	GtwID      string   `json:"gtw_id,omitempty"`
	GtwTrusted bool     `json:"gtw_trusted"`
	Timestamp  uint32   `json:"timestamp,omitempty"`
	Time       JSONTime `json:"time,omitempty"`
	Channel    uint32   `json:"channel"`
	RSSI       float32  `json:"rssi,omitempty"`
	SNR        float32  `json:"snr,omitempty"`
	RFChain    uint32   `json:"rf_chain,omitempty"`
	LocationMetadata
}
<commit_msg>Omit gtw_trusted from metadata if gateway not trusted<commit_after>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package types

// GatewayMetadata contains metadata for each gateway that received a message
type GatewayMetadata struct {
	GtwID      string   `json:"gtw_id,omitempty"`
	GtwTrusted bool     `json:"gtw_trusted,omitempty"`
	Timestamp  uint32   `json:"timestamp,omitempty"`
	Time       JSONTime `json:"time,omitempty"`
	Channel    uint32   `json:"channel"`
	RSSI       float32  `json:"rssi,omitempty"`
	SNR        float32  `json:"snr,omitempty"`
	RFChain    uint32   `json:"rf_chain,omitempty"`
	LocationMetadata
}
<|endoftext|>


<commit_before>package validation

import (
	"DNA/common"
	"DNA/common/log"
	"DNA/core/asset"
	"DNA/core/ledger"
	tx "DNA/core/transaction"
	"DNA/core/transaction/payload"
	"errors"
	"fmt"
	"math"
)

// VerifyTransaction verifys received single transaction
func VerifyTransaction(Tx *tx.Transaction) error {

	if err := CheckDuplicateInput(Tx); err != nil {
		return err
	}

	if err := CheckAssetPrecision(Tx); err != nil {
		return err
	}

	if err := CheckTransactionBalance(Tx); err != nil {
		return err
	}

	if err := CheckAttributeProgram(Tx); err != nil {
		return err
	}

	if err := CheckTransactionPayload(Tx); err != nil {
		return err
	}

	if err := CheckTransactionContracts(Tx); err != nil {
		return err
	}

	return nil
}

// VerifyTransactionWithBlock verifys a transaction with current transaction pool in memory
func VerifyTransactionWithBlock(TxPool []*tx.Transaction) error {
	//initial
	txnlist := make(map[common.Uint256]*tx.Transaction, 0)
	var txPoolInputs []string
	//sum all inputs in TxPool
	for _, Tx := range TxPool {
		for _, UTXOinput := range Tx.UTXOInputs {
			txPoolInputs = append(txPoolInputs, UTXOinput.ToString())
		}
	}
	//start check
	for _, txn := range TxPool {
		//1.check weather have duplicate transaction.
		if _, exist := txnlist[txn.Hash()]; exist {
			return errors.New("[VerifyTransactionWithBlock], duplicate transaction exist in block.")
		} else {
			txnlist[txn.Hash()] = txn
		}
		//2.check Duplicate Utxo input
		if err := CheckDuplicateUtxoInBlock(txn, txPoolInputs); err != nil {
			return err
		}
		//3.check issue amount
		switch txn.TxType {
		case tx.IssueAsset:
			//TODO: use delta mode to improve performance
			results := txn.GetMergedAssetIDValueFromOutputs()
			for k, _ := range results {
				//Get the Asset amount when RegisterAsseted.
				trx, err := tx.TxStore.GetTransaction(k)
				if trx.TxType != tx.RegisterAsset {
					return errors.New("[VerifyTransaction], TxType is illegal.")
				}
				AssetReg := trx.Payload.(*payload.RegisterAsset)

				//Get the amount has been issued of this assetID
				var quantity_issued common.Fixed64
				if AssetReg.Amount < common.Fixed64(0) {
					continue
				} else {
					quantity_issued, err = tx.TxStore.GetQuantityIssued(k)
					if err != nil {
						return errors.New("[VerifyTransaction], GetQuantityIssued failed.")
					}
				}

				//calc the amounts in txPool which are also IssueAsset
				var txPoolAmounts common.Fixed64
				for _, t := range TxPool {
					if t.TxType == tx.IssueAsset {
						outputResult := t.GetMergedAssetIDValueFromOutputs()
						for txidInPool, txValueInPool := range outputResult {
							if txidInPool == k {
								txPoolAmounts = txPoolAmounts + txValueInPool
							}
						}
					}
				}

				//calc weather out off the amount when Registed.
				//AssetReg.Amount : amount when RegisterAsset of this assedID
				//quantity_issued : amount has been issued of this assedID
				//txPoolAmounts   : amount in transactionPool of this assedID of issue transaction.
				if AssetReg.Amount-quantity_issued < txPoolAmounts {
					return errors.New("[VerifyTransaction], Amount check error.")
				}
			}
		}

	}

	return nil
}

// VerifyTransactionWithLedger verifys a transaction with history transaction in ledger
func VerifyTransactionWithLedger(Tx *tx.Transaction, ledger *ledger.Ledger) error {
	if IsDoubleSpend(Tx, ledger) {
		return errors.New("[VerifyTransactionWithLedger] IsDoubleSpend check faild.")
	}
	if exist := ledger.Store.IsTxHashDuplicate(Tx.Hash()); exist {
		return errors.New("[VerifyTransactionWithLedger] duplicate transaction check faild.")
	}
	return nil
}

//validate the transaction of duplicate UTXO input
func CheckDuplicateInput(tx *tx.Transaction) error {
	if len(tx.UTXOInputs) == 0 {
		return nil
	}
	for i, utxoin := range tx.UTXOInputs {
		for j := 0; j < i; j++ {
			if utxoin.ReferTxID == tx.UTXOInputs[j].ReferTxID && utxoin.ReferTxOutputIndex == tx.UTXOInputs[j].ReferTxOutputIndex {
				return errors.New("invalid transaction")
			}
		}
	}
	return nil
}

func CheckDuplicateUtxoInBlock(tx *tx.Transaction, txPoolInputs []string) error {
	var txInputs []string
	for _, t := range tx.UTXOInputs {
		txInputs = append(txInputs, t.ToString())
	}
	for _, i := range txInputs {
		for _, j := range txPoolInputs {
			if i == j {
				return errors.New("Duplicated UTXO inputs found in tx pool")
			}
		}
	}
	return nil
}

func IsDoubleSpend(tx *tx.Transaction, ledger *ledger.Ledger) bool {
	return ledger.IsDoubleSpend(tx)
}

func CheckAssetPrecision(Tx *tx.Transaction) error {
	if len(Tx.Outputs) == 0 {
		return nil
	}
	assetOutputs := make(map[common.Uint256][]*tx.TxOutput, len(Tx.Outputs))

	for _, v := range Tx.Outputs {
		assetOutputs[v.AssetID] = append(assetOutputs[v.AssetID], v)
	}
	for k, outputs := range assetOutputs {
		asset, err := ledger.DefaultLedger.GetAsset(k)
		if err != nil {
			return errors.New("The asset not exist in local blockchain.")
		}
		precision := asset.Precision
		for _, output := range outputs {
			if checkAmountPrecise(output.Value, precision) {
				return errors.New("The precision of asset is incorrect.")
			}
		}
	}
	return nil
}

func CheckTransactionBalance(Tx *tx.Transaction) error {
	for _, v := range Tx.Outputs {
		if v.Value <= common.Fixed64(0) {
			return errors.New("Invalide transaction UTXO output.")
		}
	}
	if Tx.TxType == tx.IssueAsset || Tx.TxType == tx.DestroyUTXO {
		if len(Tx.UTXOInputs) > 0 {
			return errors.New("Invalide Issue transaction.")
		}
		return nil
	}
	results, err := Tx.GetTransactionResults()
	if err != nil {
		return err
	}
	for k, v := range results {
		if v != 0 {
			log.Debug(fmt.Sprintf("AssetID %x in Transfer transactions %x , Input/output UTXO not equal.", k, Tx.Hash()))
			return errors.New(fmt.Sprintf("AssetID %x in Transfer transactions %x , Input/output UTXO not equal.", k, Tx.Hash()))
		}
	}
	return nil
}

func CheckAttributeProgram(Tx *tx.Transaction) error {
	//TODO: implement CheckAttributeProgram
	return nil
}

func CheckTransactionContracts(Tx *tx.Transaction) error {
	flag, err := VerifySignableData(Tx)
	if flag && err == nil {
		return nil
	} else {
		return err
	}
}

func checkAmountPrecise(amount common.Fixed64, precision byte) bool {
	return amount.GetData()%int64(math.Pow(10, 8-float64(precision))) != 0
}

func CheckTransactionPayload(Tx *tx.Transaction) error {

	switch pld := Tx.Payload.(type) {
	case *payload.BookKeeper:
		//Todo: validate bookKeeper Cert
		_ = pld.Cert
		return nil
	case *payload.RegisterAsset:
		if pld.Asset.Precision < asset.MinPrecision || pld.Asset.Precision > asset.MaxPrecision {
			return errors.New("[CheckTransactionPayload],invalid asset Precision.")
		}
		if checkAmountPrecise(pld.Amount, pld.Asset.Precision) {
			return errors.New("[CheckTransactionPayload],invalid asset value,out of precise.")
		}
	case *payload.IssueAsset:
	case *payload.TransferAsset:
	case *payload.BookKeeping:
	case *payload.PrivacyPayload:
	case *payload.Record:
	case *payload.DeployCode:
	case *payload.DataFile:
	case *payload.DestroyUTXO:
		if len(Tx.Outputs) > 0 {
			return errors.New("[CheckTransactionPayload],invalid transaction outputs.")
		}
	default:
		return errors.New("[CheckTransactionPayload],invalid transaction payload type.")
	}
	return nil
}
<commit_msg>add destroy utxo payload.<commit_after>package validation

import (
	"DNA/common"
	"DNA/common/log"
	"DNA/core/asset"
	"DNA/core/ledger"
	tx "DNA/core/transaction"
	"DNA/core/transaction/payload"
	"errors"
	"fmt"
	"math"
)

// VerifyTransaction verifys received single transaction
func VerifyTransaction(Tx *tx.Transaction) error {

	if err := CheckDuplicateInput(Tx); err != nil {
		return err
	}

	if err := CheckAssetPrecision(Tx); err != nil {
		return err
	}

	if err := CheckTransactionBalance(Tx); err != nil {
		return err
	}

	if err := CheckAttributeProgram(Tx); err != nil {
		return err
	}

	if err := CheckTransactionPayload(Tx); err != nil {
		return err
	}

	if err := CheckTransactionContracts(Tx); err != nil {
		return err
	}

	return nil
}

// VerifyTransactionWithBlock verifys a transaction with current transaction pool in memory
func VerifyTransactionWithBlock(TxPool []*tx.Transaction) error {
	//initial
	txnlist := make(map[common.Uint256]*tx.Transaction, 0)
	var txPoolInputs []string
	//sum all inputs in TxPool
	for _, Tx := range TxPool {
		for _, UTXOinput := range Tx.UTXOInputs {
			txPoolInputs = append(txPoolInputs, UTXOinput.ToString())
		}
	}
	//start check
	for _, txn := range TxPool {
		//1.check weather have duplicate transaction.
		if _, exist := txnlist[txn.Hash()]; exist {
			return errors.New("[VerifyTransactionWithBlock], duplicate transaction exist in block.")
		} else {
			txnlist[txn.Hash()] = txn
		}
		//2.check Duplicate Utxo input
		if err := CheckDuplicateUtxoInBlock(txn, txPoolInputs); err != nil {
			return err
		}
		//3.check issue amount
		switch txn.TxType {
		case tx.IssueAsset:
			//TODO: use delta mode to improve performance
			results := txn.GetMergedAssetIDValueFromOutputs()
			for k, _ := range results {
				//Get the Asset amount when RegisterAsseted.
				trx, err := tx.TxStore.GetTransaction(k)
				if trx.TxType != tx.RegisterAsset {
					return errors.New("[VerifyTransaction], TxType is illegal.")
				}
				AssetReg := trx.Payload.(*payload.RegisterAsset)

				//Get the amount has been issued of this assetID
				var quantity_issued common.Fixed64
				if AssetReg.Amount < common.Fixed64(0) {
					continue
				} else {
					quantity_issued, err = tx.TxStore.GetQuantityIssued(k)
					if err != nil {
						return errors.New("[VerifyTransaction], GetQuantityIssued failed.")
					}
				}

				//calc the amounts in txPool which are also IssueAsset
				var txPoolAmounts common.Fixed64
				for _, t := range TxPool {
					if t.TxType == tx.IssueAsset {
						outputResult := t.GetMergedAssetIDValueFromOutputs()
						for txidInPool, txValueInPool := range outputResult {
							if txidInPool == k {
								txPoolAmounts = txPoolAmounts + txValueInPool
							}
						}
					}
				}

				//calc weather out off the amount when Registed.
				//AssetReg.Amount : amount when RegisterAsset of this assedID
				//quantity_issued : amount has been issued of this assedID
				//txPoolAmounts   : amount in transactionPool of this assedID of issue transaction.
				if AssetReg.Amount-quantity_issued < txPoolAmounts {
					return errors.New("[VerifyTransaction], Amount check error.")
				}
			}
		}

	}

	return nil
}

// VerifyTransactionWithLedger verifys a transaction with history transaction in ledger
func VerifyTransactionWithLedger(Tx *tx.Transaction, ledger *ledger.Ledger) error {
	if IsDoubleSpend(Tx, ledger) {
		return errors.New("[VerifyTransactionWithLedger] IsDoubleSpend check faild.")
	}
	if exist := ledger.Store.IsTxHashDuplicate(Tx.Hash()); exist {
		return errors.New("[VerifyTransactionWithLedger] duplicate transaction check faild.")
	}
	return nil
}

//validate the transaction of duplicate UTXO input
func CheckDuplicateInput(tx *tx.Transaction) error {
	if len(tx.UTXOInputs) == 0 {
		return nil
	}
	for i, utxoin := range tx.UTXOInputs {
		for j := 0; j < i; j++ {
			if utxoin.ReferTxID == tx.UTXOInputs[j].ReferTxID && utxoin.ReferTxOutputIndex == tx.UTXOInputs[j].ReferTxOutputIndex {
				return errors.New("invalid transaction")
			}
		}
	}
	return nil
}

func CheckDuplicateUtxoInBlock(tx *tx.Transaction, txPoolInputs []string) error {
	var txInputs []string
	for _, t := range tx.UTXOInputs {
		txInputs = append(txInputs, t.ToString())
	}
	for _, i := range txInputs {
		for _, j := range txPoolInputs {
			if i == j {
				return errors.New("Duplicated UTXO inputs found in tx pool")
			}
		}
	}
	return nil
}

func IsDoubleSpend(tx *tx.Transaction, ledger *ledger.Ledger) bool {
	return ledger.IsDoubleSpend(tx)
}

func CheckAssetPrecision(Tx *tx.Transaction) error {
	if len(Tx.Outputs) == 0 {
		return nil
	}
	assetOutputs := make(map[common.Uint256][]*tx.TxOutput, len(Tx.Outputs))

	for _, v := range Tx.Outputs {
		assetOutputs[v.AssetID] = append(assetOutputs[v.AssetID], v)
	}
	for k, outputs := range assetOutputs {
		asset, err := ledger.DefaultLedger.GetAsset(k)
		if err != nil {
			return errors.New("The asset not exist in local blockchain.")
		}
		precision := asset.Precision
		for _, output := range outputs {
			if checkAmountPrecise(output.Value, precision) {
				return errors.New("The precision of asset is incorrect.")
			}
		}
	}
	return nil
}

func CheckTransactionBalance(Tx *tx.Transaction) error {
	for _, v := range Tx.Outputs {
		if v.Value <= common.Fixed64(0) {
			return errors.New("Invalide transaction UTXO output.")
		}
	}
	if Tx.TxType == tx.IssueAsset || Tx.TxType == tx.DestroyUTXO {
		return nil
	}
	results, err := Tx.GetTransactionResults()
	if err != nil {
		return err
	}
	for k, v := range results {
		if v != 0 {
			log.Debug(fmt.Sprintf("AssetID %x in Transfer transactions %x , Input/output UTXO not equal.", k, Tx.Hash()))
			return errors.New(fmt.Sprintf("AssetID %x in Transfer transactions %x , Input/output UTXO not equal.", k, Tx.Hash()))
		}
	}
	return nil
}

func CheckAttributeProgram(Tx *tx.Transaction) error {
	//TODO: implement CheckAttributeProgram
	return nil
}

func CheckTransactionContracts(Tx *tx.Transaction) error {
	flag, err := VerifySignableData(Tx)
	if flag && err == nil {
		return nil
	} else {
		return err
	}
}

func checkAmountPrecise(amount common.Fixed64, precision byte) bool {
	return amount.GetData()%int64(math.Pow(10, 8-float64(precision))) != 0
}

func CheckTransactionPayload(Tx *tx.Transaction) error {

	switch pld := Tx.Payload.(type) {
	case *payload.BookKeeper:
		//Todo: validate bookKeeper Cert
		_ = pld.Cert
		return nil
	case *payload.RegisterAsset:
		if pld.Asset.Precision < asset.MinPrecision || pld.Asset.Precision > asset.MaxPrecision {
			return errors.New("[CheckTransactionPayload],invalid asset Precision.")
		}
		if checkAmountPrecise(pld.Amount, pld.Asset.Precision) {
			return errors.New("[CheckTransactionPayload],invalid asset value,out of precise.")
		}
	case *payload.IssueAsset:
		if len(Tx.UTXOInputs) > 0 {
			return errors.New("Invalide Issue transaction.")
		}
	case *payload.TransferAsset:
	case *payload.BookKeeping:
	case *payload.PrivacyPayload:
	case *payload.Record:
	case *payload.DeployCode:
	case *payload.DataFile:
	case *payload.DestroyUTXO:
		if len(Tx.Outputs) > 0 {
			return errors.New("[CheckTransactionPayload],invalid transaction outputs.")
		}
	default:
		return errors.New("[CheckTransactionPayload],invalid transaction payload type.")
	}
	return nil
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"crypto/sha256"
	"fmt"
	"log"
	"runtime"
	"strings"

	pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
	plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
	"github.com/hashicorp/packer/packer/plugin-getter/github"
	"github.com/hashicorp/packer/version"
	"github.com/posener/complete"
)

type InitCommand struct {
	Meta
}

func (c *InitCommand) Run(args []string) int {
	ctx, cleanup := handleTermInterrupt(c.Ui)
	defer cleanup()

	cfg, ret := c.ParseArgs(args)
	if ret != 0 {
		return ret
	}

	return c.RunContext(ctx, cfg)
}

func (c *InitCommand) ParseArgs(args []string) (*InitArgs, int) {
	var cfg InitArgs
	flags := c.Meta.FlagSet("init", 0)
	flags.Usage = func() { c.Ui.Say(c.Help()) }
	cfg.AddFlagSets(flags)
	if err := flags.Parse(args); err != nil {
		return &cfg, 1
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		return &cfg, 1
	}
	cfg.Path = args[0]
	return &cfg, 0
}

func (c *InitCommand) RunContext(buildCtx context.Context, cla *InitArgs) int {
	packerStarter, ret := c.GetConfig(&cla.MetaArgs)
	if ret != 0 {
		return ret
	}

	// Get plugins requirements
	reqs, diags := packerStarter.PluginRequirements()
	ret = writeDiags(c.Ui, nil, diags)
	if ret != 0 {
		return ret
	}

	opts := plugingetter.ListInstallationsOptions{
		FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
		BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
			OS:              runtime.GOOS,
			ARCH:            runtime.GOARCH,
			APIVersionMajor: pluginsdk.APIVersionMajor,
			APIVersionMinor: pluginsdk.APIVersionMinor,
			Checksummers: []plugingetter.Checksummer{
				{Type: "sha256", Hash: sha256.New()},
			},
		},
	}

	if runtime.GOOS == "windows" && opts.Ext == "" {
		opts.BinaryInstallationOptions.Ext = ".exe"
	}

	log.Printf("[TRACE] init: %#v", opts)

	getters := []plugingetter.Getter{
		&github.Getter{
			// In the past some terraform plugins downloads were blocked from a
			// specific aws region by s3. Changing the user agent unblocked the
			// downloads so having one user agent per version will help mitigate
			// that a little more. Especially in the case someone forks this
			// code to make it more aggressive or something.
			// TODO: allow to set this from the config file or an environment
			// variable.
			UserAgent: "packer-getter-github-" + version.String(),
		},
	}

	for _, pluginRequirement := range reqs {
		// Get installed plugins that match requirement

		installs, err := pluginRequirement.ListInstallations(opts)
		if err != nil {
			c.Ui.Error(err.Error())
			return 1
		}

		log.Printf("[TRACE] for plugin %s found %d matching installation(s)", pluginRequirement.Identifier.ForDisplay(), len(installs))

		if len(installs) > 0 && cla.Upgrade == false {
			continue
		}

		newInstall, err := pluginRequirement.InstallLatest(plugingetter.InstallOptions{
			InFolders:                 opts.FromFolders,
			BinaryInstallationOptions: opts.BinaryInstallationOptions,
			Getters:                   getters,
		})
		if err != nil {
			c.Ui.Error(err.Error())
		}
		if newInstall != nil {
			msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier.ForDisplay(), newInstall.Version, newInstall.BinaryPath)
			c.Ui.Say(msg)
		}
	}
	return ret
}

func (*InitCommand) Help() string {
	helpText := `
Usage: packer init [options] [config.pkr.hcl|folder/]

  Install all the missing plugins required in a Packer config. Note that Packer
  does not have a state.

  This is the first command that should be executed when working with a new
  or existing template.

  This command is always safe to run multiple times. Though subsequent runs may
  give errors, this command will never delete anything.

Options:
  -upgrade                     On top of installing missing plugins, update
                               installed plugins to the latest available
                               version, if there is a new higher one. Note that
                               this still takes into consideration the version
                               constraint of the config.
`

	return strings.TrimSpace(helpText)
}

func (*InitCommand) Synopsis() string {
	return "Install missing plugins or upgrade plugins"
}

func (*InitCommand) AutocompleteArgs() complete.Predictor {
	return complete.PredictNothing
}

func (*InitCommand) AutocompleteFlags() complete.Flags {
	return complete.Flags{
		"-upgrade": complete.PredictNothing,
	}
}
<commit_msg>init: show successful installs in cyan (#10557)<commit_after>package command

import (
	"context"
	"crypto/sha256"
	"fmt"
	"log"
	"runtime"
	"strings"

	pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
	"github.com/hashicorp/packer/packer"
	plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
	"github.com/hashicorp/packer/packer/plugin-getter/github"
	"github.com/hashicorp/packer/version"
	"github.com/posener/complete"
)

type InitCommand struct {
	Meta
}

func (c *InitCommand) Run(args []string) int {
	ctx, cleanup := handleTermInterrupt(c.Ui)
	defer cleanup()

	cfg, ret := c.ParseArgs(args)
	if ret != 0 {
		return ret
	}

	return c.RunContext(ctx, cfg)
}

func (c *InitCommand) ParseArgs(args []string) (*InitArgs, int) {
	var cfg InitArgs
	flags := c.Meta.FlagSet("init", 0)
	flags.Usage = func() { c.Ui.Say(c.Help()) }
	cfg.AddFlagSets(flags)
	if err := flags.Parse(args); err != nil {
		return &cfg, 1
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		return &cfg, 1
	}
	cfg.Path = args[0]
	return &cfg, 0
}

func (c *InitCommand) RunContext(buildCtx context.Context, cla *InitArgs) int {
	packerStarter, ret := c.GetConfig(&cla.MetaArgs)
	if ret != 0 {
		return ret
	}

	// Get plugins requirements
	reqs, diags := packerStarter.PluginRequirements()
	ret = writeDiags(c.Ui, nil, diags)
	if ret != 0 {
		return ret
	}

	opts := plugingetter.ListInstallationsOptions{
		FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
		BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
			OS:              runtime.GOOS,
			ARCH:            runtime.GOARCH,
			APIVersionMajor: pluginsdk.APIVersionMajor,
			APIVersionMinor: pluginsdk.APIVersionMinor,
			Checksummers: []plugingetter.Checksummer{
				{Type: "sha256", Hash: sha256.New()},
			},
		},
	}

	if runtime.GOOS == "windows" && opts.Ext == "" {
		opts.BinaryInstallationOptions.Ext = ".exe"
	}

	log.Printf("[TRACE] init: %#v", opts)

	getters := []plugingetter.Getter{
		&github.Getter{
			// In the past some terraform plugins downloads were blocked from a
			// specific aws region by s3. Changing the user agent unblocked the
			// downloads so having one user agent per version will help mitigate
			// that a little more. Especially in the case someone forks this
			// code to make it more aggressive or something.
			// TODO: allow to set this from the config file or an environment
			// variable.
			UserAgent: "packer-getter-github-" + version.String(),
		},
	}

	ui := &packer.ColoredUi{
		Color: packer.UiColorCyan,
		Ui:    c.Ui,
	}

	for _, pluginRequirement := range reqs {
		// Get installed plugins that match requirement

		installs, err := pluginRequirement.ListInstallations(opts)
		if err != nil {
			c.Ui.Error(err.Error())
			return 1
		}

		log.Printf("[TRACE] for plugin %s found %d matching installation(s)", pluginRequirement.Identifier.ForDisplay(), len(installs))

		if len(installs) > 0 && cla.Upgrade == false {
			continue
		}

		newInstall, err := pluginRequirement.InstallLatest(plugingetter.InstallOptions{
			InFolders:                 opts.FromFolders,
			BinaryInstallationOptions: opts.BinaryInstallationOptions,
			Getters:                   getters,
		})
		if err != nil {
			c.Ui.Error(err.Error())
		}
		if newInstall != nil {
			msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier.ForDisplay(), newInstall.Version, newInstall.BinaryPath)
			ui.Say(msg)
		}
	}
	return ret
}

func (*InitCommand) Help() string {
	helpText := `
Usage: packer init [options] [config.pkr.hcl|folder/]

  Install all the missing plugins required in a Packer config. Note that Packer
  does not have a state.

  This is the first command that should be executed when working with a new
  or existing template.

  This command is always safe to run multiple times. Though subsequent runs may
  give errors, this command will never delete anything.

Options:
  -upgrade                     On top of installing missing plugins, update
                               installed plugins to the latest available
                               version, if there is a new higher one. Note that
                               this still takes into consideration the version
                               constraint of the config.
`

	return strings.TrimSpace(helpText)
}

func (*InitCommand) Synopsis() string {
	return "Install missing plugins or upgrade plugins"
}

func (*InitCommand) AutocompleteArgs() complete.Predictor {
	return complete.PredictNothing
}

func (*InitCommand) AutocompleteFlags() complete.Flags {
	return complete.Flags{
		"-upgrade": complete.PredictNothing,
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"
	"io/ioutil"

	. "github.com/heroku/force/lib"
	. "github.com/heroku/force/error"
)

var cmdRest = &Command{
	Run:   runRest,
	Usage: "rest <method> <url>",
	Short: "Execute a REST request",
	Long: `
Execute a REST request

Examples:

  force rest get "tooling/query?q=Select id From Account"

  force rest get appMenu/AppSwitcher
`,
}

func runRest(cmd *Command, args []string) {
	force, _ := ActiveForce()
	if len(args) != 3 {
		cmd.PrintUsage()
	} else {
		// TODO parse args looking for get, post etc
		// and handle other than get
		var (
			data = ""
			msg = ""
		)
		var err error
		if strings.ToLower(args[0]) == "get" {
			data, err = force.GetREST(args[1])
			if err != nil {
				ErrorAndExit(err.Error())
			}
			msg = strings.Replace(data, "null", "\"null\"", -1)
		} else if strings.ToLower(args[0]) == "post" ||
			strings.ToLower(args[0]) == "patch" {
			url := args[1]
			datafile, err := ioutil.ReadFile(args[2])
			data, err = force.PostPatchREST(url, string(datafile), strings.ToUpper(args[0]))
			if err != nil {
				ErrorAndExit(err.Error())
			}
			data = string(data)
			data = strings.Replace(data, "null", "\"null\"", -1)
			msg = fmt.Sprintf("%s %s\n%s", strings.ToUpper(args[0]), url, data)
		}
		fmt.Println(msg)

	}
}
<commit_msg>update rest help<commit_after>package command

import (
	"fmt"
	"strings"
	"io/ioutil"

	. "github.com/heroku/force/lib"
	. "github.com/heroku/force/error"
)

var cmdRest = &Command{
	Run:   runRest,
	Usage: "rest <method> <url>",
	Short: "Execute a REST request",
	Long: `
Execute a REST request

Examples:

  force rest get "tooling/query?q=Select id From Account"

  force rest get appMenu/AppSwitcher

  force rest post "tooling/sobjects/CustomField/00D9A0000000TgcUAE" path/to/definition.json

`,
}

func runRest(cmd *Command, args []string) {
	force, _ := ActiveForce()
	if len(args) != 3 {
		cmd.PrintUsage()
	} else {
		// TODO parse args looking for get, post etc
		// and handle other than get
		var (
			data = ""
			msg = ""
		)
		var err error
		if strings.ToLower(args[0]) == "get" {
			data, err = force.GetREST(args[1])
			if err != nil {
				ErrorAndExit(err.Error())
			}
			msg = strings.Replace(data, "null", "\"null\"", -1)
		} else if strings.ToLower(args[0]) == "post" ||
			strings.ToLower(args[0]) == "patch" {
			url := args[1]
			datafile, err := ioutil.ReadFile(args[2])
			data, err = force.PostPatchREST(url, string(datafile), strings.ToUpper(args[0]))
			if err != nil {
				ErrorAndExit(err.Error())
			}
			data = string(data)
			data = strings.Replace(data, "null", "\"null\"", -1)
			msg = fmt.Sprintf("%s %s\n%s", strings.ToUpper(args[0]), url, data)
		}
		fmt.Println(msg)

	}
}
<|endoftext|>


<commit_before>package commands

import (
	"context"
	"fmt"
	"os"
	"syscall"
	"unicode"

	"github.com/zetamatta/go-getch"

	"github.com/zetamatta/nyagos/dos"
	"github.com/zetamatta/nyagos/shell"
)

func attrib_plus_r(path string) error {
	perm, err := dos.GetFileAttributes(path)
	if err != nil {
		return err
	}
	return dos.SetFileAttributes(path, perm&^dos.FILE_ATTRIBUTE_READONLY)
}

func cmd_del(ctx context.Context, cmd *shell.Cmd) (int, error) {
	n := len(cmd.Args)
	if n <= 1 {
		fmt.Fprintln(cmd.Stderr, "Usage: del   [/q] FILE(S)...")
		fmt.Fprintln(cmd.Stderr, "       erase [/q] FILE(S)...")
		return 0, nil
	}
	all := false
	force := false
	errorcount := 0
	i := 1
	for _, arg1 := range cmd.Args[1:] {
		if ctx != nil {
			select {
			case <-ctx.Done():
				return 0, nil
			default:
			}
		}
		if arg1 == "/q" {
			all = true
			n--
			continue
		}
		if arg1 == "/f" {
			force = true
			n--
			continue
		}
		path := arg1
		stat, err := os.Lstat(path)
		if os.IsNotExist(err) {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: not found.\n", i, n-1, path)
			errorcount++
			continue
		}
		if err != nil {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: %s\n", i, n-1, path, err)
			errorcount++
			continue
		}
		if mode := stat.Mode(); mode.IsDir() {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s is directory and passed.\n",
				i, n-1, path)
			errorcount++
			continue
		}
		if all {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: Remove ", i, n-1, path)
		} else {
			fmt.Fprintf(cmd.Stdout,
				"(%d/%d) %s: Remove ? [Yes/No/All/Quit] ",
				i, n-1, path)
			ch := getch.Rune()
			if unicode.IsPrint(ch) {
				fmt.Fprintf(cmd.Stdout, "%c ", ch)
			}
			switch ch {
			case 'q', 'Q', rune(0x03):
				fmt.Fprintln(cmd.Stdout)
				return errorcount, nil
			case 'y', 'Y':
				break
			case 'a', 'A':
				all = true
			default: // for 'n','N'
				fmt.Println("-> canceled")
				continue
			}
		}
		err = syscall.Unlink(path)
		if err != nil && force {
			if err1 := attrib_plus_r(path); err1 == nil {
				err = syscall.Unlink(path)
			}
		}
		if err != nil {
			fmt.Printf("-> %s\n", err)
			errorcount++
			continue
		}
		fmt.Println("-> done.")
		i++
	}
	return errorcount, nil
}
<commit_msg>Fix #280: The message on `del *~` -> files not found<commit_after>package commands

import (
	"context"
	"fmt"
	"os"
	"syscall"
	"unicode"

	"github.com/zetamatta/go-getch"

	"github.com/zetamatta/nyagos/dos"
	"github.com/zetamatta/nyagos/shell"
)

func attrib_plus_r(path string) error {
	perm, err := dos.GetFileAttributes(path)
	if err != nil {
		return err
	}
	return dos.SetFileAttributes(path, perm&^dos.FILE_ATTRIBUTE_READONLY)
}

func cmd_del(ctx context.Context, cmd *shell.Cmd) (int, error) {
	n := len(cmd.Args)
	if n <= 1 {
		fmt.Fprintln(cmd.Stderr, "Usage: del   [/q] FILE(S)...")
		fmt.Fprintln(cmd.Stderr, "       erase [/q] FILE(S)...")
		return 0, nil
	}
	all := false
	force := false
	errorcount := 0
	i := 1
	for _, arg1 := range cmd.Args[1:] {
		if ctx != nil {
			select {
			case <-ctx.Done():
				return 0, nil
			default:
			}
		}
		if arg1 == "/q" {
			all = true
			n--
			continue
		}
		if arg1 == "/f" {
			force = true
			n--
			continue
		}
		path := arg1
		stat, err := os.Lstat(path)
		if _, ok := err.(*os.PathError); ok || os.IsNotExist(err) {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: not found.\n", i, n-1, path)
			errorcount++
			continue
		}
		if err != nil {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: %s\n", i, n-1, path, err)
			errorcount++
			continue
		}
		if mode := stat.Mode(); mode.IsDir() {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s is directory and passed.\n",
				i, n-1, path)
			errorcount++
			continue
		}
		if all {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: Remove ", i, n-1, path)
		} else {
			fmt.Fprintf(cmd.Stdout,
				"(%d/%d) %s: Remove ? [Yes/No/All/Quit] ",
				i, n-1, path)
			ch := getch.Rune()
			if unicode.IsPrint(ch) {
				fmt.Fprintf(cmd.Stdout, "%c ", ch)
			}
			switch ch {
			case 'q', 'Q', rune(0x03):
				fmt.Fprintln(cmd.Stdout)
				return errorcount, nil
			case 'y', 'Y':
				break
			case 'a', 'A':
				all = true
			default: // for 'n','N'
				fmt.Println("-> canceled")
				continue
			}
		}
		err = syscall.Unlink(path)
		if err != nil && force {
			if err1 := attrib_plus_r(path); err1 == nil {
				err = syscall.Unlink(path)
			}
		}
		if err != nil {
			fmt.Printf("-> %s\n", err)
			errorcount++
			continue
		}
		fmt.Println("-> done.")
		i++
	}
	return errorcount, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"path"
	"strconv"
	"strings"

	cli "github.com/urfave/cli"

	"github.com/gxed/go-shellwords"
	"github.com/ipfs/iptb/testbed"
	"github.com/ipfs/iptb/testbed/interfaces"
)

var RunCmd = cli.Command{
	Category:  "CORE",
	Name:      "run",
	Usage:     "concurrently run command(s) on specified nodes (or all)",
	ArgsUsage: "[nodes] -- <command...>",
	Description: `
Commands may also be passed in via stdin or a pipe, e.g. the command

$ iptb run 0 -- echo "Running on node 0"

can be equivalently written as

$ iptb run <<CMD
    0 -- echo "Running on node 0"
  CMD

or

$ echo '0 -- echo "Running on node 0"' | iptb run

All lines starting with '#' will be ignored, which allows for comments:

$ iptb run <<CMD
    # print ipfs peers
    0 -- ipfs swarm peers
  CMD

Multiple commands may also be passed via stdin/pipe:

$ iptb run <<CMDS
    0     -- echo "Running on node 0"
    [0,1] -- echo "Running on nodes 0 and 1"
          -- echo "Running on all nodes"
  CMDS

Note that any single call to ` + "`iptb run`" + ` runs *all* commands concurrently. So,
in the above example, there is no guarantee as to the order in which the lines
are printed.
`,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:   "terminator",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "stdin",
			Hidden: true,
		},
	},
	Before: func(c *cli.Context) error {
		if c.NArg() == 0 {
			finfo, err := os.Stdin.Stat()
			if err != nil {
				return err
			}
			if finfo.Size() == 0 && finfo.Mode()&os.ModeNamedPipe == 0 {
				return fmt.Errorf("error: no command input and stdin is empty")
			}
			return c.Set("stdin", "true")
		}
		if present := isTerminatorPresent(c); present {
			return c.Set("terminator", "true")
		}
		return nil
	},
	Action: func(c *cli.Context) error {
		flagRoot := c.GlobalString("IPTB_ROOT")
		flagTestbed := c.GlobalString("testbed")

		tb := testbed.NewTestbed(path.Join(flagRoot, "testbeds", flagTestbed))
		nodes, err := tb.Nodes()
		if err != nil {
			return err
		}

		var reader io.Reader
		if c.IsSet("stdin") {
			reader = bufio.NewReader(os.Stdin)
		} else {
			var builder strings.Builder
			if c.IsSet("terminator") {
				builder.WriteString("-- ")
			}
			for i, arg := range c.Args() {
				builder.WriteString(strconv.Quote(arg))
				if i != c.NArg()-1 {
					builder.WriteString(" ")
				}
			}
			reader = strings.NewReader(builder.String())
		}

		var args [][]string
		scanner := bufio.NewScanner(reader)
		line := 1
		for scanner.Scan() {
			tokens, err := shellwords.Parse(scanner.Text())
			if err != nil {
				return fmt.Errorf("parser error on line %d: %s", line, err)
			}
			if strings.HasPrefix(tokens[0], "#") {
				continue
			}
			args = append(args, tokens)
			line++
		}

		ranges := make([][]int, len(args))
		runCmds := make([]outputFunc, len(args))
		for i, cmd := range args {
			nodeRange, tokens := parseCommand(cmd, false)
			if nodeRange == "" {
				nodeRange = fmt.Sprintf("[0-%d]", len(nodes)-1)
			}
			list, err := parseRange(nodeRange)
			if err != nil {
				return fmt.Errorf("could not parse node range %s", nodeRange)
			}
			ranges[i] = list

			runCmd := func(node testbedi.Core) (testbedi.Output, error) {
				return node.RunCmd(context.Background(), nil, tokens...)
			}
			runCmds[i] = runCmd
		}

		results, err := mapListWithOutput(ranges, nodes, runCmds)
		return buildReport(results)
	},
}
<commit_msg>Fix: Small typo in error output.<commit_after>package commands

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"path"
	"strconv"
	"strings"

	cli "github.com/urfave/cli"

	"github.com/gxed/go-shellwords"
	"github.com/ipfs/iptb/testbed"
	"github.com/ipfs/iptb/testbed/interfaces"
)

var RunCmd = cli.Command{
	Category:  "CORE",
	Name:      "run",
	Usage:     "concurrently run command(s) on specified nodes (or all)",
	ArgsUsage: "[nodes] -- <command...>",
	Description: `
Commands may also be passed in via stdin or a pipe, e.g. the command

$ iptb run 0 -- echo "Running on node 0"

can be equivalently written as

$ iptb run <<CMD
    0 -- echo "Running on node 0"
  CMD

or

$ echo '0 -- echo "Running on node 0"' | iptb run

All lines starting with '#' will be ignored, which allows for comments:

$ iptb run <<CMD
    # print ipfs peers
    0 -- ipfs swarm peers
  CMD

Multiple commands may also be passed via stdin/pipe:

$ iptb run <<CMDS
    0     -- echo "Running on node 0"
    [0,1] -- echo "Running on nodes 0 and 1"
          -- echo "Running on all nodes"
  CMDS

Note that any single call to ` + "`iptb run`" + ` runs *all* commands concurrently. So,
in the above example, there is no guarantee as to the order in which the lines
are printed.
`,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:   "terminator",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "stdin",
			Hidden: true,
		},
	},
	Before: func(c *cli.Context) error {
		if c.NArg() == 0 {
			finfo, err := os.Stdin.Stat()
			if err != nil {
				return err
			}
			if finfo.Size() == 0 && finfo.Mode()&os.ModeNamedPipe == 0 {
				return fmt.Errorf("error: no command input and stdin is empty")
			}
			return c.Set("stdin", "true")
		}
		if present := isTerminatorPresent(c); present {
			return c.Set("terminator", "true")
		}
		return nil
	},
	Action: func(c *cli.Context) error {
		flagRoot := c.GlobalString("IPTB_ROOT")
		flagTestbed := c.GlobalString("testbed")

		tb := testbed.NewTestbed(path.Join(flagRoot, "testbeds", flagTestbed))
		nodes, err := tb.Nodes()
		if err != nil {
			return err
		}

		var reader io.Reader
		if c.IsSet("stdin") {
			reader = bufio.NewReader(os.Stdin)
		} else {
			var builder strings.Builder
			if c.IsSet("terminator") {
				builder.WriteString("-- ")
			}
			for i, arg := range c.Args() {
				builder.WriteString(strconv.Quote(arg))
				if i != c.NArg()-1 {
					builder.WriteString(" ")
				}
			}
			reader = strings.NewReader(builder.String())
		}

		var args [][]string
		scanner := bufio.NewScanner(reader)
		line := 1
		for scanner.Scan() {
			tokens, err := shellwords.Parse(scanner.Text())
			if err != nil {
				return fmt.Errorf("parse error on line %d: %s", line, err)
			}
			if strings.HasPrefix(tokens[0], "#") {
				continue
			}
			args = append(args, tokens)
			line++
		}

		ranges := make([][]int, len(args))
		runCmds := make([]outputFunc, len(args))
		for i, cmd := range args {
			nodeRange, tokens := parseCommand(cmd, false)
			if nodeRange == "" {
				nodeRange = fmt.Sprintf("[0-%d]", len(nodes)-1)
			}
			list, err := parseRange(nodeRange)
			if err != nil {
				return fmt.Errorf("could not parse node range %s", nodeRange)
			}
			ranges[i] = list

			runCmd := func(node testbedi.Core) (testbedi.Output, error) {
				return node.RunCmd(context.Background(), nil, tokens...)
			}
			runCmds[i] = runCmd
		}

		results, err := mapListWithOutput(ranges, nodes, runCmds)
		return buildReport(results)
	},
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"

	"code.cloudfoundry.org/garden"
	"github.com/mattn/go-shellwords"
)

type Run struct {
	Attach  bool     `short:"a" long:"attach" description:"attach to the process after it has started"`
	Dir     string   `short:"d" long:"dir" description:"current working directory of process"`
	User    string   `short:"u" long:"user" description:"user to run the process as" default:"root"`
	Command string   `short:"c" long:"command" description:"command to run in container"`
	Env     []string `short:"e" long:"env" description:"set environment variables"`
}

func (command *Run) Execute(maybeHandle []string) error {
	handle := handle(maybeHandle)
	container, err := globalClient().Lookup(handle)
	failIf(err)

	var processIo garden.ProcessIO
	if command.Attach {
		processIo = garden.ProcessIO{
			Stdin:  os.Stdin,
			Stdout: os.Stdout,
			Stderr: os.Stderr,
		}
	} else {
		processIo = garden.ProcessIO{}
	}

	args, err := shellwords.Parse(command.Command)
	failIf(err)

	process, err := container.Run(garden.ProcessSpec{
		Path: args[0],
		Args: args[1:],
		Dir:  command.Dir,
		User: command.User,
		Env:  command.Env,
	}, processIo)
	failIf(err)

	if command.Attach {
		status, err := process.Wait()
		failIf(err)
		os.Exit(status)
	} else {
		fmt.Println(process.ID())
	}

	return nil
}
<commit_msg>Optional --image flag for run subcommand<commit_after>package commands

import (
	"fmt"
	"os"

	"code.cloudfoundry.org/garden"
	"github.com/mattn/go-shellwords"
)

type Run struct {
	Attach  bool     `short:"a" long:"attach" description:"attach to the process after it has started"`
	Dir     string   `short:"d" long:"dir" description:"current working directory of process"`
	User    string   `short:"u" long:"user" description:"user to run the process as" default:"root"`
	Command string   `short:"c" long:"command" description:"command to run in container"`
	Env     []string `short:"e" long:"env" description:"set environment variables"`
	Image   string   `short:"i" long:"image" description:"Root filesystem for process"`
}

func (command *Run) Execute(maybeHandle []string) error {
	handle := handle(maybeHandle)
	container, err := globalClient().Lookup(handle)
	failIf(err)

	var processIo garden.ProcessIO
	if command.Attach {
		processIo = garden.ProcessIO{
			Stdin:  os.Stdin,
			Stdout: os.Stdout,
			Stderr: os.Stderr,
		}
	} else {
		processIo = garden.ProcessIO{}
	}

	args, err := shellwords.Parse(command.Command)
	failIf(err)

	process, err := container.Run(garden.ProcessSpec{
		Path:  args[0],
		Args:  args[1:],
		Dir:   command.Dir,
		User:  command.User,
		Env:   command.Env,
		Image: garden.ImageRef{URI: command.Image},
	}, processIo)
	failIf(err)

	if command.Attach {
		status, err := process.Wait()
		failIf(err)
		os.Exit(status)
	} else {
		fmt.Println(process.ID())
	}

	return nil
}
<|endoftext|>


<commit_before>package common

import (
	"log"
	"runtime"

	"engo.io/ecs"
	"engo.io/engo"

	"github.com/hajimehoshi/oto"
)

const (
	channelNum     = 2
	bytesPerSample = 2

	mask = ^(channelNum*bytesPerSample - 1)
)

// AudioComponent is a Component which is used by the AudioSystem
type AudioComponent struct {
	Player *Player
}

type audioEntity struct {
	*ecs.BasicEntity
	*AudioComponent
}

// AudioSystem is a System that allows for sound effects and / or music
type AudioSystem struct {
	entities []audioEntity

	otoPlayer *oto.Player
	bufsize   int
}

// New is called when the AudioSystem is added to the world.
func (a *AudioSystem) New(w *ecs.World) {
	var err error
	switch engo.CurrentBackEnd {
	case engo.BackEndMobile:
		a.bufsize = 12288
	default:
		a.bufsize = 8192
	}
	a.otoPlayer, err = oto.NewPlayer(SampleRate, channelNum, bytesPerSample, a.bufsize)
	if err != nil {
		log.Printf("audio error. Unable to create new OtoPlayer: %v \n\r", err)
	}
	runtime.SetFinalizer(a.otoPlayer, func(p *oto.Player) {
		if err := p.Close(); err != nil {
			log.Printf("audio error. Unable to close OtoPlayer: %v \n\r", err)
		}
	})
	masterVolume = 1
}

// Add adds an entity to the AudioSystem
func (a *AudioSystem) Add(basic *ecs.BasicEntity, audio *AudioComponent) {
	a.entities = append(a.entities, audioEntity{basic, audio})
}

// AddByInterface Allows an Entity to be added directly using the Audioable interface,
// which every entity containing the BasicEntity and AnimationComponent anonymously,
// automatically satisfies.
func (a *AudioSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Audioable)
	a.Add(o.GetBasicEntity(), o.GetAudioComponent())
}

// Remove removes an entity from the AudioSystem
func (a *AudioSystem) Remove(basic ecs.BasicEntity) {
	delete := -1
	for index, e := range a.entities {
		if e.BasicEntity.ID() == basic.ID() {
			delete = index
			break
		}
	}
	if delete >= 0 {
		a.entities = append(a.entities[:delete], a.entities[delete+1:]...)
	}
}

// Update is called once per frame, and updates/plays the players in the AudioSystem
func (a *AudioSystem) Update(dt float32) {
	buf := make([]byte, a.bufsize)
	a.read(buf)

	if _, err := a.otoPlayer.Write(buf); err != nil {
		log.Printf("error copying to OtoPlayer: %v \r\n", err)
	}
}

// Read reads from all the currently playing entities and combines them into a
// single stream that is passed to the oto player.
func (a *AudioSystem) read(b []byte) (int, error) {
	players := make([]*Player, 0)
	for _, e := range a.entities {
		if e.Player.isPlaying {
			players = append(players, e.Player)
		}
	}

	if len(players) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}

	l := len(b)
	l &= mask

	b16s := [][]int16{}
	for _, player := range players {
		buf, err := player.bufferToInt16(l)
		if err != nil {
			return 0, err
		}
		b16s = append(b16s, buf)
	}
	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}

	for _, player := range players {
		if player.eof() {
			if player.Repeat {
				player.Rewind()
			} else {
				player.Pause()
			}
		}
	}

	return l, nil
}
<commit_msg>separate oto on its own goroutine<commit_after>package common

import (
	"log"
	"runtime"

	"engo.io/ecs"
	"engo.io/engo"

	"github.com/hajimehoshi/oto"
)

const (
	channelNum     = 2
	bytesPerSample = 2

	mask = ^(channelNum*bytesPerSample - 1)
)

// AudioComponent is a Component which is used by the AudioSystem
type AudioComponent struct {
	Player *Player
}

type audioEntity struct {
	*ecs.BasicEntity
	*AudioComponent
}

// AudioSystem is a System that allows for sound effects and / or music
type AudioSystem struct {
	entities []audioEntity

	otoPlayer               *oto.Player
	bufsize                 int
	audioReadC, audioCloser chan struct{}
}

// New is called when the AudioSystem is added to the world.
func (a *AudioSystem) New(w *ecs.World) {
	var err error
	switch engo.CurrentBackEnd {
	case engo.BackEndMobile:
		a.bufsize = 12288
	default:
		a.bufsize = 8192
	}
	a.otoPlayer, err = oto.NewPlayer(SampleRate, channelNum, bytesPerSample, a.bufsize)
	if err != nil {
		log.Printf("audio error. Unable to create new OtoPlayer: %v \n\r", err)
	}
	a.audioCloser = make(chan struct{})
	runtime.SetFinalizer(a.otoPlayer, func(p *oto.Player) {
		if err := p.Close(); err != nil {
			log.Printf("audio error. Unable to close OtoPlayer: %v \n\r", err)
		}
		close(a.audioCloser)
	})
	// run oto on a separate thread so it doesn't slow down updates
	a.audioReadC = make(chan struct{}, 10)
	go func() {
		for {
			select {
			case <-a.audioReadC:
				buf := make([]byte, a.bufsize)
				a.read(buf)

				if _, err := a.otoPlayer.Write(buf); err != nil {
					log.Printf("error copying to OtoPlayer: %v \r\n", err)
				}
			case <-a.audioCloser:
				return
			}
		}
	}()
	masterVolume = 1
}

// Add adds an entity to the AudioSystem
func (a *AudioSystem) Add(basic *ecs.BasicEntity, audio *AudioComponent) {
	a.entities = append(a.entities, audioEntity{basic, audio})
}

// AddByInterface Allows an Entity to be added directly using the Audioable interface,
// which every entity containing the BasicEntity and AnimationComponent anonymously,
// automatically satisfies.
func (a *AudioSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Audioable)
	a.Add(o.GetBasicEntity(), o.GetAudioComponent())
}

// Remove removes an entity from the AudioSystem
func (a *AudioSystem) Remove(basic ecs.BasicEntity) {
	delete := -1
	for index, e := range a.entities {
		if e.BasicEntity.ID() == basic.ID() {
			delete = index
			break
		}
	}
	if delete >= 0 {
		a.entities = append(a.entities[:delete], a.entities[delete+1:]...)
	}
}

// Update is called once per frame, and updates/plays the players in the AudioSystem
func (a *AudioSystem) Update(dt float32) {
	select {
	case a.audioReadC <- struct{}{}:
	default:
	}
}

// Read reads from all the currently playing entities and combines them into a
// single stream that is passed to the oto player.
func (a *AudioSystem) read(b []byte) (int, error) {
	players := make([]*Player, 0)
	for _, e := range a.entities {
		if e.Player.isPlaying {
			players = append(players, e.Player)
		}
	}

	if len(players) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}

	l := len(b)
	l &= mask

	b16s := [][]int16{}
	for _, player := range players {
		buf, err := player.bufferToInt16(l)
		if err != nil {
			return 0, err
		}
		b16s = append(b16s, buf)
	}
	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}

	for _, player := range players {
		if player.eof() {
			if player.Repeat {
				player.Rewind()
			} else {
				player.Pause()
			}
		}
	}

	return l, nil
}
<|endoftext|>


<commit_before>package common

import (
	"flag"
)

// AddSharedConsulFlags adds flags shared by multiple command implementations
func AddSharedConsulFlags(cmdFlags *flag.FlagSet, consulConfig *ConsulConfig) {
	// client flags
	cmdFlags.StringVar(&consulConfig.Address, "addr", "",
		"Optional consul address and port")
	cmdFlags.StringVar(&consulConfig.Scheme, "scheme", "",
		"Optional consul scheme")
	cmdFlags.StringVar(&consulConfig.Datacenter, "dc", "",
		"Optional consul datacenter")
	cmdFlags.StringVar(&consulConfig.Token, "token", "",
		"Optional consul access token")

	// TLS settings
	cmdFlags.StringVar(&consulConfig.tls.CAFile, "ca-cert", "",
		"Optional path to a PEM encoded CA cert file")
	cmdFlags.StringVar(&consulConfig.tls.CertFile, "client-cert", "",
		"Optional path to a PEM encoded client certificate")
	cmdFlags.StringVar(&consulConfig.tls.KeyFile, "client-key", "",
		"Optional path to an unencrypted PEM encoded private key")
	cmdFlags.BoolVar(&consulConfig.tls.InsecureSkipVerify, "tls-skip-verify", false,
		"Optional bool for verifying a TLS certificate (not reccomended)")
}
<commit_msg>it always helps to init a struct before using it<commit_after>package common

import (
	"flag"
	"github.com/hashicorp/consul/api"
)

// AddSharedConsulFlags adds flags shared by multiple command implementations
func AddSharedConsulFlags(cmdFlags *flag.FlagSet, consulConfig *ConsulConfig) {
	// client flags
	cmdFlags.StringVar(&consulConfig.Address, "addr", "",
		"Optional consul address and port")
	cmdFlags.StringVar(&consulConfig.Scheme, "scheme", "",
		"Optional consul scheme")
	cmdFlags.StringVar(&consulConfig.Datacenter, "dc", "",
		"Optional consul datacenter")
	cmdFlags.StringVar(&consulConfig.Token, "token", "",
		"Optional consul access token")

	// init tls struct
	consulConfig.tls = new(api.TLSConfig)

	// TLS settings
	cmdFlags.StringVar(&consulConfig.tls.CAFile, "ca-cert", "",
		"Optional path to a PEM encoded CA cert file")
	cmdFlags.StringVar(&consulConfig.tls.CertFile, "client-cert", "",
		"Optional path to a PEM encoded client certificate")
	cmdFlags.StringVar(&consulConfig.tls.KeyFile, "client-key", "",
		"Optional path to an unencrypted PEM encoded private key")
	cmdFlags.BoolVar(&consulConfig.tls.InsecureSkipVerify, "tls-skip-verify", false,
		"Optional bool for verifying a TLS certificate (not reccomended)")
}
<|endoftext|>