<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package leadership

import (
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"launchpad.net/tomb"

	"github.com/juju/juju/leadership"
)

var logger = loggo.GetLogger("juju.worker.leadership")

// tracker implements TrackerWorker.
type tracker struct {
	tomb        tomb.Tomb
	leadership  leadership.LeadershipManager
	unitName    string
	serviceName string
	duration    time.Duration
	isMinion    bool

	claimLease        chan struct{}
	renewLease        <-chan time.Time
	claimTickets      chan chan bool
	waitLeaderTickets chan chan bool
	waitMinionTickets chan chan bool
	waitingLeader     []chan bool
	waitingMinion     []chan bool
}

// NewTrackerWorker returns a TrackerWorker that attempts to claim and retain
// service leadership for the supplied unit. It will claim leadership for twice
// the supplied duration, and once it's leader it will renew leadership every
// time the duration elapses.
// Thus, successful leadership claims on the resulting Tracker will guarantee
// leadership for the duration supplied here without generating additional calls
// to the supplied manager (which may very well be on the other side of a
// network connection).
func NewTrackerWorker(tag names.UnitTag, leadership leadership.LeadershipManager, duration time.Duration) TrackerWorker {
	unitName := tag.Id()
	serviceName, _ := names.UnitService(unitName)
	t := &tracker{
		unitName:          unitName,
		serviceName:       serviceName,
		leadership:        leadership,
		duration:          duration,
		claimTickets:      make(chan chan bool),
		waitLeaderTickets: make(chan chan bool),
		waitMinionTickets: make(chan chan bool),
	}
	go func() {
		defer t.tomb.Done()
		defer func() {
			for _, ticketCh := range t.waitingLeader {
				close(ticketCh)
			}
			for _, ticketCh := range t.waitingMinion {
				close(ticketCh)
			}
		}()
		err := t.loop()
		// TODO: jam 2015-04-02 is this the most elegant way to make
		// sure we shutdown cleanly? Essentially the lowest level sees
		// that we are dying, and propagates an ErrDying up to us so
		// that we shut down, which we then are passing back into
		// Tomb.Kill().
		// Tomb.Kill() special cases the exact object ErrDying, and has
		// no idea about errors.Cause and the general errors.Trace
		// mechanisms that we use.
		// So we explicitly unwrap before calling tomb.Kill() else
		// tomb.Stop() thinks that we have a genuine error.
		switch cause := errors.Cause(err); cause {
		case tomb.ErrDying:
			err = cause
		}
		t.tomb.Kill(err)
	}()
	return t
}

// Kill is part of the worker.Worker interface.
func (t *tracker) Kill() {
	t.tomb.Kill(nil)
}

// Wait is part of the worker.Worker interface.
func (t *tracker) Wait() error {
	return t.tomb.Wait()
}

// ServiceName is part of the Tracker interface.
func (t *tracker) ServiceName() string {
	return t.serviceName
}

// ClaimDuration is part of the Tracker interface.
func (t *tracker) ClaimDuration() time.Duration {
	return t.duration
}

// ClaimLeader is part of the Tracker interface.
func (t *tracker) ClaimLeader() Ticket {
	return t.submit(t.claimTickets)
}

// WaitLeader is part of the Tracker interface.
func (t *tracker) WaitLeader() Ticket {
	return t.submit(t.waitLeaderTickets)
}

// WaitMinion is part of the Tracker interface.
func (t *tracker) WaitMinion() Ticket {
	return t.submit(t.waitMinionTickets)
}

func (t *tracker) loop() error {
	logger.Infof("%s making initial claim for %s leadership", t.unitName, t.serviceName)
	if err := t.refresh(); err != nil {
		return errors.Trace(err)
	}
	for {
		select {
		case <-t.tomb.Dying():
			return tomb.ErrDying
		case <-t.claimLease:
			logger.Infof("%s claiming lease for %s leadership", t.unitName, t.serviceName)
			t.claimLease = nil
			if err := t.refresh(); err != nil {
				return errors.Trace(err)
			}
		case <-t.renewLease:
			logger.Infof("%s renewing lease for %s leadership", t.unitName, t.serviceName)
			t.renewLease = nil
			if err := t.refresh(); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.claimTickets:
			logger.Infof("%s got claim request for %s leadership", t.unitName, t.serviceName)
			if err := t.resolveClaim(ticketCh); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.waitLeaderTickets:
			logger.Infof("%s got wait request for %s leadership", t.unitName, t.serviceName)
			if err := t.resolveWaitLeader(ticketCh); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.waitMinionTickets:
			logger.Infof("%s got wait request for %s leadership loss", t.unitName, t.serviceName)
			if err := t.resolveWaitMinion(ticketCh); err != nil {
				return errors.Trace(err)
			}
		}
	}
}

// refresh makes a leadership request, and updates tracker state to conform to
// latest known reality.
func (t *tracker) refresh() error {
	logger.Infof("checking %s for %s leadership", t.unitName, t.serviceName)
	leaseDuration := 2 * t.duration
	untilTime := time.Now().Add(leaseDuration)
	err := t.leadership.ClaimLeadership(t.serviceName, t.unitName, leaseDuration)
	switch {
	case err == nil:
		return t.setLeader(untilTime)
	case errors.Cause(err) == leadership.ErrClaimDenied:
		return t.setMinion()
	}
	return errors.Annotatef(err, "leadership failure")
}

// setLeader arranges for lease renewal.
func (t *tracker) setLeader(untilTime time.Time) error {
	logger.Infof("%s confirmed for %s leadership until %s", t.unitName, t.serviceName, untilTime)
	renewTime := untilTime.Add(-t.duration)
	logger.Infof("%s will renew %s leadership at %s", t.unitName, t.serviceName, renewTime)
	t.isMinion = false
	t.claimLease = nil
	t.renewLease = time.After(renewTime.Sub(time.Now()))

	for len(t.waitingLeader) > 0 {
		logger.Infof("notifying %s ticket of impending %s leadership", t.unitName, t.serviceName)
		var ticketCh chan bool
		ticketCh, t.waitingLeader = t.waitingLeader[0], t.waitingLeader[1:]
		defer close(ticketCh)
		if err := t.sendTrue(ticketCh); err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// setMinion arranges for lease acquisition when there's an opportunity.
func (t *tracker) setMinion() error {
	logger.Infof("%s leadership for %s denied", t.serviceName, t.unitName)
	t.isMinion = true
	t.renewLease = nil
	if t.claimLease == nil {
		t.claimLease = make(chan struct{})
		go func() {
			defer close(t.claimLease)
			logger.Infof("%s waiting for %s leadership release", t.unitName, t.serviceName)
			err := t.leadership.BlockUntilLeadershipReleased(t.serviceName)
			if err != nil {
				logger.Warningf("error while %s waiting for %s leadership release: %v", t.unitName, t.serviceName, err)
			}
			// We don't need to do anything else with the error, because we just
			// close the claimLease channel and trigger a leadership claim on the
			// main loop; if anything's gone seriously wrong we'll find out right
			// away and shut down anyway. (And if this goroutine outlives the
			// tracker, it keeps it around as a zombie, but I don't see a way
			// around that...)
		}()
	}

	for len(t.waitingMinion) > 0 {
		logger.Infof("notifying %s ticket of impending loss of %s leadership", t.unitName, t.serviceName)
		var ticketCh chan bool
		ticketCh, t.waitingMinion = t.waitingMinion[0], t.waitingMinion[1:]
		defer close(ticketCh)
		if err := t.sendTrue(ticketCh); err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// isLeader returns true if leadership is guaranteed for the tracker's duration.
func (t *tracker) isLeader() (bool, error) {
	if !t.isMinion {
		// Last time we looked, we were leader.
		select {
		case <-t.tomb.Dying():
			return false, errors.Trace(tomb.ErrDying)
		case <-t.renewLease:
			logger.Infof("%s renewing lease for %s leadership", t.unitName, t.serviceName)
			t.renewLease = nil
			if err := t.refresh(); err != nil {
				return false, errors.Trace(err)
			}
		default:
			logger.Infof("%s still has %s leadership", t.unitName, t.serviceName)
		}
	}
	return !t.isMinion, nil
}

// resolveClaim will send true on the supplied channel if leadership can be
// successfully verified, and will always close it whether or not it sent.
func (t *tracker) resolveClaim(ticketCh chan bool) error {
	logger.Infof("resolving %s leadership ticket for %s...", t.serviceName, t.unitName)
	defer close(ticketCh)
	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if !leader {
		logger.Infof("%s is not %s leader", t.unitName, t.serviceName)
		return nil
	}
	logger.Infof("confirming %s leadership for %s", t.serviceName, t.unitName)
	return t.sendTrue(ticketCh)
}

// resolveWaitLeader will send true on the supplied channel if leadership can be
// guaranteed for the tracker's duration. It will then close the channel. If
// leadership cannot be guaranteed, the channel is left untouched until either
// the termination of the tracker or the next invocation of setLeader; at which
// point true is sent if applicable, and the channel is closed.
func (t *tracker) resolveWaitLeader(ticketCh chan bool) error {
	var dontClose bool
	defer func() {
		if !dontClose {
			close(ticketCh)
		}
	}()

	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if leader {
		logger.Infof("reporting %s leadership for %s", t.serviceName, t.unitName)
		return t.sendTrue(ticketCh)
	}

	logger.Infof("waiting for %s to attain %s leadership", t.unitName, t.serviceName)
	t.waitingLeader = append(t.waitingLeader, ticketCh)
	dontClose = true
	return nil
}

// resolveWaitMinion will close the supplied channel as soon as leadership cannot
// be guaranteed beyond the tracker's duration.
func (t *tracker) resolveWaitMinion(ticketCh chan bool) error {
	var dontClose bool
	defer func() {
		if !dontClose {
			close(ticketCh)
		}
	}()

	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if leader {
		logger.Infof("waiting for %s to lose %s leadership", t.unitName, t.serviceName)
		t.waitingMinion = append(t.waitingMinion, ticketCh)
		dontClose = true
	} else {
		logger.Infof("reporting %s leadership loss for %s", t.serviceName, t.unitName)
	}
	return nil

}

func (t *tracker) sendTrue(ticketCh chan bool) error {
	select {
	case <-t.tomb.Dying():
		return tomb.ErrDying
	case ticketCh <- true:
		return nil
	}
}

func (t *tracker) submit(tickets chan chan bool) Ticket {
	ticketCh := make(chan bool, 1)
	select {
	case <-t.tomb.Dying():
		close(ticketCh)
	case tickets <- ticketCh:
	}
	ticket := &ticket{
		ch:    ticketCh,
		ready: make(chan struct{}),
	}
	go ticket.run()
	return ticket
}

// ticket is used with tracker to communicate leadership status back to a client.
type ticket struct {
	ch      chan bool
	ready   chan struct{}
	success bool
}

func (t *ticket) run() {
	defer close(t.ready)
	// This is only safe/sane because the tracker promises to close all pending
	// ticket channels when it shuts down.
	if <-t.ch {
		t.success = true
	}
}

// Ready is part of the Ticket interface.
func (t *ticket) Ready() <-chan struct{} {
	return t.ready
}

// Wait is part of the Ticket interface.
func (t *ticket) Wait() bool {
	<-t.ready
	return t.success
}
<commit_msg>Migrated most leadership logging to debug level.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package leadership

import (
	"time"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"launchpad.net/tomb"

	"github.com/juju/juju/leadership"
)

var logger = loggo.GetLogger("juju.worker.leadership")

// tracker implements TrackerWorker.
type tracker struct {
	tomb        tomb.Tomb
	leadership  leadership.LeadershipManager
	unitName    string
	serviceName string
	duration    time.Duration
	isMinion    bool

	claimLease        chan struct{}
	renewLease        <-chan time.Time
	claimTickets      chan chan bool
	waitLeaderTickets chan chan bool
	waitMinionTickets chan chan bool
	waitingLeader     []chan bool
	waitingMinion     []chan bool
}

// NewTrackerWorker returns a TrackerWorker that attempts to claim and retain
// service leadership for the supplied unit. It will claim leadership for twice
// the supplied duration, and once it's leader it will renew leadership every
// time the duration elapses.
// Thus, successful leadership claims on the resulting Tracker will guarantee
// leadership for the duration supplied here without generating additional calls
// to the supplied manager (which may very well be on the other side of a
// network connection).
func NewTrackerWorker(tag names.UnitTag, leadership leadership.LeadershipManager, duration time.Duration) TrackerWorker {
	unitName := tag.Id()
	serviceName, _ := names.UnitService(unitName)
	t := &tracker{
		unitName:          unitName,
		serviceName:       serviceName,
		leadership:        leadership,
		duration:          duration,
		claimTickets:      make(chan chan bool),
		waitLeaderTickets: make(chan chan bool),
		waitMinionTickets: make(chan chan bool),
	}
	go func() {
		defer t.tomb.Done()
		defer func() {
			for _, ticketCh := range t.waitingLeader {
				close(ticketCh)
			}
			for _, ticketCh := range t.waitingMinion {
				close(ticketCh)
			}
		}()
		err := t.loop()
		// TODO: jam 2015-04-02 is this the most elegant way to make
		// sure we shutdown cleanly? Essentially the lowest level sees
		// that we are dying, and propagates an ErrDying up to us so
		// that we shut down, which we then are passing back into
		// Tomb.Kill().
		// Tomb.Kill() special cases the exact object ErrDying, and has
		// no idea about errors.Cause and the general errors.Trace
		// mechanisms that we use.
		// So we explicitly unwrap before calling tomb.Kill() else
		// tomb.Stop() thinks that we have a genuine error.
		switch cause := errors.Cause(err); cause {
		case tomb.ErrDying:
			err = cause
		}
		t.tomb.Kill(err)
	}()
	return t
}

// Kill is part of the worker.Worker interface.
func (t *tracker) Kill() {
	t.tomb.Kill(nil)
}

// Wait is part of the worker.Worker interface.
func (t *tracker) Wait() error {
	return t.tomb.Wait()
}

// ServiceName is part of the Tracker interface.
func (t *tracker) ServiceName() string {
	return t.serviceName
}

// ClaimDuration is part of the Tracker interface.
func (t *tracker) ClaimDuration() time.Duration {
	return t.duration
}

// ClaimLeader is part of the Tracker interface.
func (t *tracker) ClaimLeader() Ticket {
	return t.submit(t.claimTickets)
}

// WaitLeader is part of the Tracker interface.
func (t *tracker) WaitLeader() Ticket {
	return t.submit(t.waitLeaderTickets)
}

// WaitMinion is part of the Tracker interface.
func (t *tracker) WaitMinion() Ticket {
	return t.submit(t.waitMinionTickets)
}

func (t *tracker) loop() error {
	logger.Debugf("%s making initial claim for %s leadership", t.unitName, t.serviceName)
	if err := t.refresh(); err != nil {
		return errors.Trace(err)
	}
	for {
		select {
		case <-t.tomb.Dying():
			return tomb.ErrDying
		case <-t.claimLease:
			logger.Debugf("%s claiming lease for %s leadership", t.unitName, t.serviceName)
			t.claimLease = nil
			if err := t.refresh(); err != nil {
				return errors.Trace(err)
			}
		case <-t.renewLease:
			logger.Debugf("%s renewing lease for %s leadership", t.unitName, t.serviceName)
			t.renewLease = nil
			if err := t.refresh(); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.claimTickets:
			logger.Debugf("%s got claim request for %s leadership", t.unitName, t.serviceName)
			if err := t.resolveClaim(ticketCh); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.waitLeaderTickets:
			logger.Debugf("%s got wait request for %s leadership", t.unitName, t.serviceName)
			if err := t.resolveWaitLeader(ticketCh); err != nil {
				return errors.Trace(err)
			}
		case ticketCh := <-t.waitMinionTickets:
			logger.Debugf("%s got wait request for %s leadership loss", t.unitName, t.serviceName)
			if err := t.resolveWaitMinion(ticketCh); err != nil {
				return errors.Trace(err)
			}
		}
	}
}

// refresh makes a leadership request, and updates tracker state to conform to
// latest known reality.
func (t *tracker) refresh() error {
	logger.Debugf("checking %s for %s leadership", t.unitName, t.serviceName)
	leaseDuration := 2 * t.duration
	untilTime := time.Now().Add(leaseDuration)
	err := t.leadership.ClaimLeadership(t.serviceName, t.unitName, leaseDuration)
	switch {
	case err == nil:
		return t.setLeader(untilTime)
	case errors.Cause(err) == leadership.ErrClaimDenied:
		return t.setMinion()
	}
	return errors.Annotatef(err, "leadership failure")
}

// setLeader arranges for lease renewal.
func (t *tracker) setLeader(untilTime time.Time) error {
	logger.Debugf("%s confirmed for %s leadership until %s", t.unitName, t.serviceName, untilTime)
	renewTime := untilTime.Add(-t.duration)
	logger.Infof("%s will renew %s leadership at %s", t.unitName, t.serviceName, renewTime)
	t.isMinion = false
	t.claimLease = nil
	t.renewLease = time.After(renewTime.Sub(time.Now()))

	for len(t.waitingLeader) > 0 {
		logger.Debugf("notifying %s ticket of impending %s leadership", t.unitName, t.serviceName)
		var ticketCh chan bool
		ticketCh, t.waitingLeader = t.waitingLeader[0], t.waitingLeader[1:]
		defer close(ticketCh)
		if err := t.sendTrue(ticketCh); err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// setMinion arranges for lease acquisition when there's an opportunity.
func (t *tracker) setMinion() error {
	logger.Infof("%s leadership for %s denied", t.serviceName, t.unitName)
	t.isMinion = true
	t.renewLease = nil
	if t.claimLease == nil {
		t.claimLease = make(chan struct{})
		go func() {
			defer close(t.claimLease)
			logger.Debugf("%s waiting for %s leadership release", t.unitName, t.serviceName)
			err := t.leadership.BlockUntilLeadershipReleased(t.serviceName)
			if err != nil {
				logger.Warningf("error while %s waiting for %s leadership release: %v", t.unitName, t.serviceName, err)
			}
			// We don't need to do anything else with the error, because we just
			// close the claimLease channel and trigger a leadership claim on the
			// main loop; if anything's gone seriously wrong we'll find out right
			// away and shut down anyway. (And if this goroutine outlives the
			// tracker, it keeps it around as a zombie, but I don't see a way
			// around that...)
		}()
	}

	for len(t.waitingMinion) > 0 {
		logger.Debugf("notifying %s ticket of impending loss of %s leadership", t.unitName, t.serviceName)
		var ticketCh chan bool
		ticketCh, t.waitingMinion = t.waitingMinion[0], t.waitingMinion[1:]
		defer close(ticketCh)
		if err := t.sendTrue(ticketCh); err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// isLeader returns true if leadership is guaranteed for the tracker's duration.
func (t *tracker) isLeader() (bool, error) {
	if !t.isMinion {
		// Last time we looked, we were leader.
		select {
		case <-t.tomb.Dying():
			return false, errors.Trace(tomb.ErrDying)
		case <-t.renewLease:
			logger.Debugf("%s renewing lease for %s leadership", t.unitName, t.serviceName)
			t.renewLease = nil
			if err := t.refresh(); err != nil {
				return false, errors.Trace(err)
			}
		default:
			logger.Debugf("%s still has %s leadership", t.unitName, t.serviceName)
		}
	}
	return !t.isMinion, nil
}

// resolveClaim will send true on the supplied channel if leadership can be
// successfully verified, and will always close it whether or not it sent.
func (t *tracker) resolveClaim(ticketCh chan bool) error {
	logger.Debugf("resolving %s leadership ticket for %s...", t.serviceName, t.unitName)
	defer close(ticketCh)
	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if !leader {
		logger.Debugf("%s is not %s leader", t.unitName, t.serviceName)
		return nil
	}
	logger.Debugf("confirming %s leadership for %s", t.serviceName, t.unitName)
	return t.sendTrue(ticketCh)
}

// resolveWaitLeader will send true on the supplied channel if leadership can be
// guaranteed for the tracker's duration. It will then close the channel. If
// leadership cannot be guaranteed, the channel is left untouched until either
// the termination of the tracker or the next invocation of setLeader; at which
// point true is sent if applicable, and the channel is closed.
func (t *tracker) resolveWaitLeader(ticketCh chan bool) error {
	var dontClose bool
	defer func() {
		if !dontClose {
			close(ticketCh)
		}
	}()

	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if leader {
		logger.Debugf("reporting %s leadership for %s", t.serviceName, t.unitName)
		return t.sendTrue(ticketCh)
	}

	logger.Debugf("waiting for %s to attain %s leadership", t.unitName, t.serviceName)
	t.waitingLeader = append(t.waitingLeader, ticketCh)
	dontClose = true
	return nil
}

// resolveWaitMinion will close the supplied channel as soon as leadership cannot
// be guaranteed beyond the tracker's duration.
func (t *tracker) resolveWaitMinion(ticketCh chan bool) error {
	var dontClose bool
	defer func() {
		if !dontClose {
			close(ticketCh)
		}
	}()

	if leader, err := t.isLeader(); err != nil {
		return errors.Trace(err)
	} else if leader {
		logger.Debugf("waiting for %s to lose %s leadership", t.unitName, t.serviceName)
		t.waitingMinion = append(t.waitingMinion, ticketCh)
		dontClose = true
	} else {
		logger.Debugf("reporting %s leadership loss for %s", t.serviceName, t.unitName)
	}
	return nil

}

func (t *tracker) sendTrue(ticketCh chan bool) error {
	select {
	case <-t.tomb.Dying():
		return tomb.ErrDying
	case ticketCh <- true:
		return nil
	}
}

func (t *tracker) submit(tickets chan chan bool) Ticket {
	ticketCh := make(chan bool, 1)
	select {
	case <-t.tomb.Dying():
		close(ticketCh)
	case tickets <- ticketCh:
	}
	ticket := &ticket{
		ch:    ticketCh,
		ready: make(chan struct{}),
	}
	go ticket.run()
	return ticket
}

// ticket is used with tracker to communicate leadership status back to a client.
type ticket struct {
	ch      chan bool
	ready   chan struct{}
	success bool
}

func (t *ticket) run() {
	defer close(t.ready)
	// This is only safe/sane because the tracker promises to close all pending
	// ticket channels when it shuts down.
	if <-t.ch {
		t.success = true
	}
}

// Ready is part of the Ticket interface.
func (t *ticket) Ready() <-chan struct{} {
	return t.ready
}

// Wait is part of the Ticket interface.
func (t *ticket) Wait() bool {
	<-t.ready
	return t.success
}
<|endoftext|>


<commit_before>package middleware

import (
	"encoding/json"
	"github.com/codegangsta/martini"
	"net/http"
	"strings"
)

type OutputEncoder interface {
	Encode(v ...interface{}) ([]byte, error)
	MustEncode(v ...interface{}) []byte
}

type jsonEncoder struct{}

func (me jsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	return json.Marshal(data)
}

func (me jsonEncoder) MustEncode(v ...interface{}) []byte {
	if data, err := me.Encode(v...); err == nil {
		return data
	}

	return nil
}

type prettyJsonEncoder struct{}

func (me prettyJsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	return json.MarshalIndent(data, "", "  ")
}

func (me prettyJsonEncoder) MustEncode(v ...interface{}) []byte {
	if data, err := me.Encode(v...); err == nil {
		return data
	}

	return nil
}

func EncodeOutput(prettify bool) martini.Handler {
	return func(ctx martini.Context, res http.ResponseWriter, req *http.Request) {
		if strings.HasPrefix(req.RequestURI, "/ui") {
			return
		}

		if prettify {
			ctx.MapTo(prettyJsonEncoder{}, (*OutputEncoder)(nil))
		} else {
			ctx.MapTo(jsonEncoder{}, (*OutputEncoder)(nil))
		}

		res.Header().Set("Content-Type", "application/json")
	}
}
<commit_msg>add a notice for where the basic idea comes from<commit_after>// original code from https://github.com/PuerkitoBio/martini-api-example

package middleware

import (
	"encoding/json"
	"github.com/codegangsta/martini"
	"net/http"
	"strings"
)

type OutputEncoder interface {
	Encode(v ...interface{}) ([]byte, error)
	MustEncode(v ...interface{}) []byte
}

type jsonEncoder struct{}

func (me jsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	return json.Marshal(data)
}

func (me jsonEncoder) MustEncode(v ...interface{}) []byte {
	if data, err := me.Encode(v...); err == nil {
		return data
	}

	return nil
}

type prettyJsonEncoder struct{}

func (me prettyJsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	return json.MarshalIndent(data, "", "  ")
}

func (me prettyJsonEncoder) MustEncode(v ...interface{}) []byte {
	if data, err := me.Encode(v...); err == nil {
		return data
	}

	return nil
}

func EncodeOutput(prettify bool) martini.Handler {
	return func(ctx martini.Context, res http.ResponseWriter, req *http.Request) {
		if strings.HasPrefix(req.RequestURI, "/ui") {
			return
		}

		if prettify {
			ctx.MapTo(prettyJsonEncoder{}, (*OutputEncoder)(nil))
		} else {
			ctx.MapTo(jsonEncoder{}, (*OutputEncoder)(nil))
		}

		res.Header().Set("Content-Type", "application/json")
	}
}
<|endoftext|>


<commit_before>// Package metric provides functions for comparing datasets.
package metric

import (
	"math"
	"sort"

	"github.com/ready-steady/linear/metric"
	"github.com/ready-steady/statistics/distribution"
)

// MSE computes the mean-square error.
//
// https://en.wikipedia.org/wiki/Mean_squared_error
func MSE(y, yhat []float64) float64 {
	var sum, Δ float64

	for i := range y {
		Δ = yhat[i] - y[i]
		sum += Δ * Δ
	}

	return sum / float64(len(y))
}

// RMSE computes the root-mean-square error.
//
// https://en.wikipedia.org/wiki/Root-mean-square_deviation
func RMSE(y, yhat []float64) float64 {
	return math.Sqrt(MSE(y, yhat))
}

// NRMSE computes the normalized root-mean-square error.
//
// https://en.wikipedia.org/wiki/Root-mean-square_deviation#Normalized_root-mean-square_deviation
func NRMSE(y, yhat []float64) float64 {
	count := len(y)

	min, max := y[0], y[0]
	for i := 1; i < count; i++ {
		if y[i] < min {
			min = y[i]
		}
		if y[i] > max {
			max = y[i]
		}
	}

	return RMSE(y, yhat) / (max - min)
}

// KolmogorovSmirnov computes the Kolmogorov–Smirnov statistic for two samples.
//
// https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test
func KolmogorovSmirnov(data1, data2 []float64) float64 {
	edges := detect(data1, data2)

	cdf1 := distribution.CDF(data1, edges)
	cdf2 := distribution.CDF(data2, edges)

	return metric.Uniform(cdf1, cdf2)
}

// KullbackLeibler computes the Kullback–Leibler divergence of `q` from `p`
// where `p` and `q` are two discrete probability distributions. The
// distribution `p` is assumed to be absolutely continuous with respect the
// distribution `q`, that is, `q[i] = 0` implies that `p[i] = 0`.
//
// https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
func KullbackLeibler(p, q []float64) float64 {
	divergence := 0.0
	for i := range p {
		if p[i] > 0 {
			divergence += p[i] * math.Log(p[i]/q[i])
		}
	}
	return divergence
}

func detect(data1, data2 []float64) []float64 {
	n1, n2 := len(data1), len(data2)
	n := n1 + n2

	edges := make([]float64, n+2)
	edges[0] = math.Inf(-1)
	edges[1] = -edges[0]
	copy(edges[2:], data1)
	copy(edges[2+n1:], data2)

	edges = edges[:unique(edges)]
	sort.Float64s(edges)

	return edges
}

func unique(data []float64) int {
	n := len(data) - 1
	for i := 0; i < n; i++ {
		for j := i + 1; j <= n; j++ {
			if data[i] == data[j] {
				data[j] = data[n]
				n--
				j--
			}
		}
	}
	return n + 1
}
<commit_msg>metric: a cosmetic change<commit_after>// Package metric provides functions for comparing datasets.
package metric

import (
	"math"
	"sort"

	"github.com/ready-steady/linear/metric"
	"github.com/ready-steady/statistics/distribution"
)

// MSE computes the mean-square error.
//
// https://en.wikipedia.org/wiki/Mean_squared_error
func MSE(y, yhat []float64) float64 {
	var sum, Δ float64

	for i := range y {
		Δ = yhat[i] - y[i]
		sum += Δ * Δ
	}

	return sum / float64(len(y))
}

// RMSE computes the root-mean-square error.
//
// https://en.wikipedia.org/wiki/Root-mean-square_deviation
func RMSE(y, yhat []float64) float64 {
	return math.Sqrt(MSE(y, yhat))
}

// NRMSE computes the normalized root-mean-square error.
//
// https://en.wikipedia.org/wiki/Root-mean-square_deviation#Normalized_root-mean-square_deviation
func NRMSE(y, yhat []float64) float64 {
	count := len(y)

	min, max := y[0], y[0]
	for i := 1; i < count; i++ {
		if y[i] < min {
			min = y[i]
		}
		if y[i] > max {
			max = y[i]
		}
	}

	return RMSE(y, yhat) / (max - min)
}

// KolmogorovSmirnov computes the Kolmogorov–Smirnov statistic for two samples.
//
// https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test
func KolmogorovSmirnov(data1, data2 []float64) float64 {
	edges := detect(data1, data2)

	cdf1 := distribution.CDF(data1, edges)
	cdf2 := distribution.CDF(data2, edges)

	return metric.Uniform(cdf1, cdf2)
}

// KullbackLeibler computes the Kullback–Leibler divergence of q from p where p
// and q are two discrete probability distributions. The distribution p is
// assumed to be absolutely continuous with respect the distribution q, that is,
// q[i] = 0 implies that p[i] = 0.
//
// https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
func KullbackLeibler(p, q []float64) float64 {
	divergence := 0.0
	for i := range p {
		if p[i] > 0 {
			divergence += p[i] * math.Log(p[i]/q[i])
		}
	}
	return divergence
}

func detect(data1, data2 []float64) []float64 {
	n1, n2 := len(data1), len(data2)
	n := n1 + n2

	edges := make([]float64, n+2)
	edges[0] = math.Inf(-1)
	edges[1] = -edges[0]
	copy(edges[2:], data1)
	copy(edges[2+n1:], data2)

	edges = edges[:unique(edges)]
	sort.Float64s(edges)

	return edges
}

func unique(data []float64) int {
	n := len(data) - 1
	for i := 0; i < n; i++ {
		for j := i + 1; j <= n; j++ {
			if data[i] == data[j] {
				data[j] = data[n]
				n--
				j--
			}
		}
	}
	return n + 1
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 safehttp

import (
	"net/http"
)

// ResponseWriter TODO
type ResponseWriter struct {
	d  Dispatcher
	rw http.ResponseWriter

	// Having this field unexported is essential for
	// security. Otherwise one can easily overwrite
	// the struct bypassing all our safety guarantees.
	header Header
}

func newResponseWriter(d Dispatcher, rw http.ResponseWriter) ResponseWriter {
	header := newHeader(rw.Header())
	return ResponseWriter{d: d, rw: rw, header: header}
}

// Result TODO
type Result struct{}

// Write TODO
func (w *ResponseWriter) Write(resp Response) Result {
	if err := w.d.Write(w.rw, resp); err != nil {
		panic("error")
	}
	return Result{}
}

// WriteTemplate TODO
func (w *ResponseWriter) WriteTemplate(t Template, data interface{}) Result {
	if err := w.d.ExecuteTemplate(w.rw, t, data); err != nil {
		panic("error")
	}
	return Result{}
}

// ServerError TODO
func (w *ResponseWriter) ServerError(code StatusCode, resp Response) Result {
	return Result{}
}

// Redirect responds with a redirect, whose type is
// specified by the status code, to the given url.
func (w *ResponseWriter) Redirect(r *IncomingRequest, url string, code StatusCode) Result {
	http.Redirect(w.rw, r.req, url, int(code))
	return Result{}
}

// Header returns the collection of headers that will be set
// on the response. Headers must be set before writing a
// response (e.g. Write, WriteTemplate).
func (w ResponseWriter) Header() Header {
	return w.header
}

// Dispatcher TODO
type Dispatcher interface {
	Write(rw http.ResponseWriter, resp Response) error
	ExecuteTemplate(rw http.ResponseWriter, t Template, data interface{}) error
}
<commit_msg>Improved Redirect godoc<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 safehttp

import (
	"net/http"
)

// ResponseWriter TODO
type ResponseWriter struct {
	d  Dispatcher
	rw http.ResponseWriter

	// Having this field unexported is essential for
	// security. Otherwise one can easily overwrite
	// the struct bypassing all our safety guarantees.
	header Header
}

func newResponseWriter(d Dispatcher, rw http.ResponseWriter) ResponseWriter {
	header := newHeader(rw.Header())
	return ResponseWriter{d: d, rw: rw, header: header}
}

// Result TODO
type Result struct{}

// Write TODO
func (w *ResponseWriter) Write(resp Response) Result {
	if err := w.d.Write(w.rw, resp); err != nil {
		panic("error")
	}
	return Result{}
}

// WriteTemplate TODO
func (w *ResponseWriter) WriteTemplate(t Template, data interface{}) Result {
	if err := w.d.ExecuteTemplate(w.rw, t, data); err != nil {
		panic("error")
	}
	return Result{}
}

// ServerError TODO
func (w *ResponseWriter) ServerError(code StatusCode, resp Response) Result {
	return Result{}
}

// Redirect responds with a redirect to a given url, using code as the status code.
func (w *ResponseWriter) Redirect(r *IncomingRequest, url string, code StatusCode) Result {
	http.Redirect(w.rw, r.req, url, int(code))
	return Result{}
}

// Header returns the collection of headers that will be set
// on the response. Headers must be set before writing a
// response (e.g. Write, WriteTemplate).
func (w ResponseWriter) Header() Header {
	return w.header
}

// Dispatcher TODO
type Dispatcher interface {
	Write(rw http.ResponseWriter, resp Response) error
	ExecuteTemplate(rw http.ResponseWriter, t Template, data interface{}) error
}
<|endoftext|>


<commit_before>package querybuilder

import (
	"fmt"
	"runtime/debug"
	"strings"
	"time"
)

var Debug = false

type timeDuation struct {
	Label    string
	Duration time.Duration
}

var timeDurationList = []timeDuation{

	timeDuation{
		Label:    "minute",
		Duration: time.Minute,
	},
	timeDuation{
		Label:    "seconds",
		Duration: time.Second,
	},
	timeDuation{
		Label:    "milliseconds",
		Duration: time.Millisecond,
	},
	timeDuation{
		Label:    "microseconds",
		Duration: time.Microsecond,
	},
	timeDuation{
		Label:    "nanoseconds",
		Duration: time.Nanosecond,
	},
}
var Logger func(timestamp int64, cmd string, args []interface{})
var DefaultLogger = func(timestamp int64, cmd string, args []interface{}) {
	spent := time.Duration((time.Now().UnixNano() - timestamp)) * time.Nanosecond
	fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " SQL query debug:")
	fmt.Println("Query:")
	lines := strings.Split(cmd, "\n")
	for k := range lines {
		fmt.Println("\t" + lines[k])
	}
	fmt.Println("Args:")
	argsString := make([]string, len(args))
	for k := range args {
		argsString[k] = fmt.Sprint(args[k])
	}
	fmt.Println("\t[" + strings.Join(argsString, " , ") + "]")
	stacks := string(debug.Stack())
	stacklines := strings.Split(stacks, "\n")
	if len(stacklines) > 9 {
		fmt.Println("Stack:")
		fmt.Println("\t" + stacklines[7])
		fmt.Println("\t" + stacklines[8])
	}
	fmt.Println("Time spent:")
	for _, v := range timeDurationList {
		if spent > v.Duration {
			fmt.Printf("\t%d %s \n", spent/v.Duration, v.Label)
			break
		}
	}
	fmt.Println()
}

func init() {
	Logger = DefaultLogger
}
<commit_msg>update<commit_after>package querybuilder

import (
	"fmt"
	"runtime/debug"
	"strings"
	"time"
)

var Debug = false

type timeDuation struct {
	Label    string
	Duration time.Duration
}

var timeDurationList = []timeDuation{

	timeDuation{
		Label:    "minute",
		Duration: time.Minute,
	},
	timeDuation{
		Label:    "seconds",
		Duration: time.Second,
	},
	timeDuation{
		Label:    "milliseconds",
		Duration: time.Millisecond,
	},
	timeDuation{
		Label:    "microseconds",
		Duration: time.Microsecond,
	},
	timeDuation{
		Label:    "nanoseconds",
		Duration: time.Nanosecond,
	},
}
var Logger func(timestamp int64, cmd string, args []interface{})
var DefaultLogger = func(timestamp int64, cmd string, args []interface{}) {
	spent := time.Duration((time.Now().UnixNano() - timestamp)) * time.Nanosecond
	fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " SQL query debug:")
	fmt.Println("Query:")
	lines := strings.Split(cmd, "\n")
	for k := range lines {
		fmt.Println("\t" + lines[k])
	}
	fmt.Println("Args:")
	argsString := make([]string, len(args))
	for k := range args {
		argsString[k] = fmt.Sprint(args[k])
	}
	fmt.Println("\t[" + strings.Join(argsString, " , ") + "]")
	stacks := string(debug.Stack())
	stacklines := strings.Split(stacks, "\n")
	if len(stacklines) > 9 {
		fmt.Println("Stack:")
		fmt.Println("\t" + stacklines[7])
		fmt.Println("\t" + stacklines[8])
	}
	fmt.Println("Time spent:")
	for _, v := range timeDurationList {
		if spent > 10*v.Duration {
			fmt.Printf("\t%d %s \n", spent/v.Duration, v.Label)
			break
		}
	}
	fmt.Println()
}

func init() {
	Logger = DefaultLogger
}
<|endoftext|>


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

package scanner

import (
	"testing"

	"github.com/caixw/apidoc/core"
	"github.com/issue9/assert"
)

var _ core.ScanFunc = CStyle

var code1 = `
int x = 5;
/* line1
line2
line3*/
`
var comment1 = []byte(` line1
line2
line3`)

var code2 = `
int x = 5;
// line1
// line2
// line3
`

var comment2 = []byte(` line1
 line2
 line3
`)

var code3 = `
  int x=5
  // line1
  // line2
  // line3
`
var comment3 = []byte(` line1
 line2
 line3
`)

func TestCStyle(t *testing.T) {
	a := assert.New(t)

	fn := func(code string, comment []byte) {
		block, ln := CStyle([]byte(code))
		a.NotNil(block)
		a.Equal(block, comment).Equal(ln, 3)
	}

	fn(code1, comment1)
	fn(code2, comment2)
	fn(code3, comment3)
}
<commit_msg>修正scanner.TestCStyle测试错误<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package scanner

import (
	"testing"

	"github.com/caixw/apidoc/core"
	"github.com/issue9/assert"
)

var _ core.ScanFunc = CStyle

var code1 = `
int x = 5;
/* line1
line2
line3*/
`
var comment1 = []byte(` line1
line2
line3`)

var code2 = `
int x = 5;
// line1
// line2
// line3
`

var comment2 = []byte(` line1
 line2
 line3
`)

var code3 = `
  int x=5
  // line1
  // line2
  // line3
`
var comment3 = []byte(` line1
 line2
 line3
`)

func TestCStyle(t *testing.T) {
	a := assert.New(t)

	fn := func(code string, comment []byte) {
		block, pos := CStyle([]byte(code))
		a.Equal(block, comment).Equal(pos, len(comment))
	}

	fn(code1, comment1)
	fn(code2, comment2)
	fn(code3, comment3)
}
<|endoftext|>


<commit_before>// Package token implements the token type.
package token

import (
	"errors"
	"io"
)

const (
	Period             = iota // .
	Comma                     // ,
	Semicolon                 // ;
	Equals                    // =
	NotEquals                 // #
	LessThan                  // <
	GreaterThan               // >
	LessThanEqualTo           // <=
	GreaterThanEqualTo        // >=
	Plus                      // +
	Minus                     // -
	Times                     // *
	Divide                    // /
	LeftCurlyBrace            // {
	RightCurlyBrace           // }
	LeftParen                 // (
	RightParen                // )
	Exclamation               // !
	Assignment                // :=
	Integer                   // ex. 42
	Identifier                // ex. abc, abc123, ABC123
	Begin                     // BEGIN
	Call                      // CALL
	Const                     // CONST
	Do                        // DO
	End                       // END
	If                        // IF
	Odd                       // ODD
	Procedure                 // PROCEDURE
	Then                      // THEN
	Var                       // VAR
	While                     // WHILE
	Error                     // Special type for EOF and UnexpectedChar.
)

// EOF is a pointer to a Token with the Err field set to io.EOF. It is used to represent the end of
// a token stream.
var EOF = &Token{Tag: Error, Err: io.EOF}

// UnexpectedChar is a pointer to a Token with the Err field set to "Unexpected character". It is
// used to represent a input character that does not fit into any of the tags defined by the
// package.
var UnexpectedChar = &Token{Tag: Error, Err: errors.New("Unexpected character")}

// Token implements a lexical token. It contains all the information needed by the compiler to
// represent a lexical unit.
type Token struct {
	Tag int    // Tag. One of the constants defined in this package.
	Val int    // Value.
	Ln  int    // Line number.
	Lex string // Lexeme.
	Err error  // Error.
}

// New returns a new Token with the line number field set to the argument.
func New(ln int) *Token {
	return &Token{Ln: ln}
}
<commit_msg>More comments.<commit_after>// Package token implements the token type.
package token

import (
	"errors"
	"io"
)

const (
	Period             = iota // .
	Comma                     // ,
	Semicolon                 // ;
	Equals                    // =
	NotEquals                 // #
	LessThan                  // <
	GreaterThan               // >
	LessThanEqualTo           // <=
	GreaterThanEqualTo        // >=
	Plus                      // +
	Minus                     // -
	Times                     // *
	Divide                    // /
	LeftCurlyBrace            // {
	RightCurlyBrace           // }
	LeftParen                 // (
	RightParen                // )
	Exclamation               // !
	Assignment                // :=
	Integer                   // ex. 42
	Identifier                // ex. abc, abc123, ABC123
	Begin                     // BEGIN
	Call                      // CALL
	Const                     // CONST
	Do                        // DO
	End                       // END
	If                        // IF
	Odd                       // ODD
	Procedure                 // PROCEDURE
	Then                      // THEN
	Var                       // VAR
	While                     // WHILE
	Error                     // Special type for EOF and UnexpectedChar.
)

// TODO: Have initializers for errors? So we can set their line numbers.
// EOF is a pointer to a Token with the Err field set to io.EOF. It is used to represent the end of
// a token stream.
var EOF = &Token{Tag: Error, Err: io.EOF}

// UnexpectedChar is a pointer to a Token with the Err field set to "Unexpected character". It is
// used to represent a input character that does not fit into any of the tags defined by the
// package.
var UnexpectedChar = &Token{Tag: Error, Err: errors.New("Unexpected character")}

// Token implements a lexical token. It contains all the information needed by the compiler to
// represent a lexical unit.
type Token struct {
	Tag int    // Tag. One of the constants defined in this package.
	Val int    // Value.
	Ln  int    // Line number.
	Lex string // Lexeme.
	Err error  // Error.
}

// New returns a new Token with the specified line number set.
func New(ln int) *Token {
	return &Token{Ln: ln}
}
<|endoftext|>


<commit_before>// Copyright 2015 Christian Gärtner. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

package build

import (
	"errors"
	"fmt"
	"github.com/achtern/kluver/lexer"
	"strings"
)

func generateShader(tokenStream <-chan lexer.Token, requests chan LexRequest, done chan libRes, err chan error, supply, filePath string) {
	shader := Shader{}

	shader.global = make(Tokens, 0)
	shader.vertex = make(Tokens, 0)
	shader.fragment = make(Tokens, 0)

	nextNameDecIsUse := false
	useSupply := ""

	// phase 0 : global
	// phase 1 : vertex
	// phase 2 : fragment
	phase := 0
	for token := range tokenStream {
		if token.Typ == lexer.TokenError {
			err <- errors.New(token.Val)
			return
		}

		if token.Typ == lexer.TokenUse {
			nextNameDecIsUse = true
		}

		if token.Typ == lexer.TokenNameDec && nextNameDecIsUse {
			useSupply = token.Val
		}

		if token.Typ == lexer.TokenImportPath {
			supply := ""

			if useSupply != "" {
				supply = useSupply
			}

			requests <- LexRequest{token.Val, nil, supply}
			useSupply = ""
		}

		switch token.Typ {
		case lexer.TokenVertex:
			phase = 1
			continue
		case lexer.TokenFragment:
			phase = 2
			continue
		case lexer.TokenEnd:
			phase = 0
			continue
		case lexer.TokenVoid:
			continue
		}

		if token.Typ == lexer.TokenVersionNumber {
			shader.Version = token.Val
			continue
		}

		if token.Typ == lexer.TokenAction {
			// we do need the action tokens after lexing
			continue
		}

		switch phase {
		case 0:
			shader.global = append(shader.global, token)
		case 1:
			shader.vertex = append(shader.vertex, token)
		case 2:
			shader.fragment = append(shader.fragment, token)
		default:
			panic("unknow phase")
		}
	}

	done <- libRes{shader, supply, filePath}
}

// buildGeneric compiles the generic shader, lib code has been injected already
func buildGeneric(tokens Tokens, version string) (string, []Tokens, []Tokens) {
	var sb StringBuffer
	sb.Append(buildHead(version))

	providePlaceholderInserted := false
	provides := make([]Tokens, 0)
	requests := make([]Tokens, 0)

	for i := 0; i < len(tokens); i++ {
		token := tokens[i]
		switch token.Typ {
		case lexer.TokenRequire:
			if !providePlaceholderInserted {
				// insert provides before the first uniform
				sb.Append(providePlaceholder)
				providePlaceholderInserted = true
			}
			sb.Append(generateRequire(tokens[i+1], tokens[i+2]))
			i += 2
		case lexer.TokenProvide:
			provides = append(provides, Tokens{tokens[i+1], tokens[i+2]})
			sb.Append(generateProvideSetting(tokens[i+1], tokens[i+2], tokens[i+3], tokens[i+4]))
			i += 4
		case lexer.TokenRequest:
			requests = append(requests, Tokens{tokens[i+1], tokens[i+2]})
			sb.Append(generateRequest(tokens[i+1], tokens[i+2]))
			i += 2
		case lexer.TokenYield:
			if tokens[i+1].Typ == lexer.TokenActionVar {
				i += 1
			}
			// the value has been replaced by the lib injector
			sb.Append(token.Val)
			i += 1
		case lexer.TokenWrite:
			tmpToken := lexer.Token{lexer.TokenVoid, 0, "fragColor" + tokens[i+2].Val}
			provides = append(provides, Tokens{tmpToken, tokens[i+4]})
			sb.Append(generateWriteAssignment("fragColor", tokens[i+2], tokens[i+4]))
			i += 4
		default:
			sb.Append(token.Val)
		}
	}

	compiled := sb.String()

	compiled = strings.Replace(compiled, providePlaceholder, generateProvideDecBlock(provides), -1)

	return compiled, provides, requests
}

func buildHead(version string) string {
	return "#version " + version + "\n"
}

func generateRequire(typ, name lexer.Token) string {
	return fmt.Sprintf("uniform %s %s", typ.Val, name.Val)
}

func generateProvideSetting(typ, name, assign, glslAction lexer.Token) string {
	return fmt.Sprintf("%s %s %s %s", typ.Val, name.Val, assign.Val, glslAction.Val)
}

func generateProvideDecBlock(provides []Tokens) string {
	var sb StringBuffer
	for _, tokens := range provides {
		sb.Append(generateProvideDec(tokens[0], tokens[1]))
	}

	return sb.String()
}

func generateProvideDec(typ, name lexer.Token) string {
	return fmt.Sprintf("out %s %s;\n", typ.Val, strings.Trim(name.Val, " "))
}

func generateRequest(typ, name lexer.Token) string {
	return fmt.Sprintf("in %s %s", typ.Val, name.Val)
}

func generateWriteAssignment(target string, slot, name lexer.Token) string {
	return fmt.Sprintf("%s%s = %s", target, slot.Val, name.Val)
}
<commit_msg>kluver exits if it encounters unimplemented features now<commit_after>// Copyright 2015 Christian Gärtner. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.

package build

import (
	"errors"
	"fmt"
	"github.com/achtern/kluver/lexer"
	"strings"
	"os"
)

func generateShader(tokenStream <-chan lexer.Token, requests chan LexRequest, done chan libRes, err chan error, supply, filePath string) {
	shader := Shader{}

	shader.global = make(Tokens, 0)
	shader.vertex = make(Tokens, 0)
	shader.fragment = make(Tokens, 0)

	nextNameDecIsUse := false
	useSupply := ""

	// phase 0 : global
	// phase 1 : vertex
	// phase 2 : fragment
	phase := 0
	for token := range tokenStream {
		if token.Typ == lexer.TokenError {
			err <- errors.New(token.Val)
			return
		}

		if token.Typ == lexer.TokenExtends {
			fmt.Println("extending is not yet supported!")
			os.Exit(1)
		}

		if token.Typ == lexer.TokenUse {
			nextNameDecIsUse = true
		}

		if token.Typ == lexer.TokenNameDec && nextNameDecIsUse {
			useSupply = token.Val
		}

		if token.Typ == lexer.TokenImportPath {
			supply := ""

			if useSupply != "" {
				supply = useSupply
			}

			requests <- LexRequest{token.Val, nil, supply}
			useSupply = ""
		}

		switch token.Typ {
		case lexer.TokenVertex:
			phase = 1
			continue
		case lexer.TokenFragment:
			phase = 2
			continue
		case lexer.TokenEnd:
			phase = 0
			continue
		case lexer.TokenVoid:
			continue
		}

		if token.Typ == lexer.TokenVersionNumber {
			shader.Version = token.Val
			continue
		}

		if token.Typ == lexer.TokenAction {
			// we do need the action tokens after lexing
			continue
		}

		switch phase {
		case 0:
			shader.global = append(shader.global, token)
		case 1:
			shader.vertex = append(shader.vertex, token)
		case 2:
			shader.fragment = append(shader.fragment, token)
		default:
			panic("unknow phase")
		}
	}

	done <- libRes{shader, supply, filePath}
}

// buildGeneric compiles the generic shader, lib code has been injected already
func buildGeneric(tokens Tokens, version string) (string, []Tokens, []Tokens) {
	var sb StringBuffer
	sb.Append(buildHead(version))

	providePlaceholderInserted := false
	provides := make([]Tokens, 0)
	requests := make([]Tokens, 0)

	for i := 0; i < len(tokens); i++ {
		token := tokens[i]
		switch token.Typ {
		case lexer.TokenRequire:
			if !providePlaceholderInserted {
				// insert provides before the first uniform
				sb.Append(providePlaceholder)
				providePlaceholderInserted = true
			}
			sb.Append(generateRequire(tokens[i+1], tokens[i+2]))
			i += 2
		case lexer.TokenProvide:
			provides = append(provides, Tokens{tokens[i+1], tokens[i+2]})
			sb.Append(generateProvideSetting(tokens[i+1], tokens[i+2], tokens[i+3], tokens[i+4]))
			i += 4
		case lexer.TokenRequest:
			requests = append(requests, Tokens{tokens[i+1], tokens[i+2]})
			sb.Append(generateRequest(tokens[i+1], tokens[i+2]))
			i += 2
		case lexer.TokenYield:
			if tokens[i+1].Typ == lexer.TokenActionVar {
				i += 1
			}
			// the value has been replaced by the lib injector
			sb.Append(token.Val)
			i += 1
		case lexer.TokenWrite:
			tmpToken := lexer.Token{lexer.TokenVoid, 0, "fragColor" + tokens[i+2].Val}
			provides = append(provides, Tokens{tmpToken, tokens[i+4]})
			sb.Append(generateWriteAssignment("fragColor", tokens[i+2], tokens[i+4]))
			i += 4
		default:
			sb.Append(token.Val)
		}
	}

	compiled := sb.String()

	compiled = strings.Replace(compiled, providePlaceholder, generateProvideDecBlock(provides), -1)

	return compiled, provides, requests
}

func buildHead(version string) string {
	return "#version " + version + "\n"
}

func generateRequire(typ, name lexer.Token) string {
	return fmt.Sprintf("uniform %s %s", typ.Val, name.Val)
}

func generateProvideSetting(typ, name, assign, glslAction lexer.Token) string {
	return fmt.Sprintf("%s %s %s %s", typ.Val, name.Val, assign.Val, glslAction.Val)
}

func generateProvideDecBlock(provides []Tokens) string {
	var sb StringBuffer
	for _, tokens := range provides {
		sb.Append(generateProvideDec(tokens[0], tokens[1]))
	}

	return sb.String()
}

func generateProvideDec(typ, name lexer.Token) string {
	return fmt.Sprintf("out %s %s;\n", typ.Val, strings.Trim(name.Val, " "))
}

func generateRequest(typ, name lexer.Token) string {
	return fmt.Sprintf("in %s %s", typ.Val, name.Val)
}

func generateWriteAssignment(target string, slot, name lexer.Token) string {
	return fmt.Sprintf("%s%s = %s", target, slot.Val, name.Val)
}
<|endoftext|>


<commit_before>// Copyright 2016 PLUMgrid
//
// 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 main

package driver

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
        "encoding/json"
	"net/http"
	"net/http/cookiejar"

	Log "github.com/Sirupsen/logrus"
)

func pgBridgeCreate(ID string, domainid string) {
	cookieJar, _ := cookiejar.New(nil)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Jar:       cookieJar,
		Transport: tr,
	}

	url := "https://" + vip + "/0/login"
	Log.Infof("URL:> %s", url)

	var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	fmt.Println("response Cookies:", resp.Cookies())
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))

	//== PUT call

	url2 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	fmt.Println("URL:>", url2)

	var jsonStr1 = []byte(`{
				"action": {
					"action1": {
						"action_text": "create_and_link_ifc(DYN_1)"
					}
				},
				"ifc": {},
				"mobility": "true",
				"ne_description": "PLUMgrid Bridge",
				"ne_dname": "bridge-` + ID[:10] + `",
				"ne_group": "Bridge",
				"ne_type": "bridge"
	}`)

	req2, err := http.NewRequest("PUT", url2, bytes.NewBuffer(jsonStr1))
	req2.Header.Set("Accept", "application/json")
	req2.Header.Set("Content-Type", "application/json")

	resp2, err2 := client.Do(req2)
	if err2 != nil {
		fmt.Println(err2)
	}
	defer resp2.Body.Close()

	fmt.Println("response Status:", resp2.Status)
	//fmt.Println("response Headers:", resp2.Header)
	body2, _ := ioutil.ReadAll(resp2.Body)
	fmt.Println("response Body:", string(body2))

	//== PUT call

	url3 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	fmt.Println("URL:>", url3)

	var jsonStr3 = []byte(`{
					"mark_disabled": false,
					"ne_dest": "/ne/bri` + ID + `/action/action1",
					"ne_dname": "cnf-vmgroup-` + ID[10:] + `",
					"ne_type": "cnf-vmgroup",
					"rule": {
						"rules` + ID + `": {
							"add_context": "",
							"criteria": "pgtag2",
							"match": "bridge-` + ID[:10] + `"
						}
					}
	}`)

	req3, err := http.NewRequest("PUT", url3, bytes.NewBuffer(jsonStr3))
	req3.Header.Set("Accept", "application/json")
	req3.Header.Set("Content-Type", "application/json")

	resp3, err3 := client.Do(req3)
	if err3 != nil {
		fmt.Println(err3)
	}
	defer resp3.Body.Close()

	fmt.Println("response Status:", resp3.Status)
	//fmt.Println("response Headers:", resp3.Header)
	body3, _ := ioutil.ReadAll(resp3.Body)
	fmt.Println("response Body:", string(body3))

}

func pgBridgeDestroy(ID string, domainid string) {
	cookieJar, _ := cookiejar.New(nil)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Jar:       cookieJar,
		Transport: tr,
	}

	url := "https://" + vip + "/0/login"
	Log.Infof("URL:> %s", url)

	var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	fmt.Println("response Cookies:", resp.Cookies())
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))

	//== Delete call

	url2 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	fmt.Println("URL:>", url2)

	req2, err := http.NewRequest("DELETE", url2, nil)
	req2.Header.Set("Accept", "application/json")
	req2.Header.Set("Content-Type", "application/json")

	resp2, err2 := client.Do(req2)
	if err2 != nil {
		fmt.Println(err2)
	}
	defer resp2.Body.Close()

	fmt.Println("response Status:", resp2.Status)
	//fmt.Println("response Headers:", resp2.Header)
	body2, _ := ioutil.ReadAll(resp2.Body)
	fmt.Println("response Body:", string(body2))

	//== DELETE call

	url3 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	fmt.Println("URL:>", url3)

	req3, err := http.NewRequest("DELETE", url3, nil)
	req3.Header.Set("Accept", "application/json")
	req3.Header.Set("Content-Type", "application/json")

	resp3, err3 := client.Do(req3)
	if err3 != nil {
		fmt.Println(err3)
	}
	defer resp3.Body.Close()

	fmt.Println("response Status:", resp3.Status)
	//fmt.Println("response Headers:", resp3.Header)
	body3, _ := ioutil.ReadAll(resp3.Body)
	fmt.Println("response Body:", string(body3))

}

func FindDomainFromNetwork(ID string) (domainid string) {
        cookieJar, _ := cookiejar.New(nil)

        tr := &http.Transport{
                TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        }
        client := &http.Client{
                Jar:       cookieJar,
                Transport: tr,
        }

        url := "https://" + vip + "/0/login"
        Log.Infof("URL:> %s", url)

        var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
        req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
        req.Header.Set("Accept", "application/json")
        req.Header.Set("Content-Type", "application/json")

        resp, err := client.Do(req)
        if err != nil {
                fmt.Println(err)
        }
        defer resp.Body.Close()

        fmt.Println("response Status:", resp.Status)
        fmt.Println("response Headers:", resp.Header)
        fmt.Println("response Cookies:", resp.Cookies())
        body, _ := ioutil.ReadAll(resp.Body)
        fmt.Println("response Body:", string(body))

        url2 := "https://" + vip + "/0/connectivity/domain?configonly=true&level=3"
        fmt.Println("URL:>", url2)

        req2, err := http.NewRequest("GET", url2, nil)
        req2.Header.Set("Accept", "application/json")

        resp2, err2 := client.Do(req2)
        if err2 != nil {
                fmt.Println(err2)
        }
        defer resp2.Body.Close()
        //fmt.Println("response Status:", resp2.Status)
        //fmt.Println("response Headers:", resp2.Header)
        body2, _ := ioutil.ReadAll(resp2.Body)
        var domain_data map[string]interface{}
        err3 := json.Unmarshal([]byte(body2), &domain_data)
        if err3 != nil {
            panic(err3)
        }
        for domains, domain_val := range  domain_data {
            if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
                if brne, ok := nes.(map[string]interface{})["bri"+ID]; ok {
                    fmt.Println(brne)
                    domainid = domains
                    break
                }
             }
        }
        return
}
<commit_msg>Use blank identifier instead of network data<commit_after>// Copyright 2016 PLUMgrid
//
// 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 main

package driver

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
        "encoding/json"
	"net/http"
	"net/http/cookiejar"

	Log "github.com/Sirupsen/logrus"
)

func pgBridgeCreate(ID string, domainid string) {
	cookieJar, _ := cookiejar.New(nil)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Jar:       cookieJar,
		Transport: tr,
	}

	url := "https://" + vip + "/0/login"
	Log.Infof("URL:> %s", url)

	var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	fmt.Println("response Cookies:", resp.Cookies())
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))

	//== PUT call

	url2 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	fmt.Println("URL:>", url2)

	var jsonStr1 = []byte(`{
				"action": {
					"action1": {
						"action_text": "create_and_link_ifc(DYN_1)"
					}
				},
				"ifc": {},
				"mobility": "true",
				"ne_description": "PLUMgrid Bridge",
				"ne_dname": "bridge-` + ID[:10] + `",
				"ne_group": "Bridge",
				"ne_type": "bridge"
	}`)

	req2, err := http.NewRequest("PUT", url2, bytes.NewBuffer(jsonStr1))
	req2.Header.Set("Accept", "application/json")
	req2.Header.Set("Content-Type", "application/json")

	resp2, err2 := client.Do(req2)
	if err2 != nil {
		fmt.Println(err2)
	}
	defer resp2.Body.Close()

	fmt.Println("response Status:", resp2.Status)
	//fmt.Println("response Headers:", resp2.Header)
	body2, _ := ioutil.ReadAll(resp2.Body)
	fmt.Println("response Body:", string(body2))

	//== PUT call

	url3 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	fmt.Println("URL:>", url3)

	var jsonStr3 = []byte(`{
					"mark_disabled": false,
					"ne_dest": "/ne/bri` + ID + `/action/action1",
					"ne_dname": "cnf-vmgroup-` + ID[10:] + `",
					"ne_type": "cnf-vmgroup",
					"rule": {
						"rules` + ID + `": {
							"add_context": "",
							"criteria": "pgtag2",
							"match": "bridge-` + ID[:10] + `"
						}
					}
	}`)

	req3, err := http.NewRequest("PUT", url3, bytes.NewBuffer(jsonStr3))
	req3.Header.Set("Accept", "application/json")
	req3.Header.Set("Content-Type", "application/json")

	resp3, err3 := client.Do(req3)
	if err3 != nil {
		fmt.Println(err3)
	}
	defer resp3.Body.Close()

	fmt.Println("response Status:", resp3.Status)
	//fmt.Println("response Headers:", resp3.Header)
	body3, _ := ioutil.ReadAll(resp3.Body)
	fmt.Println("response Body:", string(body3))

}

func pgBridgeDestroy(ID string, domainid string) {
	cookieJar, _ := cookiejar.New(nil)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{
		Jar:       cookieJar,
		Transport: tr,
	}

	url := "https://" + vip + "/0/login"
	Log.Infof("URL:> %s", url)

	var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	fmt.Println("response Cookies:", resp.Cookies())
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))

	//== Delete call

	url2 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	fmt.Println("URL:>", url2)

	req2, err := http.NewRequest("DELETE", url2, nil)
	req2.Header.Set("Accept", "application/json")
	req2.Header.Set("Content-Type", "application/json")

	resp2, err2 := client.Do(req2)
	if err2 != nil {
		fmt.Println(err2)
	}
	defer resp2.Body.Close()

	fmt.Println("response Status:", resp2.Status)
	//fmt.Println("response Headers:", resp2.Header)
	body2, _ := ioutil.ReadAll(resp2.Body)
	fmt.Println("response Body:", string(body2))

	//== DELETE call

	url3 := "https://" + vip + "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	fmt.Println("URL:>", url3)

	req3, err := http.NewRequest("DELETE", url3, nil)
	req3.Header.Set("Accept", "application/json")
	req3.Header.Set("Content-Type", "application/json")

	resp3, err3 := client.Do(req3)
	if err3 != nil {
		fmt.Println(err3)
	}
	defer resp3.Body.Close()

	fmt.Println("response Status:", resp3.Status)
	//fmt.Println("response Headers:", resp3.Header)
	body3, _ := ioutil.ReadAll(resp3.Body)
	fmt.Println("response Body:", string(body3))

}

func FindDomainFromNetwork(ID string) (domainid string) {
        cookieJar, _ := cookiejar.New(nil)

        tr := &http.Transport{
                TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        }
        client := &http.Client{
                Jar:       cookieJar,
                Transport: tr,
        }

        url := "https://" + vip + "/0/login"
        Log.Infof("URL:> %s", url)

        var jsonStr = []byte(`{"userName":"` + username + `", "password":"` + password + `"}`)
        req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
        req.Header.Set("Accept", "application/json")
        req.Header.Set("Content-Type", "application/json")

        resp, err := client.Do(req)
        if err != nil {
                fmt.Println(err)
        }
        defer resp.Body.Close()

        fmt.Println("response Status:", resp.Status)
        fmt.Println("response Headers:", resp.Header)
        fmt.Println("response Cookies:", resp.Cookies())
        body, _ := ioutil.ReadAll(resp.Body)
        fmt.Println("response Body:", string(body))

        url2 := "https://" + vip + "/0/connectivity/domain?configonly=true&level=3"
        fmt.Println("URL:>", url2)

        req2, err := http.NewRequest("GET", url2, nil)
        req2.Header.Set("Accept", "application/json")

        resp2, err2 := client.Do(req2)
        if err2 != nil {
                fmt.Println(err2)
        }
        defer resp2.Body.Close()
        //fmt.Println("response Status:", resp2.Status)
        //fmt.Println("response Headers:", resp2.Header)
        body2, _ := ioutil.ReadAll(resp2.Body)
        var domain_data map[string]interface{}
        err3 := json.Unmarshal([]byte(body2), &domain_data)
        if err3 != nil {
            panic(err3)
        }
        for domains, domain_val := range  domain_data {
            if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
                if _, ok := nes.(map[string]interface{})["bri"+ID]; ok {
                    domainid = domains
                    break
                }
             }
        }
        return
}
<|endoftext|>


<commit_before>package boot

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

// BuildConfig holds configuration parameters for the automated circuit app build system
type BuildConfig struct {
	Repo             string  // Repo to fetch
	Pkg              string  // Package to build
	Host             string  // Build host
	Tool             string  // Build tool path
	Jail             string  // Build jail path
	RebuildGo        bool    // Rebuild Go even if no new version available
	ShipDir          string  // Local directory where built runtime and libraries will be delivered
	ZookeeperInclude string  // Path to Zookeeper include files on build host
	ZookeeperLib     string  // Path to Zookeeper library files on build host
}

var Build *BuildConfig

func parseBuildConfig() {
	bfile := os.Getenv("CIR_BUILD")
	Build = &BuildConfig{}
	data, err := ioutil.ReadFile(bfile)
	if err != nil {
		Build = nil
		fmt.Fprintf(os.Stderr, "Not using a build config file (%s)", err)
		return
	}
	if err = json.Unmarshal(data, Build); err != nil {
		fmt.Fprintf(os.Stderr, "Problem parsing build file (%s)", err)
		os.Exit(1)
	}
}
<commit_msg>add comments to build config<commit_after>package boot

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

// BuildConfig holds configuration parameters for the automated circuit app build system
type BuildConfig struct {
	Repo             string  // User repo to fetch
	GoPath           string  // User GOPATH relative to user repo; or empty string if user repo meant to be cloned at root of GOPATH
	Pkg              string  // User side-effect package to include in the circuit runtime build
	Host             string  // Host where build takes place
	Tool             string  // Build tool path on build host
	Jail             string  // Build jail path on build host
	RebuildGo        bool    // Rebuild Go even if a newer version is not available
	ShipDir          string  // Local directory where built runtime binary and dynamic libraries will be delivered
	ZookeeperInclude string  // Path to Zookeeper include files on build host
	ZookeeperLib     string  // Path to Zookeeper library files on build host
}

var Build *BuildConfig

func parseBuildConfig() {
	bfile := os.Getenv("CIR_BUILD")
	Build = &BuildConfig{}
	data, err := ioutil.ReadFile(bfile)
	if err != nil {
		Build = nil
		fmt.Fprintf(os.Stderr, "Not using a build config file (%s)", err)
		return
	}
	if err = json.Unmarshal(data, Build); err != nil {
		fmt.Fprintf(os.Stderr, "Problem parsing build file (%s)", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package websocket

import (
	"io"
	"net"
	"time"

	"github.com/gorilla/websocket"
	"v2ray.com/core/common/errors"
)

// connection is a wrapper for net.Conn over WebSocket connection.
type connection struct {
	wsc    *websocket.Conn
	reader io.Reader
}

// Read implements net.Conn.Read()
func (c *connection) Read(b []byte) (int, error) {
	for {
		reader, err := c.getReader()
		if err != nil {
			return 0, err
		}

		nBytes, err := reader.Read(b)
		if errors.Cause(err) == io.EOF {
			c.reader = nil
			continue
		}
		return nBytes, err
	}
}

func (c *connection) getReader() (io.Reader, error) {
	if c.reader != nil {
		return c.reader, nil
	}

	_, reader, err := c.wsc.NextReader()
	if err != nil {
		return nil, err
	}
	c.reader = reader
	return reader, nil
}

func (c *connection) Write(b []byte) (int, error) {
	if err := c.wsc.WriteMessage(websocket.BinaryMessage, b); err != nil {
		return 0, err
	}
	return len(b), nil
}

func (c *connection) Close() error {
	c.wsc.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5))
	return c.wsc.Close()
}

func (c *connection) LocalAddr() net.Addr {
	return c.wsc.LocalAddr()
}

func (c *connection) RemoteAddr() net.Addr {
	return c.wsc.RemoteAddr()
}

func (c *connection) SetDeadline(t time.Time) error {
	if err := c.SetReadDeadline(t); err != nil {
		return err
	}
	return c.SetWriteDeadline(t)
}

func (c *connection) SetReadDeadline(t time.Time) error {
	return c.wsc.SetReadDeadline(t)
}

func (c *connection) SetWriteDeadline(t time.Time) error {
	return c.wsc.SetWriteDeadline(t)
}
<commit_msg>implement write multi buffer in websocket<commit_after>package websocket

import (
	"io"
	"net"
	"time"

	"github.com/gorilla/websocket"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/errors"
)

// connection is a wrapper for net.Conn over WebSocket connection.
type connection struct {
	wsc         *websocket.Conn
	reader      io.Reader
	writeBuffer []byte
}

// Read implements net.Conn.Read()
func (c *connection) Read(b []byte) (int, error) {
	for {
		reader, err := c.getReader()
		if err != nil {
			return 0, err
		}

		nBytes, err := reader.Read(b)
		if errors.Cause(err) == io.EOF {
			c.reader = nil
			continue
		}
		return nBytes, err
	}
}

func (c *connection) getReader() (io.Reader, error) {
	if c.reader != nil {
		return c.reader, nil
	}

	_, reader, err := c.wsc.NextReader()
	if err != nil {
		return nil, err
	}
	c.reader = reader
	return reader, nil
}

func (c *connection) Write(b []byte) (int, error) {
	if err := c.wsc.WriteMessage(websocket.BinaryMessage, b); err != nil {
		return 0, err
	}
	return len(b), nil
}

func (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) (int, error) {
	defer mb.Release()

	if c.writeBuffer == nil {
		c.writeBuffer = make([]byte, 4096)
	}
	totalBytes := 0
	for !mb.IsEmpty() {
		nBytes, err := mb.Read(c.writeBuffer)
		if err != nil {
			return totalBytes, err
		}
		totalBytes += nBytes
		if _, err := c.Write(c.writeBuffer[:nBytes]); err != nil {
			return totalBytes, err
		}
	}
	return totalBytes, nil
}

func (c *connection) Close() error {
	c.wsc.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5))
	return c.wsc.Close()
}

func (c *connection) LocalAddr() net.Addr {
	return c.wsc.LocalAddr()
}

func (c *connection) RemoteAddr() net.Addr {
	return c.wsc.RemoteAddr()
}

func (c *connection) SetDeadline(t time.Time) error {
	if err := c.SetReadDeadline(t); err != nil {
		return err
	}
	return c.SetWriteDeadline(t)
}

func (c *connection) SetReadDeadline(t time.Time) error {
	return c.wsc.SetReadDeadline(t)
}

func (c *connection) SetWriteDeadline(t time.Time) error {
	return c.wsc.SetWriteDeadline(t)
}
<|endoftext|>


<commit_before>/*
 * ZDNS Copyright 2019 Regents of the University of Michigan
 *
 * 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 alookup

import (
	"reflect"
	"testing"

	"github.com/zmap/zdns"
	"github.com/zmap/zdns/modules/miekg"
)

// Mock the actual Miekg lookup.
func (s *Lookup) DoTypedMiekgLookup(name string, dnsType uint16, nameServer string) (interface{}, []interface{}, zdns.Status, error) {
	if res, ok := mockResults[name]; ok {
		return res, nil, zdns.STATUS_NOERROR, nil
	} else {
		return nil, nil, zdns.STATUS_NO_ANSWER, nil
	}
}

var mockResults = make(map[string]miekg.Result)

func TestDoLookup(t *testing.T) {
	gc := new(zdns.GlobalConf)
	gc.NameServers = []string{"127.0.0.1"}

	glf := new(GlobalLookupFactory)
	glf.GlobalConf = gc
	glf.IPv4Lookup = true
	glf.IPv6Lookup = false

	rlf := new(RoutineLookupFactory)
	rlf.Factory = glf

	l, err := rlf.MakeLookup()
	if l == nil || err != nil {
		t.Error("Failed to initialize lookup")
	}

	// Case 1: single A response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ := l.DoLookup("example.com", "")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, nil)

	// Case 2: double A response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "A",
				Class:  "IN",
				Name:   "example.com",
				Answer: "192.0.2.2",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com", "")
	verifyResult(t, res.(Result), []string{"192.0.2.1", "192.0.2.2"}, nil)

	// Case 3: mixed A and AAAA response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::1",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com", "")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, nil)

	// Case 4: same mixed response, but both types requested.
	glf.IPv6Lookup = true

	res, _, _, _ = l.DoLookup("example.com", "")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, []string{"2001:db8::1"})

	// Case 5: double AAAA response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "AAAA",
			Class:  "IN",
			Name:   "example.com",
			Answer: "2001:db8::1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::2",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::1", "2001:db8::2"})

	// Case 6: CNAME
	mockResults["cname.example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "CNAME",
			Class:  "IN",
			Name:   "cname.example.com",
			Answer: "example.com.",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("cname.example.com", "")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::1", "2001:db8::2"})

	// Case 7: AAAA + CNAME (if this ever happens to be returned)
	mockResults["cname.example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "AAAA",
			Class:  "IN",
			Name:   "cname.example.com",
			Answer: "2001:db8::3",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "CNAME",
				Class:  "IN",
				Name:   "cname.example.com",
				Answer: "example.com.",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("cname.example.com", "")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::3"})

	// Case 8: unexpected MX record only
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "MX",
			Class:  "IN",
			Name:   "example.com",
			Answer: "mail.example.com.",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, status, _ := l.DoLookup("example.com", "")
	if status != zdns.STATUS_NO_ANSWER {
		t.Errorf("Expected NO_ANSWER status, got %v", status)
	} else if res != nil {
		t.Error("Received results where expected none")
	}

	// Case 3: unexpected MX record in answer section, but valid A record in additionals
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "MX",
			Class:  "IN",
			Name:   "example.com",
			Answer: "mail.example.com.",
		}},
		Additional: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.3",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::4",
			}},
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com", "")
	verifyResult(t, res.(Result), []string{"192.0.2.3"}, []string{"2001:db8::4"})
}

func verifyResult(t *testing.T, res Result, ipv4 []string, ipv6 []string) {
	if ipv4 == nil && res.IPv4Addresses != nil && len(res.IPv4Addresses) > 0 {
		t.Error("Received IPv4 addresses while none expected")
	} else if ipv4 != nil {
		if res.IPv4Addresses == nil || len(res.IPv4Addresses) == 0 {
			t.Error("Received no IPv4 addresses while expected")
		} else if len(res.IPv4Addresses) != len(ipv4) {
			t.Errorf("Received %v IPv4 addresses while %v is expected", len(res.IPv4Addresses), len(ipv4))
		} else if !reflect.DeepEqual(res.IPv4Addresses, ipv4) {
			t.Error("Received unexpected IPv4 address(es)")
		}
	}

	if ipv6 == nil && res.IPv6Addresses != nil && len(res.IPv4Addresses) > 0 {
		t.Error("Received no IPv6 addresses while expected")
	} else if ipv6 != nil {
		if res.IPv6Addresses == nil || len(res.IPv6Addresses) == 0 {
			t.Error("Received no IPv6 addresses while expected")
		} else if len(res.IPv4Addresses) != len(ipv4) {
			t.Errorf("Received %v IPv6 addresses while %v is expected", len(res.IPv6Addresses), len(ipv6))
		} else if !reflect.DeepEqual(res.IPv6Addresses, ipv6) {
			t.Error("Received unexpected IPv6 address(es)")
		}
	}
}
<commit_msg>Revert "trying to fix up tests"<commit_after>/*
 * ZDNS Copyright 2019 Regents of the University of Michigan
 *
 * 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 alookup

import (
	"github.com/zmap/zdns"
	"github.com/zmap/zdns/modules/miekg"
	"reflect"
	"testing"
)

// Mock the actual Miekg lookup.
func (s *Lookup) DoTypedMiekgLookup(name string, dnsType uint16) (interface{}, []interface{}, zdns.Status, error) {
	if res, ok := mockResults[name]; ok {
		return res, nil, zdns.STATUS_NOERROR, nil
	} else {
		return nil, nil, zdns.STATUS_NO_ANSWER, nil
	}
}

var mockResults = make(map[string]miekg.Result)

func TestDoLookup(t *testing.T) {
	gc := new(zdns.GlobalConf)
	gc.NameServers = []string{"127.0.0.1"}

	glf := new(GlobalLookupFactory)
	glf.GlobalConf = gc
	glf.IPv4Lookup = true
	glf.IPv6Lookup = false

	rlf := new(RoutineLookupFactory)
	rlf.Factory = glf

	l, err := rlf.MakeLookup()
	if l == nil || err != nil {
		t.Error("Failed to initialize lookup")
	}

	// Case 1: single A response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ := l.DoLookup("example.com")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, nil)

	// Case 2: double A response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "A",
				Class:  "IN",
				Name:   "example.com",
				Answer: "192.0.2.2",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), []string{"192.0.2.1", "192.0.2.2"}, nil)

	// Case 3: mixed A and AAAA response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::1",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, nil)

	// Case 4: same mixed response, but both types requested.
	glf.IPv6Lookup = true

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), []string{"192.0.2.1"}, []string{"2001:db8::1"})

	// Case 5: double AAAA response
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "AAAA",
			Class:  "IN",
			Name:   "example.com",
			Answer: "2001:db8::1",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::2",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::1", "2001:db8::2"})

	// Case 6: CNAME
	mockResults["cname.example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "CNAME",
			Class:  "IN",
			Name:   "cname.example.com",
			Answer: "example.com.",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("cname.example.com")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::1", "2001:db8::2"})

	// Case 7: AAAA + CNAME (if this ever happens to be returned)
	mockResults["cname.example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "AAAA",
			Class:  "IN",
			Name:   "cname.example.com",
			Answer: "2001:db8::3",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "CNAME",
				Class:  "IN",
				Name:   "cname.example.com",
				Answer: "example.com.",
			}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("cname.example.com")
	verifyResult(t, res.(Result), nil, []string{"2001:db8::3"})

	// Case 8: unexpected MX record only
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "MX",
			Class:  "IN",
			Name:   "example.com",
			Answer: "mail.example.com.",
		}},
		Additional:  nil,
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, status, _ := l.DoLookup("example.com")
	if status != zdns.STATUS_NO_ANSWER {
		t.Errorf("Expected NO_ANSWER status, got %v", status)
	} else if res != nil {
		t.Error("Received results where expected none")
	}

	// Case 3: unexpected MX record in answer section, but valid A record in additionals
	mockResults["example.com"] = miekg.Result{
		Answers: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "MX",
			Class:  "IN",
			Name:   "example.com",
			Answer: "mail.example.com.",
		}},
		Additional: []interface{}{miekg.Answer{
			Ttl:    3600,
			Type:   "A",
			Class:  "IN",
			Name:   "example.com",
			Answer: "192.0.2.3",
		},
			miekg.Answer{
				Ttl:    3600,
				Type:   "AAAA",
				Class:  "IN",
				Name:   "example.com",
				Answer: "2001:db8::4",
			}},
		Authorities: nil,
		Protocol:    "",
		Flags:       miekg.DNSFlags{},
	}

	res, _, _, _ = l.DoLookup("example.com")
	verifyResult(t, res.(Result), []string{"192.0.2.3"}, []string{"2001:db8::4"})
}

func verifyResult(t *testing.T, res Result, ipv4 []string, ipv6 []string) {
	if ipv4 == nil && res.IPv4Addresses != nil && len(res.IPv4Addresses) > 0 {
		t.Error("Received IPv4 addresses while none expected")
	} else if ipv4 != nil {
		if res.IPv4Addresses == nil || len(res.IPv4Addresses) == 0 {
			t.Error("Received no IPv4 addresses while expected")
		} else if len(res.IPv4Addresses) != len(ipv4) {
			t.Errorf("Received %v IPv4 addresses while %v is expected", len(res.IPv4Addresses), len(ipv4))
		} else if !reflect.DeepEqual(res.IPv4Addresses, ipv4) {
			t.Error("Received unexpected IPv4 address(es)")
		}
	}

	if ipv6 == nil && res.IPv6Addresses != nil && len(res.IPv4Addresses) > 0 {
		t.Error("Received no IPv6 addresses while expected")
	} else if ipv6 != nil {
		if res.IPv6Addresses == nil || len(res.IPv6Addresses) == 0 {
			t.Error("Received no IPv6 addresses while expected")
		} else if len(res.IPv4Addresses) != len(ipv4) {
			t.Errorf("Received %v IPv6 addresses while %v is expected", len(res.IPv6Addresses), len(ipv6))
		} else if !reflect.DeepEqual(res.IPv6Addresses, ipv6) {
			t.Error("Received unexpected IPv6 address(es)")
		}
	}
}
<|endoftext|>


<commit_before>/*
 Route Adapters for SpaceDock Backend

 SpaceDock-Extras is licensed under the Terms of the MIT License.
 Copyright (c) 2017 Dorian Stoll (StollD), RockyTV
*/

package adapter

import (
    "SpaceDock"
    "SpaceDock/routes"
    "SpaceDock/utils"
    "github.com/spf13/cast"
    "gopkg.in/kataras/iris.v6"
)

func init() {
    Register(GET, "/api/adapter/mods/:modid", mods_adapter)
}

/*
 Path: /api/adapter/mods/:modid
 Method: GET
 Description: Returns information for one mod
 */
func mods_adapter(ctx *iris.Context) {
    // Get params
    modid := cast.ToUint(ctx.GetString("modid"))

    // Get the mods gameshort
    mod := &objects.Mod{}
    SpaceDock.Database.Where("id = ?", modid).First(mod)
    if mod.ID != modid {
        utils.WriteJSON(ctx, iris.StatusNotFound, utils.Error("The modid is invalid").Code(2130))
        return
    }
    ctx.Redirect("/api/mods/" + mod.Game.Short + "/" + cast.ToString(modid), iris.StatusPermanentRedirect)
}
<commit_msg>Bugfixing<commit_after>/*
 Route Adapters for SpaceDock Backend

 SpaceDock-Extras is licensed under the Terms of the MIT License.
 Copyright (c) 2017 Dorian Stoll (StollD), RockyTV
*/

package adapter

import (
    "SpaceDock"
    "SpaceDock/routes"
    "SpaceDock/utils"
    "SpaceDock/objects"
    "github.com/spf13/cast"
    "gopkg.in/kataras/iris.v6"
)

func init() {
    routes.Register(routes.GET, "/api/adapter/mods/:modid", mods_adapter)
}

/*
 Path: /api/adapter/mods/:modid
 Method: GET
 Description: Returns information for one mod
 */
func mods_adapter(ctx *iris.Context) {
    // Get params
    modid := cast.ToUint(ctx.GetString("modid"))

    // Get the mods gameshort
    mod := &objects.Mod{}
    SpaceDock.Database.Where("id = ?", modid).First(mod)
    if mod.ID != modid {
        utils.WriteJSON(ctx, iris.StatusNotFound, utils.Error("The modid is invalid").Code(2130))
        return
    }
    ctx.Redirect("/api/mods/" + mod.Game.Short + "/" + cast.ToString(modid), iris.StatusPermanentRedirect)
}<|endoftext|>