<commit_before>package zmq

import (
	"bytes"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/zeromq/goczmq"
)

const (
	HeartbeatInterval = time.Second
	HeartbeatLiveness = 3

	Ready     = "\001"
	Heartbeat = "\002"
)

// Broker implements the Paranoid Pirate queue described in the zguide:
// http://zguide.zeromq.org/py:all#Robust-Reliable-Queuing-Paranoid-Pirate-Pattern
//
// NOTE(limouren): it might make a good interface
type Broker struct {
	// NOTE: goroutines are caller of plugin, so frontend is Go side,
	// backend is plugin side
	frontendAddr, backendAddr string
}

// NewBroker returns a new *Broker.
func NewBroker(frontendAddr, backendAddr string) (*Broker, error) {
	return &Broker{frontendAddr, backendAddr}, nil
}

// Run kicks start the Broker and listens for requests. It blocks function
// execution.
func (lb *Broker) Run() {
	frontend, backend := mustInitEndpoints(lb.frontendAddr, lb.backendAddr)
	backendPoller, bothPoller := mustInitPollers(frontend, backend)

	workers := workerQueue{}
	heartbeatAt := time.Now().Add(HeartbeatInterval)
	for {
		var sock *goczmq.Sock
		if workers.Len() == 0 {
			sock = backendPoller.Wait(heartbeatIntervalMS)
		} else {
			sock = bothPoller.Wait(heartbeatIntervalMS)
		}

		switch sock {
		case backend:
			frames, err := backend.RecvMessage()
			if err != nil {
				panic(err)
			}

			address := frames[0]
			workers.Ready(newWorker(address))

			msg := frames[1:]
			if len(msg) == 1 {
				switch status := string(msg[0]); status {
				case Ready:
					log.Infof("zmq/broker: ready worker = %s", address)
				case Heartbeat:
					// do nothing
				default:
					log.Errorf("zmq/broker: invalid message from worker = %s: %s", address, msg)
				}
			} else {
				frontend.SendMessage(msg)
				log.Debugf("zmq/broker: backend => frontend: %#x, %s\n", msg[0], msg)
			}
		case frontend:
			frames, err := frontend.RecvMessage()
			if err != nil {
				panic(err)
			}

			frames = append([][]byte{workers.Next()}, frames...)
			backend.SendMessage(frames)
			log.Debugf("zmq/broker: frontend => backend: %#x, %s\n", frames[0], frames)
		case nil:
			// do nothing
		default:
			panic("zmq/broker: received unknown socket")
		}

		if heartbeatAt.Before(time.Now()) {
			for _, worker := range workers {
				msg := [][]byte{worker.address, []byte(Heartbeat)}
				backend.SendMessage(msg)
			}
			heartbeatAt = time.Now().Add(HeartbeatInterval)
		}

		workers.Purge()
	}
}

func mustInitEndpoints(frontendAddr, backendAddr string) (*goczmq.Sock, *goczmq.Sock) {
	frontend, err := goczmq.NewRouter(frontendAddr)
	if err != nil {
		panic(err)
	}

	backend, err := goczmq.NewRouter(backendAddr)
	if err != nil {
		panic(err)
	}

	return frontend, backend
}

func mustInitPollers(frontend, backend *goczmq.Sock) (*goczmq.Poller, *goczmq.Poller) {
	backendPoller, err := goczmq.NewPoller(backend)
	if err != nil {
		panic(err)
	}

	bothPoller, err := goczmq.NewPoller(frontend, backend)
	if err != nil {
		panic(err)
	}

	return backendPoller, bothPoller
}

var heartbeatIntervalMS int = int(HeartbeatInterval.Seconds() * 1000)

type pworker struct {
	address []byte
	expiry  time.Time
}

func newWorker(address []byte) pworker {
	return pworker{
		address,
		time.Now().Add(HeartbeatLiveness * HeartbeatInterval),
	}
}

type workerQueue []pworker

func (q workerQueue) Len() int {
	return len(q)
}

func (q *workerQueue) Next() []byte {
	workers := *q
	worker := workers[len(workers)-1]
	*q = workers[:len(workers)-1]
	return worker.address
}

func (q *workerQueue) Ready(worker pworker) {
	workers := *q
	if len(workers) == 0 {
		*q = append(workers, worker)
		return
	}

	var (
		i int
		w pworker
	)
	for i, w = range workers {
		if bytes.Equal(w.address, worker.address) {
			break
		}
	}
	*q = append(append(workers[:i], workers[i+1:]...), worker)
}

func (q *workerQueue) Purge() {
	workers := *q

	now := time.Now()
	var (
		i int
		w pworker
	)
	for i, w = range workers {
		if w.expiry.After(now) {
			break
		}
		*q = workers[i+1:]
		log.Infof("zmq/broker: disconnected worker = %s", w.address)
	}
}
<commit_msg>zmq/broker: add shutdown signal for worker<commit_after>package zmq

import (
	"bytes"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/zeromq/goczmq"
)

const (
	HeartbeatInterval = time.Second
	HeartbeatLiveness = 3

	Ready     = "\001"
	Heartbeat = "\002"
	Shutdown  = "\003"
)

// Broker implements the Paranoid Pirate queue described in the zguide:
// http://zguide.zeromq.org/py:all#Robust-Reliable-Queuing-Paranoid-Pirate-Pattern
// with the addition of:
//
// 1. Shutdown signal, which signifies a normal termination of worker to provide
//    a fast path of worker removal
//
// NOTE(limouren): it might make a good interface
type Broker struct {
	// NOTE: goroutines are caller of plugin, so frontend is Go side,
	// backend is plugin side
	frontendAddr, backendAddr string
}

// NewBroker returns a new *Broker.
func NewBroker(frontendAddr, backendAddr string) (*Broker, error) {
	return &Broker{frontendAddr, backendAddr}, nil
}

// Run kicks start the Broker and listens for requests. It blocks function
// execution.
func (lb *Broker) Run() {
	frontend, backend := mustInitEndpoints(lb.frontendAddr, lb.backendAddr)
	backendPoller, bothPoller := mustInitPollers(frontend, backend)

	workers := workerQueue{}
	heartbeatAt := time.Now().Add(HeartbeatInterval)
	for {
		var sock *goczmq.Sock
		if workers.Len() == 0 {
			sock = backendPoller.Wait(heartbeatIntervalMS)
		} else {
			sock = bothPoller.Wait(heartbeatIntervalMS)
		}

		switch sock {
		case backend:
			frames, err := backend.RecvMessage()
			if err != nil {
				panic(err)
			}

			address := frames[0]
			workers.Ready(newWorker(address))

			msg := frames[1:]
			if len(msg) == 1 {
				switch status := string(msg[0]); status {
				case Ready:
					log.Infof("zmq/broker: ready worker = %s", address)
				case Heartbeat:
					// do nothing
				case Shutdown:
					workers.Remove(address)
					log.Infof("zmq/broker: shutdown of worker = %s", address)
				default:
					log.Errorf("zmq/broker: invalid message from worker = %s: %s", address, msg)
				}
			} else {
				frontend.SendMessage(msg)
				log.Debugf("zmq/broker: backend => frontend: %#x, %s\n", msg[0], msg)
			}
		case frontend:
			frames, err := frontend.RecvMessage()
			if err != nil {
				panic(err)
			}

			frames = append([][]byte{workers.Next()}, frames...)
			backend.SendMessage(frames)
			log.Debugf("zmq/broker: frontend => backend: %#x, %s\n", frames[0], frames)
		case nil:
			// do nothing
		default:
			panic("zmq/broker: received unknown socket")
		}

		if heartbeatAt.Before(time.Now()) {
			for _, worker := range workers {
				msg := [][]byte{worker.address, []byte(Heartbeat)}
				backend.SendMessage(msg)
			}
			heartbeatAt = time.Now().Add(HeartbeatInterval)
		}

		workers.Purge()
	}
}

func mustInitEndpoints(frontendAddr, backendAddr string) (*goczmq.Sock, *goczmq.Sock) {
	frontend, err := goczmq.NewRouter(frontendAddr)
	if err != nil {
		panic(err)
	}

	backend, err := goczmq.NewRouter(backendAddr)
	if err != nil {
		panic(err)
	}

	return frontend, backend
}

func mustInitPollers(frontend, backend *goczmq.Sock) (*goczmq.Poller, *goczmq.Poller) {
	backendPoller, err := goczmq.NewPoller(backend)
	if err != nil {
		panic(err)
	}

	bothPoller, err := goczmq.NewPoller(frontend, backend)
	if err != nil {
		panic(err)
	}

	return backendPoller, bothPoller
}

var heartbeatIntervalMS int = int(HeartbeatInterval.Seconds() * 1000)

type pworker struct {
	address []byte
	expiry  time.Time
}

func newWorker(address []byte) pworker {
	return pworker{
		address,
		time.Now().Add(HeartbeatLiveness * HeartbeatInterval),
	}
}

type workerQueue []pworker

func (q workerQueue) Len() int {
	return len(q)
}

func (q *workerQueue) Next() []byte {
	workers := *q
	worker := workers[len(workers)-1]
	*q = workers[:len(workers)-1]
	return worker.address
}

func (q *workerQueue) Ready(worker pworker) {
	workers := *q
	if len(workers) == 0 {
		*q = append(workers, worker)
		return
	}

	var (
		i int
		w pworker
	)
	for i, w = range workers {
		if bytes.Equal(w.address, worker.address) {
			break
		}
	}
	*q = append(append(workers[:i], workers[i+1:]...), worker)
}

func (q *workerQueue) Purge() {
	workers := *q

	now := time.Now()
	for i, w := range workers {
		if w.expiry.After(now) {
			break
		}
		*q = workers[i+1:]
		log.Infof("zmq/broker: disconnected worker = %s", w.address)
	}
}

func (q *workerQueue) Remove(address []byte) {
	workers := *q

	for i, w := range workers {
		if bytes.Equal(w.address, address) {
			*q = append(workers[:i], workers[i+1:]...)
			break
		}
	}
}
<|endoftext|>


<commit_before>package osdn

import (
	"fmt"
	"github.com/golang/glog"
	"strings"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"

	"github.com/openshift/openshift-sdn/ovssubnet"
	osdnapi "github.com/openshift/openshift-sdn/pkg/api"

	osclient "github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/sdn/api"
)

type OsdnRegistryInterface struct {
	oClient osclient.Interface
	kClient kclient.Interface
}

func NetworkPluginName() string {
	return "redhat/openshift-ovs-subnet"
}

func Master(osClient osclient.Client, kClient kclient.Client, clusterNetwork string, clusterNetworkLength uint) {
	osdnInterface := newOsdnRegistryInterface(osClient, kClient)

	// get hostname
	output, err := exec.New().Command("hostname", "-f").CombinedOutput()
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	host := strings.TrimSpace(string(output))

	kc, err := ovssubnet.NewKubeController(&osdnInterface, host, "")
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	kc.StartMaster(false, clusterNetwork, clusterNetworkLength)
}

func Node(osClient osclient.Client, kClient kclient.Client, hostname string, publicIP string) {
	osdnInterface := newOsdnRegistryInterface(osClient, kClient)
	kc, err := ovssubnet.NewKubeController(&osdnInterface, hostname, publicIP)
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	kc.StartNode(false, false)
}

func newOsdnRegistryInterface(osClient osclient.Client, kClient kclient.Client) OsdnRegistryInterface {
	return OsdnRegistryInterface{&osClient, &kClient}
}

func (oi *OsdnRegistryInterface) InitSubnets() error {
	return nil
}

func (oi *OsdnRegistryInterface) GetSubnets() (*[]osdnapi.Subnet, error) {
	hostSubnetList, err := oi.oClient.HostSubnets().List()
	if err != nil {
		return nil, err
	}
	// convert HostSubnet to osdnapi.Subnet
	subList := make([]osdnapi.Subnet, 0)
	for _, subnet := range hostSubnetList.Items {
		subList = append(subList, osdnapi.Subnet{Minion: subnet.HostIP, Sub: subnet.Subnet})
	}
	return &subList, nil
}

func (oi *OsdnRegistryInterface) GetSubnet(minion string) (*osdnapi.Subnet, error) {
	hs, err := oi.oClient.HostSubnets().Get(minion)
	if err != nil {
		return nil, err
	}
	return &osdnapi.Subnet{Minion: hs.Host, Sub: hs.Subnet}, nil
}

func (oi *OsdnRegistryInterface) DeleteSubnet(minion string) error {
	return oi.oClient.HostSubnets().Delete(minion)
}

func (oi *OsdnRegistryInterface) CreateSubnet(minion string, sub *osdnapi.Subnet) error {
	hs := &api.HostSubnet{
		TypeMeta:   kapi.TypeMeta{Kind: "HostSubnet"},
		ObjectMeta: kapi.ObjectMeta{Name: minion},
		Host:       minion,
		HostIP:     sub.Minion,
		Subnet:     sub.Sub,
	}
	_, err := oi.oClient.HostSubnets().Create(hs)
	return err
}

func (oi *OsdnRegistryInterface) WatchSubnets(receiver chan *osdnapi.SubnetEvent, stop chan bool) error {
	// double go :(
	revision := ""
	wi, err := oi.oClient.HostSubnets().Watch(revision)
	if err != nil {
		return err
	}
	go func() {
		for {
			ev := <-wi.ResultChan()
			switch ev.Type {
			case watch.Added:
				// create SubnetEvent
				hs := ev.Object.(*api.HostSubnet)
				receiver <- &osdnapi.SubnetEvent{Type: osdnapi.Added, Minion: hs.Host, Sub: osdnapi.Subnet{Minion: hs.HostIP, Sub: hs.Subnet}}
			case watch.Deleted:
				hs := ev.Object.(*api.HostSubnet)
				receiver <- &osdnapi.SubnetEvent{Type: osdnapi.Deleted, Minion: hs.Host, Sub: osdnapi.Subnet{Minion: hs.HostIP, Sub: hs.Subnet}}
			case watch.Modified:
				hs := ev.Object.(*api.HostSubnet)
				receiver <- &osdnapi.SubnetEvent{Type: osdnapi.Added, Minion: hs.Host, Sub: osdnapi.Subnet{Minion: hs.HostIP, Sub: hs.Subnet}}
			case watch.Error:
				fmt.Errorf("Error in watching subnets")
				return
			}
		}
	}()
	return nil
}

func (oi *OsdnRegistryInterface) InitMinions() error {
	// return no error, as this gets initialized by apiserver
	return nil
}

func (oi *OsdnRegistryInterface) GetMinions() (*[]string, error) {
	nodes, err := oi.kClient.Nodes().List(labels.Everything(), fields.Everything())
	if err != nil {
		return nil, err
	}
	// convert kapi.NodeList to []string
	minionList := make([]string, 0)
	for _, minion := range nodes.Items {
		minionList = append(minionList, minion.Name)
	}
	return &minionList, nil
}

func (oi *OsdnRegistryInterface) CreateMinion(minion string, data string) error {
	return fmt.Errorf("Feature not supported in native mode. SDN cannot create/register minions.")
}

func (oi *OsdnRegistryInterface) WatchMinions(receiver chan *osdnapi.MinionEvent, stop chan bool) error {
	wi, err := oi.kClient.Nodes().Watch(labels.Everything(), fields.Everything(), "0")
	if err != nil {
		return err
	}
	go func() {
		for {
			ev := <-wi.ResultChan()
			switch ev.Type {
			case watch.Added:
				// create minionEvent
				node := ev.Object.(*kapi.Node)
				receiver <- &osdnapi.MinionEvent{Type: osdnapi.Added, Minion: node.ObjectMeta.Name}
			case watch.Deleted:
				node := ev.Object.(*kapi.Node)
				receiver <- &osdnapi.MinionEvent{Type: osdnapi.Deleted, Minion: node.ObjectMeta.Name}
			case watch.Modified:
				node := ev.Object.(*kapi.Node)
				receiver <- &osdnapi.MinionEvent{Type: osdnapi.Added, Minion: node.ObjectMeta.Name}
			case watch.Error:
				fmt.Errorf("Error in watching subnets")
				return
			}
		}
	}()
	return nil
}

func (oi *OsdnRegistryInterface) WriteNetworkConfig(network string, subnetLength uint) error {
	cn := &api.ClusterNetwork{
		TypeMeta:         kapi.TypeMeta{Kind: "ClusterNetwork"},
		ObjectMeta:       kapi.ObjectMeta{Name: "default"},
		Network:          network,
		HostSubnetLength: int(subnetLength),
	}
	_, err := oi.oClient.ClusterNetwork().Create(cn)
	return err
}

func (oi *OsdnRegistryInterface) GetContainerNetwork() (string, error) {
	cn, err := oi.oClient.ClusterNetwork().Get("default")
	return cn.Network, err
}

func (oi *OsdnRegistryInterface) GetSubnetLength() (uint64, error) {
	cn, err := oi.oClient.ClusterNetwork().Get("default")
	return uint64(cn.HostSubnetLength), err
}

func (oi *OsdnRegistryInterface) CheckEtcdIsAlive(seconds uint64) bool {
	// always assumed to be true as we run through the apiserver
	return true
}
<commit_msg>fix looping on a closed channel - bz1222853, bz1223274<commit_after>package osdn

import (
	"fmt"
	"github.com/golang/glog"
	"strings"
	"time"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"

	"github.com/openshift/openshift-sdn/ovssubnet"
	osdnapi "github.com/openshift/openshift-sdn/pkg/api"

	osclient "github.com/openshift/origin/pkg/client"
	oscache "github.com/openshift/origin/pkg/client/cache"
	"github.com/openshift/origin/pkg/sdn/api"
)

type OsdnRegistryInterface struct {
	oClient osclient.Interface
	kClient kclient.Interface
}

func NetworkPluginName() string {
	return "redhat/openshift-ovs-subnet"
}

func Master(osClient osclient.Client, kClient kclient.Client, clusterNetwork string, clusterNetworkLength uint) {
	osdnInterface := newOsdnRegistryInterface(osClient, kClient)

	// get hostname
	output, err := exec.New().Command("hostname", "-f").CombinedOutput()
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	host := strings.TrimSpace(string(output))

	kc, err := ovssubnet.NewKubeController(&osdnInterface, host, "")
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	kc.StartMaster(false, clusterNetwork, clusterNetworkLength)
}

func Node(osClient osclient.Client, kClient kclient.Client, hostname string, publicIP string) {
	osdnInterface := newOsdnRegistryInterface(osClient, kClient)
	kc, err := ovssubnet.NewKubeController(&osdnInterface, hostname, publicIP)
	if err != nil {
		glog.Fatalf("SDN initialization failed: %v", err)
	}
	kc.StartNode(false, false)
}

func newOsdnRegistryInterface(osClient osclient.Client, kClient kclient.Client) OsdnRegistryInterface {
	return OsdnRegistryInterface{&osClient, &kClient}
}

func (oi *OsdnRegistryInterface) InitSubnets() error {
	return nil
}

func (oi *OsdnRegistryInterface) GetSubnets() (*[]osdnapi.Subnet, error) {
	hostSubnetList, err := oi.oClient.HostSubnets().List()
	if err != nil {
		return nil, err
	}
	// convert HostSubnet to osdnapi.Subnet
	subList := make([]osdnapi.Subnet, 0)
	for _, subnet := range hostSubnetList.Items {
		subList = append(subList, osdnapi.Subnet{Minion: subnet.HostIP, Sub: subnet.Subnet})
	}
	return &subList, nil
}

func (oi *OsdnRegistryInterface) GetSubnet(minion string) (*osdnapi.Subnet, error) {
	hs, err := oi.oClient.HostSubnets().Get(minion)
	if err != nil {
		return nil, err
	}
	return &osdnapi.Subnet{Minion: hs.Host, Sub: hs.Subnet}, nil
}

func (oi *OsdnRegistryInterface) DeleteSubnet(minion string) error {
	return oi.oClient.HostSubnets().Delete(minion)
}

func (oi *OsdnRegistryInterface) CreateSubnet(minion string, sub *osdnapi.Subnet) error {
	hs := &api.HostSubnet{
		TypeMeta:   kapi.TypeMeta{Kind: "HostSubnet"},
		ObjectMeta: kapi.ObjectMeta{Name: minion},
		Host:       minion,
		HostIP:     sub.Minion,
		Subnet:     sub.Sub,
	}
	_, err := oi.oClient.HostSubnets().Create(hs)
	return err
}

func (oi *OsdnRegistryInterface) WatchSubnets(receiver chan *osdnapi.SubnetEvent, stop chan bool) error {
	subnetEventQueue := oscache.NewEventQueue(cache.MetaNamespaceKeyFunc)
	listWatch := &cache.ListWatch{
		ListFunc: func() (runtime.Object, error) {
			return oi.oClient.HostSubnets().List()
		},
		WatchFunc: func(resourceVersion string) (watch.Interface, error) {
			return oi.oClient.HostSubnets().Watch(resourceVersion)
		},
	}
	cache.NewReflector(listWatch, &api.HostSubnet{}, subnetEventQueue, 4*time.Minute).Run()

	for {
		eventType, obj, err := subnetEventQueue.Pop()
		if err != nil {
			return err
		}
		switch eventType {
		case watch.Added, watch.Modified:
			// create SubnetEvent
			hs := obj.(*api.HostSubnet)
			receiver <- &osdnapi.SubnetEvent{Type: osdnapi.Added, Minion: hs.Host, Sub: osdnapi.Subnet{Minion: hs.HostIP, Sub: hs.Subnet}}
		case watch.Deleted:
			hs := obj.(*api.HostSubnet)
			receiver <- &osdnapi.SubnetEvent{Type: osdnapi.Deleted, Minion: hs.Host, Sub: osdnapi.Subnet{Minion: hs.HostIP, Sub: hs.Subnet}}
		}
	}
	return nil
}

func (oi *OsdnRegistryInterface) InitMinions() error {
	// return no error, as this gets initialized by apiserver
	return nil
}

func (oi *OsdnRegistryInterface) GetMinions() (*[]string, error) {
	nodes, err := oi.kClient.Nodes().List(labels.Everything(), fields.Everything())
	if err != nil {
		return nil, err
	}
	// convert kapi.NodeList to []string
	minionList := make([]string, 0)
	for _, minion := range nodes.Items {
		minionList = append(minionList, minion.Name)
	}
	return &minionList, nil
}

func (oi *OsdnRegistryInterface) CreateMinion(minion string, data string) error {
	return fmt.Errorf("Feature not supported in native mode. SDN cannot create/register minions.")
}

func (oi *OsdnRegistryInterface) WatchMinions(receiver chan *osdnapi.MinionEvent, stop chan bool) error {
	minionEventQueue := oscache.NewEventQueue(cache.MetaNamespaceKeyFunc)
	listWatch := &cache.ListWatch{
		ListFunc: func() (runtime.Object, error) {
			return oi.kClient.Nodes().List(labels.Everything(), fields.Everything())
		},
		WatchFunc: func(resourceVersion string) (watch.Interface, error) {
			return oi.kClient.Nodes().Watch(labels.Everything(), fields.Everything(), resourceVersion)
		},
	}
	cache.NewReflector(listWatch, &kapi.Node{}, minionEventQueue, 4*time.Minute).Run()

	for {
		eventType, obj, err := minionEventQueue.Pop()
		if err != nil {
			return err
		}
		switch eventType {
		case watch.Added, watch.Modified:
			// create minionEvent
			node := obj.(*kapi.Node)
			receiver <- &osdnapi.MinionEvent{Type: osdnapi.Added, Minion: node.ObjectMeta.Name}
		case watch.Deleted:
			node := obj.(*kapi.Node)
			receiver <- &osdnapi.MinionEvent{Type: osdnapi.Deleted, Minion: node.ObjectMeta.Name}
		}
	}
	return nil
}

func (oi *OsdnRegistryInterface) WriteNetworkConfig(network string, subnetLength uint) error {
	cn := &api.ClusterNetwork{
		TypeMeta:         kapi.TypeMeta{Kind: "ClusterNetwork"},
		ObjectMeta:       kapi.ObjectMeta{Name: "default"},
		Network:          network,
		HostSubnetLength: int(subnetLength),
	}
	_, err := oi.oClient.ClusterNetwork().Create(cn)
	return err
}

func (oi *OsdnRegistryInterface) GetContainerNetwork() (string, error) {
	cn, err := oi.oClient.ClusterNetwork().Get("default")
	return cn.Network, err
}

func (oi *OsdnRegistryInterface) GetSubnetLength() (uint64, error) {
	cn, err := oi.oClient.ClusterNetwork().Get("default")
	return uint64(cn.HostSubnetLength), err
}

func (oi *OsdnRegistryInterface) CheckEtcdIsAlive(seconds uint64) bool {
	// always assumed to be true as we run through the apiserver
	return true
}
<|endoftext|>


<commit_before>package pool

import (
	"net"
	"errors"
	"sync"
	"time"
)

//blockingPool implements the Pool interface.
//Connestions from blockingPool offer a kind of blocking mechanism that is derived from buffered channel.
type blockingPool struct {
	//mutex is to make closing the pool and recycling the connection an atomic operation
	mutex sync.Mutex

	//timeout to Get, default to 3
	timeout time.Duration

	//storage for net.Conn connections
	conns chan *WrappedConn

	//net.Conn generator
	factory Factory

	livetime time.Duration
}

//Factory is a function to create new connections
//which is provided by the user
type Factory func() (net.Conn, error)

//Create a new blocking pool. As no new connections would be made when the pool is busy,
//the number of connections of the pool is kept no more than initCap and maxCap does not
//make sense but the api is reserved. The timeout to block Get() is set to 3 by default
//concerning that it is better to be related with Get() method.
func NewBlockingPool(initCap, maxCap int, livetime time.Duration, factory Factory) (Pool, error) {
	if initCap < 0 || maxCap < 1 || initCap > maxCap {
		return nil, errors.New("invalid capacity settings")
	}

	newPool := &blockingPool{
		timeout: 3,
		conns: make(chan *WrappedConn, maxCap),
		factory: factory,
		livetime: livetime,
	}

	for i := 0; i < initCap; i++ {
		conn, _ := factory()
		//It doesn't matter if conn it nil, nil is checked whenever Get() is called,
		//so error counted from factory() is ignored.
		newPool.conns <- newPool.wrap(conn)
	}
	return newPool, nil
}

//Get blocks for an available connection.
func (p *blockingPool) Get() (net.Conn, error) {
	//in case that pool is closed or pool.conns is set to nil
	conns := p.conns
	if conns == nil {
		return nil, ErrClosed
	}

	select {
	case conn := <-conns:
		if time.Since(conn.start) > p.livetime {
			if conn.Conn != nil {
				conn.Conn.Close()
				conn.Conn = nil
			}
		}
		if conn.Conn == nil {
			var err error
			conn.Conn, err = p.factory()
			if err != nil {
				conn.start = time.Now()
				p.put(conn)
				return nil, err
			}
		}
		conn.unusable = false
		return conn, nil
	case <-time.After(time.Second*p.timeout):
		return nil, ErrTimeout
	}
}

//put puts the connection back to the pool. If the pool is closed, put simply close
//any connections received and return immediately. A nil net.Conn is illegal and will be rejected.
func (p *blockingPool) put(conn *WrappedConn) error {
	//in case that pool is closed and pool.conns is set to nil
	conns := p.conns
	if conns == nil {
		//conn.Conn is possibly nil coz factory() may fail, in which case conn is immediately
		//put back to the pool
		if conn.Conn != nil {
			conn.Conn.Close()
			conn.Conn = nil
		}
		return ErrClosed
	}

	//if conn is marked unusable, underlying net.Conn is set to nil
	if conn.unusable {
		if conn.Conn != nil {
			conn.Conn.Close()
			conn.Conn = nil
		}
	}

	//It is impossible to block as number of connections is never more than length of channel
	conns <-conn
	return nil
}

//TODO
//Close set connection channel to nil and close all the relative connections.
//Yet not implemented.
func (p *blockingPool) Close() {}

//TODO
//Len return the number of current active(in use or available) connections.
func (p *blockingPool) Len() int {
	return 0;
}

<commit_msg>update<commit_after>package pool

import (
	"net"
	"errors"
	"sync"
	"time"
)

//blockingPool implements the Pool interface.
//Connestions from blockingPool offer a kind of blocking mechanism that is derived from buffered channel.
type blockingPool struct {
	//mutex is to make closing the pool and recycling the connection an atomic operation
	mutex sync.Mutex

	//timeout to Get, default to 3
	timeout time.Duration

	//storage for net.Conn connections
	conns chan *WrappedConn

	//net.Conn generator
	factory Factory

	livetime time.Duration
}

//Factory is a function to create new connections
//which is provided by the user
type Factory func() (net.Conn, error)

//Create a new blocking pool. As no new connections would be made when the pool is busy,
//the number of connections of the pool is kept no more than initCap and maxCap does not
//make sense but the api is reserved. The timeout to block Get() is set to 3 by default
//concerning that it is better to be related with Get() method.
func NewBlockingPool(initCap, maxCap int, livetime time.Duration, factory Factory) (Pool, error) {
	if initCap < 0 || maxCap < 1 || initCap > maxCap {
		return nil, errors.New("invalid capacity settings")
	}

	newPool := &blockingPool{
		timeout: 3,
		conns: make(chan *WrappedConn, maxCap),
		factory: factory,
		livetime: livetime,
	}

	for i := 0; i < initCap; i++ {
		newPool.conns <- newPool.wrap(nil)
	}
	return newPool, nil
}

//Get blocks for an available connection.
func (p *blockingPool) Get() (net.Conn, error) {
	//in case that pool is closed or pool.conns is set to nil
	conns := p.conns
	if conns == nil {
		return nil, ErrClosed
	}

	select {
	case conn := <-conns:
		if time.Since(conn.start) > p.livetime {
			if conn.Conn != nil {
				conn.Conn.Close()
				conn.Conn = nil
			}
		}
		if conn.Conn == nil {
			var err error
			conn.Conn, err = p.factory()
			if err != nil {
				conn.start = time.Now()
				p.put(conn)
				return nil, err
			}
		}
		conn.unusable = false
		return conn, nil
	case <-time.After(time.Second*p.timeout):
		return nil, ErrTimeout
	}
}

//put puts the connection back to the pool. If the pool is closed, put simply close
//any connections received and return immediately. A nil net.Conn is illegal and will be rejected.
func (p *blockingPool) put(conn *WrappedConn) error {
	//in case that pool is closed and pool.conns is set to nil
	conns := p.conns
	if conns == nil {
		//conn.Conn is possibly nil coz factory() may fail, in which case conn is immediately
		//put back to the pool
		if conn.Conn != nil {
			conn.Conn.Close()
			conn.Conn = nil
		}
		return ErrClosed
	}

	//if conn is marked unusable, underlying net.Conn is set to nil
	if conn.unusable {
		if conn.Conn != nil {
			conn.Conn.Close()
			conn.Conn = nil
		}
	}

	//It is impossible to block as number of connections is never more than length of channel
	conns <-conn
	return nil
}

//TODO
//Close set connection channel to nil and close all the relative connections.
//Yet not implemented.
func (p *blockingPool) Close() {}

//TODO
//Len return the number of current active(in use or available) connections.
func (p *blockingPool) Len() int {
	return 0;
}

<|endoftext|>


<commit_before>// Package buildlib builds the dynamic library for LuaTeX
package buildlib

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"speedatapublisher/sphelper/config"
)

// BuildCLib builds the dynamic C library
func BuildCLib(cfg *config.Config, goos string, goarch string) error {
	fmt.Println("Building dynamic lua glue library for", goos)
	srcdir := cfg.Srcdir
	os.Chdir(filepath.Join(srcdir, "c"))
	dylibbuild := filepath.Join(cfg.Builddir, "dylib")

	var cmd *exec.Cmd
	switch goos {
	case "darwin":
		cmd = exec.Command("clang", "-dynamiclib", "-fPIC", "-undefined", "dynamic_lookup", "-o", filepath.Join(dylibbuild, "luaglue.so"), "luaglue.c", "-I/opt/homebrew/opt/lua@5.3/include/lua")
	case "linux":
		cmd = exec.Command("cc", "-shared", "-fPIC", "-o", filepath.Join(dylibbuild, "luaglue.so"), "luaglue.c", "-I/usr/include/lua5.3/")
	case "windows":
		cmd = exec.Command("/usr/bin/x86_64-w64-mingw32-gcc", "-shared", "-o", filepath.Join(dylibbuild, "luaglue.dll"), "luaglue.c", "-I/usr/include/lua5.3/", "-L/luatex-bin/luatex/windows/amd64/default/", "-llua53w64", "-llibsplib", "-L"+dylibbuild)
	}
	outbuf, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(outbuf))
		return err
	}
	return nil
}

// BuildLib builds the dynamic library
func BuildLib(cfg *config.Config, goos string, goarch string) error {
	fmt.Println("Building dynamic library for", goos)
	srcdir := cfg.Srcdir
	os.Chdir(filepath.Join(srcdir, "go", "splib"))
	libraryextension := ".so"
	switch goos {
	case "darwin":
		libraryextension = ".dylib"
	case "windows":
		libraryextension = ".dll"
	}
	dylibbuild := filepath.Join(cfg.Builddir, "dylib")
	cmd := exec.Command("go", "build", "-buildmode=c-shared", "-o", filepath.Join(dylibbuild, "libsplib"+libraryextension), "speedatapublisher/splib")
	cmd.Env = os.Environ()
	if goos != runtime.GOOS {
		ccenv := os.Getenv("CC_" + goos)
		cmd.Env = append(cmd.Env, "CC="+ccenv)
		cmd.Env = append(cmd.Env, "GOOS="+goos)
	}
	if goarch != "" {
		cmd.Env = append(cmd.Env, "GOARCH="+goarch)
	}
	cmd.Env = append(cmd.Env, "CGO_ENABLED=1")
	outbuf, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(outbuf))
		return err
	}
	return nil

}
<commit_msg>Build platform specific luaglue library<commit_after>// Package buildlib builds the dynamic library for LuaTeX
package buildlib

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"speedatapublisher/sphelper/config"
)

// BuildCLib builds the dynamic C library
func BuildCLib(cfg *config.Config, goos string, goarch string) error {
	fmt.Println("Building dynamic lua glue library for", goos)
	srcdir := cfg.Srcdir
	os.Chdir(filepath.Join(srcdir, "c"))
	dylibbuild := filepath.Join(cfg.Builddir, "dylib")

	var cmd *exec.Cmd
	var triple string
	switch goos {
	case "darwin":
		switch goarch {
		case "amd64":
			triple = "x86_64-apple-macos11"
		case "arm64":
			triple = "arm64-apple-macos11"
		}
		cmd = exec.Command("clang", "-dynamiclib", "-target", triple, "-fPIC", "-undefined", "dynamic_lookup", "-o", filepath.Join(dylibbuild, "luaglue.so"), "luaglue.c", "-I/opt/homebrew/opt/lua@5.3/include/lua")
	case "linux":
		cmd = exec.Command("cc", "-shared", "-fPIC", "-o", filepath.Join(dylibbuild, "luaglue.so"), "luaglue.c", "-I/usr/include/lua5.3/")
	case "windows":
		cmd = exec.Command("/usr/bin/x86_64-w64-mingw32-gcc", "-shared", "-o", filepath.Join(dylibbuild, "luaglue.dll"), "luaglue.c", "-I/usr/include/lua5.3/", "-L/luatex-bin/luatex/windows/amd64/default/", "-llua53w64", "-llibsplib", "-L"+dylibbuild)
	}
	outbuf, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(outbuf))
		return err
	}
	return nil
}

// BuildLib builds the dynamic library
func BuildLib(cfg *config.Config, goos string, goarch string) error {
	fmt.Println("Building dynamic library for", goos)
	srcdir := cfg.Srcdir
	os.Chdir(filepath.Join(srcdir, "go", "splib"))
	libraryextension := ".so"
	switch goos {
	case "darwin":
		libraryextension = ".dylib"
	case "windows":
		libraryextension = ".dll"
	}
	dylibbuild := filepath.Join(cfg.Builddir, "dylib")
	cmd := exec.Command("go", "build", "-buildmode=c-shared", "-o", filepath.Join(dylibbuild, "libsplib"+libraryextension), "speedatapublisher/splib")
	cmd.Env = os.Environ()
	if goos != runtime.GOOS {
		ccenv := os.Getenv("CC_" + goos)
		cmd.Env = append(cmd.Env, "CC="+ccenv)
		cmd.Env = append(cmd.Env, "GOOS="+goos)
	}
	if goarch != "" {
		cmd.Env = append(cmd.Env, "GOARCH="+goarch)
	}
	cmd.Env = append(cmd.Env, "CGO_ENABLED=1")
	outbuf, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(outbuf))
		return err
	}
	return nil

}
<|endoftext|>


<commit_before>package dusl

import (
  "fmt"
)

// Sparser stands for Superpermissive-Parser.
// The Sparse method converts an ambit into a syntax tree,
// the SparseUndent method converts an entire source into a syntax tree.
type Sparser interface {
  Sparse(ambit *Ambit) *Syntax
  SparseUndent(src *Source) *Syntax
}

type sparser struct {
  precedenceLevels
  spanner spannerI
}

func newSparser(spanner spannerI, precedence *precedenceLevels) Sparser {
  return &sparser{ spanner: spanner, precedenceLevels: *precedence }
}

// SparseUndent returns the syntax tree constructed for the given source.
func (this *sparser) SparseUndent(source *Source) *Syntax {
  root := Undent(source)
  this.sparseSQ(root)
  return root
}

func (this *sparser) sparseSQ(node *Syntax) {
  if node.Cat == "SQ" {
    this.sparseSQ(node.Left)
    this.sparseSQ(node.Right)
    return
  }
  if node.Cat == "SN" {
    node.Left = this.Sparse(node.Left.Ambit)
    this.sparseSQ(node.Right)
    return
  }
  // <empty
}

// Sparse returns the syntax tree constructed for the given ambit.
func (this *sparser) Sparse(ambit *Ambit) *Syntax {
  return this.sparse(ambit, this.spanner.span(ambit), 1)
}

func (this *sparser) sparse(ambit *Ambit, spans []*spanT, minPrecedence int) *Syntax {
  ambit, spans = trimSpans(ambit, spans)
  if len(spans) == 0 {
    return &Syntax{ Ambit: ambit }
  }
  if len(spans) == 1 {
    span := spans[0]
    lit := span.Lit
    if span.Children == nil {
      if span.Cat == "OP" {
        if this.precedenceEFE[lit] < minPrecedence {
          return &Syntax{ Cat: "ERR", Err: fmt.Sprintf("unexpected: %s", lit), Ambit: ambit }
        }
        return &Syntax{ Cat: "OP", Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                        Left: &Syntax{ Ambit: span.Ambit.CollapseLeft() },
                        Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
      }
      return &Syntax{ Cat: span.Cat, Lit: lit, Err: span.Err, Ambit: ambit, OpAmbit: span.Ambit }
    }
    // span.Cat == "BB"
    precedence, recognized := this.precedenceB[lit]
    if !recognized {
      return &Syntax{ Cat: "ERR", Err: fmt.Sprintf("unexpected: %s", lit), Ambit: ambit }
    }
    return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: span.Ambit,
                    Left: this.sparse(span.SubAmbit, span.Children, precedence),
                    Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
  }
  l, splitPrecedence, splitLoc, splitPrecLeft, splitPrecRight := len(spans)-1, maxPrecedence+1, -1, -1, -1
  if span, ws := spans[0], spans[1]; span.Cat != "OP" && ws.Cat == "WS" {
    if len(spans) == 2 || (spans[2].Cat != "OP" && spans[2].Cat != "ERR") {
      return &Syntax{ Cat: "JUXT", Lit: " ", Ambit: ambit, OpAmbit: ws.Ambit,
                      Left: this.sparse(span.Ambit, spans[:1], minPrecedence),
                      Right: this.sparse(ambit.SubtractLeft(ws.Ambit), spans[1:], minPrecedence) }
    }
  }
  if span := spans[0]; span.Cat == "OP" {
    lit := span.Lit
    prec := this.precedenceEFA[lit]
    if prec == minPrecedence {
      return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                      Left: &Syntax{ Ambit: span.Ambit.CollapseLeft() },
                      Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[1:], prec) }
    }
    if prec > minPrecedence && prec < splitPrecedence {
      splitLoc, splitPrecedence, splitPrecRight = 0, prec, prec
    }
  }
  if span := spans[l]; span.Cat == "OP" {
    lit := span.Lit
    prec := this.precedenceAFE[lit]
    if prec == minPrecedence {
      return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                      Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:l], prec),
                      Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
    }
    if prec >= minPrecedence && prec < splitPrecedence {
      splitLoc, splitPrecedence, splitPrecLeft = l, prec, prec
    }
  }
  for indexLR := 1; indexLR < l; indexLR++ {
    if span := spans[indexLR]; span.Cat == "OP" {
      lit := span.Lit
      prec := this.precedenceAFB[lit]
      if prec >= minPrecedence && prec < splitPrecedence {
        if this.checkInfixCandidate(spans, indexLR, prec, prec+1) {
          if prec == minPrecedence {
            return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                            Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:indexLR], prec+1),
                            Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[indexLR+1:], prec) }
          }
          splitLoc, splitPrecedence, splitPrecLeft, splitPrecRight = indexLR, prec, prec+1, prec
        }
      }
    }
    indexRL := l - indexLR
    if span := spans[indexRL]; span.Cat == "OP" {
      lit := span.Lit
      prec := this.precedenceBFA[lit]
      if prec >= minPrecedence && prec < splitPrecedence {
        if this.checkInfixCandidate(spans, indexRL, prec+1, prec) {
          if prec == minPrecedence {
            return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                            Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:indexRL], prec),
                            Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[indexRL+1:], prec+1) }
          }
          splitLoc, splitPrecedence, splitPrecLeft, splitPrecRight = indexRL, prec, prec, prec+1
        }
      }
    }
  }
  if splitLoc >= 0 {
    splitSpan := spans[splitLoc]
    if splitLoc == 0 {
      return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                      Left: &Syntax{ Ambit: splitSpan.Ambit.CollapseLeft() },
                      Right: this.sparse(ambit.SubtractLeft(splitSpan.Ambit), spans[1:], splitPrecRight) }
    }
    if splitLoc == l {
      return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                      Left: this.sparse(ambit.SubtractRight(splitSpan.Ambit), spans[:l], splitPrecLeft),
                      Right: &Syntax{ Ambit: splitSpan.Ambit.CollapseRight() } }
    }
    return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                    Left: this.sparse(ambit.SubtractRight(splitSpan.Ambit), spans[:splitLoc], splitPrecLeft),
                    Right: this.sparse(ambit.SubtractLeft(splitSpan.Ambit), spans[splitLoc+1:], splitPrecRight) }
  }
  firstSpan, secondSpan := spans[0], spans[1]
  if secondSpan.Cat == "WS" {
    return &Syntax{ Cat: "JUXT", Lit: " ", Ambit: ambit, OpAmbit: secondSpan.Ambit,
                    Left: this.sparse(ambit.SubtractRight(secondSpan.Ambit), spans[:1], minPrecedence),
                    Right: this.sparse(ambit.SubtractLeft(secondSpan.Ambit), spans[2:], minPrecedence) }
  }
  return &Syntax{ Cat: "GLUE", Lit: "", Ambit: ambit, OpAmbit: secondSpan.Ambit.CollapseLeft(),
                  Left: this.sparse(ambit.SubtractRight(secondSpan.Ambit), spans[:1], minPrecedence),
                  Right: this.sparse(ambit.SubtractLeft(firstSpan.Ambit), spans[1:], minPrecedence) }
}

func (this *sparser) checkInfixCandidate(spans []*spanT, index int, minPrecLeft int, minPrecRight int) bool {
  indexRL := index-1
  for indexRL >= 0 {
    span := spans[indexRL]
    if span.Cat != "WS" {
      if span.Cat != "OP" {
        break
      }
      lit := span.Lit
      prec := this.precedenceEFE[lit]
      if prec >= minPrecLeft {
        break
      }
      prec = this.precedenceAFE[lit]
      if prec < minPrecLeft {
        return false
      }
      minPrecLeft = prec
    }
    indexRL--
  }
  if indexRL < 0 {
    return false
  }
  l := len(spans)-1
  indexLR := index+1
  for indexLR <= l {
    span := spans[indexLR]
    if span.Cat != "WS" {
      if span.Cat != "OP" {
        break
      }
      lit := span.Lit
      prec := this.precedenceEFE[lit]
      if prec >= minPrecRight {
        break
      }
      prec = this.precedenceEFA[lit]
      if prec < minPrecRight {
        return false
      }
      minPrecRight = prec
    }
    indexLR++
  }
  if indexLR > l {
    return false
  }
  return true
}

func trimSpans(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  return trimSpansLeft(trimSpansRight(ambit, spans))
}

func trimSpansLeft(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  for index, span := range spans {
    if span.Cat != "WS" {
      return ambit, spans[index:]
    }
    ambit = ambit.SubtractLeft(span.Ambit)
  }
  return ambit, nil
}

func trimSpansRight(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  for index := len(spans)-1; index >= 0; index-- {
    span := spans[index]
    if span.Cat != "WS" {
      return ambit, spans[:index+1]
    }
    ambit = ambit.SubtractRight(span.Ambit)
  }
  return ambit, nil
}
<commit_msg>Allow weak-binding juxtaposition preceding operators that are exclusively zero-ary<commit_after>package dusl

import (
  "fmt"
)

// Sparser stands for Superpermissive-Parser.
// The Sparse method converts an ambit into a syntax tree,
// the SparseUndent method converts an entire source into a syntax tree.
type Sparser interface {
  Sparse(ambit *Ambit) *Syntax
  SparseUndent(src *Source) *Syntax
}

type sparser struct {
  precedenceLevels
  spanner spannerI
}

func newSparser(spanner spannerI, precedence *precedenceLevels) Sparser {
  return &sparser{ spanner: spanner, precedenceLevels: *precedence }
}

// SparseUndent returns the syntax tree constructed for the given source.
func (this *sparser) SparseUndent(source *Source) *Syntax {
  root := Undent(source)
  this.sparseSQ(root)
  return root
}

func (this *sparser) sparseSQ(node *Syntax) {
  if node.Cat == "SQ" {
    this.sparseSQ(node.Left)
    this.sparseSQ(node.Right)
    return
  }
  if node.Cat == "SN" {
    node.Left = this.Sparse(node.Left.Ambit)
    this.sparseSQ(node.Right)
    return
  }
  // <empty
}

// Sparse returns the syntax tree constructed for the given ambit.
func (this *sparser) Sparse(ambit *Ambit) *Syntax {
  return this.sparse(ambit, this.spanner.span(ambit), 1)
}

func (this *sparser) sparse(ambit *Ambit, spans []*spanT, minPrecedence int) *Syntax {
  ambit, spans = trimSpans(ambit, spans)
  if len(spans) == 0 {
    return &Syntax{ Ambit: ambit }
  }
  if len(spans) == 1 {
    span := spans[0]
    lit := span.Lit
    if span.Children == nil {
      if span.Cat == "OP" {
        if this.precedenceEFE[lit] < minPrecedence {
          return &Syntax{ Cat: "ERR", Err: fmt.Sprintf("unexpected: %s", lit), Ambit: ambit }
        }
        return &Syntax{ Cat: "OP", Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                        Left: &Syntax{ Ambit: span.Ambit.CollapseLeft() },
                        Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
      }
      return &Syntax{ Cat: span.Cat, Lit: lit, Err: span.Err, Ambit: ambit, OpAmbit: span.Ambit }
    }
    // span.Cat == "BB"
    precedence, recognized := this.precedenceB[lit]
    if !recognized {
      return &Syntax{ Cat: "ERR", Err: fmt.Sprintf("unexpected: %s", lit), Ambit: ambit }
    }
    return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: span.Ambit,
                    Left: this.sparse(span.SubAmbit, span.Children, precedence),
                    Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
  }
  l, splitPrecedence, splitLoc, splitPrecLeft, splitPrecRight := len(spans)-1, maxPrecedence+1, -1, -1, -1
  if span, ws := spans[0], spans[1]; span.Cat != "OP" && ws.Cat == "WS" {
    juxtaposition := false
    if len(spans) == 2 {
      juxtaposition = true
    } else {
      cat := spans[2].Cat
      if cat != "ERR" {
        if cat != "OP" {
          juxtaposition = true
        } else {
          lit := spans[2].Lit
          if this.precedenceEFA[lit] == 0 && this.precedenceAFE[lit] == 0 && this.precedenceAFB[lit] == 0 && this.precedenceBFA[lit] == 0 {
            juxtaposition = true
          }
        }
      }
    }
    if juxtaposition {
      return &Syntax{ Cat: "JUXT", Lit: " ", Ambit: ambit, OpAmbit: ws.Ambit,
                      Left: this.sparse(span.Ambit, spans[:1], minPrecedence),
                      Right: this.sparse(ambit.SubtractLeft(ws.Ambit), spans[1:], minPrecedence) }
    }
  }
  if span := spans[0]; span.Cat == "OP" {
    lit := span.Lit
    prec := this.precedenceEFA[lit]
    if prec == minPrecedence {
      return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                      Left: &Syntax{ Ambit: span.Ambit.CollapseLeft() },
                      Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[1:], prec) }
    }
    if prec > minPrecedence && prec < splitPrecedence {
      splitLoc, splitPrecedence, splitPrecRight = 0, prec, prec
    }
  }
  if span := spans[l]; span.Cat == "OP" {
    lit := span.Lit
    prec := this.precedenceAFE[lit]
    if prec == minPrecedence {
      return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                      Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:l], prec),
                      Right: &Syntax{ Ambit: span.Ambit.CollapseRight() } }
    }
    if prec >= minPrecedence && prec < splitPrecedence {
      splitLoc, splitPrecedence, splitPrecLeft = l, prec, prec
    }
  }
  for indexLR := 1; indexLR < l; indexLR++ {
    if span := spans[indexLR]; span.Cat == "OP" {
      lit := span.Lit
      prec := this.precedenceAFB[lit]
      if prec >= minPrecedence && prec < splitPrecedence {
        if this.checkInfixCandidate(spans, indexLR, prec, prec+1) {
          if prec == minPrecedence {
            return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                            Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:indexLR], prec+1),
                            Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[indexLR+1:], prec) }
          }
          splitLoc, splitPrecedence, splitPrecLeft, splitPrecRight = indexLR, prec, prec+1, prec
        }
      }
    }
    indexRL := l - indexLR
    if span := spans[indexRL]; span.Cat == "OP" {
      lit := span.Lit
      prec := this.precedenceBFA[lit]
      if prec >= minPrecedence && prec < splitPrecedence {
        if this.checkInfixCandidate(spans, indexRL, prec+1, prec) {
          if prec == minPrecedence {
            return &Syntax{ Cat: span.Cat, Lit: lit, Ambit: ambit, OpAmbit: span.Ambit,
                            Left: this.sparse(ambit.SubtractRight(span.Ambit), spans[:indexRL], prec),
                            Right: this.sparse(ambit.SubtractLeft(span.Ambit), spans[indexRL+1:], prec+1) }
          }
          splitLoc, splitPrecedence, splitPrecLeft, splitPrecRight = indexRL, prec, prec, prec+1
        }
      }
    }
  }
  if splitLoc >= 0 {
    splitSpan := spans[splitLoc]
    if splitLoc == 0 {
      return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                      Left: &Syntax{ Ambit: splitSpan.Ambit.CollapseLeft() },
                      Right: this.sparse(ambit.SubtractLeft(splitSpan.Ambit), spans[1:], splitPrecRight) }
    }
    if splitLoc == l {
      return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                      Left: this.sparse(ambit.SubtractRight(splitSpan.Ambit), spans[:l], splitPrecLeft),
                      Right: &Syntax{ Ambit: splitSpan.Ambit.CollapseRight() } }
    }
    return &Syntax{ Cat: splitSpan.Cat, Lit: splitSpan.Lit, Ambit: ambit, OpAmbit: splitSpan.Ambit,
                    Left: this.sparse(ambit.SubtractRight(splitSpan.Ambit), spans[:splitLoc], splitPrecLeft),
                    Right: this.sparse(ambit.SubtractLeft(splitSpan.Ambit), spans[splitLoc+1:], splitPrecRight) }
  }
  firstSpan, secondSpan := spans[0], spans[1]
  if secondSpan.Cat == "WS" {
    return &Syntax{ Cat: "JUXT", Lit: " ", Ambit: ambit, OpAmbit: secondSpan.Ambit,
                    Left: this.sparse(ambit.SubtractRight(secondSpan.Ambit), spans[:1], minPrecedence),
                    Right: this.sparse(ambit.SubtractLeft(secondSpan.Ambit), spans[2:], minPrecedence) }
  }
  return &Syntax{ Cat: "GLUE", Lit: "", Ambit: ambit, OpAmbit: secondSpan.Ambit.CollapseLeft(),
                  Left: this.sparse(ambit.SubtractRight(secondSpan.Ambit), spans[:1], minPrecedence),
                  Right: this.sparse(ambit.SubtractLeft(firstSpan.Ambit), spans[1:], minPrecedence) }
}

func (this *sparser) checkInfixCandidate(spans []*spanT, index int, minPrecLeft int, minPrecRight int) bool {
  indexRL := index-1
  for indexRL >= 0 {
    span := spans[indexRL]
    if span.Cat != "WS" {
      if span.Cat != "OP" {
        break
      }
      lit := span.Lit
      prec := this.precedenceEFE[lit]
      if prec >= minPrecLeft {
        break
      }
      prec = this.precedenceAFE[lit]
      if prec < minPrecLeft {
        return false
      }
      minPrecLeft = prec
    }
    indexRL--
  }
  if indexRL < 0 {
    return false
  }
  l := len(spans)-1
  indexLR := index+1
  for indexLR <= l {
    span := spans[indexLR]
    if span.Cat != "WS" {
      if span.Cat != "OP" {
        break
      }
      lit := span.Lit
      prec := this.precedenceEFE[lit]
      if prec >= minPrecRight {
        break
      }
      prec = this.precedenceEFA[lit]
      if prec < minPrecRight {
        return false
      }
      minPrecRight = prec
    }
    indexLR++
  }
  if indexLR > l {
    return false
  }
  return true
}

func trimSpans(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  return trimSpansLeft(trimSpansRight(ambit, spans))
}

func trimSpansLeft(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  for index, span := range spans {
    if span.Cat != "WS" {
      return ambit, spans[index:]
    }
    ambit = ambit.SubtractLeft(span.Ambit)
  }
  return ambit, nil
}

func trimSpansRight(ambit *Ambit, spans []*spanT) (*Ambit, []*spanT) {
  for index := len(spans)-1; index >= 0; index-- {
    span := spans[index]
    if span.Cat != "WS" {
      return ambit, spans[:index+1]
    }
    ambit = ambit.SubtractRight(span.Ambit)
  }
  return ambit, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Hari haran. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/gorilla/websocket"
	"golang.org/x/crypto/ssh/terminal"
)

func speculoHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(w, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		log.Fatal(err)
		return
	}

	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err)
	}
	defer terminal.Restore(0, oldState)
	term := terminal.NewTerminal(os.Stdin, "> ")

	term.AutoCompleteCallback = func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
		if key == '\x03' {
			fmt.Println()
			if oldState != nil {
				terminal.Restore(0, oldState)
			}
			os.Exit(0)
		}
		return "", 0, false
	}

	go func() {
		for {
			_, r, err := ws.ReadMessage() // messageType is ignored
			if err != nil {
				log.Fatal(err)
			}
			term.Write(r)
			term.Write([]byte("\n"))
		}
	}()

	for {
		text, err := term.ReadLine()
		if err != nil {
			// Ctrl-D is EOF. So, quit without printing stacktrace.
			if err == io.EOF {
				fmt.Println()
				if oldState != nil {
					terminal.Restore(0, oldState)
				}
				os.Exit(0)
			}
			panic(err)
		}
		inputcommand := []byte(text)
		if err := ws.WriteMessage(1, inputcommand); err != nil {
			log.Println(err)
		}
	}
}

func main() {
	path, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir(path)))
	http.HandleFunc("/repl", speculoHandler)

	fmt.Println("Open http://localhost:8080 and type js commands in the terminal!")
	http.ListenAndServe(":8080", nil)
}
<commit_msg>reduce allocation in hot path<commit_after>// Copyright 2014 Hari haran. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/gorilla/websocket"
	"golang.org/x/crypto/ssh/terminal"
)

func speculoHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(w, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		log.Fatal(err)
		return
	}

	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err)
	}
	defer terminal.Restore(0, oldState)
	term := terminal.NewTerminal(os.Stdin, "> ")

	term.AutoCompleteCallback = func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
		if key == '\x03' { // Ctrl-C keycode is \x03
			fmt.Println()
			if oldState != nil {
				terminal.Restore(0, oldState)
			}
			os.Exit(0)
		}
		return "", 0, false
	}

	go func() {
		newline := []byte("\n")
		for {
			_, r, err := ws.ReadMessage() // messageType is ignored
			if err != nil {
				log.Fatal(err)
			}
			term.Write(r)
			term.Write(newline)
		}
	}()

	for {
		text, err := term.ReadLine()
		if err != nil {
			// Ctrl-D is EOF. So, quit without printing stacktrace.
			if err == io.EOF {
				fmt.Println()
				if oldState != nil {
					terminal.Restore(0, oldState)
				}
				os.Exit(0)
			}
			panic(err)
		}
		inputcommand := []byte(text)
		if err := ws.WriteMessage(1, inputcommand); err != nil {
			log.Println(err)
		}
	}
}

func main() {
	path, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir(path)))
	http.HandleFunc("/repl", speculoHandler)

	fmt.Println("Open http://localhost:8080 and type js commands in the terminal!")
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>// Copyright © 2018 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package api

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestGet(t *testing.T) {
	t.Log("Testing get")

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		p := r.URL.Path
		switch p {
		case "/valid":
			_, _ = w.Write([]byte(`valid`))
		default:
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		}
	}))
	defer ts.Close()

	c, err := New(ts.URL)
	if err != nil {
		t.Fatalf("unexpected error (%s)", err)
	}

	tests := []struct {
		name        string
		rpath       string
		shouldErr   bool
		expectedErr string
	}{
		{"invalid path (empty)", "", true, "invalid request path (empty)"},
		{"invalid path (bad)", "/%/%", true, "creating request url: parse /%/%: invalid URL escape \"%/%\""},
		{"invalid path (not found)", "/not_found", true, "404 Not Found - " + ts.URL + "/not_found - Not Found"},
		{"valid", "/valid", false, ""},
	}

	for _, test := range tests {
		t.Log("\t", test.name)

		_, err := c.get(context.Background(), test.rpath)

		if test.shouldErr {
			if err == nil {
				t.Fatal("expected error")
			}
			if err.Error() != test.expectedErr {
				t.Fatalf("unexpected error (%s)", err)
			}
			continue
		}
		if err != nil {
			t.Fatalf("expected no error, got (%s)", err)
		}
	}
}
<commit_msg>fix: error msg format in test<commit_after>// Copyright © 2018 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package api

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestGet(t *testing.T) {
	t.Log("Testing get")

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		p := r.URL.Path
		switch p {
		case "/valid":
			_, _ = w.Write([]byte(`valid`))
		default:
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		}
	}))
	defer ts.Close()

	c, err := New(ts.URL)
	if err != nil {
		t.Fatalf("unexpected error (%s)", err)
	}

	tests := []struct {
		name        string
		rpath       string
		shouldErr   bool
		expectedErr string
	}{
		{"invalid path (empty)", "", true, "invalid request path (empty)"},
		{"invalid path (bad)", "/%/%", true, `creating request url: parse "/%/%": invalid URL escape "%/%"`},
		{"invalid path (not found)", "/not_found", true, "404 Not Found - " + ts.URL + "/not_found - Not Found"},
		{"valid", "/valid", false, ""},
	}

	for _, test := range tests {
		t.Log("\t", test.name)

		_, err := c.get(context.Background(), test.rpath)

		if test.shouldErr {
			if err == nil {
				t.Fatal("expected error")
			}
			if err.Error() != test.expectedErr {
				t.Fatalf("unexpected error (%s)", err)
			}
			continue
		}
		if err != nil {
			t.Fatalf("expected no error, got (%s)", err)
		}
	}
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package spinner is a simple package to add a spinner/indicator to your application.
package spinner

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"time"
	"unicode/utf8"

	"github.com/fatih/color"
)

// CharSets contains the available character sets
var CharSets = [][]string{
	{"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"},
	{"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"},
	{"▖", "▘", "▝", "▗"},
	{"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"},
	{"◢", "◣", "◤", "◥"},
	{"◰", "◳", "◲", "◱"},
	{"◴", "◷", "◶", "◵"},
	{"◐", "◓", "◑", "◒"},
	{".", "o", "O", "@", "*"},
	{"|", "/", "-", "\\"},
	{"◡◡", "⊙⊙", "◠◠"},
	{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
	{">))'>", " >))'>", "  >))'>", "   >))'>", "    >))'>", "   <'((<", "  <'((<", " <'((<"},
	{"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"},
	{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
	{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"},
	{"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"},
	{"■", "□", "▪", "▫"},
	{"←", "↑", "→", "↓"},
	{"╫", "╪"},
	{"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"},
	{"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"},
	{"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"},
	{"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"},
	{"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"},
	{"ｦ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ﾝ"},
	{".", "..", "..."},
	{"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"},
	{".", "o", "O", "°", "O", "o", "."},
	{"+", "x"},
	{"v", "<", "^", ">"},
	{">>--->", " >>--->", "  >>--->", "   >>--->", "    >>--->", "    <---<<", "   <---<<", "  <---<<", " <---<<", "<---<<"},
	{"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"},
	{"[          ]", "[=         ]", "[==        ]", "[===       ]", "[====      ]", "[=====     ]", "[======    ]", "[=======   ]", "[========  ]", "[========= ]", "[==========]"},
	{"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"},
}

// state is a type for the spinner status
type state uint8

// Spinner struct to hold the provided options
type Spinner struct {
	chars    []string                      // chosen character set
	Delay    time.Duration                 // speed of the spinner
	Prefix   string                        // Text preppended to the spinner
	Suffix   string                        // Text appended to the spinner
	stopChan chan bool                     // channel used to stop the spinner
	ST       state                         // spinner status
	w        io.Writer                     // to make testing better
	color    func(a ...interface{}) string // default color is white
}

//go:generate stringer -type=state
const (
	stopped state = iota
	running
)

// validColors holds an array of the only colors allowed
var validColors = []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

// validColor will make sure the given color is actually allowed
func validColor(c string) bool {
	for _, i := range validColors {
		if c == i {
			return true
		}
	}
	return false
}

// New provides a pointer to an instance of Spinner with the supplied options
func New(c []string, t time.Duration) *Spinner {
	s := &Spinner{
		Delay:    t,
		stopChan: make(chan bool, 1),
		color:    color.New(color.FgWhite).SprintFunc(),
		w:        os.Stdout,
	}
	s.UpdateCharSet(c)
	return s
}

// Start will start the spinner
func (s *Spinner) Start() {
	if s.ST == running {
		return
	}
	s.ST = running
	go func() {
		for {
			for i := 0; i < len(s.chars); i++ {
				select {
				case <-s.stopChan:
					return
				default:
					out := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
					fmt.Fprint(s.w, out)
					time.Sleep(s.Delay)
					erase(s.w, out)
				}
			}
		}
	}()
}

// erase deletes written characters
func erase(w io.Writer, a string) {
	n := utf8.RuneCountInString(a)
	for i := 0; i < n; i++ {
		fmt.Fprintf(w, "\b")
	}
}

// Color will set the struct field for the given color to be used
func (s *Spinner) Color(c string) error {
	if validColor(c) {
		switch {
		case c == "red":
			s.color = color.New(color.FgRed).SprintFunc()
			s.Restart()
		case c == "yellow":
			s.color = color.New(color.FgYellow).SprintFunc()
			s.Restart()
		case c == "green":
			s.color = color.New(color.FgGreen).SprintFunc()
			s.Restart()
		case c == "magenta":
			s.color = color.New(color.FgMagenta).SprintFunc()
			s.Restart()
		case c == "blue":
			s.color = color.New(color.FgBlue).SprintFunc()
			s.Restart()
		case c == "cyan":
			s.color = color.New(color.FgCyan).SprintFunc()
			s.Restart()
		case c == "white":
			s.color = color.New(color.FgWhite).SprintFunc()
			s.Restart()
		default:
			return errors.New("invalid color")
		}
	}
	return nil
}

// Stop stops the spinner
func (s *Spinner) Stop() {
	if s.ST == running {
		s.stopChan <- true
		s.ST = stopped
	}
}

// Restart will stop and start the spinner
func (s *Spinner) Restart() {
	s.Stop()
	s.Start()
}

// Reverse will reverse the order of the slice assigned to that spinner
func (s *Spinner) Reverse() {
	for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
		s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
	}
}

// UpdateSpeed is a convenience function to not have to make you
//create a new instance of the Spinner
func (s *Spinner) UpdateSpeed(delay time.Duration) { s.Delay = delay }

// UpdateCharSet will change the previously select character set to
// the provided one
func (s *Spinner) UpdateCharSet(chars []string) {
	// so that changes to the slice outside of the spinner don't change it
	// unexpectedly, create an internal copy
	n := make([]string, len(chars))
	copy(n, chars)
	s.chars = n
}

// GenerateNumberSequence will generate a slice of integers at the
// provided length and convert them each to a string
func GenerateNumberSequence(length int) []string {
	numSeq := make([]string, 0)
	for i := 0; i < length; i++ {
		numSeq = append(numSeq, strconv.Itoa(i))
	}
	return numSeq
}
<commit_msg>lint suggested using an array rather than a slice.  Updated to comply<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package spinner is a simple package to add a spinner/indicator to your application.
package spinner

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"time"
	"unicode/utf8"

	"github.com/fatih/color"
)

// CharSets contains the available character sets
var CharSets = [][]string{
	{"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"},
	{"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"},
	{"▖", "▘", "▝", "▗"},
	{"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"},
	{"◢", "◣", "◤", "◥"},
	{"◰", "◳", "◲", "◱"},
	{"◴", "◷", "◶", "◵"},
	{"◐", "◓", "◑", "◒"},
	{".", "o", "O", "@", "*"},
	{"|", "/", "-", "\\"},
	{"◡◡", "⊙⊙", "◠◠"},
	{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
	{">))'>", " >))'>", "  >))'>", "   >))'>", "    >))'>", "   <'((<", "  <'((<", " <'((<"},
	{"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"},
	{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
	{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"},
	{"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"},
	{"■", "□", "▪", "▫"},
	{"←", "↑", "→", "↓"},
	{"╫", "╪"},
	{"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"},
	{"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"},
	{"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"},
	{"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"},
	{"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"},
	{"ｦ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ﾝ"},
	{".", "..", "..."},
	{"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"},
	{".", "o", "O", "°", "O", "o", "."},
	{"+", "x"},
	{"v", "<", "^", ">"},
	{">>--->", " >>--->", "  >>--->", "   >>--->", "    >>--->", "    <---<<", "   <---<<", "  <---<<", " <---<<", "<---<<"},
	{"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"},
	{"[          ]", "[=         ]", "[==        ]", "[===       ]", "[====      ]", "[=====     ]", "[======    ]", "[=======   ]", "[========  ]", "[========= ]", "[==========]"},
	{"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"},
}

// state is a type for the spinner status
type state uint8

// Spinner struct to hold the provided options
type Spinner struct {
	chars    []string                      // chosen character set
	Delay    time.Duration                 // speed of the spinner
	Prefix   string                        // Text preppended to the spinner
	Suffix   string                        // Text appended to the spinner
	stopChan chan bool                     // channel used to stop the spinner
	ST       state                         // spinner status
	w        io.Writer                     // to make testing better
	color    func(a ...interface{}) string // default color is white
}

//go:generate stringer -type=state
const (
	stopped state = iota
	running
)

// validColors holds an array of the only colors allowed
var validColors = []string{"red", "green", "yellow", "blue", "magenta", "cyan", "white"}

// validColor will make sure the given color is actually allowed
func validColor(c string) bool {
	for _, i := range validColors {
		if c == i {
			return true
		}
	}
	return false
}

// New provides a pointer to an instance of Spinner with the supplied options
func New(c []string, t time.Duration) *Spinner {
	s := &Spinner{
		Delay:    t,
		stopChan: make(chan bool, 1),
		color:    color.New(color.FgWhite).SprintFunc(),
		w:        os.Stdout,
	}
	s.UpdateCharSet(c)
	return s
}

// Start will start the spinner
func (s *Spinner) Start() {
	if s.ST == running {
		return
	}
	s.ST = running
	go func() {
		for {
			for i := 0; i < len(s.chars); i++ {
				select {
				case <-s.stopChan:
					return
				default:
					out := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
					fmt.Fprint(s.w, out)
					time.Sleep(s.Delay)
					erase(s.w, out)
				}
			}
		}
	}()
}

// erase deletes written characters
func erase(w io.Writer, a string) {
	n := utf8.RuneCountInString(a)
	for i := 0; i < n; i++ {
		fmt.Fprintf(w, "\b")
	}
}

// Color will set the struct field for the given color to be used
func (s *Spinner) Color(c string) error {
	if validColor(c) {
		switch {
		case c == "red":
			s.color = color.New(color.FgRed).SprintFunc()
			s.Restart()
		case c == "yellow":
			s.color = color.New(color.FgYellow).SprintFunc()
			s.Restart()
		case c == "green":
			s.color = color.New(color.FgGreen).SprintFunc()
			s.Restart()
		case c == "magenta":
			s.color = color.New(color.FgMagenta).SprintFunc()
			s.Restart()
		case c == "blue":
			s.color = color.New(color.FgBlue).SprintFunc()
			s.Restart()
		case c == "cyan":
			s.color = color.New(color.FgCyan).SprintFunc()
			s.Restart()
		case c == "white":
			s.color = color.New(color.FgWhite).SprintFunc()
			s.Restart()
		default:
			return errors.New("invalid color")
		}
	}
	return nil
}

// Stop stops the spinner
func (s *Spinner) Stop() {
	if s.ST == running {
		s.stopChan <- true
		s.ST = stopped
	}
}

// Restart will stop and start the spinner
func (s *Spinner) Restart() {
	s.Stop()
	s.Start()
}

// Reverse will reverse the order of the slice assigned to that spinner
func (s *Spinner) Reverse() {
	for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
		s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
	}
}

// UpdateSpeed is a convenience function to not have to make you
//create a new instance of the Spinner
func (s *Spinner) UpdateSpeed(delay time.Duration) { s.Delay = delay }

// UpdateCharSet will change the previously select character set to
// the provided one
func (s *Spinner) UpdateCharSet(chars []string) {
	// so that changes to the slice outside of the spinner don't change it
	// unexpectedly, create an internal copy
	n := make([]string, len(chars))
	copy(n, chars)
	s.chars = n
}

// GenerateNumberSequence will generate a slice of integers at the
// provided length and convert them each to a string
func GenerateNumberSequence(length int) []string {
	//numSeq := make([]string, 0)
	var numSeq []string
	for i := 0; i < length; i++ {
		numSeq = append(numSeq, strconv.Itoa(i))
	}
	return numSeq
}
<|endoftext|>


<commit_before>// Copyright 2015 tsuru 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 api

import (
	"fmt"
	stdLog "log"
	"net/http"
	"os"
	"reflect"
	"time"

	"github.com/codegangsta/negroni"
	"github.com/tsuru/tsuru/api/context"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/io"
	"github.com/tsuru/tsuru/log"
)

const (
	tsuruMin      = "0.15.0"
	craneMin      = "0.7.0"
	tsuruAdminMin = "0.9.0"
)

func validate(token string, r *http.Request) (auth.Token, error) {
	t, err := app.AuthScheme.Auth(token)
	if err != nil {
		t, err = auth.APIAuth(token)
		if err != nil {
			return nil, err
		}
	}
	if t.IsAppToken() {
		if q := r.URL.Query().Get(":app"); q != "" && t.GetAppName() != q {
			return nil, &errors.HTTP{
				Code:    http.StatusForbidden,
				Message: fmt.Sprintf("app token mismatch, token for %q, request for %q", t.GetAppName(), q),
			}
		}
	} else if user, err := t.User(); err == nil {
		if q := r.URL.Query().Get(":app"); q != "" {
			_, err = getApp(q, user, r)
			if err != nil {
				return nil, err
			}
		}
	}
	return t, nil
}

func contextClearerMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer context.Clear(r)
	next(w, r)
}

func flushingWriterMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer func() {
		if r.Body != nil {
			r.Body.Close()
		}
	}()
	fw := io.FlushingWriter{ResponseWriter: w}
	next(&fw, r)
}

func setVersionHeadersMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	w.Header().Set("Supported-Tsuru", tsuruMin)
	w.Header().Set("Supported-Crane", craneMin)
	w.Header().Set("Supported-Tsuru-Admin", tsuruAdminMin)
	next(w, r)
}

func errorHandlingMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	next(w, r)
	err := context.GetRequestError(r)
	if err != nil {
		code := http.StatusInternalServerError
		if e, ok := err.(*errors.HTTP); ok {
			code = e.Code
		}
		flushing, ok := w.(*io.FlushingWriter)
		if ok && flushing.Wrote() {
			fmt.Fprintln(w, err)
		} else {
			http.Error(w, err.Error(), code)
		}
		log.Error(err.Error())
	}
}

func authTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	token := r.Header.Get("Authorization")
	if token != "" {
		t, err := validate(token, r)
		if err != nil {
			if err != auth.ErrInvalidToken {
				context.AddRequestError(r, err)
				return
			}
			log.Debugf("Ignored invalid token for %s: %s", r.URL.Path, err.Error())
		} else {
			context.SetAuthToken(r, t)
		}
	}
	next(w, r)
}

type appLockMiddleware struct {
	excludedHandlers []http.Handler
}

var lockWaitDuration time.Duration = 10 * time.Second

func (m *appLockMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == "GET" {
		next(w, r)
		return
	}
	currentHandler := context.GetDelayedHandler(r)
	if currentHandler != nil {
		currentHandlerPtr := reflect.ValueOf(currentHandler).Pointer()
		for _, h := range m.excludedHandlers {
			if reflect.ValueOf(h).Pointer() == currentHandlerPtr {
				next(w, r)
				return
			}
		}
	}
	appName := r.URL.Query().Get(":app")
	if appName == "" {
		appName = r.URL.Query().Get(":appname")
	}
	if appName == "" {
		next(w, r)
		return
	}
	t := context.GetAuthToken(r)
	var owner string
	if t != nil {
		if t.IsAppToken() {
			owner = t.GetAppName()
		} else {
			owner = t.GetUserName()
		}
	}
	_, err := app.GetByName(appName)
	if err == app.ErrAppNotFound {
		context.AddRequestError(r, &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()})
		return
	}
	ok, err := app.AcquireApplicationLockWait(appName, owner, fmt.Sprintf("%s %s", r.Method, r.URL.Path), lockWaitDuration)
	if err != nil {
		context.AddRequestError(r, fmt.Errorf("Error trying to acquire application lock: %s", err))
		return
	}
	if ok {
		defer func() {
			if !context.IsPreventUnlock(r) {
				app.ReleaseApplicationLock(appName)
			}
		}()
		next(w, r)
		return
	}
	a, err := app.GetByName(appName)
	httpErr := &errors.HTTP{Code: http.StatusInternalServerError}
	if err != nil {
		if err == app.ErrAppNotFound {
			httpErr.Code = http.StatusNotFound
			httpErr.Message = err.Error()
		} else {
			httpErr.Message = fmt.Sprintf("Error to get application: %s", err)
		}
	} else {
		httpErr.Code = http.StatusConflict
		if a.Lock.Locked {
			httpErr.Message = fmt.Sprintf("%s", &a.Lock)
		} else {
			httpErr.Message = "Not locked anymore, please try again."
		}
	}
	context.AddRequestError(r, httpErr)
}

func runDelayedHandler(w http.ResponseWriter, r *http.Request) {
	h := context.GetDelayedHandler(r)
	if h != nil {
		h.ServeHTTP(w, r)
	}
}

type loggerMiddleware struct {
	logger *stdLog.Logger
}

func newLoggerMiddleware() *loggerMiddleware {
	return &loggerMiddleware{
		logger: stdLog.New(os.Stdout, "", 0),
	}
}

func (l *loggerMiddleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()
	next(rw, r)
	duration := time.Since(start)
	res := rw.(negroni.ResponseWriter)
	nowFormatted := time.Now().Format(time.RFC3339Nano)
	l.logger.Printf("%s %s %s %d in %0.6fms", nowFormatted, r.Method, r.URL.Path, res.Status(), float64(duration)/float64(time.Millisecond))
}
<commit_msg>api: update minimum requirements for tsuru and tsuru-admin<commit_after>// Copyright 2015 tsuru 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 api

import (
	"fmt"
	stdLog "log"
	"net/http"
	"os"
	"reflect"
	"time"

	"github.com/codegangsta/negroni"
	"github.com/tsuru/tsuru/api/context"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/io"
	"github.com/tsuru/tsuru/log"
)

const (
	tsuruMin      = "0.17.0"
	craneMin      = "0.7.0"
	tsuruAdminMin = "0.11.0"
)

func validate(token string, r *http.Request) (auth.Token, error) {
	t, err := app.AuthScheme.Auth(token)
	if err != nil {
		t, err = auth.APIAuth(token)
		if err != nil {
			return nil, err
		}
	}
	if t.IsAppToken() {
		if q := r.URL.Query().Get(":app"); q != "" && t.GetAppName() != q {
			return nil, &errors.HTTP{
				Code:    http.StatusForbidden,
				Message: fmt.Sprintf("app token mismatch, token for %q, request for %q", t.GetAppName(), q),
			}
		}
	} else if user, err := t.User(); err == nil {
		if q := r.URL.Query().Get(":app"); q != "" {
			_, err = getApp(q, user, r)
			if err != nil {
				return nil, err
			}
		}
	}
	return t, nil
}

func contextClearerMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer context.Clear(r)
	next(w, r)
}

func flushingWriterMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	defer func() {
		if r.Body != nil {
			r.Body.Close()
		}
	}()
	fw := io.FlushingWriter{ResponseWriter: w}
	next(&fw, r)
}

func setVersionHeadersMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	w.Header().Set("Supported-Tsuru", tsuruMin)
	w.Header().Set("Supported-Crane", craneMin)
	w.Header().Set("Supported-Tsuru-Admin", tsuruAdminMin)
	next(w, r)
}

func errorHandlingMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	next(w, r)
	err := context.GetRequestError(r)
	if err != nil {
		code := http.StatusInternalServerError
		if e, ok := err.(*errors.HTTP); ok {
			code = e.Code
		}
		flushing, ok := w.(*io.FlushingWriter)
		if ok && flushing.Wrote() {
			fmt.Fprintln(w, err)
		} else {
			http.Error(w, err.Error(), code)
		}
		log.Error(err.Error())
	}
}

func authTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	token := r.Header.Get("Authorization")
	if token != "" {
		t, err := validate(token, r)
		if err != nil {
			if err != auth.ErrInvalidToken {
				context.AddRequestError(r, err)
				return
			}
			log.Debugf("Ignored invalid token for %s: %s", r.URL.Path, err.Error())
		} else {
			context.SetAuthToken(r, t)
		}
	}
	next(w, r)
}

type appLockMiddleware struct {
	excludedHandlers []http.Handler
}

var lockWaitDuration time.Duration = 10 * time.Second

func (m *appLockMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == "GET" {
		next(w, r)
		return
	}
	currentHandler := context.GetDelayedHandler(r)
	if currentHandler != nil {
		currentHandlerPtr := reflect.ValueOf(currentHandler).Pointer()
		for _, h := range m.excludedHandlers {
			if reflect.ValueOf(h).Pointer() == currentHandlerPtr {
				next(w, r)
				return
			}
		}
	}
	appName := r.URL.Query().Get(":app")
	if appName == "" {
		appName = r.URL.Query().Get(":appname")
	}
	if appName == "" {
		next(w, r)
		return
	}
	t := context.GetAuthToken(r)
	var owner string
	if t != nil {
		if t.IsAppToken() {
			owner = t.GetAppName()
		} else {
			owner = t.GetUserName()
		}
	}
	_, err := app.GetByName(appName)
	if err == app.ErrAppNotFound {
		context.AddRequestError(r, &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()})
		return
	}
	ok, err := app.AcquireApplicationLockWait(appName, owner, fmt.Sprintf("%s %s", r.Method, r.URL.Path), lockWaitDuration)
	if err != nil {
		context.AddRequestError(r, fmt.Errorf("Error trying to acquire application lock: %s", err))
		return
	}
	if ok {
		defer func() {
			if !context.IsPreventUnlock(r) {
				app.ReleaseApplicationLock(appName)
			}
		}()
		next(w, r)
		return
	}
	a, err := app.GetByName(appName)
	httpErr := &errors.HTTP{Code: http.StatusInternalServerError}
	if err != nil {
		if err == app.ErrAppNotFound {
			httpErr.Code = http.StatusNotFound
			httpErr.Message = err.Error()
		} else {
			httpErr.Message = fmt.Sprintf("Error to get application: %s", err)
		}
	} else {
		httpErr.Code = http.StatusConflict
		if a.Lock.Locked {
			httpErr.Message = fmt.Sprintf("%s", &a.Lock)
		} else {
			httpErr.Message = "Not locked anymore, please try again."
		}
	}
	context.AddRequestError(r, httpErr)
}

func runDelayedHandler(w http.ResponseWriter, r *http.Request) {
	h := context.GetDelayedHandler(r)
	if h != nil {
		h.ServeHTTP(w, r)
	}
}

type loggerMiddleware struct {
	logger *stdLog.Logger
}

func newLoggerMiddleware() *loggerMiddleware {
	return &loggerMiddleware{
		logger: stdLog.New(os.Stdout, "", 0),
	}
}

func (l *loggerMiddleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()
	next(rw, r)
	duration := time.Since(start)
	res := rw.(negroni.ResponseWriter)
	nowFormatted := time.Now().Format(time.RFC3339Nano)
	l.logger.Printf("%s %s %s %d in %0.6fms", nowFormatted, r.Method, r.URL.Path, res.Status(), float64(duration)/float64(time.Millisecond))
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/hashicorp/raft"
)

// Operator can be used to perform low-level operator tasks for Consul.
type Operator struct {
	c *Client
}

// Operator returns a handle to the operator endpoints.
func (c *Client) Operator() *Operator {
	return &Operator{c}
}

// RaftConfigration is returned when querying for the current Raft configuration.
// This has the low-level Raft structure, as well as some supplemental
// information from Consul.
type RaftConfiguration struct {
	// Configuration is the low-level Raft configuration structure.
	Configuration raft.Configuration

	// NodeMap maps IDs in the Raft configuration to node names known by
	// Consul. It's possible that not all configuration entries may have
	// an entry here if the node isn't known to Consul. Given how this is
	// generated, this may also contain entries that aren't present in the
	// Raft configuration.
	NodeMap map[raft.ServerID]string

	// Leader is the ID of the current Raft leader. This may be blank if
	// there isn't one.
	Leader raft.ServerID
}

// RaftGetConfiguration is used to query the current Raft peer set.
func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) {
	r := op.c.newRequest("GET", "/v1/operator/raft/configuration")
	r.setQueryOptions(q)
	_, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var out RaftConfiguration
	if err := decodeBody(resp, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
// quorum but no longer known to Serf or the catalog) by address in the form of
// "IP:port".
func (op *Operator) RaftRemovePeerByAddress(address raft.ServerAddress, q *WriteOptions) error {
	r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
	r.setWriteOptions(q)

	// TODO (slackpad) Currently we made address a query parameter. Once
	// IDs are in place this will be DELETE /v1/raft-peer/<id>.
	r.params.Set("address", string(address))

	_, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return err
	}

	resp.Body.Close()
	return nil
}
<commit_msg>Fixes a stale comment.<commit_after>package api

import (
	"github.com/hashicorp/raft"
)

// Operator can be used to perform low-level operator tasks for Consul.
type Operator struct {
	c *Client
}

// Operator returns a handle to the operator endpoints.
func (c *Client) Operator() *Operator {
	return &Operator{c}
}

// RaftConfigration is returned when querying for the current Raft configuration.
// This has the low-level Raft structure, as well as some supplemental
// information from Consul.
type RaftConfiguration struct {
	// Configuration is the low-level Raft configuration structure.
	Configuration raft.Configuration

	// NodeMap maps IDs in the Raft configuration to node names known by
	// Consul. It's possible that not all configuration entries may have
	// an entry here if the node isn't known to Consul. Given how this is
	// generated, this may also contain entries that aren't present in the
	// Raft configuration.
	NodeMap map[raft.ServerID]string

	// Leader is the ID of the current Raft leader. This may be blank if
	// there isn't one.
	Leader raft.ServerID
}

// RaftGetConfiguration is used to query the current Raft peer set.
func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) {
	r := op.c.newRequest("GET", "/v1/operator/raft/configuration")
	r.setQueryOptions(q)
	_, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var out RaftConfiguration
	if err := decodeBody(resp, &out); err != nil {
		return nil, err
	}
	return &out, nil
}

// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
// quorum but no longer known to Serf or the catalog) by address in the form of
// "IP:port".
func (op *Operator) RaftRemovePeerByAddress(address raft.ServerAddress, q *WriteOptions) error {
	r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
	r.setWriteOptions(q)

	// TODO (slackpad) Currently we made address a query parameter. Once
	// IDs are in place this will be DELETE /v1/operator/raft/peer/<id>.
	r.params.Set("address", string(address))

	_, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return err
	}

	resp.Body.Close()
	return nil
}
<|endoftext|>