<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"
)

var client *http.Client
var successCount, totalPush int

func gatling(url string, object string, xHeaders string, ch chan<- bool, rtype string, otype string) {

	count := 0
	out := []byte(object)
	cheads := strings.Split(xHeaders, ",")

	for {

		switch strings.ToUpper(rtype) {
		case "POST":
			request, _ := http.NewRequest(strings.ToUpper(rtype), url, bytes.NewBuffer(out))
			switch otype {
			case "xml":
				request.Header.Set("Content-Type", "text/xml")
			case "json":
				request.Header.Set("Content-Type", "application/json")
			default:
				log.Printf("[*] Invalid content type. Please specify json or xml")
				os.Exit(1)
			}
			if len(cheads) > 0 {
				for _, v := range cheads {
					hs := strings.Split(v, ":")
					request.Header.Set(hs[0], hs[1])
				}
			}
			response, err := client.Do(request)
			if err != nil {
				log.Fatalf("[*] Error making POST request: %s", err)
			}
			defer response.Body.Close()

			log.Printf("[*] Request complete! Finished Request No: #%v, Status: %v", count, response.StatusCode)

			totalPush++
			count++

			if response.StatusCode == 200 || response.StatusCode == 201 {
				successCount++
			}
			ch <- true

		case "GET":
			request, _ := http.NewRequest(strings.ToUpper(rtype), url, nil)
			if len(cheads) > 0 {
				for _, v := range cheads {
					hs := strings.Split(v, ":")
					request.Header.Set(hs[0], hs[1])
				}
			}
			response, err := client.Do(request)
			if err != nil {
				log.Fatalf("[*] Error making GET request: %s", err)
			}
			defer response.Body.Close()
			log.Printf("[*] Request complete! Finished Request No: #%v, Status: %v", count, response.StatusCode)
			totalPush++
			count++

			if response.StatusCode == 200 || response.StatusCode == 201 {
				successCount++
			}
			ch <- true

		default:
			log.Printf("[*] Bad HTTP method specified. Please specify either 'GET' or 'POST' as 'rtype'")
		}

	}

}

func main() {

	nCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(nCPU)

	urlString := flag.String("url", "", "Url to stress test e.g. 'http://acme.com'.")
	requestInt := flag.Int("rps", 0, "Number of requests to make simultaneously.")
	requestObject := flag.String("object", "", "Custom object to post e.g. {'foo':'bar'}.")
	objType := flag.String("objectType", "", "Type of object to post. e.g. 'xml' or 'json'.")
	numRequests := flag.Int("numR", 0, "Total number of requests to make.")
	reqType := flag.String("type", "", "HTTP request type you'd like to make. Either 'GET' or 'POST'.")
	heads := flag.String("headers", "", "Set HTTP headers. Format should be for example 'Auth:SomeToken,X-Header:Sugar'. Headers should be separated by commas.")
	flag.Parse()

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n\nParameters:\n", os.Args[0])
		flag.PrintDefaults()
	}

	// Customizing Transport to have larger connection pool
	defaultRoundTripper := http.DefaultTransport
	defaultTransportPointer, yoo := defaultRoundTripper.(*http.Transport)
	if !yoo {
		panic(fmt.Sprintf("defaultRoundTripper lied! Not an *http.Transport"))
	}

	defaultTransport := *defaultTransportPointer
	defaultTransport.MaxIdleConns = 1500
	defaultTransport.MaxIdleConnsPerHost = 1500

	client = &http.Client{Transport: &defaultTransport}

	start := time.Now()
	switch *urlString {
	case "":
		flag.Usage()
	default:
		ch := make(chan bool)
		for i := 0; i < *requestInt; i++ {
			go gatling(*urlString, *requestObject, *heads, ch, *reqType, *objType)
		}

		for r := 0; r < *numRequests; r++ {
			<-ch
		}

		elapsedTime := time.Since(start)
		failedCount := totalPush - successCount
		log.Printf("[*] Total number of successful requests: %v", successCount)
		log.Printf("[*] Total number of failed requests: %v", failedCount)
		log.Printf("[*] Total number of requests: %v", totalPush)
		log.Printf("[*] Total time elapsed: %v", elapsedTime)
	}

}
<commit_msg>updated request flags<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"
)

var client *http.Client
var successCount, totalPush int

func gatling(url string, object string, xHeaders string, ch chan<- bool, rtype string, otype string) {

	count := 0
	out := []byte(object)
	cheads := strings.Split(xHeaders, ",")

	for {

		switch strings.ToUpper(rtype) {
		case "POST":
			request, _ := http.NewRequest(strings.ToUpper(rtype), url, bytes.NewBuffer(out))
			switch otype {
			case "xml":
				request.Header.Set("Content-Type", "text/xml")
			case "json":
				request.Header.Set("Content-Type", "application/json")
			default:
				log.Printf("[*] Invalid content type. Please specify json or xml")
				os.Exit(1)
			}
			if len(cheads) > 0 {
				for _, v := range cheads {
					hs := strings.Split(v, ":")
					request.Header.Set(hs[0], hs[1])
				}
			}
			response, err := client.Do(request)
			if err != nil {
				log.Fatalf("[*] Error making POST request: %s", err)
			}
			defer response.Body.Close()

			log.Printf("[*] Request complete! Finished Request No: #%v, Status: %v", count, response.StatusCode)

			totalPush++
			count++

			if response.StatusCode == 200 || response.StatusCode == 201 {
				successCount++
			}
			ch <- true

		case "GET":
			request, _ := http.NewRequest(strings.ToUpper(rtype), url, nil)
			if len(cheads) > 0 {
				for _, v := range cheads {
					hs := strings.Split(v, ":")
					request.Header.Set(hs[0], hs[1])
				}
			}
			response, err := client.Do(request)
			if err != nil {
				log.Fatalf("[*] Error making GET request: %s", err)
			}
			defer response.Body.Close()
			log.Printf("[*] Request complete! Finished Request No: #%v, Status: %v", count, response.StatusCode)
			totalPush++
			count++

			if response.StatusCode == 200 || response.StatusCode == 201 {
				successCount++
			}
			ch <- true

		default:
			log.Printf("[*] Bad HTTP method specified. Please specify either 'GET' or 'POST' as 'rtype'")
		}

	}

}

func main() {

	nCPU := runtime.NumCPU()
	runtime.GOMAXPROCS(nCPU)

	url := flag.String("url", "", "Url to stress test e.g. 'http://acme.com'.")
	request := flag.Int("rps", 0, "Number of requests to make simultaneously.")
	data := flag.String("data", "", "Custom object to post e.g. {'foo':'bar'}.")
	dataType := flag.String("data-type", "", "Type of object to post. e.g. 'xml' or 'json'.")
	numRequests := flag.Int("total-requests", 0, "Total number of requests to make.")
	requestType := flag.String("type", "", "HTTP request type you'd like to make. Either 'GET' or 'POST'.")
	heads := flag.String("headers", "", "Set HTTP headers. Format should be for example 'Auth:SomeToken,X-Header:Sugar'. Headers should be separated by commas.")
	flag.Parse()

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n\nParameters:\n", os.Args[0])
		flag.PrintDefaults()
	}

	// Customizing Transport to have larger connection pool
	defaultRoundTripper := http.DefaultTransport
	defaultTransportPointer, yoo := defaultRoundTripper.(*http.Transport)
	if !yoo {
		panic(fmt.Sprintf("defaultRoundTripper lied! Not an *http.Transport"))
	}

	defaultTransport := *defaultTransportPointer
	defaultTransport.MaxIdleConns = 1500
	defaultTransport.MaxIdleConnsPerHost = 1500

	client = &http.Client{Transport: &defaultTransport}

	start := time.Now()
	switch *url {
	case "":
		flag.Usage()
	default:
		ch := make(chan bool)
		for i := 0; i < *request; i++ {
			go gatling(*url, *data, *heads, ch, *requestType, *dataType)
		}

		for r := 0; r < *numRequests; r++ {
			<-ch
		}

		elapsedTime := time.Since(start)
		failedCount := totalPush - successCount
		log.Printf("[*] Total number of successful requests: %v", successCount)
		log.Printf("[*] Total number of failed requests: %v", failedCount)
		log.Printf("[*] Total number of requests: %v", totalPush)
		log.Printf("[*] Total time elapsed: %v", elapsedTime)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
	"sync"

	"github.com/flynn/go-discoverd"
	"github.com/flynn/strowger/types"
)

func NewTCPListener(ip string, startPort, endPort int, ds DataStore, dc DiscoverdClient) *TCPListener {
	l := &TCPListener{
		IP:         ip,
		ds:         ds,
		wm:         NewWatchManager(),
		discoverd:  dc,
		services:   make(map[int]*tcpService),
		serviceIDs: make(map[string]*tcpService),
		listeners:  make(map[int]net.Listener),
		startPort:  startPort,
		endPort:    endPort,
	}
	l.Watcher = l.wm
	l.DataStoreReader = l.ds
	return l
}

type TCPListener struct {
	Watcher
	DataStoreReader

	IP string

	discoverd DiscoverdClient
	ds        DataStore
	wm        *WatchManager

	startPort int
	endPort   int
	listeners map[int]net.Listener

	mtx        sync.RWMutex
	services   map[int]*tcpService
	serviceIDs map[string]*tcpService
	closed     bool
}

func (l *TCPListener) AddRoute(route *strowger.Route) error {
	r := route.TCPRoute()
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	if l.closed {
		return ErrClosed
	}
	if r.Port == 0 {
		return l.addWithAllocatedPort(route)
	}
	route.ID = md5sum(strconv.Itoa(r.Port))
	return l.ds.Add(route)
}

var ErrNoPorts = errors.New("strowger: no ports available")

func (l *TCPListener) addWithAllocatedPort(route *strowger.Route) error {
	r := route.TCPRoute()
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	for r.Port = range l.listeners {
		r.Route.ID = md5sum(strconv.Itoa(r.Port))
		tempRoute := r.ToRoute()
		if err := l.ds.Add(tempRoute); err == nil {
			*route = *tempRoute
			return nil
		}
	}
	return ErrNoPorts
}

func (l *TCPListener) RemoveRoute(id string) error {
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	if l.closed {
		return ErrClosed
	}
	return l.ds.Remove(id)
}

func (l *TCPListener) Start() error {
	started := make(chan error)

	for i := l.startPort; i <= l.endPort; i++ {
		listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", l.IP, i))
		if err != nil {
			l.Close()
			return err
		}
		l.listeners[i] = listener
	}

	go l.ds.Sync(&tcpSyncHandler{l: l}, started)
	return <-started
}

func (l *TCPListener) Close() error {
	l.mtx.Lock()
	defer l.mtx.Unlock()
	l.ds.StopSync()
	for _, s := range l.services {
		s.Close()
	}
	for _, listener := range l.listeners {
		listener.Close()
	}
	l.closed = true
	return nil
}

type tcpSyncHandler struct {
	l *TCPListener
}

func (h *tcpSyncHandler) Add(data *strowger.Route) error {
	r := data.TCPRoute()

	h.l.mtx.Lock()
	defer h.l.mtx.Unlock()
	if h.l.closed {
		return nil
	}
	if _, ok := h.l.services[r.Port]; ok {
		return ErrExists
	}

	s := &tcpService{
		addr:   h.l.IP + ":" + strconv.Itoa(r.Port),
		port:   r.Port,
		parent: h.l,
	}
	var err error
	s.ss, err = h.l.discoverd.NewServiceSet(r.Service)
	if err != nil {
		return err
	}

	if listener, ok := h.l.listeners[r.Port]; ok {
		s.l = listener
		delete(h.l.listeners, r.Port)
	}

	started := make(chan error)
	go s.Serve(started)
	if err := <-started; err != nil {
		s.ss.Close()
		if s.l != nil {
			h.l.listeners[r.Port] = s.l
		}
		return err
	}
	h.l.services[r.Port] = s
	h.l.serviceIDs[data.ID] = s
	go h.l.wm.Send(&strowger.Event{Event: "add", ID: data.ID})
	return nil
}

func (h *tcpSyncHandler) Remove(id string) error {
	h.l.mtx.Lock()
	defer h.l.mtx.Unlock()
	if h.l.closed {
		return nil
	}

	service, ok := h.l.serviceIDs[id]
	if !ok {
		return ErrNotFound
	}
	service.Close()
	delete(h.l.services, service.port)
	delete(h.l.serviceIDs, id)
	go h.l.wm.Send(&strowger.Event{Event: "remove", ID: id})
	return nil
}

type tcpService struct {
	parent *TCPListener
	addr   string
	port   int
	l      net.Listener
	ss     discoverd.ServiceSet
}

func (s *tcpService) Close() {
	if s.port >= s.parent.startPort && s.port <= s.parent.endPort {
		s.parent.listeners[s.port] = s.l
	} else {
		s.l.Close()
	}
	s.ss.Close()
}

func (s *tcpService) Serve(started chan<- error) {
	var err error
	// TODO: close the listener while there are no backends available
	if s.l == nil {
		s.l, err = net.Listen("tcp", s.addr)
	}
	started <- err
	if err != nil {
		return
	}
	for {
		conn, err := s.l.Accept()
		if err != nil {
			break
		}
		go s.handle(conn)
	}
}

func (s *tcpService) getBackend() (conn net.Conn) {
	var err error
	for _, addr := range shuffle(s.ss.Addrs()) {
		// TODO: set deadlines
		conn, err = net.Dial("tcp", addr)
		if err != nil {
			log.Println("Error connecting to TCP backend:", err)
			// TODO: limit number of backends tried
			// TODO: temporarily quarantine failing backends
			continue
		}
		return
	}
	if err == nil {
		log.Println("No TCP backends found")
	} else {
		log.Println("Unable to find live backend, last error:", err)
	}
	return
}

func (s *tcpService) handle(conn net.Conn) {
	defer conn.Close()
	backend := s.getBackend()
	if backend == nil {
		return
	}
	defer backend.Close()

	// TODO: PROXY protocol

	done := make(chan struct{})
	go func() {
		io.Copy(backend, conn)
		backend.(*net.TCPConn).CloseWrite()
		close(done)
	}()
	io.Copy(conn, backend)
	conn.(*net.TCPConn).CloseWrite()
	<-done
	return
}
<commit_msg>Don't start TCP listeners if no ports are specified<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
	"sync"

	"github.com/flynn/go-discoverd"
	"github.com/flynn/strowger/types"
)

func NewTCPListener(ip string, startPort, endPort int, ds DataStore, dc DiscoverdClient) *TCPListener {
	l := &TCPListener{
		IP:         ip,
		ds:         ds,
		wm:         NewWatchManager(),
		discoverd:  dc,
		services:   make(map[int]*tcpService),
		serviceIDs: make(map[string]*tcpService),
		listeners:  make(map[int]net.Listener),
		startPort:  startPort,
		endPort:    endPort,
	}
	l.Watcher = l.wm
	l.DataStoreReader = l.ds
	return l
}

type TCPListener struct {
	Watcher
	DataStoreReader

	IP string

	discoverd DiscoverdClient
	ds        DataStore
	wm        *WatchManager

	startPort int
	endPort   int
	listeners map[int]net.Listener

	mtx        sync.RWMutex
	services   map[int]*tcpService
	serviceIDs map[string]*tcpService
	closed     bool
}

func (l *TCPListener) AddRoute(route *strowger.Route) error {
	r := route.TCPRoute()
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	if l.closed {
		return ErrClosed
	}
	if r.Port == 0 {
		return l.addWithAllocatedPort(route)
	}
	route.ID = md5sum(strconv.Itoa(r.Port))
	return l.ds.Add(route)
}

var ErrNoPorts = errors.New("strowger: no ports available")

func (l *TCPListener) addWithAllocatedPort(route *strowger.Route) error {
	r := route.TCPRoute()
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	for r.Port = range l.listeners {
		r.Route.ID = md5sum(strconv.Itoa(r.Port))
		tempRoute := r.ToRoute()
		if err := l.ds.Add(tempRoute); err == nil {
			*route = *tempRoute
			return nil
		}
	}
	return ErrNoPorts
}

func (l *TCPListener) RemoveRoute(id string) error {
	l.mtx.RLock()
	defer l.mtx.RUnlock()
	if l.closed {
		return ErrClosed
	}
	return l.ds.Remove(id)
}

func (l *TCPListener) Start() error {
	started := make(chan error)

	if l.startPort != 0 && l.endPort != 0 {
		for i := l.startPort; i <= l.endPort; i++ {
			listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", l.IP, i))
			if err != nil {
				l.Close()
				return err
			}
			l.listeners[i] = listener
		}
	}

	go l.ds.Sync(&tcpSyncHandler{l: l}, started)
	return <-started
}

func (l *TCPListener) Close() error {
	l.mtx.Lock()
	defer l.mtx.Unlock()
	l.ds.StopSync()
	for _, s := range l.services {
		s.Close()
	}
	for _, listener := range l.listeners {
		listener.Close()
	}
	l.closed = true
	return nil
}

type tcpSyncHandler struct {
	l *TCPListener
}

func (h *tcpSyncHandler) Add(data *strowger.Route) error {
	r := data.TCPRoute()

	h.l.mtx.Lock()
	defer h.l.mtx.Unlock()
	if h.l.closed {
		return nil
	}
	if _, ok := h.l.services[r.Port]; ok {
		return ErrExists
	}

	s := &tcpService{
		addr:   h.l.IP + ":" + strconv.Itoa(r.Port),
		port:   r.Port,
		parent: h.l,
	}
	var err error
	s.ss, err = h.l.discoverd.NewServiceSet(r.Service)
	if err != nil {
		return err
	}

	if listener, ok := h.l.listeners[r.Port]; ok {
		s.l = listener
		delete(h.l.listeners, r.Port)
	}

	started := make(chan error)
	go s.Serve(started)
	if err := <-started; err != nil {
		s.ss.Close()
		if s.l != nil {
			h.l.listeners[r.Port] = s.l
		}
		return err
	}
	h.l.services[r.Port] = s
	h.l.serviceIDs[data.ID] = s
	go h.l.wm.Send(&strowger.Event{Event: "add", ID: data.ID})
	return nil
}

func (h *tcpSyncHandler) Remove(id string) error {
	h.l.mtx.Lock()
	defer h.l.mtx.Unlock()
	if h.l.closed {
		return nil
	}

	service, ok := h.l.serviceIDs[id]
	if !ok {
		return ErrNotFound
	}
	service.Close()
	delete(h.l.services, service.port)
	delete(h.l.serviceIDs, id)
	go h.l.wm.Send(&strowger.Event{Event: "remove", ID: id})
	return nil
}

type tcpService struct {
	parent *TCPListener
	addr   string
	port   int
	l      net.Listener
	ss     discoverd.ServiceSet
}

func (s *tcpService) Close() {
	if s.port >= s.parent.startPort && s.port <= s.parent.endPort {
		s.parent.listeners[s.port] = s.l
	} else {
		s.l.Close()
	}
	s.ss.Close()
}

func (s *tcpService) Serve(started chan<- error) {
	var err error
	// TODO: close the listener while there are no backends available
	if s.l == nil {
		s.l, err = net.Listen("tcp", s.addr)
	}
	started <- err
	if err != nil {
		return
	}
	for {
		conn, err := s.l.Accept()
		if err != nil {
			break
		}
		go s.handle(conn)
	}
}

func (s *tcpService) getBackend() (conn net.Conn) {
	var err error
	for _, addr := range shuffle(s.ss.Addrs()) {
		// TODO: set deadlines
		conn, err = net.Dial("tcp", addr)
		if err != nil {
			log.Println("Error connecting to TCP backend:", err)
			// TODO: limit number of backends tried
			// TODO: temporarily quarantine failing backends
			continue
		}
		return
	}
	if err == nil {
		log.Println("No TCP backends found")
	} else {
		log.Println("Unable to find live backend, last error:", err)
	}
	return
}

func (s *tcpService) handle(conn net.Conn) {
	defer conn.Close()
	backend := s.getBackend()
	if backend == nil {
		return
	}
	defer backend.Close()

	// TODO: PROXY protocol

	done := make(chan struct{})
	go func() {
		io.Copy(backend, conn)
		backend.(*net.TCPConn).CloseWrite()
		close(done)
	}()
	io.Copy(conn, backend)
	conn.(*net.TCPConn).CloseWrite()
	<-done
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package kms

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"

	"github.com/minio/kes"
)

// Config contains various KMS-related configuration
// parameters - like KMS endpoints or authentication
// credentials.
type Config struct {
	// Endpoints contains a list of KMS server
	// HTTP endpoints.
	Endpoints []string

	// DefaultKeyID is the key ID used when
	// no explicit key ID is specified for
	// a cryptographic operation.
	DefaultKeyID string

	// Certificate is the client TLS certificate
	// to authenticate to KMS via mTLS.
	Certificate tls.Certificate

	// RootCAs is a set of root CA certificates
	// to verify the KMS server TLS certificate.
	RootCAs *x509.CertPool
}

// NewWithConfig returns a new KMS using the given
// configuration.
func NewWithConfig(config Config) (KMS, error) {
	if len(config.Endpoints) == 0 {
		return nil, errors.New("kms: no server endpoints")
	}
	var endpoints = make([]string, len(config.Endpoints)) // Copy => avoid being affect by any changes to the original slice
	copy(endpoints, config.Endpoints)

	client := kes.NewClientWithConfig("", &tls.Config{
		MinVersion:   tls.VersionTLS12,
		Certificates: []tls.Certificate{config.Certificate},
		RootCAs:      config.RootCAs,
	})
	client.Endpoints = endpoints
	return &kesClient{
		client:       client,
		defaultKeyID: config.DefaultKeyID,
	}, nil
}

type kesClient struct {
	defaultKeyID string
	client       *kes.Client
}

var _ KMS = (*kesClient)(nil) // compiler check

// Stat returns the current KES status containing a
// list of KES endpoints and the default key ID.
func (c *kesClient) Stat() (Status, error) {
	var endpoints = make([]string, len(c.client.Endpoints))
	copy(endpoints, c.client.Endpoints)
	return Status{
		Name:       "KES",
		Endpoints:  endpoints,
		DefaultKey: c.defaultKeyID,
	}, nil
}

// CreateKey tries to create a new key at the KMS with the
// given key ID.
//
// If the a key with the same keyID already exists then
// CreateKey returns kes.ErrKeyExists.
func (c *kesClient) CreateKey(keyID string) error {
	return c.client.CreateKey(context.Background(), keyID)
}

// GenerateKey generates a new data encryption key using
// the key at the KES server referenced by the key ID.
//
// The default key ID will be used if keyID is empty.
//
// The context is associated and tied to the generated DEK.
// The same context must be provided when the generated
// key should be decrypted.
func (c *kesClient) GenerateKey(keyID string, ctx Context) (DEK, error) {
	if keyID == "" {
		keyID = c.defaultKeyID
	}
	ctxBytes, err := ctx.MarshalText()
	if err != nil {
		return DEK{}, err
	}
	dek, err := c.client.GenerateKey(context.Background(), keyID, ctxBytes)
	if err != nil {
		return DEK{}, nil
	}
	return DEK{
		KeyID:      keyID,
		Plaintext:  dek.Plaintext,
		Ciphertext: dek.Ciphertext,
	}, nil
}

// DecryptKey decrypts the ciphertext with the key at the KES
// server referenced by the key ID. The context must match the
// context value used to generate the ciphertext.
func (c *kesClient) DecryptKey(keyID string, ciphertext []byte, ctx Context) ([]byte, error) {
	ctxBytes, err := ctx.MarshalText()
	if err != nil {
		return nil, err
	}
	return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes)
}
<commit_msg>kms: KES client should return non-nil error when GenerateKey fails (#12290)<commit_after>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package kms

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"

	"github.com/minio/kes"
)

// Config contains various KMS-related configuration
// parameters - like KMS endpoints or authentication
// credentials.
type Config struct {
	// Endpoints contains a list of KMS server
	// HTTP endpoints.
	Endpoints []string

	// DefaultKeyID is the key ID used when
	// no explicit key ID is specified for
	// a cryptographic operation.
	DefaultKeyID string

	// Certificate is the client TLS certificate
	// to authenticate to KMS via mTLS.
	Certificate tls.Certificate

	// RootCAs is a set of root CA certificates
	// to verify the KMS server TLS certificate.
	RootCAs *x509.CertPool
}

// NewWithConfig returns a new KMS using the given
// configuration.
func NewWithConfig(config Config) (KMS, error) {
	if len(config.Endpoints) == 0 {
		return nil, errors.New("kms: no server endpoints")
	}
	var endpoints = make([]string, len(config.Endpoints)) // Copy => avoid being affect by any changes to the original slice
	copy(endpoints, config.Endpoints)

	client := kes.NewClientWithConfig("", &tls.Config{
		MinVersion:   tls.VersionTLS12,
		Certificates: []tls.Certificate{config.Certificate},
		RootCAs:      config.RootCAs,
	})
	client.Endpoints = endpoints
	return &kesClient{
		client:       client,
		defaultKeyID: config.DefaultKeyID,
	}, nil
}

type kesClient struct {
	defaultKeyID string
	client       *kes.Client
}

var _ KMS = (*kesClient)(nil) // compiler check

// Stat returns the current KES status containing a
// list of KES endpoints and the default key ID.
func (c *kesClient) Stat() (Status, error) {
	var endpoints = make([]string, len(c.client.Endpoints))
	copy(endpoints, c.client.Endpoints)
	return Status{
		Name:       "KES",
		Endpoints:  endpoints,
		DefaultKey: c.defaultKeyID,
	}, nil
}

// CreateKey tries to create a new key at the KMS with the
// given key ID.
//
// If the a key with the same keyID already exists then
// CreateKey returns kes.ErrKeyExists.
func (c *kesClient) CreateKey(keyID string) error {
	return c.client.CreateKey(context.Background(), keyID)
}

// GenerateKey generates a new data encryption key using
// the key at the KES server referenced by the key ID.
//
// The default key ID will be used if keyID is empty.
//
// The context is associated and tied to the generated DEK.
// The same context must be provided when the generated
// key should be decrypted.
func (c *kesClient) GenerateKey(keyID string, ctx Context) (DEK, error) {
	if keyID == "" {
		keyID = c.defaultKeyID
	}
	ctxBytes, err := ctx.MarshalText()
	if err != nil {
		return DEK{}, err
	}
	dek, err := c.client.GenerateKey(context.Background(), keyID, ctxBytes)
	if err != nil {
		return DEK{}, err
	}
	return DEK{
		KeyID:      keyID,
		Plaintext:  dek.Plaintext,
		Ciphertext: dek.Ciphertext,
	}, nil
}

// DecryptKey decrypts the ciphertext with the key at the KES
// server referenced by the key ID. The context must match the
// context value used to generate the ciphertext.
func (c *kesClient) DecryptKey(keyID string, ciphertext []byte, ctx Context) ([]byte, error) {
	ctxBytes, err := ctx.MarshalText()
	if err != nil {
		return nil, err
	}
	return c.client.Decrypt(context.Background(), keyID, ciphertext, ctxBytes)
}
<|endoftext|>


<commit_before>package mux

import (
	"errors"
	"fmt"
	"log"
	"sync"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/client"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/msg"
)

// Mux will manage all connections and subscriptions. Will check if subscriptions
// limit is reached and spawn new connection when that happens. It will also listen
// to all incomming client messages and reconnect client with all its subscriptions
// in case of a failure
type Mux struct {
	cid           int
	publicChan    chan msg.Msg
	publicClients map[int]*client.Client
	privateChan   chan msg.Msg
	privateClient *client.Client
	mtx           *sync.RWMutex
	Err           error
	transform     bool
	apikey        string
	apisec        string
	subInfo       map[int64]event.Info
	authenticated bool
	publicURL     string
	authURL       string
}

// New returns pointer to instance of mux
func New() *Mux {
	return &Mux{
		publicChan:    make(chan msg.Msg),
		privateChan:   make(chan msg.Msg),
		publicClients: make(map[int]*client.Client),
		mtx:           &sync.RWMutex{},
		subInfo:       map[int64]event.Info{},
		publicURL:     "wss://api-pub.bitfinex.com/ws/2",
		authURL:       "wss://api.staging.bitfinex.com/ws/2",
	}
}

// TransformRaw enables data transformation and mapping to appropriate
// models before sending it to consumer
func (m *Mux) TransformRaw() *Mux {
	m.transform = true
	return m
}

// WithAPIKEY accepts and persists api key
func (m *Mux) WithAPIKEY(key string) *Mux {
	m.apikey = key
	return m
}

// WithAPISEC accepts and persists api sec
func (m *Mux) WithAPISEC(sec string) *Mux {
	m.apisec = sec
	return m
}

// WithAuthURL accepts and persists auth url
func (m *Mux) WithAuthURL(url string) *Mux {
	m.authURL = url
	return m
}

// Subscribe - given the details in form of event.Subscribe,
// subscribes client to public channels
func (m *Mux) Subscribe(sub event.Subscribe) *Mux {
	if m.Err != nil {
		return m
	}

	m.mtx.Lock()
	defer m.mtx.Unlock()

	if subscribed := m.publicClients[m.cid].SubAdded(sub); subscribed {
		return m
	}

	if m.Err = m.publicClients[m.cid].Subscribe(sub); m.Err != nil {
		return m
	}

	if limitReached := m.publicClients[m.cid].SubsLimitReached(); limitReached {
		log.Printf("subs limit is reached on cid: %d, spawning new conn\n", m.cid)
		m.addPublicClient()
	}
	return m
}

// Start creates initial clients for accepting connections
func (m *Mux) Start() *Mux {
	if m.hasAPIKeys() && m.privateClient == nil {
		m.addPrivateClient()
	}

	return m.addPublicClient()
}

// Listen accepts a callback func that will get called each time mux
// receives a message from any of its clients/subscriptions. It
// should be called last, after all setup calls are made
func (m *Mux) Listen(cb func(interface{}, error)) error {
	if m.Err != nil {
		return m.Err
	}

	for {
		select {
		case ms, ok := <-m.publicChan:
			if !ok {
				return errors.New("channel has closed unexpectedly")
			}
			if ms.Err != nil {
				cb(nil, fmt.Errorf("conn:%d has failed | err:%s | reconnecting", ms.CID, ms.Err))
				m.resetPublicClient(ms.CID)
				continue
			}
			// return raw payload data if transform is off
			if !m.transform {
				cb(ms.Data, nil)
				continue
			}
			// handle event type message
			if ms.IsEvent() {
				cb(m.recordEvent(ms.ProcessEvent()))
				continue
			}
			// handle data type message
			if ms.IsRaw() {
				cb(ms.ProcessRaw(m.subInfo))
				continue
			}
			cb(nil, fmt.Errorf("unrecognized msg signature: %s", ms.Data))
		case ms, ok := <-m.privateChan:
			if !ok {
				return errors.New("channel has closed unexpectedly")
			}
			if ms.Err != nil {
				cb(nil, fmt.Errorf("err: %s | reconnecting", ms.Err))
				m.resetPrivateClient()
				continue
			}
			// return raw payload data if transform is off
			if !m.transform {
				cb(ms.Data, nil)
				continue
			}
			// handle event type message
			if ms.IsEvent() {
				cb(m.recordEvent(ms.ProcessEvent()))
				continue
			}
			// handle data type message
			if ms.IsRaw() {
				cb(ms.ProcessPrivateRaw())
				continue
			}
			cb(nil, fmt.Errorf("unrecognized msg signature: %s", ms.Data))
		}
	}
}

// Send meant for authenticated input, takes payload in form of interface
// and calls client with it
func (m *Mux) Send(pld interface{}) error {
	if !m.authenticated || m.privateClient == nil {
		return errors.New("not authorized")
	}
	return m.privateClient.Send(pld)
}

func (m *Mux) hasAPIKeys() bool {
	return len(m.apikey) != 0 && len(m.apisec) != 0
}

func (m *Mux) recordEvent(i event.Info, err error) (event.Info, error) {
	switch i.Event {
	case "subscribed":
		m.subInfo[i.ChanID] = i
	case "auth":
		if i.Status == "OK" {
			m.subInfo[i.ChanID] = i
			m.authenticated = true
		}
	}
	// add more cases if/when needed
	return i, err
}

func (m *Mux) resetPublicClient(cid int) {
	// pull old client subscriptions
	subs := m.publicClients[cid].GetAllSubs()
	// add fresh client
	m.addPublicClient()
	// resubscribe old events
	for _, sub := range subs {
		log.Printf("resubscribing: %+v\n", sub)
		m.Subscribe(sub)
	}
	// remove old, closed channel from the list
	delete(m.publicClients, cid)
}

func (m *Mux) resetPrivateClient() {
	m.authenticated = false
	m.privateClient = nil
	m.addPrivateClient()
}

func (m *Mux) addPublicClient() *Mux {
	// adding new client so making sure we increment cid
	m.cid++
	// create new public client and pass error to mux if any
	c, err := client.
		New().
		WithID(m.cid).
		WithSubsLimit(25).
		Public(m.publicURL)
	if err != nil {
		m.Err = err
		return m
	}
	// add new client to list for later reference
	m.publicClients[m.cid] = c
	// start listening for incoming client messages
	go c.Read(m.publicChan)
	return m
}

func (m *Mux) addPrivateClient() *Mux {
	// create new private client and pass error to mux if any
	c, err := client.New().Private(m.apikey, m.apisec, m.authURL)
	if err != nil {
		m.Err = err
		return m
	}

	m.privateClient = c
	go c.Read(m.privateChan)
	return m
}
<commit_msg>adopting new message processing flow, exposing channel id to mux for updating subscriptions last_called_at<commit_after>package mux

import (
	"errors"
	"fmt"
	"log"
	"sync"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/event"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/client"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/mux/msg"
)

// Mux will manage all connections and subscriptions. Will check if subscriptions
// limit is reached and spawn new connection when that happens. It will also listen
// to all incomming client messages and reconnect client with all its subscriptions
// in case of a failure
type Mux struct {
	cid           int
	publicChan    chan msg.Msg
	publicClients map[int]*client.Client
	privateChan   chan msg.Msg
	privateClient *client.Client
	mtx           *sync.RWMutex
	Err           error
	transform     bool
	apikey        string
	apisec        string
	subInfo       map[int64]event.Info
	authenticated bool
	publicURL     string
	authURL       string
}

// New returns pointer to instance of mux
func New() *Mux {
	return &Mux{
		publicChan:    make(chan msg.Msg),
		privateChan:   make(chan msg.Msg),
		publicClients: make(map[int]*client.Client),
		mtx:           &sync.RWMutex{},
		subInfo:       map[int64]event.Info{},
		publicURL:     "wss://api-pub.bitfinex.com/ws/2",
		authURL:       "wss://api.staging.bitfinex.com/ws/2",
	}
}

// TransformRaw enables data transformation and mapping to appropriate
// models before sending it to consumer
func (m *Mux) TransformRaw() *Mux {
	m.transform = true
	return m
}

// WithAPIKEY accepts and persists api key
func (m *Mux) WithAPIKEY(key string) *Mux {
	m.apikey = key
	return m
}

// WithAPISEC accepts and persists api sec
func (m *Mux) WithAPISEC(sec string) *Mux {
	m.apisec = sec
	return m
}

// WithAuthURL accepts and persists auth url
func (m *Mux) WithAuthURL(url string) *Mux {
	m.authURL = url
	return m
}

// Subscribe - given the details in form of event.Subscribe,
// subscribes client to public channels
func (m *Mux) Subscribe(sub event.Subscribe) *Mux {
	if m.Err != nil {
		return m
	}

	m.mtx.Lock()
	defer m.mtx.Unlock()

	if subscribed := m.publicClients[m.cid].SubAdded(sub); subscribed {
		return m
	}

	if m.Err = m.publicClients[m.cid].Subscribe(sub); m.Err != nil {
		return m
	}

	if limitReached := m.publicClients[m.cid].SubsLimitReached(); limitReached {
		log.Printf("subs limit is reached on cid: %d, spawning new conn\n", m.cid)
		m.addPublicClient()
	}
	return m
}

// Start creates initial clients for accepting connections
func (m *Mux) Start() *Mux {
	if m.hasAPIKeys() && m.privateClient == nil {
		m.addPrivateClient()
	}

	return m.addPublicClient()
}

// Listen accepts a callback func that will get called each time mux
// receives a message from any of its clients/subscriptions. It
// should be called last, after all setup calls are made
func (m *Mux) Listen(cb func(interface{}, error)) error {
	if m.Err != nil {
		return m.Err
	}

	for {
		select {
		case ms, ok := <-m.publicChan:
			if !ok {
				return errors.New("channel has closed unexpectedly")
			}
			if ms.Err != nil {
				cb(nil, fmt.Errorf("conn:%d has failed | err:%s | reconnecting", ms.CID, ms.Err))
				m.resetPublicClient(ms.CID)
				continue
			}
			// return raw payload data if transform is off
			if !m.transform {
				cb(ms.Data, nil)
				continue
			}
			// handle event type message
			if ms.IsEvent() {
				cb(m.recordEvent(ms.ProcessEvent()))
				continue
			}
			// handle data type message
			if ms.IsRaw() {
				raw, pld, chID, _, err := ms.PreprocessRaw()
				if err != nil {
					cb(nil, err)
					continue
				}

				inf, ok := m.subInfo[chID]
				if !ok {
					cb(nil, fmt.Errorf("unrecognized chanId:%d", chID))
				}
				cb(ms.ProcessPublic(raw, pld, chID, inf))
				continue
			}
			cb(nil, fmt.Errorf("unrecognized msg signature: %s", ms.Data))
		case ms, ok := <-m.privateChan:
			if !ok {
				return errors.New("channel has closed unexpectedly")
			}
			if ms.Err != nil {
				cb(nil, fmt.Errorf("err: %s | reconnecting", ms.Err))
				m.resetPrivateClient()
				continue
			}
			// return raw payload data if transform is off
			if !m.transform {
				cb(ms.Data, nil)
				continue
			}
			// handle event type message
			if ms.IsEvent() {
				cb(m.recordEvent(ms.ProcessEvent()))
				continue
			}
			// handle data type message
			if ms.IsRaw() {
				raw, pld, chID, msgType, err := ms.PreprocessRaw()
				if err != nil {
					cb(nil, err)
					continue
				}
				cb(ms.ProcessPrivate(raw, pld, chID, msgType))
				continue
			}
			cb(nil, fmt.Errorf("unrecognized msg signature: %s", ms.Data))
		}
	}
}

// Send meant for authenticated input, takes payload in form of interface
// and calls client with it
func (m *Mux) Send(pld interface{}) error {
	if !m.authenticated || m.privateClient == nil {
		return errors.New("not authorized")
	}
	return m.privateClient.Send(pld)
}

func (m *Mux) hasAPIKeys() bool {
	return len(m.apikey) != 0 && len(m.apisec) != 0
}

func (m *Mux) recordEvent(i event.Info, err error) (event.Info, error) {
	switch i.Event {
	case "subscribed":
		m.subInfo[i.ChanID] = i
	case "auth":
		if i.Status == "OK" {
			m.subInfo[i.ChanID] = i
			m.authenticated = true
		}
	}
	// add more cases if/when needed
	return i, err
}

func (m *Mux) resetPublicClient(cid int) {
	// pull old client subscriptions
	subs := m.publicClients[cid].GetAllSubs()
	// add fresh client
	m.addPublicClient()
	// resubscribe old events
	for _, sub := range subs {
		log.Printf("resubscribing: %+v\n", sub)
		m.Subscribe(sub)
	}
	// remove old, closed channel from the list
	delete(m.publicClients, cid)
}

func (m *Mux) resetPrivateClient() {
	m.authenticated = false
	m.privateClient = nil
	m.addPrivateClient()
}

func (m *Mux) addPublicClient() *Mux {
	// adding new client so making sure we increment cid
	m.cid++
	// create new public client and pass error to mux if any
	c, err := client.
		New().
		WithID(m.cid).
		WithSubsLimit(25).
		Public(m.publicURL)
	if err != nil {
		m.Err = err
		return m
	}
	// add new client to list for later reference
	m.publicClients[m.cid] = c
	// start listening for incoming client messages
	go c.Read(m.publicChan)
	return m
}

func (m *Mux) addPrivateClient() *Mux {
	// create new private client and pass error to mux if any
	c, err := client.New().Private(m.apikey, m.apisec, m.authURL)
	if err != nil {
		m.Err = err
		return m
	}

	m.privateClient = c
	go c.Read(m.privateChan)
	return m
}
<|endoftext|>


<commit_before>package goja

import (
	"reflect"
	"strconv"
)

type objectGoSliceReflect struct {
	objectGoReflect
	lengthProp valueProperty
}

func (o *objectGoSliceReflect) init() {
	o.baseObject.init()
	o.class = classArray
	o.prototype = o.val.runtime.global.ArrayPrototype
	o.lengthProp.writable = false
	o._setLen()
	o.baseObject._put("length", &o.lengthProp)
}

func (o *objectGoSliceReflect) _setLen() {
	o.lengthProp.value = intToValue(int64(o.value.Len()))
}

func (o *objectGoSliceReflect) _has(n Value) bool {
	if idx := toIdx(n); idx >= 0 {
		return idx < int64(o.value.Len())
	}
	return false
}

func (o *objectGoSliceReflect) _hasStr(name string) bool {
	if idx := strToIdx(name); idx >= 0 {
		return idx < int64(o.value.Len())
	}
	return false
}

func (o *objectGoSliceReflect) getIdx(idx int64) Value {
	if idx < int64(o.value.Len()) {
		return o.val.runtime.ToValue(o.value.Index(int(idx)).Interface())
	}
	return nil
}

func (o *objectGoSliceReflect) _get(n Value) Value {
	if idx := toIdx(n); idx >= 0 {
		return o.getIdx(idx)
	}
	return nil
}

func (o *objectGoSliceReflect) _getStr(name string) Value {
	if idx := strToIdx(name); idx >= 0 {
		return o.getIdx(idx)
	}
	return nil
}

func (o *objectGoSliceReflect) get(n Value) Value {
	if v := o._get(n); v != nil {
		return v
	}
	return o.objectGoReflect.get(n)
}

func (o *objectGoSliceReflect) getProp(n Value) Value {
	if v := o._get(n); v != nil {
		return v
	}
	return o.objectGoReflect.getProp(n)
}

func (o *objectGoSliceReflect) getPropStr(name string) Value {
	if v := o._getStr(name); v != nil {
		return v
	}
	return o.objectGoReflect.getPropStr(name)
}

func (o *objectGoSliceReflect) getOwnProp(name string) Value {
	if v := o._getStr(name); v != nil {
		return v
	}
	return o.objectGoReflect.getOwnProp(name)
}

func (o *objectGoSliceReflect) putIdx(idx int64, v Value, throw bool) {
	if idx >= int64(o.value.Len()) {
		o.val.runtime.typeErrorResult(throw, "Cannot extend a Go reflect slice")
		return
	}
	val, err := o.val.runtime.toReflectValue(v, o.value.Type().Elem())
	if err != nil {
		o.val.runtime.typeErrorResult(throw, "Go type conversion error: %v", err)
		return
	}
	o.value.Index(int(idx)).Set(val)
}

func (o *objectGoSliceReflect) put(n Value, val Value, throw bool) {
	if idx := toIdx(n); idx >= 0 {
		o.putIdx(idx, val, throw)
		return
	}
	// TODO: length
	o.objectGoReflect.put(n, val, throw)
}

func (o *objectGoSliceReflect) putStr(name string, val Value, throw bool) {
	if idx := strToIdx(name); idx >= 0 {
		o.putIdx(idx, val, throw)
		return
	}
	// TODO: length
	o.objectGoReflect.putStr(name, val, throw)
}

func (o *objectGoSliceReflect) hasProperty(n Value) bool {
	if o._has(n) {
		return true
	}
	return o.objectGoReflect.hasProperty(n)
}

func (o *objectGoSliceReflect) hasPropertyStr(name string) bool {
	if o._hasStr(name) {
		return true
	}
	return o.objectGoReflect.hasOwnPropertyStr(name)
}

func (o *objectGoSliceReflect) hasOwnProperty(n Value) bool {
	if o._has(n) {
		return true
	}
	return o.objectGoReflect.hasOwnProperty(n)
}

func (o *objectGoSliceReflect) hasOwnPropertyStr(name string) bool {
	if o._hasStr(name) {
		return true
	}
	return o.objectGoReflect.hasOwnPropertyStr(name)
}

func (o *objectGoSliceReflect) _putProp(name string, value Value, writable, enumerable, configurable bool) Value {
	o.putStr(name, value, false)
	return value
}

func (o *objectGoSliceReflect) defineOwnProperty(name Value, descr objectImpl, throw bool) bool {
	if descr.hasPropertyStr("get") || descr.hasPropertyStr("set") {
		o.val.runtime.typeErrorResult(throw, "Host objects do not support accessor properties")
		return false
	}
	o.put(name, descr.getStr("value"), throw)
	return true
}

func (o *objectGoSliceReflect) toPrimitiveNumber() Value {
	return o.toPrimitiveString()
}

func (o *objectGoSliceReflect) toPrimitiveString() Value {
	return o.val.runtime.arrayproto_join(FunctionCall{
		This: o.val,
	})
}

func (o *objectGoSliceReflect) toPrimitive() Value {
	return o.toPrimitiveString()
}

func (o *objectGoSliceReflect) deleteStr(name string, throw bool) bool {
	if idx := strToIdx(name); idx >= 0 && idx < int64(o.value.Len()) {
		o.value.Index(int(idx)).Set(reflect.Zero(o.value.Type().Elem()))
		return true
	}
	return o.objectGoReflect.deleteStr(name, throw)
}

func (o *objectGoSliceReflect) delete(name Value, throw bool) bool {
	if idx := toIdx(name); idx >= 0 && idx < int64(o.value.Len()) {
		o.value.Index(int(idx)).Set(reflect.Zero(o.value.Type().Elem()))
		return true
	}
	return true
}

type gosliceReflectPropIter struct {
	o          *objectGoSliceReflect
	recursive  bool
	idx, limit int
}

func (i *gosliceReflectPropIter) next() (propIterItem, iterNextFunc) {
	if i.idx < i.limit && i.idx < i.o.value.Len() {
		name := strconv.Itoa(i.idx)
		i.idx++
		return propIterItem{name: name, enumerable: _ENUM_TRUE}, i.next
	}

	if i.recursive {
		return i.o.prototype.self._enumerate(i.recursive)()
	}

	return propIterItem{}, nil
}

func (o *objectGoSliceReflect) enumerate(all, recursive bool) iterNextFunc {
	return (&propFilterIter{
		wrapped: o._enumerate(recursive),
		all:     all,
		seen:    make(map[string]bool),
	}).next
}

func (o *objectGoSliceReflect) _enumerate(recursive bool) iterNextFunc {
	return (&gosliceReflectPropIter{
		o:         o,
		recursive: recursive,
		limit:     o.value.Len(),
	}).next
}

func (o *objectGoSliceReflect) equal(other objectImpl) bool {
	if other, ok := other.(*objectGoSliceReflect); ok {
		return o.value.Interface() == other.value.Interface()
	}
	return false
}

func (o *objectGoSliceReflect) sortLen() int64 {
	return int64(o.value.Len())
}

func (o *objectGoSliceReflect) sortGet(i int64) Value {
	return o.get(intToValue(i))
}

func (o *objectGoSliceReflect) swap(i, j int64) {
	ii := intToValue(i)
	jj := intToValue(j)
	x := o.get(ii)
	y := o.get(jj)

	o.put(ii, y, false)
	o.put(jj, x, false)
}
<commit_msg>Fixed init() call<commit_after>package goja

import (
	"reflect"
	"strconv"
)

type objectGoSliceReflect struct {
	objectGoReflect
	lengthProp valueProperty
}

func (o *objectGoSliceReflect) init() {
	o.objectGoReflect.init()
	o.class = classArray
	o.prototype = o.val.runtime.global.ArrayPrototype
	o.lengthProp.writable = false
	o._setLen()
	o.baseObject._put("length", &o.lengthProp)
}

func (o *objectGoSliceReflect) _setLen() {
	o.lengthProp.value = intToValue(int64(o.value.Len()))
}

func (o *objectGoSliceReflect) _has(n Value) bool {
	if idx := toIdx(n); idx >= 0 {
		return idx < int64(o.value.Len())
	}
	return false
}

func (o *objectGoSliceReflect) _hasStr(name string) bool {
	if idx := strToIdx(name); idx >= 0 {
		return idx < int64(o.value.Len())
	}
	return false
}

func (o *objectGoSliceReflect) getIdx(idx int64) Value {
	if idx < int64(o.value.Len()) {
		return o.val.runtime.ToValue(o.value.Index(int(idx)).Interface())
	}
	return nil
}

func (o *objectGoSliceReflect) _get(n Value) Value {
	if idx := toIdx(n); idx >= 0 {
		return o.getIdx(idx)
	}
	return nil
}

func (o *objectGoSliceReflect) _getStr(name string) Value {
	if idx := strToIdx(name); idx >= 0 {
		return o.getIdx(idx)
	}
	return nil
}

func (o *objectGoSliceReflect) get(n Value) Value {
	if v := o._get(n); v != nil {
		return v
	}
	return o.objectGoReflect.get(n)
}

func (o *objectGoSliceReflect) getProp(n Value) Value {
	if v := o._get(n); v != nil {
		return v
	}
	return o.objectGoReflect.getProp(n)
}

func (o *objectGoSliceReflect) getPropStr(name string) Value {
	if v := o._getStr(name); v != nil {
		return v
	}
	return o.objectGoReflect.getPropStr(name)
}

func (o *objectGoSliceReflect) getOwnProp(name string) Value {
	if v := o._getStr(name); v != nil {
		return v
	}
	return o.objectGoReflect.getOwnProp(name)
}

func (o *objectGoSliceReflect) putIdx(idx int64, v Value, throw bool) {
	if idx >= int64(o.value.Len()) {
		o.val.runtime.typeErrorResult(throw, "Cannot extend a Go reflect slice")
		return
	}
	val, err := o.val.runtime.toReflectValue(v, o.value.Type().Elem())
	if err != nil {
		o.val.runtime.typeErrorResult(throw, "Go type conversion error: %v", err)
		return
	}
	o.value.Index(int(idx)).Set(val)
}

func (o *objectGoSliceReflect) put(n Value, val Value, throw bool) {
	if idx := toIdx(n); idx >= 0 {
		o.putIdx(idx, val, throw)
		return
	}
	// TODO: length
	o.objectGoReflect.put(n, val, throw)
}

func (o *objectGoSliceReflect) putStr(name string, val Value, throw bool) {
	if idx := strToIdx(name); idx >= 0 {
		o.putIdx(idx, val, throw)
		return
	}
	// TODO: length
	o.objectGoReflect.putStr(name, val, throw)
}

func (o *objectGoSliceReflect) hasProperty(n Value) bool {
	if o._has(n) {
		return true
	}
	return o.objectGoReflect.hasProperty(n)
}

func (o *objectGoSliceReflect) hasPropertyStr(name string) bool {
	if o._hasStr(name) {
		return true
	}
	return o.objectGoReflect.hasOwnPropertyStr(name)
}

func (o *objectGoSliceReflect) hasOwnProperty(n Value) bool {
	if o._has(n) {
		return true
	}
	return o.objectGoReflect.hasOwnProperty(n)
}

func (o *objectGoSliceReflect) hasOwnPropertyStr(name string) bool {
	if o._hasStr(name) {
		return true
	}
	return o.objectGoReflect.hasOwnPropertyStr(name)
}

func (o *objectGoSliceReflect) _putProp(name string, value Value, writable, enumerable, configurable bool) Value {
	o.putStr(name, value, false)
	return value
}

func (o *objectGoSliceReflect) defineOwnProperty(name Value, descr objectImpl, throw bool) bool {
	if descr.hasPropertyStr("get") || descr.hasPropertyStr("set") {
		o.val.runtime.typeErrorResult(throw, "Host objects do not support accessor properties")
		return false
	}
	o.put(name, descr.getStr("value"), throw)
	return true
}

func (o *objectGoSliceReflect) toPrimitiveNumber() Value {
	return o.toPrimitiveString()
}

func (o *objectGoSliceReflect) toPrimitiveString() Value {
	return o.val.runtime.arrayproto_join(FunctionCall{
		This: o.val,
	})
}

func (o *objectGoSliceReflect) toPrimitive() Value {
	return o.toPrimitiveString()
}

func (o *objectGoSliceReflect) deleteStr(name string, throw bool) bool {
	if idx := strToIdx(name); idx >= 0 && idx < int64(o.value.Len()) {
		o.value.Index(int(idx)).Set(reflect.Zero(o.value.Type().Elem()))
		return true
	}
	return o.objectGoReflect.deleteStr(name, throw)
}

func (o *objectGoSliceReflect) delete(name Value, throw bool) bool {
	if idx := toIdx(name); idx >= 0 && idx < int64(o.value.Len()) {
		o.value.Index(int(idx)).Set(reflect.Zero(o.value.Type().Elem()))
		return true
	}
	return true
}

type gosliceReflectPropIter struct {
	o          *objectGoSliceReflect
	recursive  bool
	idx, limit int
}

func (i *gosliceReflectPropIter) next() (propIterItem, iterNextFunc) {
	if i.idx < i.limit && i.idx < i.o.value.Len() {
		name := strconv.Itoa(i.idx)
		i.idx++
		return propIterItem{name: name, enumerable: _ENUM_TRUE}, i.next
	}

	if i.recursive {
		return i.o.prototype.self._enumerate(i.recursive)()
	}

	return propIterItem{}, nil
}

func (o *objectGoSliceReflect) enumerate(all, recursive bool) iterNextFunc {
	return (&propFilterIter{
		wrapped: o._enumerate(recursive),
		all:     all,
		seen:    make(map[string]bool),
	}).next
}

func (o *objectGoSliceReflect) _enumerate(recursive bool) iterNextFunc {
	return (&gosliceReflectPropIter{
		o:         o,
		recursive: recursive,
		limit:     o.value.Len(),
	}).next
}

func (o *objectGoSliceReflect) equal(other objectImpl) bool {
	if other, ok := other.(*objectGoSliceReflect); ok {
		return o.value.Interface() == other.value.Interface()
	}
	return false
}

func (o *objectGoSliceReflect) sortLen() int64 {
	return int64(o.value.Len())
}

func (o *objectGoSliceReflect) sortGet(i int64) Value {
	return o.get(intToValue(i))
}

func (o *objectGoSliceReflect) swap(i, j int64) {
	ii := intToValue(i)
	jj := intToValue(j)
	x := o.get(ii)
	y := o.get(jj)

	o.put(ii, y, false)
	o.put(jj, x, false)
}
<|endoftext|>


<commit_before>// Package tuntap provides a portable interface to create and use
// TUN/TAP virtual network interfaces.
//
// Note that while this package lets you create the interface and pass
// packets to/from it, it does not provide an API to configure the
// interface. Interface configuration is a very large topic and should
// be dealt with separately.
package tuntap

import (
	"encoding/binary"
	"io"
	"net"
	"os"
	"unsafe"
)

type DevKind int

const (
	// Receive/send layer routable 3 packets (IP, IPv6...). Notably,
	// you don't receive link-local multicast with this interface
	// type.
	DevTun DevKind = iota
	// Receive/send Ethernet II frames. You receive all packets that
	// would be visible on an Ethernet link, including broadcast and
	// multicast traffic.
	DevTap
)

const (
	// various ethernet protocols, using the same names as linux does
	ETH_P_IP   int = 0x0800
	ETH_P_IPV6 int = 0x86dd
)

type Packet struct {
	// The Ethernet type of the packet. Commonly seen values are
	// 0x8000 for IPv4 and 0x86dd for IPv6.
	Protocol int
	// True if the packet was too large to be read completely.
	Truncated bool
	// The raw bytes of the Ethernet payload (for DevTun) or the full
	// Ethernet frame (for DevTap).
	Body []byte
}

type Interface struct {
	name string
	file *os.File
}

// Disconnect from the tun/tap interface.
//
// If the interface isn't configured to be persistent, it is
// immediately destroyed by the kernel.
func (t *Interface) Close() error {
	return t.file.Close()
}

// The name of the interface. May be different from the name given to
// Open(), if the latter was a pattern.
func (t *Interface) Name() string {
	return t.name
}

// Read a single packet from the kernel.
func (t *Interface) ReadPacket() (*Packet, error) {
	buf := make([]byte, 1600)

	n, err := t.file.Read(buf)
	if err != nil {
		return nil, err
	}

	pkt := &Packet{Body: buf[4:n]}
	pkt.Protocol = int(binary.BigEndian.Uint16(buf[2:4]))
	flags := *(*uint16)(unsafe.Pointer(&buf[0]))
	if flags&flagTruncated != 0 {
		pkt.Truncated = true
	}
	return pkt, nil
}

// Send a single packet to the kernel.
func (t *Interface) WritePacket(pkt *Packet) error {
	// If only we had writev(), I could do zero-copy here...
	buf := make([]byte, len(pkt.Body)+4)
	binary.BigEndian.PutUint16(buf[2:4], uint16(pkt.Protocol))
	copy(buf[4:], pkt.Body)
	n, err := t.file.Write(buf)
	if err != nil {
		return err
	}
	if n != len(buf) {
		return io.ErrShortWrite
	}
	return nil
}

// Open connects to the specified tun/tap interface.
//
// If the specified device has been configured as persistent, this
// simply looks like a "cable connected" event to observers of the
// interface. Otherwise, the interface is created out of thin air.
//
// ifPattern can be an exact interface name, e.g. "tun42", or a
// pattern containing one %d format specifier, e.g. "tun%d". In the
// latter case, the kernel will select an available interface name and
// create it.
//
// Returns a TunTap object with channels to send/receive packets, or
// nil and an error if connecting to the interface failed.
func Open(ifPattern string, kind DevKind) (*Interface, error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	ifName, err := createInterface(file, ifPattern, kind)
	if err != nil {
		file.Close()
		return nil, err
	}

	return &Interface{ifName, file}, nil
}

// query parts of Packets
// NOTE: think whether this wouldn't be better done with a interface and two implemenations, one for each protocol

// return the destination IP
func (p *Packet) DIP() net.IP {
	switch p.Protocol {
	case ETH_P_IP:
		return net.IP(p.Body[16:20])
	case ETH_P_IPV6:
		return net.IP(p.Body[24:40])
	}
	return net.IP{}
}

// return the source IP
func (p *Packet) SIP() net.IP {
	switch p.Protocol {
	case ETH_P_IP:
		return net.IP(p.Body[12:16])
	case ETH_P_IPV6:
		return net.IP(p.Body[8:24])
	}
	return net.IP{}
}

// return the 6-bit DSCP field
func (p *Packet) DSCP() int {
	switch p.Protocol {
	case ETH_P_IP:
		return int(p.Body[1] >> 2)
	case ETH_P_IPV6:
		return int((p.Body[0]&0x0f)<<2 | (p.Body[1]&0xf0)>>6)
	}
	return 0
}
<commit_msg>added IPProto()<commit_after>// Package tuntap provides a portable interface to create and use
// TUN/TAP virtual network interfaces.
//
// Note that while this package lets you create the interface and pass
// packets to/from it, it does not provide an API to configure the
// interface. Interface configuration is a very large topic and should
// be dealt with separately.
package tuntap

import (
	"encoding/binary"
	"io"
	"net"
	"os"
	"unsafe"
)

type DevKind int

const (
	// Receive/send layer routable 3 packets (IP, IPv6...). Notably,
	// you don't receive link-local multicast with this interface
	// type.
	DevTun DevKind = iota
	// Receive/send Ethernet II frames. You receive all packets that
	// would be visible on an Ethernet link, including broadcast and
	// multicast traffic.
	DevTap
)

const (
	// various ethernet protocols, using the same names as linux does
	ETH_P_IP   int = 0x0800
	ETH_P_IPV6 int = 0x86dd
)

type Packet struct {
	// The Ethernet type of the packet. Commonly seen values are
	// 0x8000 for IPv4 and 0x86dd for IPv6.
	Protocol int
	// True if the packet was too large to be read completely.
	Truncated bool
	// The raw bytes of the Ethernet payload (for DevTun) or the full
	// Ethernet frame (for DevTap).
	Body []byte
}

type Interface struct {
	name string
	file *os.File
}

// Disconnect from the tun/tap interface.
//
// If the interface isn't configured to be persistent, it is
// immediately destroyed by the kernel.
func (t *Interface) Close() error {
	return t.file.Close()
}

// The name of the interface. May be different from the name given to
// Open(), if the latter was a pattern.
func (t *Interface) Name() string {
	return t.name
}

// Read a single packet from the kernel.
func (t *Interface) ReadPacket() (*Packet, error) {
	buf := make([]byte, 1600)

	n, err := t.file.Read(buf)
	if err != nil {
		return nil, err
	}

	pkt := &Packet{Body: buf[4:n]}
	pkt.Protocol = int(binary.BigEndian.Uint16(buf[2:4]))
	flags := *(*uint16)(unsafe.Pointer(&buf[0]))
	if flags&flagTruncated != 0 {
		pkt.Truncated = true
	}
	return pkt, nil
}

// Send a single packet to the kernel.
func (t *Interface) WritePacket(pkt *Packet) error {
	// If only we had writev(), I could do zero-copy here...
	buf := make([]byte, len(pkt.Body)+4)
	binary.BigEndian.PutUint16(buf[2:4], uint16(pkt.Protocol))
	copy(buf[4:], pkt.Body)
	n, err := t.file.Write(buf)
	if err != nil {
		return err
	}
	if n != len(buf) {
		return io.ErrShortWrite
	}
	return nil
}

// Open connects to the specified tun/tap interface.
//
// If the specified device has been configured as persistent, this
// simply looks like a "cable connected" event to observers of the
// interface. Otherwise, the interface is created out of thin air.
//
// ifPattern can be an exact interface name, e.g. "tun42", or a
// pattern containing one %d format specifier, e.g. "tun%d". In the
// latter case, the kernel will select an available interface name and
// create it.
//
// Returns a TunTap object with channels to send/receive packets, or
// nil and an error if connecting to the interface failed.
func Open(ifPattern string, kind DevKind) (*Interface, error) {
	file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	ifName, err := createInterface(file, ifPattern, kind)
	if err != nil {
		file.Close()
		return nil, err
	}

	return &Interface{ifName, file}, nil
}

// query parts of Packets
// NOTE: think whether this wouldn't be better done with a interface and two implemenations, one for each protocol

// return the destination IP
func (p *Packet) DIP() net.IP {
	switch p.Protocol {
	case ETH_P_IP:
		return net.IP(p.Body[16:20])
	case ETH_P_IPV6:
		return net.IP(p.Body[24:40])
	}
	return net.IP{}
}

// return the source IP
func (p *Packet) SIP() net.IP {
	switch p.Protocol {
	case ETH_P_IP:
		return net.IP(p.Body[12:16])
	case ETH_P_IPV6:
		return net.IP(p.Body[8:24])
	}
	return net.IP{}
}

// return the 6-bit DSCP field
func (p *Packet) DSCP() int {
	switch p.Protocol {
	case ETH_P_IP:
		return int(p.Body[1] >> 2)
	case ETH_P_IPV6:
		return int((p.Body[0]&0x0f)<<2 | (p.Body[1]&0xf0)>>6)
	}
	return 0
}

// return the IP protocol, the offset to the IP datagram payload, and true if the payload is from a non-first fragment
// returns 0,0,false if parsing fails or the IPv6 header 59 (no-next-header) is found
func (p *Packet) IPProto() (int, int, bool) {
	fragment := false
	switch p.Protocol {
	case ETH_P_IP:
		fragment = (p.Body[6]&0x1f)|p.Body[7] != 0
		return int(p.Body[9]), int(p.Body[0]&0xf) << 4, fragment
	case ETH_P_IPV6:
		// finding the IP protocol in the case of IPv6 is slightly messy. we have to scan down the IPv6 header chain and find the last one
		next := p.Body[6]
		at := 40
		for true {
			if at+4 > len(p.Body) {
				// off the end of the body. there must have been a garbage value somewhere
				return 0, 0, false
			}
			switch next {
			case 0, // hop-by-hop
				43, // routing extension
				60: // destination options extension
				// skip over this header and continue to the next one
				next = p.Body[at]
				at += 8 + int(p.Body[at+1])*8
			case 44: // fragment extension
				next = p.Body[at]
				at += 8
				fragment = p.Body[at+2]|(p.Body[at+3]&0xf8) != 0
			case 51: // AH header (it is likely that the next proto is ESP, but just in case it isn't we might as well decode it)
				next = p.Body[at]
				at += 8 + int(p.Body[at+1])*4 // note unlike most IPv6 headers the length of AH is in 4-byte units
			case 59: // no next header
				return 0, len(p.Body), fragment
			default:
				return int(next), at, fragment
			}
		}
	}
	return 0, 0, false
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strconv"
	"strings"
	"syscall"

	"encoding/json"
	"io/ioutil"
	"net/http"
	"os/signal"

	"github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
)

// These are the error codes returned.
const (
	ExitLoadConfigError = iota
	ExitParseConfigError
)

type (
	// Spriteful handles the API endpoints.
	Spriteful struct {
		BindHost   string   `json:"bind-host"`
		BindPort   int      `json:"bind-port"`
		Repository string   `json:"repository"`
		Servers    []Server `json:"servers"`
	}

	// Server represents a server with it's boot configuration.
	Server struct {
		MacAddress  string                 `json:"mac"`
		Kernel      string                 `json:"kernel"`
		Initrd      []string               `json:"initrd"`
		CommandLine map[string]interface{} `json:"cmdline"`
	}

	// PixieResponse is the response required by pixie core for booting up servers.
	PixieResponse struct {
		Kernel      string                 `json:"kernel"`
		Initrd      []string               `json:"initrd"`
		CommandLine map[string]interface{} `json:"cmdline"`
	}
)

// main starts Spriteful API using the provided configuration.
func main() {
	logrus.Info("Starting Spriteful API...")
	config := flag.String("config", "config.json", "spriteful configuration")
	flag.Parse()
	data, err := ioutil.ReadFile(*config)
	if err != nil {
		logrus.WithField(logrus.ErrorKey, err).Fatal("unable to read config")
		os.Exit(ExitLoadConfigError)
	}
	var sprite Spriteful
	if err := json.Unmarshal(data, &sprite); err != nil {
		logrus.WithField(logrus.ErrorKey, err).Fatal("unable to parse config.")
		os.Exit(ExitParseConfigError)
	}
	logrus.Infof(`Config "%s" loaded.`, *config)

	sprite.startApi()
}

// startApi starts the Spriteful API.
func (s *Spriteful) startApi() {
	container := restful.NewContainer()
	s.register(container)

	bindAddress := net.JoinHostPort(s.BindHost, strconv.Itoa(s.BindPort))
	server := &http.Server{
		Addr:    bindAddress,
		Handler: container,
	}
	go server.ListenAndServe()
	logrus.Infof(`Spriteful API now listening at "%s".`, bindAddress)

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
	<-ch
	logrus.Info("Shutting down Spriteful API...")
}

// register registers the endpoints for the API.
func (s *Spriteful) register(container *restful.Container) {
	logrus.Info("Creating API endpoints...")

	ws := &restful.WebService{}
	ws.Path("/api/v1")

	ws.Route(ws.GET("boot/{mac-addr}").To(s.handleBootRequest).
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON).
		Param(ws.PathParameter("mac-addr", "the mac address")).
		Writes(PixieResponse{}))
	logrus.Info(`pixiecore endpoint created at "api/v1/boot/{mac}".`)

	ws.Route(ws.GET("/static/{resource:*}").To(s.handleResourceRequest).
		Param(ws.PathParameter("resource", "the resource file")))
	logrus.Info(`static endpoint created at "api/v1/static/{.*}".`)

	container.Add(ws)
}

// handleBootRequest handles the http request for server boot configuration.
func (s *Spriteful) handleBootRequest(req *restful.Request, res *restful.Response) {
	logrus.Info("Received pixiecore request...")
	macAddress := req.PathParameter("mac-addr")
	server, err := s.findServerConfig(macAddress)
	if err != nil {
		res.WriteError(http.StatusNotFound, err)
	} else {
		res.WriteEntity(&PixieResponse{
			Kernel:      server.Kernel,
			Initrd:      server.Initrd,
			CommandLine: server.CommandLine,
		})
	}
}

// handleResourceRequest handles the http request for static  resources.
func (s *Spriteful) handleResourceRequest(req *restful.Request, res *restful.Response) {
	logrus.Info("Received resource request...")
	resource := req.PathParameter("resource")

	resourcePath, err := s.findResource(resource)
	if err != nil {
		res.WriteError(http.StatusNotFound, err)
	} else {
		http.ServeFile(res.ResponseWriter, req.Request, resourcePath)
	}
}

// findServerConfig returns the server config for the requested MAC address.
// Returns an error if no configuration is found.
func (s *Spriteful) findServerConfig(macAddress string) (*Server, error) {
	logrus.Infof(`requesting configuration for server "%s".`, macAddress)
	for _, server := range s.Servers {
		if strings.EqualFold(macAddress, server.MacAddress) {
			logrus.Info("configuration found.")
			return &server, nil
		}
	}
	logrus.Warn("configuration not found.")
	return nil, errors.New(fmt.Sprintf("no configuration defined for %s.", macAddress))
}

// findResource returns the full resource path if the requested resource exists.
// Returns an error if the resource does not exist.
func (s *Spriteful) findResource(resource string) (string, error) {
	logrus.Info(`requesting resource "%s".`, resource)
	resourcePath := path.Join(s.Repository, resource)
	if _, err := os.Stat(resourcePath); os.IsNotExist(err) {
		logrus.Warn("resource does not exist.")
		return "", errors.New(fmt.Sprintf("resource does not exist at %s.", resourcePath))
	}
	logrus.Info("resource found.")
	return resourcePath, nil
}
<commit_msg>fixed wrong logging<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strconv"
	"strings"
	"syscall"

	"encoding/json"
	"io/ioutil"
	"net/http"
	"os/signal"

	"github.com/Sirupsen/logrus"
	"github.com/emicklei/go-restful"
)

// These are the error codes returned.
const (
	ExitLoadConfigError = iota
	ExitParseConfigError
)

type (
	// Spriteful handles the API endpoints.
	Spriteful struct {
		BindHost   string   `json:"bind-host"`
		BindPort   int      `json:"bind-port"`
		Repository string   `json:"repository"`
		Servers    []Server `json:"servers"`
	}

	// Server represents a server with it's boot configuration.
	Server struct {
		MacAddress  string                 `json:"mac"`
		Kernel      string                 `json:"kernel"`
		Initrd      []string               `json:"initrd"`
		CommandLine map[string]interface{} `json:"cmdline"`
	}

	// PixieResponse is the response required by pixie core for booting up servers.
	PixieResponse struct {
		Kernel      string                 `json:"kernel"`
		Initrd      []string               `json:"initrd"`
		CommandLine map[string]interface{} `json:"cmdline"`
	}
)

// main starts Spriteful API using the provided configuration.
func main() {
	logrus.Info("Starting Spriteful API...")
	config := flag.String("config", "config.json", "spriteful configuration")
	flag.Parse()
	data, err := ioutil.ReadFile(*config)
	if err != nil {
		logrus.WithField(logrus.ErrorKey, err).Fatal("unable to read config")
		os.Exit(ExitLoadConfigError)
	}
	var sprite Spriteful
	if err := json.Unmarshal(data, &sprite); err != nil {
		logrus.WithField(logrus.ErrorKey, err).Fatal("unable to parse config.")
		os.Exit(ExitParseConfigError)
	}
	logrus.Infof(`Config "%s" loaded.`, *config)

	sprite.startApi()
}

// startApi starts the Spriteful API.
func (s *Spriteful) startApi() {
	container := restful.NewContainer()
	s.register(container)

	bindAddress := net.JoinHostPort(s.BindHost, strconv.Itoa(s.BindPort))
	server := &http.Server{
		Addr:    bindAddress,
		Handler: container,
	}
	go server.ListenAndServe()
	logrus.Infof(`Spriteful API now listening at "%s".`, bindAddress)

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
	<-ch
	logrus.Info("Shutting down Spriteful API...")
}

// register registers the endpoints for the API.
func (s *Spriteful) register(container *restful.Container) {
	logrus.Info("Creating API endpoints...")

	ws := &restful.WebService{}
	ws.Path("/api/v1")

	ws.Route(ws.GET("boot/{mac-addr}").To(s.handleBootRequest).
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON).
		Param(ws.PathParameter("mac-addr", "the mac address")).
		Writes(PixieResponse{}))
	logrus.Info(`pixiecore endpoint created at "api/v1/boot/{mac}".`)

	ws.Route(ws.GET("/static/{resource:*}").To(s.handleResourceRequest).
		Param(ws.PathParameter("resource", "the resource file")))
	logrus.Info(`static endpoint created at "api/v1/static/{.*}".`)

	container.Add(ws)
}

// handleBootRequest handles the http request for server boot configuration.
func (s *Spriteful) handleBootRequest(req *restful.Request, res *restful.Response) {
	logrus.Info("Received pixiecore request...")
	macAddress := req.PathParameter("mac-addr")
	server, err := s.findServerConfig(macAddress)
	if err != nil {
		res.WriteError(http.StatusNotFound, err)
	} else {
		res.WriteEntity(&PixieResponse{
			Kernel:      server.Kernel,
			Initrd:      server.Initrd,
			CommandLine: server.CommandLine,
		})
	}
}

// handleResourceRequest handles the http request for static  resources.
func (s *Spriteful) handleResourceRequest(req *restful.Request, res *restful.Response) {
	logrus.Info("Received resource request...")
	resource := req.PathParameter("resource")

	resourcePath, err := s.findResource(resource)
	if err != nil {
		res.WriteError(http.StatusNotFound, err)
	} else {
		http.ServeFile(res.ResponseWriter, req.Request, resourcePath)
	}
}

// findServerConfig returns the server config for the requested MAC address.
// Returns an error if no configuration is found.
func (s *Spriteful) findServerConfig(macAddress string) (*Server, error) {
	logrus.Infof(`requesting configuration for server "%s".`, macAddress)
	for _, server := range s.Servers {
		if strings.EqualFold(macAddress, server.MacAddress) {
			logrus.Info("configuration found.")
			return &server, nil
		}
	}
	logrus.Warn("configuration not found.")
	return nil, errors.New(fmt.Sprintf("no configuration defined for %s.", macAddress))
}

// findResource returns the full resource path if the requested resource exists.
// Returns an error if the resource does not exist.
func (s *Spriteful) findResource(resource string) (string, error) {
	logrus.Infof(`requesting resource "%s".`, resource)
	resourcePath := path.Join(s.Repository, resource)
	if _, err := os.Stat(resourcePath); os.IsNotExist(err) {
		logrus.Warn("resource does not exist.")
		return "", errors.New(fmt.Sprintf("resource does not exist at %s.", resourcePath))
	}
	logrus.Info("resource found.")
	return resourcePath, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"os/exec"
	"sync"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	checkoutCmd = &cobra.Command{
		Use:   "checkout",
		Short: "Checks out LFS files into the working copy",
		Run:   checkoutCommand,
	}
)

func checkoutCommand(cmd *cobra.Command, args []string) {

	// Parameters are filters
	// firstly convert any pathspecs to the root of the repo, in case this is being executed in a sub-folder
	var rootedpaths = make([]string, len(args))
	inchan := make(chan string, 1)
	outchan, err := lfs.ConvertCwdFilesRelativeToRepo(inchan)
	if err != nil {
		Panic(err, "Could not checkout")
	}
	for _, arg := range args {
		inchan <- arg
		rootedpaths = append(rootedpaths, <-outchan)
	}
	close(inchan)
	checkoutWithIncludeExclude(rootedpaths, nil)
}

func init() {
	RootCmd.AddCommand(checkoutCmd)
}

// Checkout from items reported from the fetch process (in parallel)
func checkoutAllFromFetchChan(c chan *lfs.WrappedPointer) {
	tracerx.Printf("starting fetch/parallel checkout")
	checkoutFromFetchChan(nil, nil, c)
}

func checkoutFromFetchChan(include []string, exclude []string, in chan *lfs.WrappedPointer) {
	ref, err := git.CurrentRef()
	if err != nil {
		Panic(err, "Could not checkout")
	}
	// Need to ScanTree to identify multiple files with the same content (fetch will only report oids once)
	pointers, err := lfs.ScanTree(ref)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	// Map oid to multiple pointers
	mapping := make(map[string][]*lfs.WrappedPointer)
	for _, pointer := range pointers {
		if lfs.FilenamePassesIncludeExcludeFilter(pointer.Name, include, exclude) {
			mapping[pointer.Oid] = append(mapping[pointer.Oid], pointer)
		}
	}

	// Launch git update-index
	c := make(chan *lfs.WrappedPointer)
	var wait sync.WaitGroup
	wait.Add(1)

	go func() {
		checkoutWithChan(c)
		wait.Done()
	}()

	// Feed it from in, which comes from fetch
	for p := range in {
		// Add all of the files for this oid
		for _, fp := range mapping[p.Oid] {
			c <- fp
		}
	}
	close(c)
	wait.Wait()
}

func checkoutWithIncludeExclude(include []string, exclude []string) {
	ref, err := git.CurrentRef()
	if err != nil {
		Panic(err, "Could not checkout")
	}

	pointers, err := lfs.ScanTree(ref)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	var wait sync.WaitGroup
	wait.Add(1)

	c := make(chan *lfs.WrappedPointer)

	go func() {
		checkoutWithChan(c)
		wait.Done()
	}()

	// Count bytes for progress
	var totalBytes int64
	for _, pointer := range pointers {
		totalBytes += pointer.Size
	}
	progress := lfs.NewProgressMeter(len(pointers), totalBytes, false)
	totalBytes = 0
	for _, pointer := range pointers {
		totalBytes += pointer.Size
		if lfs.FilenamePassesIncludeExcludeFilter(pointer.Name, include, exclude) {
			progress.Add(pointer.Name)
			c <- pointer
			// not strictly correct (parallel) but we don't have a callback & it's just local
			// plus only 1 slot in channel so it'll block & be close
			progress.TransferBytes("checkout", pointer.Name, pointer.Size, totalBytes, int(pointer.Size))
			progress.FinishTransfer(pointer.Name)
		} else {
			progress.Skip(pointer.Size)
		}
	}
	close(c)
	wait.Wait()
	progress.Finish()

}

func checkoutAll() {
	checkoutWithIncludeExclude(nil, nil)
}

// Populate the working copy with the real content of objects where the file is
// either missing, or contains a matching pointer placeholder, from a list of pointers.
// If the file exists but has other content it is left alone
func checkoutWithChan(in <-chan *lfs.WrappedPointer) {
	// Fire up the update-index command
	cmd := exec.Command("git", "update-index", "-q", "--refresh", "--stdin")
	updateIdxStdin, err := cmd.StdinPipe()
	if err != nil {
		Panic(err, "Could not update the index")
	}

	if err := cmd.Start(); err != nil {
		Panic(err, "Could not update the index")
	}

	// Get a converter from repo-relative to cwd-relative
	// Since writing data & calling git update-index must be relative to cwd
	repopathchan := make(chan string, 1)
	cwdpathchan, err := lfs.ConvertRepoFilesRelativeToCwd(repopathchan)
	if err != nil {
		Panic(err, "Could not convert file paths")
	}

	// As files come in, write them to the wd and update the index
	for pointer := range in {

		// Check the content - either missing or still this pointer (not exist is ok)
		filepointer, err := lfs.DecodePointerFromFile(pointer.Name)
		if err != nil && !os.IsNotExist(err) {
			if err == lfs.NotAPointerError {
				// File has non-pointer content, leave it alone
				continue
			}
			Panic(err, "Problem accessing %v", pointer.Name)
		}
		if filepointer != nil && filepointer.Oid != pointer.Oid {
			// User has probably manually reset a file to another commit
			// while leaving it a pointer; don't mess with this
			continue
		}
		// OK now we can (over)write the file content
		repopathchan <- pointer.Name
		cwdfilepath := <-cwdpathchan
		err = lfs.PointerSmudgeToFile(cwdfilepath, pointer.Pointer, nil)
		if err != nil {
			Panic(err, "Could not checkout file")
		}

		updateIdxStdin.Write([]byte(cwdfilepath + "\n"))
	}
	close(repopathchan)

	updateIdxStdin.Close()
	if err := cmd.Wait(); err != nil {
		Panic(err, "Error updating the git index")
	}

}
<commit_msg>ンンンン ン<commit_after>package commands

import (
	"os"
	"os/exec"
	"sync"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	checkoutCmd = &cobra.Command{
		Use:   "checkout",
		Short: "Checks out LFS files into the working copy",
		Run:   checkoutCommand,
	}
)

func checkoutCommand(cmd *cobra.Command, args []string) {

	// Parameters are filters
	// firstly convert any pathspecs to the root of the repo, in case this is being executed in a sub-folder
	var rootedpaths = make([]string, len(args))
	inchan := make(chan string, 1)
	outchan, err := lfs.ConvertCwdFilesRelativeToRepo(inchan)
	if err != nil {
		Panic(err, "Could not checkout")
	}
	for _, arg := range args {
		inchan <- arg
		rootedpaths = append(rootedpaths, <-outchan)
	}
	close(inchan)
	checkoutWithIncludeExclude(rootedpaths, nil)
}

func init() {
	RootCmd.AddCommand(checkoutCmd)
}

// Checkout from items reported from the fetch process (in parallel)
func checkoutAllFromFetchChan(c chan *lfs.WrappedPointer) {
	tracerx.Printf("starting fetch/parallel checkout")
	checkoutFromFetchChan(nil, nil, c)
}

func checkoutFromFetchChan(include []string, exclude []string, in chan *lfs.WrappedPointer) {
	ref, err := git.CurrentRef()
	if err != nil {
		Panic(err, "Could not checkout")
	}
	// Need to ScanTree to identify multiple files with the same content (fetch will only report oids once)
	pointers, err := lfs.ScanTree(ref)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	// Map oid to multiple pointers
	mapping := make(map[string][]*lfs.WrappedPointer)
	for _, pointer := range pointers {
		if lfs.FilenamePassesIncludeExcludeFilter(pointer.Name, include, exclude) {
			mapping[pointer.Oid] = append(mapping[pointer.Oid], pointer)
		}
	}

	// Launch git update-index
	c := make(chan *lfs.WrappedPointer)
	var wait sync.WaitGroup
	wait.Add(1)

	go func() {
		checkoutWithChan(c)
		wait.Done()
	}()

	// Feed it from in, which comes from fetch
	for p := range in {
		// Add all of the files for this oid
		for _, fp := range mapping[p.Oid] {
			c <- fp
		}
	}
	close(c)
	wait.Wait()
}

func checkoutWithIncludeExclude(include []string, exclude []string) {
	ref, err := git.CurrentRef()
	if err != nil {
		Panic(err, "Could not checkout")
	}

	pointers, err := lfs.ScanTree(ref)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	var wait sync.WaitGroup
	wait.Add(1)

	c := make(chan *lfs.WrappedPointer, 1)

	go func() {
		checkoutWithChan(c)
		wait.Done()
	}()

	// Count bytes for progress
	var totalBytes int64
	for _, pointer := range pointers {
		totalBytes += pointer.Size
	}
	progress := lfs.NewProgressMeter(len(pointers), totalBytes, false)
	progress.Start()
	totalBytes = 0
	for _, pointer := range pointers {
		totalBytes += pointer.Size
		if lfs.FilenamePassesIncludeExcludeFilter(pointer.Name, include, exclude) {
			progress.Add(pointer.Name)
			c <- pointer
			// not strictly correct (parallel) but we don't have a callback & it's just local
			// plus only 1 slot in channel so it'll block & be close
			progress.TransferBytes("checkout", pointer.Name, pointer.Size, totalBytes, int(pointer.Size))
			progress.FinishTransfer(pointer.Name)
		} else {
			progress.Skip(pointer.Size)
		}
	}
	close(c)
	wait.Wait()
	progress.Finish()

}

func checkoutAll() {
	checkoutWithIncludeExclude(nil, nil)
}

// Populate the working copy with the real content of objects where the file is
// either missing, or contains a matching pointer placeholder, from a list of pointers.
// If the file exists but has other content it is left alone
func checkoutWithChan(in <-chan *lfs.WrappedPointer) {
	// Fire up the update-index command
	cmd := exec.Command("git", "update-index", "-q", "--refresh", "--stdin")
	updateIdxStdin, err := cmd.StdinPipe()
	if err != nil {
		Panic(err, "Could not update the index")
	}

	if err := cmd.Start(); err != nil {
		Panic(err, "Could not update the index")
	}

	// Get a converter from repo-relative to cwd-relative
	// Since writing data & calling git update-index must be relative to cwd
	repopathchan := make(chan string, 1)
	cwdpathchan, err := lfs.ConvertRepoFilesRelativeToCwd(repopathchan)
	if err != nil {
		Panic(err, "Could not convert file paths")
	}

	// As files come in, write them to the wd and update the index
	for pointer := range in {

		// Check the content - either missing or still this pointer (not exist is ok)
		filepointer, err := lfs.DecodePointerFromFile(pointer.Name)
		if err != nil && !os.IsNotExist(err) {
			if err == lfs.NotAPointerError {
				// File has non-pointer content, leave it alone
				continue
			}
			Panic(err, "Problem accessing %v", pointer.Name)
		}
		if filepointer != nil && filepointer.Oid != pointer.Oid {
			// User has probably manually reset a file to another commit
			// while leaving it a pointer; don't mess with this
			continue
		}
		// OK now we can (over)write the file content
		repopathchan <- pointer.Name
		cwdfilepath := <-cwdpathchan
		err = lfs.PointerSmudgeToFile(cwdfilepath, pointer.Pointer, nil)
		if err != nil {
			Panic(err, "Could not checkout file")
		}

		updateIdxStdin.Write([]byte(cwdfilepath + "\n"))
	}
	close(repopathchan)

	updateIdxStdin.Close()
	if err := cmd.Wait(); err != nil {
		Panic(err, "Error updating the git index")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"time"
	"github.com/valyala/fasthttp"
	"net"
)

var bytesSlash = []byte("/") // heap optimization
var byteZero = []byte{0}     // heap optimization

// HTTPClient is a reusable HTTP Client.
type HTTPClient struct {
	client     fasthttp.Client
	Host       []byte
	HostString string
	debug      int
}

// HTTPClientDoOptions wraps options uses when calling `Do`.
type HTTPClientDoOptions struct {
	Debug                int
	PrettyPrintResponses bool
}

// NewHTTPClient creates a new HTTPClient.
func NewHTTPClient(host string, debug int, timeout time.Duration) *HTTPClient {
	return &HTTPClient{
		client: fasthttp.Client{
			Name: "query_benchmarker",
			Dial: func(addr string) (net.Conn, error) {
				return fasthttp.DialTimeout(addr, timeout)
			},
		},
		Host:       []byte(host),
		HostString: host,
		debug:      debug,
	}
}

// Do performs the action specified by the given Query. It uses fasthttp, and
// tries to minimize heap allocations.
func (w *HTTPClient) Do(q *Query, opts *HTTPClientDoOptions) (lag float64, err error) {
	// populate uri from the reusable byte slice:
	uri := make([]byte, 0, 100)
	uri = append(uri, w.Host...)
	uri = append(uri, bytesSlash...)
	uri = append(uri, q.Path...)

	// populate a request with data from the Query:
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)

	req.Header.SetMethodBytes(q.Method)
	req.Header.SetRequestURIBytes(uri)
	req.SetBody(q.Body)
	// Perform the request while tracking latency:
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)
	start := time.Now()
	err = w.client.Do(req, resp)
	lag = float64(time.Since(start).Nanoseconds()) / 1e6 // milliseconds

	if err != nil || resp.StatusCode() != fasthttp.StatusOK {
		values, _ := url.ParseQuery(string(uri))
		fmt.Printf("debug: url: %s, path %s, parsed url - %s\n", string(uri), q.Path, values)
	}

	// Check that the status code was 200 OK:
	if err == nil {
		sc := resp.StatusCode()
		if sc != fasthttp.StatusOK {
			err = fmt.Errorf("Invalid write response (status %d): %s", sc, resp.Body())
			return
		}
	}

	if opts != nil {
		// Print debug messages, if applicable:
		switch opts.Debug {
		case 1:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms\n", q.HumanLabel, lag)
		case 2:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
		case 3:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
			fmt.Fprintf(os.Stderr, "debug:   request: %s\n", string(q.String()))
		case 4:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
			fmt.Fprintf(os.Stderr, "debug:   request: %s\n", string(q.String()))
			fmt.Fprintf(os.Stderr, "debug:   response: %s\n", string(resp.Body()))
		default:
		}

		// Pretty print JSON responses, if applicable:
		if opts.PrettyPrintResponses {
			// InfluxQL responses are in JSON and can be pretty-printed here.
			// Flux responses are just simple CSV.

			prefix := fmt.Sprintf("ID %d: ", q.ID)
			if json.Valid(resp.Body()) {
				var pretty bytes.Buffer
				err = json.Indent(&pretty, resp.Body(), prefix, "  ")
				if err != nil {
					return
				}

				_, err = fmt.Fprintf(os.Stderr, "%s%s\n", prefix, pretty)
				if err != nil {
					return
				}
			} else {
				_, err = fmt.Fprintf(os.Stderr, "%s%s\n", prefix, resp.Body())
				if err != nil {
					return
				}
			}
		}
	}

	return lag, err
}
<commit_msg>resolved conflict<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"time"
	"net"
	"github.com/valyala/fasthttp"
)

var bytesSlash = []byte("/") // heap optimization
var byteZero = []byte{0}     // heap optimization

// HTTPClient is a reusable HTTP Client.
type HTTPClient struct {
	client     fasthttp.Client
	Host       []byte
	HostString string
	debug      int
}

// HTTPClientDoOptions wraps options uses when calling `Do`.
type HTTPClientDoOptions struct {
	Debug                int
	PrettyPrintResponses bool
}

// NewHTTPClient creates a new HTTPClient.
func NewHTTPClient(host string, debug int, timeout time.Duration) *HTTPClient {
	return &HTTPClient{
		client: fasthttp.Client{
			Name: "query_benchmarker",
			Dial: func(addr string) (net.Conn, error) {
				return fasthttp.DialTimeout(addr, timeout)
			},
		},
		Host:       []byte(host),
		HostString: host,
		debug:      debug,
	}
}

// Do performs the action specified by the given Query. It uses fasthttp, and
// tries to minimize heap allocations.
func (w *HTTPClient) Do(q *Query, opts *HTTPClientDoOptions) (lag float64, err error) {
	// populate uri from the reusable byte slice:
	uri := make([]byte, 0, 100)
	uri = append(uri, w.Host...)
	uri = append(uri, bytesSlash...)
	uri = append(uri, q.Path...)

	// populate a request with data from the Query:
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)

	req.Header.SetMethodBytes(q.Method)
	req.Header.SetRequestURIBytes(uri)
	req.SetBody(q.Body)
	// Perform the request while tracking latency:
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)
	start := time.Now()
	err = w.client.Do(req, resp)
	lag = float64(time.Since(start).Nanoseconds()) / 1e6 // milliseconds

	if err != nil || resp.StatusCode() != fasthttp.StatusOK {
		values, _ := url.ParseQuery(string(uri))
		fmt.Printf("debug: url: %s, path %s, parsed url - %s\n", string(uri), q.Path, values)
	}

	// Check that the status code was 200 OK:
	if err == nil {
		sc := resp.StatusCode()
		if sc != fasthttp.StatusOK {
			err = fmt.Errorf("Invalid write response (status %d): %s", sc, resp.Body())
			return
		}
	}

	if opts != nil {
		// Print debug messages, if applicable:
		switch opts.Debug {
		case 1:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms\n", q.HumanLabel, lag)
		case 2:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
		case 3:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
			fmt.Fprintf(os.Stderr, "debug:   request: %s\n", string(q.String()))
		case 4:
			fmt.Fprintf(os.Stderr, "debug: %s in %7.2fms -- %s\n", q.HumanLabel, lag, q.HumanDescription)
			fmt.Fprintf(os.Stderr, "debug:   request: %s\n", string(q.String()))
			fmt.Fprintf(os.Stderr, "debug:   response: %s\n", string(resp.Body()))
		default:
		}

		// Pretty print JSON responses, if applicable:
		if opts.PrettyPrintResponses {
			// InfluxQL responses are in JSON and can be pretty-printed here.
			// Flux responses are just simple CSV.

			prefix := fmt.Sprintf("ID %d: ", q.ID)
			if json.Valid(resp.Body()) {
				var pretty bytes.Buffer
				err = json.Indent(&pretty, resp.Body(), prefix, "  ")
				if err != nil {
					return
				}

				_, err = fmt.Fprintf(os.Stderr, "%s%s\n", prefix, pretty)
				if err != nil {
					return
				}
			} else {
				_, err = fmt.Fprintf(os.Stderr, "%s%s\n", prefix, resp.Body())
				if err != nil {
					return
				}
			}
		}
	}

	return lag, err
}
<|endoftext|>


<commit_before>// Copyright 2012 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 format

import (
	"bytes"
	"go/parser"
	"go/token"
	"io/ioutil"
	"strings"
	"testing"
)

const testfile = "format_test.go"

func diff(t *testing.T, dst, src []byte) {
	line := 1
	offs := 0 // line offset
	for i := 0; i < len(dst) && i < len(src); i++ {
		d := dst[i]
		s := src[i]
		if d != s {
			t.Errorf("dst:%d: %s\n", line, dst[offs:i+1])
			t.Errorf("src:%d: %s\n", line, src[offs:i+1])
			return
		}
		if s == '\n' {
			line++
			offs = i + 1
		}
	}
	if len(dst) != len(src) {
		t.Errorf("len(dst) = %d, len(src) = %d\nsrc = %q", len(dst), len(src), src)
	}
}

func TestNode(t *testing.T) {
	src, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatal(err)
	}

	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, testfile, src, parser.ParseComments)
	if err != nil {
		t.Fatal(err)
	}

	var buf bytes.Buffer

	if err = Node(&buf, fset, file); err != nil {
		t.Fatal("Node failed:", err)
	}

	diff(t, buf.Bytes(), src)
}

func TestSource(t *testing.T) {
	src, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatal(err)
	}

	res, err := Source(src)
	if err != nil {
		t.Fatal("Source failed:", err)
	}

	diff(t, res, src)
}

// Test cases that are expected to fail are marked by the prefix "ERROR".
var tests = []string{
	// declaration lists
	`import "go/format"`,
	"var x int",
	"var x int\n\ntype T struct{}",

	// statement lists
	"x := 0",
	"f(a, b, c)\nvar x int = f(1, 2, 3)",

	// indentation, leading and trailing space
	"\tx := 0\n\tgo f()",
	"\tx := 0\n\tgo f()\n\n\n",
	"\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n",
	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n",
	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation inside raw strings

	// erroneous programs
	"ERRORvar x",
	"ERROR1 + 2 +",
	"ERRORx :=  0",
}

func String(s string) (string, error) {
	res, err := Source([]byte(s))
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func TestPartial(t *testing.T) {
	for _, src := range tests {
		if strings.HasPrefix(src, "ERROR") {
			// test expected to fail
			src = src[5:] // remove ERROR prefix
			res, err := String(src)
			if err == nil && res == src {
				t.Errorf("formatting succeeded but was expected to fail:\n%q", src)
			}
		} else {
			// test expected to succeed
			res, err := String(src)
			if err != nil {
				t.Errorf("formatting failed (%s):\n%q", err, src)
			} else if res != src {
				t.Errorf("formatting incorrect:\nsource: %q\nresult: %q", src, res)
			}
		}
	}
}
<commit_msg>go/format: fix failing test (fix build)<commit_after>// Copyright 2012 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 format

import (
	"bytes"
	"go/parser"
	"go/token"
	"io/ioutil"
	"strings"
	"testing"
)

const testfile = "format_test.go"

func diff(t *testing.T, dst, src []byte) {
	line := 1
	offs := 0 // line offset
	for i := 0; i < len(dst) && i < len(src); i++ {
		d := dst[i]
		s := src[i]
		if d != s {
			t.Errorf("dst:%d: %s\n", line, dst[offs:i+1])
			t.Errorf("src:%d: %s\n", line, src[offs:i+1])
			return
		}
		if s == '\n' {
			line++
			offs = i + 1
		}
	}
	if len(dst) != len(src) {
		t.Errorf("len(dst) = %d, len(src) = %d\nsrc = %q", len(dst), len(src), src)
	}
}

func TestNode(t *testing.T) {
	src, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatal(err)
	}

	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, testfile, src, parser.ParseComments)
	if err != nil {
		t.Fatal(err)
	}

	var buf bytes.Buffer

	if err = Node(&buf, fset, file); err != nil {
		t.Fatal("Node failed:", err)
	}

	diff(t, buf.Bytes(), src)
}

func TestSource(t *testing.T) {
	src, err := ioutil.ReadFile(testfile)
	if err != nil {
		t.Fatal(err)
	}

	res, err := Source(src)
	if err != nil {
		t.Fatal("Source failed:", err)
	}

	diff(t, res, src)
}

// Test cases that are expected to fail are marked by the prefix "ERROR".
var tests = []string{
	// declaration lists
	`import "go/format"`,
	"var x int",
	"var x int\n\ntype T struct{}",

	// statement lists
	"x := 0",
	"f(a, b, c)\nvar x int = f(1, 2, 3)",

	// indentation, leading and trailing space
	"\tx := 0\n\tgo f()",
	"\tx := 0\n\tgo f()\n\n\n",
	"\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n",
	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n",
	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation inside raw strings

	// erroneous programs
	"ERROR1 + 2 +",
	"ERRORx :=  0",
}

func String(s string) (string, error) {
	res, err := Source([]byte(s))
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func TestPartial(t *testing.T) {
	for _, src := range tests {
		if strings.HasPrefix(src, "ERROR") {
			// test expected to fail
			src = src[5:] // remove ERROR prefix
			res, err := String(src)
			if err == nil && res == src {
				t.Errorf("formatting succeeded but was expected to fail:\n%q", src)
			}
		} else {
			// test expected to succeed
			res, err := String(src)
			if err != nil {
				t.Errorf("formatting failed (%s):\n%q", err, src)
			} else if res != src {
				t.Errorf("formatting incorrect:\nsource: %q\nresult: %q", src, res)
			}
		}
	}
}
<|endoftext|>