<commit_before>package main

import (
	"fmt"
	"github.com/byrnedo/capitan/container"
	"github.com/byrnedo/capitan/helpers"
	. "github.com/byrnedo/capitan/logger"
	"github.com/codeskyblue/go-sh"
	"os"
	"os/signal"
	"sort"
	"sync"
	"syscall"
)

var (
	allDone = make(chan bool, 1)
)

type ProjectConfig struct {
	ProjectName           string
	ProjectSeparator      string
	ContainerSettingsList SettingsList
}

type SettingsList []container.Container

func (s SettingsList) Len() int {
	return len(s)
}
func (s SettingsList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s SettingsList) Less(i, j int) bool {
	return s[i].Placement < s[j].Placement
}

func (settings *ProjectConfig) LaunchCleanupWatcher() {

	var (
		killBegan     = make(chan bool, 1)
		killDone      = make(chan bool, 1)
		stopDone      = make(chan bool, 1)
		signalChannel = make(chan os.Signal)
	)
	signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)

	go func() {

		var (
			killing bool
		)

		for {
			select {
			case <-killBegan:
				killing = true
			case <-stopDone:
				if !killing {
					allDone <- true
				}
			case <-killDone:
				allDone <- true
			}
		}
	}()

	go func() {
		var calls int
		for {
			sig := <-signalChannel
			switch sig {
			case os.Interrupt, syscall.SIGTERM:
				calls++
				if calls == 1 {
					go func() {
						settings.CapitanStop(nil, false)
						stopDone <- true
					}()
				} else if calls == 2 {
					killBegan <- true
					settings.CapitanKill(nil, false)
					killDone <- true
				}
			default:
				Debug.Println("Unhandled signal", sig)
			}
		}
		Info.Println("Done cleaning up")
	}()
}

func newerImage(container string, image string) bool {

	conImage := helpers.GetContainerImageId(container)
	localImage := helpers.GetImageId(image)
	if conImage != "" && localImage != "" && conImage != localImage {
		return true
	}
	return false
}

func haveArgsChanged(container string, runArgs []interface{}) bool {

	uniqueLabel := fmt.Sprintf("%s", runArgs)
	if helpers.GetContainerUniqueLabel(container) != uniqueLabel {
		return true
	}
	return false
	// remove and restart

}

func (settings *ProjectConfig) CapitanCreate(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)

	for _, set := range settings.ContainerSettingsList {
		if err := set.Create(dryRun); err != nil {
			return err
		}
	}
	return nil

}

// The 'up' command
//
// Creates a container if it doesn't exist
// Starts a container if stopped
// Recreates a container if the container's image has a newer id locally
// OR if the command used to create the container is now changed (i.e.
// config has changed.
func (settings *ProjectConfig) CapitanUp(attach bool, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)

	wg := sync.WaitGroup{}

	for _, set := range settings.ContainerSettingsList {
		var (
			err error
		)

		//create new
		if !helpers.ContainerExists(set.Name) {
			if helpers.GetImageId(set.Image) == "" {
				Warning.Printf("Capitan was unable to find image %s locally\n", set.Image)

				if set.Build != "" {
					Info.Println("Building image")
					if err := set.BuildImage(); err != nil {
						return err
					}
				} else {
					Info.Println("Pulling image")
					if err := helpers.PullImage(set.Image); err != nil {
						return err
					}
				}
			}
			if err = set.Run(attach, dryRun, &wg); err != nil {
				return err
			}
			continue
		}

		// check image change or args change
		if helpers.GetImageId(set.Image) == "" {
			Warning.Printf("Capitan was unable to find image %s locally\n", set.Image)

			if set.Build != "" {
				Info.Println("Building image")
				if err := set.BuildImage(); err != nil {
					return err
				}
			} else {
				Info.Println("Pulling image")
				if err := helpers.PullImage(set.Image); err != nil {
					return err
				}
			}
		}

		if newerImage(set.Name, set.Image) {
			// remove and restart
			Info.Println("Removing (different image available):", set.Name)
			if err = set.RecreateAndRun(attach, dryRun, &wg); err != nil {
				return err
			}

			continue
		}

		if haveArgsChanged(set.Name, set.GetRunArguments()) {
			// remove and restart
			Info.Println("Removing (run arguments changed):", set.Name)
			if err = set.RecreateAndRun(attach, dryRun, &wg); err != nil {
				return err
			}
			continue
		}

		//attach if running
		if helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already running " + set.Name)
			if attach {
				Info.Println("Attaching")
				if err := set.Attach(&wg); err != nil {
					return err
				}
			}
			continue
		}

		Info.Println("Starting " + set.Name)

		if dryRun {
			continue
		}

		//start if stopped
		if err = set.Start(attach, &wg); err != nil {
			return err
		}
		continue

	}
	wg.Wait()
	if !dryRun && attach {
		<-allDone
	}
	return nil
}

// Starts stopped containers
func (settings *ProjectConfig) CapitanStart(attach bool, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	wg := sync.WaitGroup{}
	for _, set := range settings.ContainerSettingsList {
		if helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already running " + set.Name)
			if attach {
				Info.Println("Attaching")
				if err := set.Attach(&wg); err != nil {
					return err
				}
			}
			continue
		}
		Info.Println("Starting " + set.Name)
		if !dryRun {
			if err := set.Start(attach, &wg); err != nil {
				return err
			}
		}
	}
	wg.Wait()
	if !dryRun && attach {
		<-allDone
	}
	return nil
}

// Command to restart all containers
func (settings *ProjectConfig) CapitanRestart(args []string, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		Info.Println("Restarting " + set.Name)
		if !dryRun {
			if err := set.Restart(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Print all container IPs
func (settings *ProjectConfig) CapitanIP() error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		ip := set.IP()
		Info.Printf("%s: %s", set.Name, ip)
	}
	return nil
}

// Stream all container logs
func (settings *ProjectConfig) CapitanLogs() error {
	sort.Sort(settings.ContainerSettingsList)
	var wg sync.WaitGroup
	for _, set := range settings.ContainerSettingsList {
		var (
			ses *sh.Session
			err error
		)
		if ses, err = set.Logs(); err != nil {
			Error.Println("Error getting log for " + set.Name + ": " + err.Error())
			continue
		}

		wg.Add(1)

		go func() {
			ses.Wait()
			wg.Done()
		}()

	}
	wg.Wait()
	return nil
}

// Stream all container stats
func (settings *ProjectConfig) CapitanStats() error {
	var (
		args []interface{}
	)
	sort.Sort(settings.ContainerSettingsList)

	args = make([]interface{}, len(settings.ContainerSettingsList))

	for i, set := range settings.ContainerSettingsList {
		args[i] = set.Name
	}

	ses := sh.NewSession()
	ses.Command("docker", append([]interface{}{"stats"}, args...)...)
	ses.Start()
	ses.Wait()
	return nil
}

// Print `docker ps` ouptut for all containers in project
func (settings *ProjectConfig) CapitanPs(args []string) error {
	sort.Sort(settings.ContainerSettingsList)
	allArgs := append([]interface{}{"ps"}, helpers.ToInterfaceSlice(args)...)
	for _, set := range settings.ContainerSettingsList {
		allArgs = append(allArgs, "-f", "name="+set.Name)
	}
	var (
		err error
		out []byte
	)
	if out, err = helpers.RunCmd(allArgs...); err != nil {
		return err
	}
	Info.Print(string(out))
	return nil
}

// Kill all running containers in project
func (settings *ProjectConfig) CapitanKill(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {
		if !helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already dead:", set.Name)
			continue
		}
		Info.Println("Killing " + set.Name)
		if !dryRun {
			if err := set.Kill(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Stops the containers in the project
func (settings *ProjectConfig) CapitanStop(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {
		if !helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already dead:", set.Name)
			continue
		}
		Info.Println("Stopping " + set.Name)
		if !dryRun {
			if err := set.Stop(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Remove all containers in project
func (settings *ProjectConfig) CapitanRm(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {

		if !dryRun && helpers.ContainerExists(set.Name) {
			Info.Println("Removing " + set.Name)
			if err := set.Rm(args); err != nil {
				return err
			}
		} else {
			Info.Println("Container doesn't exist:", set.Name)
		}
	}
	return nil
}

// The build command
func (settings *ProjectConfig) CapitanBuild(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		if len(set.Build) == 0 {
			continue
		}
		Info.Println("Building " + set.Name)
		if !dryRun {
			if err := set.BuildImage(); err != nil {
				return err
			}
		}

	}
	return nil
}

// The build command
func (settings *ProjectConfig) CapitanPull(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		if len(set.Build) > 0 || set.Image == "" {
			continue
		}
		Info.Println("Pulling", set.Image, "for", set.Name)
		if !dryRun {
			if err := helpers.PullImage(set.Image); err != nil {
				return err
			}
		}

	}
	return nil
}
<commit_msg>Create command pulls or builds beforehand<commit_after>package main

import (
	"fmt"
	"github.com/byrnedo/capitan/container"
	"github.com/byrnedo/capitan/helpers"
	. "github.com/byrnedo/capitan/logger"
	"github.com/codeskyblue/go-sh"
	"os"
	"os/signal"
	"sort"
	"sync"
	"syscall"
)

var (
	allDone = make(chan bool, 1)
)

type ProjectConfig struct {
	ProjectName           string
	ProjectSeparator      string
	ContainerSettingsList SettingsList
}

type SettingsList []container.Container

func (s SettingsList) Len() int {
	return len(s)
}
func (s SettingsList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s SettingsList) Less(i, j int) bool {
	return s[i].Placement < s[j].Placement
}

func (settings *ProjectConfig) LaunchCleanupWatcher() {

	var (
		killBegan     = make(chan bool, 1)
		killDone      = make(chan bool, 1)
		stopDone      = make(chan bool, 1)
		signalChannel = make(chan os.Signal)
	)
	signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)

	go func() {

		var (
			killing bool
		)

		for {
			select {
			case <-killBegan:
				killing = true
			case <-stopDone:
				if !killing {
					allDone <- true
				}
			case <-killDone:
				allDone <- true
			}
		}
	}()

	go func() {
		var calls int
		for {
			sig := <-signalChannel
			switch sig {
			case os.Interrupt, syscall.SIGTERM:
				calls++
				if calls == 1 {
					go func() {
						settings.CapitanStop(nil, false)
						stopDone <- true
					}()
				} else if calls == 2 {
					killBegan <- true
					settings.CapitanKill(nil, false)
					killDone <- true
				}
			default:
				Debug.Println("Unhandled signal", sig)
			}
		}
		Info.Println("Done cleaning up")
	}()
}

func newerImage(container string, image string) bool {

	conImage := helpers.GetContainerImageId(container)
	localImage := helpers.GetImageId(image)
	if conImage != "" && localImage != "" && conImage != localImage {
		return true
	}
	return false
}

func haveArgsChanged(container string, runArgs []interface{}) bool {

	uniqueLabel := fmt.Sprintf("%s", runArgs)
	if helpers.GetContainerUniqueLabel(container) != uniqueLabel {
		return true
	}
	return false
	// remove and restart

}

func (settings *ProjectConfig) CapitanCreate(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)

	for _, set := range settings.ContainerSettingsList {

		if helpers.GetImageId(set.Image) == "" {
			Warning.Printf("Capitan was unable to find image %s locally\n", set.Image)

			if set.Build != "" {
				Info.Println("Building image")
				if err := set.BuildImage(); err != nil {
					return err
				}
			} else {
				Info.Println("Pulling image")
				if err := helpers.PullImage(set.Image); err != nil {
					return err
				}
			}
		}

		if err := set.Create(dryRun); err != nil {
			return err
		}
	}
	return nil

}

// The 'up' command
//
// Creates a container if it doesn't exist
// Starts a container if stopped
// Recreates a container if the container's image has a newer id locally
// OR if the command used to create the container is now changed (i.e.
// config has changed.
func (settings *ProjectConfig) CapitanUp(attach bool, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)

	wg := sync.WaitGroup{}

	for _, set := range settings.ContainerSettingsList {
		var (
			err error
		)

		if helpers.GetImageId(set.Image) == "" {
			Warning.Printf("Capitan was unable to find image %s locally\n", set.Image)

			if set.Build != "" {
				Info.Println("Building image")
				if err := set.BuildImage(); err != nil {
					return err
				}
			} else {
				Info.Println("Pulling image")
				if err := helpers.PullImage(set.Image); err != nil {
					return err
				}
			}
		}

		//create new
		if !helpers.ContainerExists(set.Name) {
			if err = set.Run(attach, dryRun, &wg); err != nil {
				return err
			}
			continue
		}

		if newerImage(set.Name, set.Image) {
			// remove and restart
			Info.Println("Removing (different image available):", set.Name)
			if err = set.RecreateAndRun(attach, dryRun, &wg); err != nil {
				return err
			}

			continue
		}

		if haveArgsChanged(set.Name, set.GetRunArguments()) {
			// remove and restart
			Info.Println("Removing (run arguments changed):", set.Name)
			if err = set.RecreateAndRun(attach, dryRun, &wg); err != nil {
				return err
			}
			continue
		}

		//attach if running
		if helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already running " + set.Name)
			if attach {
				Info.Println("Attaching")
				if err := set.Attach(&wg); err != nil {
					return err
				}
			}
			continue
		}

		Info.Println("Starting " + set.Name)

		if dryRun {
			continue
		}

		//start if stopped
		if err = set.Start(attach, &wg); err != nil {
			return err
		}
		continue

	}
	wg.Wait()
	if !dryRun && attach {
		<-allDone
	}
	return nil
}

// Starts stopped containers
func (settings *ProjectConfig) CapitanStart(attach bool, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	wg := sync.WaitGroup{}
	for _, set := range settings.ContainerSettingsList {
		if helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already running " + set.Name)
			if attach {
				Info.Println("Attaching")
				if err := set.Attach(&wg); err != nil {
					return err
				}
			}
			continue
		}
		Info.Println("Starting " + set.Name)
		if !dryRun {
			if err := set.Start(attach, &wg); err != nil {
				return err
			}
		}
	}
	wg.Wait()
	if !dryRun && attach {
		<-allDone
	}
	return nil
}

// Command to restart all containers
func (settings *ProjectConfig) CapitanRestart(args []string, dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		Info.Println("Restarting " + set.Name)
		if !dryRun {
			if err := set.Restart(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Print all container IPs
func (settings *ProjectConfig) CapitanIP() error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		ip := set.IP()
		Info.Printf("%s: %s", set.Name, ip)
	}
	return nil
}

// Stream all container logs
func (settings *ProjectConfig) CapitanLogs() error {
	sort.Sort(settings.ContainerSettingsList)
	var wg sync.WaitGroup
	for _, set := range settings.ContainerSettingsList {
		var (
			ses *sh.Session
			err error
		)
		if ses, err = set.Logs(); err != nil {
			Error.Println("Error getting log for " + set.Name + ": " + err.Error())
			continue
		}

		wg.Add(1)

		go func() {
			ses.Wait()
			wg.Done()
		}()

	}
	wg.Wait()
	return nil
}

// Stream all container stats
func (settings *ProjectConfig) CapitanStats() error {
	var (
		args []interface{}
	)
	sort.Sort(settings.ContainerSettingsList)

	args = make([]interface{}, len(settings.ContainerSettingsList))

	for i, set := range settings.ContainerSettingsList {
		args[i] = set.Name
	}

	ses := sh.NewSession()
	ses.Command("docker", append([]interface{}{"stats"}, args...)...)
	ses.Start()
	ses.Wait()
	return nil
}

// Print `docker ps` ouptut for all containers in project
func (settings *ProjectConfig) CapitanPs(args []string) error {
	sort.Sort(settings.ContainerSettingsList)
	allArgs := append([]interface{}{"ps"}, helpers.ToInterfaceSlice(args)...)
	for _, set := range settings.ContainerSettingsList {
		allArgs = append(allArgs, "-f", "name="+set.Name)
	}
	var (
		err error
		out []byte
	)
	if out, err = helpers.RunCmd(allArgs...); err != nil {
		return err
	}
	Info.Print(string(out))
	return nil
}

// Kill all running containers in project
func (settings *ProjectConfig) CapitanKill(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {
		if !helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already dead:", set.Name)
			continue
		}
		Info.Println("Killing " + set.Name)
		if !dryRun {
			if err := set.Kill(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Stops the containers in the project
func (settings *ProjectConfig) CapitanStop(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {
		if !helpers.ContainerIsRunning(set.Name) {
			Info.Println("Already dead:", set.Name)
			continue
		}
		Info.Println("Stopping " + set.Name)
		if !dryRun {
			if err := set.Stop(args); err != nil {
				return err
			}
		}
	}
	return nil
}

// Remove all containers in project
func (settings *ProjectConfig) CapitanRm(args []string, dryRun bool) error {
	sort.Sort(sort.Reverse(settings.ContainerSettingsList))
	for _, set := range settings.ContainerSettingsList {

		if !dryRun && helpers.ContainerExists(set.Name) {
			Info.Println("Removing " + set.Name)
			if err := set.Rm(args); err != nil {
				return err
			}
		} else {
			Info.Println("Container doesn't exist:", set.Name)
		}
	}
	return nil
}

// The build command
func (settings *ProjectConfig) CapitanBuild(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		if len(set.Build) == 0 {
			continue
		}
		Info.Println("Building " + set.Name)
		if !dryRun {
			if err := set.BuildImage(); err != nil {
				return err
			}
		}

	}
	return nil
}

// The build command
func (settings *ProjectConfig) CapitanPull(dryRun bool) error {
	sort.Sort(settings.ContainerSettingsList)
	for _, set := range settings.ContainerSettingsList {
		if len(set.Build) > 0 || set.Image == "" {
			continue
		}
		Info.Println("Pulling", set.Image, "for", set.Name)
		if !dryRun {
			if err := helpers.PullImage(set.Image); err != nil {
				return err
			}
		}

	}
	return nil
}
<|endoftext|>


<commit_before>package collector

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
)

type descMap map[string]*prometheus.Desc

const (
	namespace = "squid"
	timeout   = 10 * time.Second
)

var (
	up = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "up"),
		"Was the last query of squid successful?",
		[]string{"region"}, nil,
	)

	counters descMap
)

/*Exporter entry point to squid exporter */
type Exporter struct {
	client SquidClient

	hostname string
	port     int
}

/*New initializes a new exporter */
func New(hostname string, port int, login string, password string) *Exporter {
	c := NewCacheObjectClient(hostname, port, login, password)

	return &Exporter{
		c,

		hostname,
		port,
	}
}

// Describe describes all the metrics ever exported by the ECS exporter. It
// implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	ch <- up

	for _, v := range counters {
		ch <- v
	}

}

/*Collect fetches metrics from squid manager and pushes them to promethus */
func (e *Exporter) Collect(c chan<- prometheus.Metric) {
	c <- prometheus.MustNewConstMetric(up, prometheus.GaugeValue, 0, e.hostname)

	insts, err := e.client.GetCounters()

	if err == nil {
		for i := range insts {
			if d, ok := counters[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, insts[i].Value)
			}
		}
	} else {
		log.Println("Could not fetch metrics from squid instance: ", err)
	}
}

func init() {
	prometheus.MustRegister(version.NewCollector("squid_exporter"))

	counters = generateSquidCounters()
}
<commit_msg>Fix squid_up to show if squid service is running<commit_after>package collector

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
)

type descMap map[string]*prometheus.Desc

const (
	namespace = "squid"
	timeout   = 10 * time.Second
)

var (
	counters descMap
)

/*Exporter entry point to squid exporter */
type Exporter struct {
	client SquidClient

	hostname string
	port     int

	up *prometheus.GaugeVec
}

/*New initializes a new exporter */
func New(hostname string, port int, login string, password string) *Exporter {
	c := NewCacheObjectClient(hostname, port, login, password)

	return &Exporter{
		c,

		hostname,
		port,

		prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "up",
			Help:      "Was the last query of squid successful?",
		}, []string{"region"}),
	}
}

// Describe describes all the metrics ever exported by the ECS exporter. It
// implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.up.Describe(ch)

	for _, v := range counters {
		ch <- v
	}

}

/*Collect fetches metrics from squid manager and pushes them to promethus */
func (e *Exporter) Collect(c chan<- prometheus.Metric) {
	insts, err := e.client.GetCounters()

	if err == nil {
		e.up.With(prometheus.Labels{"region": e.hostname}).Set(1)
		for i := range insts {
			if d, ok := counters[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, insts[i].Value)
			}
		}
	} else {
		e.up.With(prometheus.Labels{"region": e.hostname}).Set(0)
		log.Println("Could not fetch metrics from squid instance: ", err)
	}
	e.up.Collect(c)
}

func init() {
	prometheus.MustRegister(version.NewCollector("squid_exporter"))

	counters = generateSquidCounters()
}
<|endoftext|>


<commit_before>package tests

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/networkservicemesh/networkservicemesh/controlplane/pkg/apis/crossconnect"
	"github.com/networkservicemesh/networkservicemesh/controlplane/pkg/monitor/crossconnect_monitor"
	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"net"
	"sync"
	"testing"
)

func startClient(target string) {
	conn, err := grpc.Dial(target, grpc.WithInsecure())
	defer conn.Close()

	Expect(err).To(BeNil())
	monitorClient := crossconnect.NewMonitorCrossConnectClient(conn)
	stream, err := monitorClient.MonitorCrossConnects(context.Background(), &empty.Empty{})
	Expect(err).To(BeNil())

	event, err := stream.Recv()
	Expect(err).To(BeNil())
	logrus.Infof("Receive event: %v", event)
	Expect(event).NotTo(BeNil())
	Expect(event.Type).To(Equal(crossconnect.CrossConnectEventType_INITIAL_STATE_TRANSFER))
	Expect(event.CrossConnects).NotTo(BeNil())
	Expect(event.CrossConnects["1"]).NotTo(BeNil())
}

func TestSimple(t *testing.T) {
	RegisterTestingT(t)

	listener, err := net.Listen("tcp", "localhost:5002")
	defer listener.Close()
	Expect(err).To(BeNil())

	grpcServer := grpc.NewServer()
	monitor := crossconnect_monitor.NewCrossConnectMonitor()
	crossconnect.RegisterMonitorCrossConnectServer(grpcServer, monitor)

	go func() {
		grpcServer.Serve(listener)
	}()

	monitor.Update(&crossconnect.CrossConnect{Id: "1"})

	startClient("localhost:5002")
}

func TestSeveralRecipient(t *testing.T) {
	RegisterTestingT(t)

	listener, err := net.Listen("tcp", "localhost:5002")
	defer listener.Close()
	Expect(err).To(BeNil())

	grpcServer := grpc.NewServer()
	monitor := crossconnect_monitor.NewCrossConnectMonitor()
	crossconnect.RegisterMonitorCrossConnectServer(grpcServer, monitor)

	go func() {
		err := grpcServer.Serve(listener)
		Expect(err).To(BeNil())
	}()

	monitor.Update(&crossconnect.CrossConnect{Id: "1"})

	var wg sync.WaitGroup
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func() {
			startClient("localhost:5002")
			wg.Done()
		}()
	}
	wg.Wait()
}
<commit_msg>Fix Monitor server test stability (#710)<commit_after>package tests

import (
	"context"
	"fmt"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/networkservicemesh/networkservicemesh/controlplane/pkg/apis/crossconnect"
	"github.com/networkservicemesh/networkservicemesh/controlplane/pkg/monitor/crossconnect_monitor"
	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"net"
	"sync"
	"testing"
)

func startClient(target string) {
	conn, err := grpc.Dial(target, grpc.WithInsecure())
	defer conn.Close()

	Expect(err).To(BeNil())
	monitorClient := crossconnect.NewMonitorCrossConnectClient(conn)
	stream, err := monitorClient.MonitorCrossConnects(context.Background(), &empty.Empty{})
	Expect(err).To(BeNil())

	event, err := stream.Recv()
	Expect(err).To(BeNil())
	logrus.Infof("Receive event: %v", event)
	Expect(event).NotTo(BeNil())
	Expect(event.Type).To(Equal(crossconnect.CrossConnectEventType_INITIAL_STATE_TRANSFER))
	Expect(event.CrossConnects).NotTo(BeNil())
	Expect(event.CrossConnects["1"]).NotTo(BeNil())
}

func TestSimple(t *testing.T) {
	RegisterTestingT(t)

	listener, err := net.Listen("tcp", "localhost:0")
	defer listener.Close()
	Expect(err).To(BeNil())

	grpcServer := grpc.NewServer()
	monitor := crossconnect_monitor.NewCrossConnectMonitor()
	crossconnect.RegisterMonitorCrossConnectServer(grpcServer, monitor)

	go func() {
		grpcServer.Serve(listener)
	}()

	monitor.Update(&crossconnect.CrossConnect{Id: "1"})

	startClient(listenerAddress(listener))
}

func listenerAddress(listener net.Listener) string {
	port := listener.Addr().(*net.TCPAddr).Port
	logrus.Infof("Connect to port: %d", port)
	return fmt.Sprintf("localhost:%d", port)
}

func TestSeveralRecipient(t *testing.T) {
	RegisterTestingT(t)

	listener, err := net.Listen("tcp", "localhost:0")
	defer listener.Close()
	Expect(err).To(BeNil())

	grpcServer := grpc.NewServer()
	monitor := crossconnect_monitor.NewCrossConnectMonitor()
	crossconnect.RegisterMonitorCrossConnectServer(grpcServer, monitor)

	var waitServe sync.WaitGroup
	waitServe.Add(1)
	go func() {
		go waitServe.Done()
		_ = grpcServer.Serve(listener)
	}()
	waitServe.Wait()
	monitor.Update(&crossconnect.CrossConnect{Id: "1"})

	var wg sync.WaitGroup
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func() {
			startClient(listenerAddress(listener))
			wg.Done()
		}()
	}
	wg.Wait()
	logrus.Infof("######END")
}
<|endoftext|>


<commit_before>package combiner

import (
  "time"
  "log"
  "fmt"
  "io/ioutil"
  "errors"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
  "pdfcombiner/cpdf"
)

var (
  verbose = true
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  defdocs = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf",
                     "100035.pdf","100037.pdf","100038.pdf","100093.pdf"}
)

type Job struct {
  BucketName string
  EmployerId int
  DocList    []string
  Callback   string
  Errors     []error
  Bucket     *s3.Bucket
}

type stat struct {
  filename string
  size     int
  dlSecs   time.Duration
}

func (j *Job) IsValid() bool {
 return (j.BucketName != "") &&
        (j.Callback   != "") &&
        (j.EmployerId > 0)   &&
        (j.DocCount() > 0)
}

func (j *Job) DocCount() int {
  return len(j.DocList)
}

func (j *Job) AddError(newErr error) {
  log.Println(newErr)
  j.Errors = append(j.Errors, newErr)
}

func (j *Job) connect() {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  j.Bucket = s.Bucket(bucketName)
}

func (j *Job) getFile(docname string, c chan stat, e chan error) {
  start := time.Now()
  data, err := j.Bucket.Get(j.s3Path(docname))
  if err != nil {
    e <- fmt.Errorf("%v: %v", docname, err)
    return
  }
  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil {
    e <- err; return
    return
  }
  c <- stat{ filename: docname,
             size: len(data),
             dlSecs: time.Since(start) }
}

func (j *Job) s3Path(docname string) string {
  return fmt.Sprintf("%d/docs/%s", j.EmployerId, docname)
}

func (j *Job) getAllFiles() {
  start := time.Now()
  j.connect()
  c := make(chan stat)
  e := make(chan error)
  for _,doc := range j.DocList{
    go j.getFile(doc,c,e)
  }

  totalBytes := j.waitForDownloads(c,e)
  printSummary(start, totalBytes, j.DocCount())
}

func (j *Job) waitForDownloads(c chan stat, e chan error) (totalBytes int) {
  for _,_ = range j.DocList{
    select {
      case packet := <-c:
        if verbose { log.Printf("%s was %d bytes\n", packet.filename,packet.size) }
        totalBytes += packet.size
      case err := <-e:
        j.AddError(err)
      case <-time.After(2 * time.Minute):
        j.AddError(errors.New("Timed out while downloading"))
        return
    }
  }
  return
}

func printSummary(start time.Time, bytes int, count int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, count, seconds, mbps)
}

func (j *Job) postToCallback(){
  log.Println("work complete, posting success to callback:",j.Callback)
  log.Println(j)
}

func (j *Job) Combine() bool {
  defer j.postToCallback()
  j.getAllFiles()
  cpdf.Merge(j.DocList)
  return true
}

<commit_msg>Only combine if no errors<commit_after>package combiner

import (
  "time"
  "log"
  "fmt"
  "io/ioutil"
  "errors"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
  "pdfcombiner/cpdf"
)

var (
  verbose = true
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  defdocs = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf",
                     "100035.pdf","100037.pdf","100038.pdf","100093.pdf"}
)

type Job struct {
  BucketName string
  EmployerId int
  DocList    []string
  Callback   string
  Errors     []error
  Bucket     *s3.Bucket
}

type stat struct {
  filename string
  size     int
  dlSecs   time.Duration
}

func (j *Job) IsValid() bool {
 return (j.BucketName != "") &&
        (j.Callback   != "") &&
        (j.EmployerId > 0)   &&
        (j.DocCount() > 0)
}

func (j *Job) DocCount() int {
  return len(j.DocList)
}

func (j *Job) AddError(newErr error) {
  log.Println(newErr)
  j.Errors = append(j.Errors, newErr)
}

func (j *Job) connect() {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  j.Bucket = s.Bucket(bucketName)
}

func (j *Job) getFile(docname string, c chan stat, e chan error) {
  start := time.Now()
  data, err := j.Bucket.Get(j.s3Path(docname))
  if err != nil {
    e <- fmt.Errorf("%v: %v", docname, err)
    return
  }
  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil {
    e <- err; return
    return
  }
  c <- stat{ filename: docname,
             size: len(data),
             dlSecs: time.Since(start) }
}

func (j *Job) s3Path(docname string) string {
  return fmt.Sprintf("%d/docs/%s", j.EmployerId, docname)
}

func (j *Job) getAllFiles() {
  start := time.Now()
  j.connect()
  c := make(chan stat)
  e := make(chan error)
  for _,doc := range j.DocList{
    go j.getFile(doc,c,e)
  }

  totalBytes := j.waitForDownloads(c,e)
  printSummary(start, totalBytes, j.DocCount())
}

func (j *Job) waitForDownloads(c chan stat, e chan error) (totalBytes int) {
  for _,_ = range j.DocList{
    select {
      case packet := <-c:
        if verbose { log.Printf("%s was %d bytes\n", packet.filename,packet.size) }
        totalBytes += packet.size
      case err := <-e:
        j.AddError(err)
      case <-time.After(2 * time.Minute):
        j.AddError(errors.New("Timed out while downloading"))
        return
    }
  }
  return
}

func printSummary(start time.Time, bytes int, count int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, count, seconds, mbps)
}

func (j *Job) postToCallback(){
  log.Println("work complete, posting success to callback:",j.Callback)
  log.Println(j)
}

func (j *Job) Combine() bool {
  defer j.postToCallback()
  j.getAllFiles()
  if len(j.Errors) > 0 {
    cpdf.Merge(j.DocList)
  }
  return true
}

<|endoftext|>


<commit_before>package weavebox

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/httprouter"
	"golang.org/x/net/context"
)

// weavebox is opinion based minimalistic web framework for making fast and
// powerfull web application in the Go programming language. It is backed by
// the fastest and most optimized request router available. Weavebox also
// provides a gracefull webserver that can serve TLS encripted requests aswell.

var defaultErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

type Weavebox struct {
	// ErrorHandler is invoked whenever a Handler returns an error
	ErrorHandler ErrorHandlerFunc

	// NotFoundHandler is invoked whenever the router could not match a route
	// against the request url
	NotFoundHandler http.Handler

	// Output writes the access-log and debug parameters
	Output io.Writer

	// EnableLog lets you turn of the default access-log
	EnableLog bool

	templateEngine Renderer
	router         *httprouter.Router
	middleware     []Handler
	prefix         string
}

// New returns a new Weavebox object
func New() *Weavebox {
	return &Weavebox{
		router:       httprouter.New(),
		Output:       os.Stderr,
		ErrorHandler: defaultErrorHandler,
		EnableLog:    true,
	}
}

// Serve serves the application on the given port
func (w *Weavebox) Serve(port int) error {
	w.init()
	portStr := fmt.Sprintf(":%d", port)
	fmt.Fprintf(w.Output, "app listening on 0.0.0.0:%d\n", port)
	return ListenAndServe(portStr, w)
}

// ServeTLS servers the application one the given port with TLS encription.
func (w *Weavebox) ServeTLS(port int, keyFile, certFile string) error {
	w.init()
	portStr := fmt.Sprintf(":%d", port)
	fmt.Fprintf(w.Output, "app listening on 0.0.0.0:%d\n", port)
	return ListenAndServeTLS(portStr, w, keyFile, certFile)
}

// Get registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is GET
func (w *Weavebox) Get(route string, h Handler) {
	w.add("GET", route, h)
}

// Post registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is POST
func (w *Weavebox) Post(route string, h Handler) {
	w.add("POST", route, h)
}

// Put registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is PUT
func (w *Weavebox) Put(route string, h Handler) {
	w.add("PUT", route, h)
}

// Delete registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is DELETE
func (w *Weavebox) Delete(route string, h Handler) {
	w.add("DELETE", route, h)
}

// Static registers the prefix to the router and start to act as a fileserver
// ex. "/public", "./assets"
func (w *Weavebox) Static(prefix, dir string) {
	w.router.ServeFiles(path.Join(prefix, "*filepath"), http.Dir(dir))
}

// Use appends a Handler to the box middleware. Different middleware can be set
// for each subrouter (Box).
func (w *Weavebox) Use(handlers ...Handler) {
	for _, h := range handlers {
		w.middleware = append(w.middleware, h)
	}
}

// Subrouter returns a new Box that will inherit all of its parents middleware.
// you can reset the middleware registered to the box by calling Reset()
func (w *Weavebox) Subrouter(prefix string) *Box {
	b := &Box{*w}
	b.Weavebox.prefix += prefix
	return b
}

// Box act as a subrouter and wil inherit all of its parents middleware
type Box struct {
	Weavebox
}

// Reset clears all middleware
func (b *Box) Reset() *Box {
	b.Weavebox.middleware = nil
	return b
}

// SetTemplateEngine allows the use of any template engine out there, if it
// satisfies the Renderer interface
func (w *Weavebox) SetTemplateEngine(t Renderer) {
	w.templateEngine = t
}

// ServeHTTP
func (w *Weavebox) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if w.EnableLog {
		start := time.Now()
		logger := &responseLogger{w: rw}
		w.router.ServeHTTP(logger, r)
		w.writeLog(r, start, logger.Status(), logger.Size())
		// saves an allocation by seperating the whole logger if log is disabled
	} else {
		w.router.ServeHTTP(rw, r)
	}
}

func (w *Weavebox) init() {
	if w.NotFoundHandler != nil {
		w.router.NotFound = w.NotFoundHandler
	}
}

func (w *Weavebox) add(method, route string, h Handler) {
	path := path.Join(w.prefix, route)
	w.router.Handle(method, path, w.makeHTTPRouterHandle(h))
}

func (w *Weavebox) makeHTTPRouterHandle(h Handler) httprouter.Handle {
	return func(rw http.ResponseWriter, r *http.Request, params httprouter.Params) {
		ctx := &Context{
			Context:  context.Background(),
			Vars:     params,
			weavebox: w,
		}
		for _, handler := range w.middleware {
			if err := handler(ctx, rw, r); err != nil {
				w.ErrorHandler(rw, r, err)
				return
			}
		}

		if err := h(ctx, rw, r); err != nil {
			w.ErrorHandler(rw, r, err)
			return
		}
	}
}

func (w *Weavebox) writeLog(r *http.Request, start time.Time, status, size int) {
	host, _, _ := net.SplitHostPort(r.Host)
	fmt.Fprintf(w.Output, "%s - [%s] %s %s %s %d %d %d\n",
		host,
		start.Format("02/Jan/2006:15:04:05 -0700"),
		r.Method,
		r.RequestURI,
		r.Proto,
		status,
		size,
		time.Now().Sub(start),
	)
}

// Handler is a opinion / idiom of how weavebox thinks a request handler should
// look like. It requires a Context, ResponseWriter, Request and returns an error
type Handler func(ctx *Context, w http.ResponseWriter, r *http.Request) error

// ErrorHandlerFunc is invoked when a Handler returns an error, and can be used
// to centralize error handling.
type ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)

// Context is required in each weavebox Handler and can be used to pass information
// between requests.
type Context struct {
	// Context is a idiomatic way to pass information between requests.
	// More information about context.Context can be found here:
	// https://godoc.org/golang.org/x/net/context
	Context context.Context

	// Vars carries the named request URL parameters that are passed in the route
	// prefix. To get a parameter by name: Vars.GetByName(<param>)
	Vars     httprouter.Params
	weavebox *Weavebox
}

// Render calls the templateEngines Render function
func (c *Context) Render(w io.Writer, name string, data interface{}) error {
	return c.weavebox.templateEngine.Render(w, name, data)
}

type responseLogger struct {
	w      http.ResponseWriter
	status int
	size   int
}

func (l *responseLogger) Write(p []byte) (int, error) {
	if l.status == 0 {
		l.status = http.StatusOK
	}
	size, err := l.w.Write(p)
	l.size += size
	return size, err
}

func (l *responseLogger) Header() http.Header {
	return l.w.Header()
}

func (l *responseLogger) WriteHeader(code int) {
	l.w.WriteHeader(code)
	l.status = code
}

func (l *responseLogger) Status() int {
	return l.status
}

func (l *responseLogger) Size() int {
	return l.size
}

// Renderer renders any kind of template. Weavebox allows the use of different
// Template engines if they implement the Render method
type Renderer interface {
	Render(w io.Writer, name string, data interface{}) error
}

// JSON is a helper function for writing a JSON encoded representation of v to
// the ResponseWriter.
func JSON(w http.ResponseWriter, code int, v interface{}) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	return json.NewEncoder(w).Encode(v)
}

// Text is a helper function for writing a text/plain string to the ResponseWriter
func Text(w http.ResponseWriter, code int, text string) error {
	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(code)
	w.Write([]byte(text))
	return nil
}
<commit_msg>fixed importpath httprouter<commit_after>package weavebox

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/julienschmidt/httprouter"
	"golang.org/x/net/context"
)

// weavebox is opinion based minimalistic web framework for making fast and
// powerfull web application in the Go programming language. It is backed by
// the fastest and most optimized request router available. Weavebox also
// provides a gracefull webserver that can serve TLS encripted requests aswell.

var defaultErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

type Weavebox struct {
	// ErrorHandler is invoked whenever a Handler returns an error
	ErrorHandler ErrorHandlerFunc

	// NotFoundHandler is invoked whenever the router could not match a route
	// against the request url
	NotFoundHandler http.Handler

	// Output writes the access-log and debug parameters
	Output io.Writer

	// EnableLog lets you turn of the default access-log
	EnableLog bool

	templateEngine Renderer
	router         *httprouter.Router
	middleware     []Handler
	prefix         string
}

// New returns a new Weavebox object
func New() *Weavebox {
	return &Weavebox{
		router:       httprouter.New(),
		Output:       os.Stderr,
		ErrorHandler: defaultErrorHandler,
		EnableLog:    true,
	}
}

// Serve serves the application on the given port
func (w *Weavebox) Serve(port int) error {
	w.init()
	portStr := fmt.Sprintf(":%d", port)
	fmt.Fprintf(w.Output, "app listening on 0.0.0.0:%d\n", port)
	return ListenAndServe(portStr, w)
}

// ServeTLS servers the application one the given port with TLS encription.
func (w *Weavebox) ServeTLS(port int, certFile, keyFile string) error {
	w.init()
	portStr := fmt.Sprintf(":%d", port)
	fmt.Fprintf(w.Output, "app listening TLS on 0.0.0.0:%d\n", port)
	return ListenAndServeTLS(portStr, w, certFile, keyFile)
}

// Get registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is GET
func (w *Weavebox) Get(route string, h Handler) {
	w.add("GET", route, h)
}

// Post registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is POST
func (w *Weavebox) Post(route string, h Handler) {
	w.add("POST", route, h)
}

// Put registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is PUT
func (w *Weavebox) Put(route string, h Handler) {
	w.add("PUT", route, h)
}

// Delete registers a route prefix and will invoke the Handler when the route
// matches the prefix and the request METHOD is DELETE
func (w *Weavebox) Delete(route string, h Handler) {
	w.add("DELETE", route, h)
}

// Static registers the prefix to the router and start to act as a fileserver
// ex. "/public", "./assets"
func (w *Weavebox) Static(prefix, dir string) {
	w.router.ServeFiles(path.Join(prefix, "*filepath"), http.Dir(dir))
}

// Use appends a Handler to the box middleware. Different middleware can be set
// for each subrouter (Box).
func (w *Weavebox) Use(handlers ...Handler) {
	for _, h := range handlers {
		w.middleware = append(w.middleware, h)
	}
}

// Subrouter returns a new Box that will inherit all of its parents middleware.
// you can reset the middleware registered to the box by calling Reset()
func (w *Weavebox) Subrouter(prefix string) *Box {
	b := &Box{*w}
	b.Weavebox.prefix += prefix
	return b
}

// Box act as a subrouter and wil inherit all of its parents middleware
type Box struct {
	Weavebox
}

// Reset clears all middleware
func (b *Box) Reset() *Box {
	b.Weavebox.middleware = nil
	return b
}

// SetTemplateEngine allows the use of any template engine out there, if it
// satisfies the Renderer interface
func (w *Weavebox) SetTemplateEngine(t Renderer) {
	w.templateEngine = t
}

// ServeHTTP
func (w *Weavebox) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if w.EnableLog {
		start := time.Now()
		logger := &responseLogger{w: rw}
		w.router.ServeHTTP(logger, r)
		w.writeLog(r, start, logger.Status(), logger.Size())
		// saves an allocation by seperating the whole logger if log is disabled
	} else {
		w.router.ServeHTTP(rw, r)
	}
}

func (w *Weavebox) init() {
	if w.NotFoundHandler != nil {
		w.router.NotFound = w.NotFoundHandler
	}
}

func (w *Weavebox) add(method, route string, h Handler) {
	path := path.Join(w.prefix, route)
	w.router.Handle(method, path, w.makeHTTPRouterHandle(h))
}

func (w *Weavebox) makeHTTPRouterHandle(h Handler) httprouter.Handle {
	return func(rw http.ResponseWriter, r *http.Request, params httprouter.Params) {
		ctx := &Context{
			Context:  context.Background(),
			Vars:     params,
			weavebox: w,
		}
		for _, handler := range w.middleware {
			if err := handler(ctx, rw, r); err != nil {
				w.ErrorHandler(rw, r, err)
				return
			}
		}

		if err := h(ctx, rw, r); err != nil {
			w.ErrorHandler(rw, r, err)
			return
		}
	}
}

func (w *Weavebox) writeLog(r *http.Request, start time.Time, status, size int) {
	host, _, _ := net.SplitHostPort(r.Host)
	fmt.Fprintf(w.Output, "%s - [%s] %s %s %s %d %d %d\n",
		host,
		start.Format("02/Jan/2006:15:04:05 -0700"),
		r.Method,
		r.RequestURI,
		r.Proto,
		status,
		size,
		time.Now().Sub(start),
	)
}

// Handler is a opinion / idiom of how weavebox thinks a request handler should
// look like. It requires a Context, ResponseWriter, Request and returns an error
type Handler func(ctx *Context, w http.ResponseWriter, r *http.Request) error

// ErrorHandlerFunc is invoked when a Handler returns an error, and can be used
// to centralize error handling.
type ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)

// Context is required in each weavebox Handler and can be used to pass information
// between requests.
type Context struct {
	// Context is a idiomatic way to pass information between requests.
	// More information about context.Context can be found here:
	// https://godoc.org/golang.org/x/net/context
	Context context.Context

	// Vars carries the named request URL parameters that are passed in the route
	// prefix. To get a parameter by name: Vars.GetByName(<param>)
	Vars     httprouter.Params
	weavebox *Weavebox
}

// Render calls the templateEngines Render function
func (c *Context) Render(w io.Writer, name string, data interface{}) error {
	return c.weavebox.templateEngine.Render(w, name, data)
}

type responseLogger struct {
	w      http.ResponseWriter
	status int
	size   int
}

func (l *responseLogger) Write(p []byte) (int, error) {
	if l.status == 0 {
		l.status = http.StatusOK
	}
	size, err := l.w.Write(p)
	l.size += size
	return size, err
}

func (l *responseLogger) Header() http.Header {
	return l.w.Header()
}

func (l *responseLogger) WriteHeader(code int) {
	l.w.WriteHeader(code)
	l.status = code
}

func (l *responseLogger) Status() int {
	return l.status
}

func (l *responseLogger) Size() int {
	return l.size
}

// Renderer renders any kind of template. Weavebox allows the use of different
// Template engines if they implement the Render method
type Renderer interface {
	Render(w io.Writer, name string, data interface{}) error
}

// JSON is a helper function for writing a JSON encoded representation of v to
// the ResponseWriter.
func JSON(w http.ResponseWriter, code int, v interface{}) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	return json.NewEncoder(w).Encode(v)
}

// Text is a helper function for writing a text/plain string to the ResponseWriter
func Text(w http.ResponseWriter, code int, text string) error {
	w.Header().Set("Content-Type", "text/plain")
	w.WriteHeader(code)
	w.Write([]byte(text))
	return nil
}
<|endoftext|>


<commit_before>package acjs

import (
	"encoding/json"
	"fmt"
	"github.com/unix4fun/ac/accp"
	"github.com/unix4fun/ac/ackp"
	"github.com/unix4fun/ac/acutl"
)

type ACKxMessage struct {
	Type     int    `json:"type"`
	MyNick   string `json:"me"`
	PeerNick string `json:"peer"`
	Server   string `json:"server"`
	Channel  string `json:"channel"`
	Blob     []byte `json:"blob"`
}

type ACKxReply struct {
	Type  int    `json:"type"`
	Bada  bool   `json:"bada"`
	Errno int    `json:"errno"`
	Blob  []byte `json:"blob"`
	Nonce uint32 `json:"nonce"`
}

func (kx *ACKxMessage) validate() error {
	acutl.DebugLog.Printf("CALL [%p] Validate(%d))\n", kx, kx.Type)
	if (len(kx.MyNick) > 0) && (len(kx.PeerNick) > 0) && (len(kx.Server) > 0) && (len(kx.Channel) > 0) {
		switch kx.Type {
		case KXPACK:
			return nil
		case KXUNPACK:
			if len(kx.Blob) > 0 {
				return nil
			}
		} // end of switch..
	} // end of if...

	acutl.DebugLog.Printf("RET [%p] Validate(%d) -> [Error: Invalid KX message]\n", kx, kx.Type)
	return fmt.Errorf("Invalid KX[%d] message!\n", kx.Type)
}

func (kx *ACKxMessage) HandlerKXPACK() (msgReply []byte, err error) {
	acutl.DebugLog.Printf("CALL [%p] HandleKXPACK(%d:%s -> %s (%s/%s))\n",
		kx,
		kx.Type,
		kx.MyNick,
		kx.PeerNick,
		kx.Server,
		kx.Channel)

	err = kx.validate()
	if err != nil {
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -1,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}
	acctx, ok_a := ackp.ACmap.GetSKMapEntry(kx.Server, kx.Channel)
	me, ok_b := ackp.ACmap.GetPKMapEntry(kx.Server, kx.MyNick)
	peer, ok_c := ackp.ACmap.GetPKMapEntry(kx.Server, kx.PeerNick)
	acrnd, ok_d := ackp.ACmap.GetRDMapEntry(kx.Server, kx.Channel)

	if ok_a == false || ok_b == false || ok_c == false || ok_d == false {
		err = fmt.Errorf("KXPACK_Handler().GetSKMapEntry/GetPKMapEntry(): failed")
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -2,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}

	kxMsg, err := accp.CreateKXMessageNACL(acctx, acrnd, peer.GetPubkey(), me.GetPrivkey(), []byte(kx.Channel), []byte(kx.MyNick), []byte(kx.PeerNick))
	if err != nil {
		err = fmt.Errorf("KXPACK_Handler().CreateKXMessage(): failed")
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -3,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}

	msgReply, _ = json.Marshal(&ACKxReply{
		Type:  R_KXPACK,
		Bada:  true,
		Errno: 0,
		Blob:  kxMsg,
		Nonce: acctx.GetNonce(),
	})
	acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [OK]\n",
		kx,
		kx.Type,
		kx.MyNick,
		kx.PeerNick,
		kx.Server,
		kx.Channel)
	return
	return
}

func (kx *ACKxMessage) HandlerKXUNPACK() (msgReply []byte, err error) {
	return
}

//
//
// Handle KEY Exchange MESSAGES..
//
//
func HandleKXMsg(msg []byte) (msgReply []byte, err error) {
	acutl.DebugLog.Printf("CALL HandleKXMsg(msg[%d]:[%s])\n", len(msg), msg)
	req := &ACKxMessage{}

	// let's unmarshall the message first
	err = json.Unmarshal(msg, req)
	if err != nil {
		acutl.DebugLog.Printf("RET HandlerKXMsg(%s) -> [Error: %s]\n", msg, err.Error())
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXERR,
			Bada:  false,
			Errno: -1,
			Blob:  []byte(err.Error()),
		})
		return
	}

	switch req.Type {
	case KXPACK:
		msgReply, err = req.HandlerKXPACK()
	case KXUNPACK:
		msgReply, err = req.HandlerKXUNPACK()
	default:
		err = fmt.Errorf("Invalid KX Message.")
		msgReply, _ = json.Marshal(&ACPkReply{
			Type:  R_KXERR,
			Bada:  false,
			Errno: -2,
			Blob:  []byte(err.Error()),
		})
	}

	acutl.DebugLog.Printf("RET HandleKXMsg(msg[%d]:[%s]) -> [reply[%d]: %s]\n", len(msg), msg, len(msgReply), msgReply)
	return
}
<commit_msg>introduced key exchange messages.<commit_after>package acjs

import (
	"encoding/json"
	"fmt"
	"github.com/unix4fun/ac/accp"
	"github.com/unix4fun/ac/ackp"
	"github.com/unix4fun/ac/acutl"
)

type ACKxMessage struct {
	Type     int    `json:"type"`
	MyNick   string `json:"me"`
	PeerNick string `json:"peer"`
	Server   string `json:"server"`
	Channel  string `json:"channel"`
	Blob     []byte `json:"blob"`
}

type ACKxReply struct {
	Type  int    `json:"type"`
	Bada  bool   `json:"bada"`
	Errno int    `json:"errno"`
	Blob  []byte `json:"blob"`
	Nonce uint32 `json:"nonce"`
}

func (kx *ACKxMessage) validate() error {
	acutl.DebugLog.Printf("CALL [%p] Validate(%d))\n", kx, kx.Type)
	if (len(kx.MyNick) > 0) && (len(kx.PeerNick) > 0) && (len(kx.Server) > 0) && (len(kx.Channel) > 0) {
		switch kx.Type {
		case KXPACK:
			return nil
		case KXUNPACK:
			if len(kx.Blob) > 0 {
				return nil
			}
		} // end of switch..
	} // end of if...

	acutl.DebugLog.Printf("RET [%p] Validate(%d) -> [Error: Invalid KX message]\n", kx, kx.Type)
	return fmt.Errorf("Invalid KX[%d] message!\n", kx.Type)
}

func (kx *ACKxMessage) HandlerKXPACK() (msgReply []byte, err error) {
	acutl.DebugLog.Printf("CALL [%p] HandleKXPACK(%d:%s -> %s (%s/%s))\n",
		kx,
		kx.Type,
		kx.MyNick,
		kx.PeerNick,
		kx.Server,
		kx.Channel)

	err = kx.validate()
	if err != nil {
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -1,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}
	acctx, ok_a := ackp.ACmap.GetSKMapEntry(kx.Server, kx.Channel)
	me, ok_b := ackp.ACmap.GetPKMapEntry(kx.Server, kx.MyNick)
	peer, ok_c := ackp.ACmap.GetPKMapEntry(kx.Server, kx.PeerNick)
	acrnd, ok_d := ackp.ACmap.GetRDMapEntry(kx.Server, kx.Channel)

	if ok_a == false || ok_b == false || ok_c == false || ok_d == false {
		err = fmt.Errorf("KXPACK_Handler().GetSKMapEntry/GetPKMapEntry(): failed")
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -2,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}

	kxMsg, err := accp.CreateKXMessageNACL(acctx, acrnd, peer.GetPubkey(), me.GetPrivkey(), []byte(kx.Channel), []byte(kx.MyNick), []byte(kx.PeerNick))
	if err != nil {
		//err = fmt.Errorf("KXPACK_Handler().CreateKXMessage(): failed")
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXPACK,
			Bada:  false,
			Errno: -3,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.MyNick,
			kx.PeerNick,
			kx.Server,
			kx.Channel, err.Error())
		return
	}

	msgReply, _ = json.Marshal(&ACKxReply{
		Type:  R_KXPACK,
		Bada:  true,
		Errno: 0,
		Blob:  kxMsg,
		Nonce: acctx.GetNonce(),
	})
	acutl.DebugLog.Printf("RET [%p] HandleKXPACK(%d:%s -> %s (%s/%s)) -> [OK]\n",
		kx,
		kx.Type,
		kx.MyNick,
		kx.PeerNick,
		kx.Server,
		kx.Channel)
	return
}

func (kx *ACKxMessage) HandlerKXUNPACK() (msgReply []byte, err error) {
	//var responseType AcKeyExchangeMessageResponseAcKXRespMsgType
	//responseType = AcKeyExchangeMessageResponse_KXR_UNPACK

	//channel := acMessageKxReq.GetChannel()
	//mynick := acMessageKxReq.GetMynick()
	//peernick := acMessageKxReq.GetPeernick()
	//blobMsg := acMessageKxReq.GetBlob()
	//reqServ := acMessageKxReq.GetServer()

	//acutl.DebugLog.Printf("(CALL) KXUNPACK <- DH( %s/%s <KX:%s> '%s' -> '%s' ) \n", channel, reqServ, blobMsg, peernick, mynick)
	acutl.DebugLog.Printf("CALL [%p] HandleKXUNPACK(%d:%s -> %s[%s] (%s/%s))\n",
		kx,
		kx.Type,
		kx.PeerNick,
		kx.MyNick,
		kx.Blob,
		kx.Server,
		kx.Channel)

	// XXX TODO: missing the server..
	/*
		if len(channel) == 0 || len(mynick) == 0 || len(peernick) == 0 || len(blobMsg) == 0 || len(reqServ) == 0 {
			retErr := &acutl.AcError{Value: -1, Msg: "KXUNPACK_Handler().args(channel|serv|mynick|peernick): 0 bytes", Err: nil}
			acMsgResponse = &AcKeyExchangeMessageResponse{
				Type:      &responseType,
				Bada:      proto.Bool(false),
				ErrorCode: proto.Int32(-1),
			}
			acutl.DebugLog.Printf("(RET[!]) KXUNPACK -> (-1) ! %s\n", retErr.Error())
			return acMsgResponse, retErr
		}
	*/
	err = kx.validate()
	if err != nil {
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXUNPACK,
			Bada:  false,
			Errno: -1,
			Blob:  []byte(err.Error()),
		})
		acutl.DebugLog.Printf("RET [%p] HandleKXUNPACK(%d:%s -> %s[%s] (%s/%s)) -> [Error: %s]\n",
			kx,
			kx.Type,
			kx.PeerNick,
			kx.MyNick,
			kx.Blob,
			kx.Server,
			kx.Channel, err.Error())
		return
	}

	me, ok_b := ackp.ACmap.GetPKMapEntry(kx.Server, kx.MyNick)
	peer, ok_c := ackp.ACmap.GetPKMapEntry(kx.Server, kx.PeerNick)

	if ok_b == false || ok_c == false || peer.GetPubkey() == nil || me.GetPrivkey() == nil {
		/*
			retErr := &acutl.AcError{Value: -2, Msg: "KXUNPACK_Handler().PKMapLookup(mynick|peernick) failure", Err: nil}
			acMsgResponse = &AcKeyExchangeMessageResponse{
				Type:      &responseType,
				Bada:      proto.Bool(false),
				ErrorCode: proto.Int32(-2),
			}
			acutl.DebugLog.Printf("(RET[!]) KXUNPACK -> (-2) ! GetPKMapEntry(%s): %t - GetPKMapEntry(%s): %t\n%s\n", mynick, ok_b, peernick, ok_c, retErr.Error())
		*/

		err = fmt.Errorf("KXUNPACK_Handler().PKMapLookup(mynick|peernick) failure")
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXUNPACK,
			Bada:  false,
			Errno: -2,
			Blob:  []byte(err.Error()),
		})
		//return acMsgResponse, retErr
		return
	}

	// XXX ok this is how we handle private and channel key exchange as in
	// private/queries there is no "channel"
	// we're going to see if it's a channel or private message key exchange
	// if it's channel we build a "channel"
	// KXPACK => mynick=peernick
	// KXUNPACK => peernick=mynick
	//    kx_channel := []byte(channel)
	//    ok_channel, _ :=  accp.IsValidChannelName(kx_channel)
	//    fmt.Printf("[+] KXUNPACK: is %s a valid channel: %t\n", channel, ok_channel)
	//    if ok_channel == false {
	//        // private channel building!
	//        kxc_build := new(bytes.Buffer)
	//        kxc_build.Write([]byte(peernick))
	//        kxc_build.WriteByte(byte('='))
	//        kxc_build.Write([]byte(mynick))
	//        kx_channel = kxc_build.Bytes()
	//        fmt.Printf("[+] KXUNPACK: not a channel, private conversation let's use this: %s\n", kx_channel)
	//    }

	acctx, acrnd, err := accp.OpenKXMessageNACL(peer.GetPubkey(), me.GetPrivkey(), kx.Blob, []byte(kx.Channel), []byte(kx.MyNick), []byte(kx.PeerNick))
	//    acctx, err := accp.OpenKXMessage(peer.GetPubkey(), me.GetPrivkey(), blobMsg, kx_channel, []byte(mynick), []byte(peernick))
	if err != nil {
		/*
			retErr := &acutl.AcError{Value: -3, Msg: "KXUNPACK_Handler().OpenKXMessage(): ", Err: err}
			acMsgResponse = &AcKeyExchangeMessageResponse{
				Type:      &responseType,
				Bada:      proto.Bool(false),
				ErrorCode: proto.Int32(-3),
			}
			acutl.DebugLog.Printf("(RET[!]) KXUNPACK -> (-3) ! %s\n", retErr.Error())
			return acMsgResponse, retErr
		*/
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXUNPACK,
			Bada:  false,
			Errno: -3,
			Blob:  []byte(err.Error()),
		})
		return
	}

	ackp.ACmap.SetSKMapEntry(kx.Server, kx.Channel, acctx)
	ackp.ACmap.SetRDMapEntry(kx.Server, kx.Channel, acrnd)

	/*`
	acMsgResponse = &AcKeyExchangeMessageResponse{
		Type:      &responseType,
		Bada:      proto.Bool(true),
		ErrorCode: proto.Int32(0),
		Nonce:     proto.Uint32(acctx.GetNonce()),
	}
	// XXX TODO REMOVE THE REAL DISPLAY OF THE KEY!!!!
	acutl.DebugLog.Printf("(RET) KXUNPACK -> (0) ! Key [%s/%s]\n", reqServ, channel)
	return acMsgResponse, nil
	*/
	msgReply, _ = json.Marshal(&ACKxReply{
		Type:  R_KXUNPACK,
		Bada:  true,
		Errno: 0,
		Nonce: acctx.GetNonce(),
	})
	acutl.DebugLog.Printf("RET [%p] HandleKXUNPACK(%d:%s -> %s[%s] (%s/%s)) -> [OK]\n",
		kx,
		kx.Type,
		kx.PeerNick,
		kx.MyNick,
		kx.Blob,
		kx.Server,
		kx.Channel)
	return
}

//
//
// Handle KEY Exchange MESSAGES..
//
//
func HandleKXMsg(msg []byte) (msgReply []byte, err error) {
	acutl.DebugLog.Printf("CALL HandleKXMsg(msg[%d]:[%s])\n", len(msg), msg)
	req := &ACKxMessage{}

	// let's unmarshall the message first
	err = json.Unmarshal(msg, req)
	if err != nil {
		acutl.DebugLog.Printf("RET HandlerKXMsg(%s) -> [Error: %s]\n", msg, err.Error())
		msgReply, _ = json.Marshal(&ACKxReply{
			Type:  R_KXERR,
			Bada:  false,
			Errno: -1,
			Blob:  []byte(err.Error()),
		})
		return
	}

	switch req.Type {
	case KXPACK:
		msgReply, err = req.HandlerKXPACK()
	case KXUNPACK:
		msgReply, err = req.HandlerKXUNPACK()
	default:
		err = fmt.Errorf("Invalid KX Message.")
		msgReply, _ = json.Marshal(&ACPkReply{
			Type:  R_KXERR,
			Bada:  false,
			Errno: -2,
			Blob:  []byte(err.Error()),
		})
	}

	acutl.DebugLog.Printf("RET HandleKXMsg(msg[%d]:[%s]) -> [reply[%d]: %s]\n", len(msg), msg, len(msgReply), msgReply)
	return
}
<|endoftext|>


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

package gameboy

import (
	"fmt"
	"io"
	"⚛sdl"
	"os"
)

type Config struct {
	SaveDir      string
	Verbose      bool
	Debug        bool
	Scale        int
	AudioFreq    int
	AudioBuffers int
	AudioDriver  string
	Fullscreen   bool

	Joystick        int
	JoyButtonA      int
	JoyButtonB      int
	JoyButtonStart  int
	JoyButtonSelect int
	JoyAxisX        int
	JoyAxisY        int
}

func Start(path string, cfg Config, in <-chan int, out chan<- interface{}) {
	var rom romImage
	var err interface{}

	defer func() {
		out <- err
	}()

	if rom, err = loadROM(path); err != nil {
		return
	}

	if cfg.Verbose {
		rom.printInfo()
	}

	if sdl.Init(sdl.INIT_VIDEO|sdl.INIT_AUDIO|sdl.INIT_JOYSTICK) != 0 {
		err = sdl.GetError()
		return
	}
	defer sdl.Quit()

	var mem *memory
	if mem, err = newMemory(rom, &cfg); err != nil {
		return
	}

	if e := mem.load(cfg.SaveDir); e != nil && cfg.Verbose {
		fmt.Fprintf(os.Stderr, "load failed: %v\n", e)
	}

	var audio *mixer
	if audio, err = newMixer(mem); err != nil {
		return
	}
	defer audio.close()

	sys := newCPU(mem)
	lcd := newDisplay(mem)

	mem.connect(sys, lcd, audio)

	joy := openJoystick(&cfg)
	if joy != nil {
		defer joy.Close()
	}

	go mem.monitorEvents()

	run(&cfg, sys, in)

	if e := mem.save(cfg.SaveDir); e != nil && cfg.Verbose {
		fmt.Fprintf(os.Stderr, "save failed: %v\n", e)
	}
}

func run(cfg *Config, sys *cpu, in <-chan int) {
	defer func() {
		if e := recover(); e != nil {
			if cfg.Debug {
				fmt.Fprintf(os.Stderr, "panic: %v\n\n", e)
				sys.dump(os.Stderr)
				fmt.Fprint(os.Stderr, "RUNTIME TRACE\n\n")
			}
			panic(e)
		}
	}()

	t := 0
	for {
		if t >= refreshTicks {
			select {
			case <-in:
				return
			default:
				if sys.quit {
					return
				}
			}
			t = 0
		}
		s := 0
		for s < 10 {
			ts := sys.step()
			sys.updateTimers(ts)
			s += ts
		}
		sys.lcd.step(s)
		sys.audio.step(s)
		t += s
	}
}

func openJoystick(cfg *Config) (joy *sdl.Joystick) {
	n := sdl.NumJoysticks()
	if n == 0 {
		if cfg.Verbose {
			fmt.Println("no joysticks")
		}
		return
	}

	if cfg.Joystick >= n {
		if cfg.Verbose {
			fmt.Printf("no such joystick: %d (found %d)\n",
				cfg.Joystick, n)
		}
		return
	}

	joy = sdl.JoystickOpen(cfg.Joystick)
	if joy == nil {
		fmt.Fprintf(os.Stderr,
			"failed to open joystick: %v\n",
			sdl.GetError())
		return
	}

	sdl.JoystickEventState(sdl.ENABLE)

	if cfg.Verbose {
		fmt.Printf("using joystick %d\n", cfg.Joystick)
	}

	return joy
}

func (rom romImage) printInfo() {
	fmt.Printf("Loaded ROM image '%s'\n", rom.title())
	fmt.Printf("Logo match: %t\n", rom.checkLogo())
	fmt.Printf("Header checksum: %t\n", rom.doHeaderChecksum())
	fmt.Printf("Global checksum: %t\n", rom.doGlobalChecksum())
	fmt.Printf("ERAM: %d bytes\n", rom.ramSize())
	if mbc, err := rom.mbcType(); err == nil {
		fmt.Printf("MBC: %d\n", mbc)
	}
}

func (sys *cpu) dump(w io.Writer) {
	fmt.Fprintf(w,
		"LAST INSTRUCTION\n"+
			"%04X\t%s\n\n"+
			"CPU STATE\n"+
			"%v\n\n",
		sys.mar, sys.disasm(sys.mar), sys)
	sys.dumpStack(w)
	sys.memory.dump(w)
}
<commit_msg>Change system stepping<commit_after>// Copyright 2011 Kevin Bulusek. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gameboy

import (
	"fmt"
	"io"
	"⚛sdl"
	"os"
)

type Config struct {
	SaveDir      string
	Verbose      bool
	Debug        bool
	Scale        int
	AudioFreq    int
	AudioBuffers int
	AudioDriver  string
	Fullscreen   bool

	Joystick        int
	JoyButtonA      int
	JoyButtonB      int
	JoyButtonStart  int
	JoyButtonSelect int
	JoyAxisX        int
	JoyAxisY        int
}

func Start(path string, cfg Config, in <-chan int, out chan<- interface{}) {
	var rom romImage
	var err interface{}

	defer func() {
		out <- err
	}()

	if rom, err = loadROM(path); err != nil {
		return
	}

	if cfg.Verbose {
		rom.printInfo()
	}

	if sdl.Init(sdl.INIT_VIDEO|sdl.INIT_AUDIO|sdl.INIT_JOYSTICK) != 0 {
		err = sdl.GetError()
		return
	}
	defer sdl.Quit()

	var mem *memory
	if mem, err = newMemory(rom, &cfg); err != nil {
		return
	}

	if e := mem.load(cfg.SaveDir); e != nil && cfg.Verbose {
		fmt.Fprintf(os.Stderr, "load failed: %v\n", e)
	}

	var audio *mixer
	if audio, err = newMixer(mem); err != nil {
		return
	}
	defer audio.close()

	sys := newCPU(mem)
	lcd := newDisplay(mem)

	mem.connect(sys, lcd, audio)

	joy := openJoystick(&cfg)
	if joy != nil {
		defer joy.Close()
	}

	go mem.monitorEvents()

	run(&cfg, sys, in)

	if e := mem.save(cfg.SaveDir); e != nil && cfg.Verbose {
		fmt.Fprintf(os.Stderr, "save failed: %v\n", e)
	}
}

func run(cfg *Config, sys *cpu, in <-chan int) {
	defer func() {
		if e := recover(); e != nil {
			if cfg.Debug {
				fmt.Fprintf(os.Stderr, "panic: %v\n\n", e)
				sys.dump(os.Stderr)
				fmt.Fprint(os.Stderr, "RUNTIME TRACE\n\n")
			}
			panic(e)
		}
	}()

	for !sys.quit {
		for t := 0; t < refreshTicks; {
			s := sys.step()
			sys.updateTimers(s)
			sys.lcd.step(s)
			sys.audio.step(s)
			t += s
		}
		select {
		case <-in:
			sys.quit = true
		default:
			// non-blocking
		}
	}
}

func openJoystick(cfg *Config) (joy *sdl.Joystick) {
	n := sdl.NumJoysticks()
	if n == 0 {
		if cfg.Verbose {
			fmt.Println("no joysticks")
		}
		return
	}

	if cfg.Joystick >= n {
		if cfg.Verbose {
			fmt.Printf("no such joystick: %d (found %d)\n",
				cfg.Joystick, n)
		}
		return
	}

	joy = sdl.JoystickOpen(cfg.Joystick)
	if joy == nil {
		fmt.Fprintf(os.Stderr,
			"failed to open joystick: %v\n",
			sdl.GetError())
		return
	}

	sdl.JoystickEventState(sdl.ENABLE)

	if cfg.Verbose {
		fmt.Printf("using joystick %d\n", cfg.Joystick)
	}

	return joy
}

func (rom romImage) printInfo() {
	fmt.Printf("Loaded ROM image '%s'\n", rom.title())
	fmt.Printf("Logo match: %t\n", rom.checkLogo())
	fmt.Printf("Header checksum: %t\n", rom.doHeaderChecksum())
	fmt.Printf("Global checksum: %t\n", rom.doGlobalChecksum())
	fmt.Printf("ERAM: %d bytes\n", rom.ramSize())
	if mbc, err := rom.mbcType(); err == nil {
		fmt.Printf("MBC: %d\n", mbc)
	}
}

func (sys *cpu) dump(w io.Writer) {
	fmt.Fprintf(w,
		"LAST INSTRUCTION\n"+
			"%04X\t%s\n\n"+
			"CPU STATE\n"+
			"%v\n\n",
		sys.mar, sys.disasm(sys.mar), sys)
	sys.dumpStack(w)
	sys.memory.dump(w)
}
<|endoftext|>


<commit_before>package elements

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStandardRelations(t *testing.T) {
	r1, ok := IsRelation("l-->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, Left, r1.direction)
	assert.Equal(t, Regular, r1.arrowTypeRight)
	assert.Equal(t, 0, r1.arrowTypeLeft)

	r2, ok := IsRelation("d|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, Down, r2.direction)
	assert.Equal(t, 1, r2.size)
	assert.Equal(t, Filled, r2.arrowTypeRight)
	assert.Equal(t, 0, r2.arrowTypeLeft)
	assert.Equal(t, Right, r2.arrowLocation)

	r3, ok := IsRelation("foo-->")
	assert.Equal(t, false, ok)
	assert.Nil(t, r3)

	r4, ok := IsRelation("u-->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, Up, r4.direction)
	assert.Equal(t, 2, r4.size)
	assert.Equal(t, Regular, r4.arrowTypeRight)
	assert.Equal(t, 0, r4.arrowTypeLeft)

	r5, ok := IsRelation("u-f-->")
	assert.Equal(t, false, ok)
	assert.Nil(t, r5)
}

func TestRelationWithText(t *testing.T) {
	r1, ok := IsRelation("<-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "This is a ] test", r1.text)
	assert.Equal(t, 2, r1.size)
	assert.Equal(t, Right, r1.direction)
	assert.Equal(t, Both, r1.arrowLocation)
	assert.Equal(t, Regular, r1.arrowTypeLeft)
	assert.Equal(t, Regular, r1.arrowTypeRight)

	r2, ok := IsRelation("<l-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "This is a ] test", r2.text)
	assert.Equal(t, 2, r2.size)
	assert.Equal(t, Left, r2.direction)
	assert.Equal(t, Both, r2.arrowLocation)
	assert.Equal(t, Regular, r2.arrowTypeLeft)
	assert.Equal(t, Regular, r2.arrowTypeRight)

	r3, ok := IsRelation("<|l-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "This is a ] test", r3.text)
	assert.Equal(t, 2, r3.size)
	assert.Equal(t, Left, r3.direction)
	assert.Equal(t, Both, r3.arrowLocation)
	assert.Equal(t, Filled, r3.arrowTypeLeft)
	assert.Equal(t, Regular, r3.arrowTypeRight)

	r4, ok := IsRelation("<|l-[This is a ] test]-|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, "This is a ] test", r4.text)
	assert.Equal(t, 2, r4.size)
	assert.Equal(t, Left, r4.direction)
	assert.Equal(t, Both, r4.arrowLocation)
	assert.Equal(t, Filled, r4.arrowTypeLeft)
	assert.Equal(t, Filled, r4.arrowTypeRight)
}

func TestLeftRelation(t *testing.T) {
	r1, ok := IsRelation("<.[Foo].")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo", r1.text)
	assert.Equal(t, 2, r1.size)
	assert.Equal(t, Left, r1.direction)
	assert.Equal(t, Left, r1.arrowLocation)
	assert.Equal(t, Regular, r1.arrowTypeLeft)
	assert.Equal(t, Dotted, r1.kind)
	assert.Equal(t, 0, r1.arrowTypeRight)

	r2, ok := IsRelation("<u===[Foo ✓ Bar]=|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 4, r2.size)
	assert.Equal(t, Up, r2.direction)
	assert.Equal(t, Both, r2.arrowLocation)
	assert.Equal(t, Regular, r2.arrowTypeLeft)
	assert.Equal(t, Thick, r2.kind)
	assert.Equal(t, Filled, r2.arrowTypeRight)

	r3, ok := IsRelation("<|u==[Foo ✓ Bar]=")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "Foo ✓ Bar", r3.text)
	assert.Equal(t, 3, r3.size)
	assert.Equal(t, Up, r3.direction)
	assert.Equal(t, Left, r3.arrowLocation)
	assert.Equal(t, Filled, r3.arrowTypeLeft)
	assert.Equal(t, Thick, r3.kind)
	assert.Equal(t, 0, r3.arrowTypeRight)
}

func TestSingleRelations(t *testing.T) {
	r1, ok := IsRelation("r[Foo ✓ Bar]>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo ✓ Bar", r1.text)
	assert.Equal(t, 1, r1.size)
	assert.Equal(t, Right, r1.direction)
	assert.Equal(t, Right, r1.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r1.kind)
	assert.Equal(t, Regular, r1.arrowTypeRight)

	r2, ok := IsRelation("l[Foo ✓ Bar]|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 1, r2.size)
	assert.Equal(t, Left, r2.direction)
	assert.Equal(t, Right, r2.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r2.kind)
	assert.Equal(t, Filled, r2.arrowTypeRight)
}

func TestRelationWithoutArrows(t *testing.T) {
	r1, ok := IsRelation("u-[Foo ✓ Bar]---")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo ✓ Bar", r1.text)
	assert.Equal(t, 4, r1.size)
	assert.Equal(t, Up, r1.direction)
	assert.Equal(t, 0, r1.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r1.kind)
	assert.Equal(t, 0, r1.arrowTypeRight)

	r2, ok := IsRelation("u[Foo ✓ Bar]---")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 3, r2.size)
	assert.Equal(t, Up, r2.direction)
	assert.Equal(t, 0, r2.arrowLocation)
	assert.Equal(t, 0, r2.arrowTypeLeft)
	assert.Equal(t, Dashed, r2.kind)
	assert.Equal(t, 0, r2.arrowTypeRight)

	r3, ok := IsRelation("l[Foo ✓ Bar]....")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "Foo ✓ Bar", r3.text)
	assert.Equal(t, 4, r3.size)
	assert.Equal(t, Left, r3.direction)
	assert.Equal(t, 0, r3.arrowLocation)
	assert.Equal(t, 0, r3.arrowTypeLeft)
	assert.Equal(t, Dotted, r3.kind)
	assert.Equal(t, 0, r2.arrowTypeRight)

	r4, ok := IsRelation("u[]   ")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, "", r4.text)
	assert.Equal(t, 3, r4.size)
	assert.Equal(t, Up, r4.direction)
	assert.Equal(t, 0, r4.arrowLocation)
	assert.Equal(t, 0, r4.arrowTypeLeft)
	assert.Equal(t, Empty, r4.kind)
	assert.Equal(t, 0, r4.arrowTypeRight)

	r5, ok := IsRelation("u[abc]==|v")
	assert.Equal(t, false, ok)
	assert.Nil(t, r5)
}
<commit_msg>Added constructor tests<commit_after>package elements

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStandardRelations(t *testing.T) {
	r1, ok := IsRelation("l-->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, Left, r1.direction)
	assert.Equal(t, Regular, r1.arrowTypeRight)
	assert.Equal(t, 0, r1.arrowTypeLeft)

	r2, ok := IsRelation("d|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, Down, r2.direction)
	assert.Equal(t, 1, r2.size)
	assert.Equal(t, Filled, r2.arrowTypeRight)
	assert.Equal(t, 0, r2.arrowTypeLeft)
	assert.Equal(t, Right, r2.arrowLocation)

	r3, ok := IsRelation("foo-->")
	assert.Equal(t, false, ok)
	assert.Nil(t, r3)

	r4, ok := IsRelation("u-->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, Up, r4.direction)
	assert.Equal(t, 2, r4.size)
	assert.Equal(t, Regular, r4.arrowTypeRight)
	assert.Equal(t, 0, r4.arrowTypeLeft)

	r5, ok := IsRelation("u-f-->")
	assert.Equal(t, false, ok)
	assert.Nil(t, r5)
}

func TestRelationWithText(t *testing.T) {
	r1, ok := IsRelation("<-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "This is a ] test", r1.text)
	assert.Equal(t, 2, r1.size)
	assert.Equal(t, Right, r1.direction)
	assert.Equal(t, Both, r1.arrowLocation)
	assert.Equal(t, Regular, r1.arrowTypeLeft)
	assert.Equal(t, Regular, r1.arrowTypeRight)

	r2, ok := IsRelation("<l-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "This is a ] test", r2.text)
	assert.Equal(t, 2, r2.size)
	assert.Equal(t, Left, r2.direction)
	assert.Equal(t, Both, r2.arrowLocation)
	assert.Equal(t, Regular, r2.arrowTypeLeft)
	assert.Equal(t, Regular, r2.arrowTypeRight)

	r3, ok := IsRelation("<|l-[This is a ] test]->")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "This is a ] test", r3.text)
	assert.Equal(t, 2, r3.size)
	assert.Equal(t, Left, r3.direction)
	assert.Equal(t, Both, r3.arrowLocation)
	assert.Equal(t, Filled, r3.arrowTypeLeft)
	assert.Equal(t, Regular, r3.arrowTypeRight)

	r4, ok := IsRelation("<|l-[This is a ] test]-|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, "This is a ] test", r4.text)
	assert.Equal(t, 2, r4.size)
	assert.Equal(t, Left, r4.direction)
	assert.Equal(t, Both, r4.arrowLocation)
	assert.Equal(t, Filled, r4.arrowTypeLeft)
	assert.Equal(t, Filled, r4.arrowTypeRight)
}

func TestLeftRelation(t *testing.T) {
	r1, ok := IsRelation("<.[Foo].")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo", r1.text)
	assert.Equal(t, 2, r1.size)
	assert.Equal(t, Left, r1.direction)
	assert.Equal(t, Left, r1.arrowLocation)
	assert.Equal(t, Regular, r1.arrowTypeLeft)
	assert.Equal(t, Dotted, r1.kind)
	assert.Equal(t, 0, r1.arrowTypeRight)

	r2, ok := IsRelation("<u===[Foo ✓ Bar]=|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 4, r2.size)
	assert.Equal(t, Up, r2.direction)
	assert.Equal(t, Both, r2.arrowLocation)
	assert.Equal(t, Regular, r2.arrowTypeLeft)
	assert.Equal(t, Thick, r2.kind)
	assert.Equal(t, Filled, r2.arrowTypeRight)

	r3, ok := IsRelation("<|u==[Foo ✓ Bar]=")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "Foo ✓ Bar", r3.text)
	assert.Equal(t, 3, r3.size)
	assert.Equal(t, Up, r3.direction)
	assert.Equal(t, Left, r3.arrowLocation)
	assert.Equal(t, Filled, r3.arrowTypeLeft)
	assert.Equal(t, Thick, r3.kind)
	assert.Equal(t, 0, r3.arrowTypeRight)
}

func TestSingleRelations(t *testing.T) {
	r1, ok := IsRelation("r[Foo ✓ Bar]>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo ✓ Bar", r1.text)
	assert.Equal(t, 1, r1.size)
	assert.Equal(t, Right, r1.direction)
	assert.Equal(t, Right, r1.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r1.kind)
	assert.Equal(t, Regular, r1.arrowTypeRight)

	r2, ok := IsRelation("l[Foo ✓ Bar]|>")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 1, r2.size)
	assert.Equal(t, Left, r2.direction)
	assert.Equal(t, Right, r2.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r2.kind)
	assert.Equal(t, Filled, r2.arrowTypeRight)
}

func TestRelationWithoutArrows(t *testing.T) {
	r1, ok := IsRelation("u-[Foo ✓ Bar]---")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r1)
	assert.Equal(t, "Foo ✓ Bar", r1.text)
	assert.Equal(t, 4, r1.size)
	assert.Equal(t, Up, r1.direction)
	assert.Equal(t, 0, r1.arrowLocation)
	assert.Equal(t, 0, r1.arrowTypeLeft)
	assert.Equal(t, Dashed, r1.kind)
	assert.Equal(t, 0, r1.arrowTypeRight)

	r2, ok := IsRelation("u[Foo ✓ Bar]---")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r2)
	assert.Equal(t, "Foo ✓ Bar", r2.text)
	assert.Equal(t, 3, r2.size)
	assert.Equal(t, Up, r2.direction)
	assert.Equal(t, 0, r2.arrowLocation)
	assert.Equal(t, 0, r2.arrowTypeLeft)
	assert.Equal(t, Dashed, r2.kind)
	assert.Equal(t, 0, r2.arrowTypeRight)

	r3, ok := IsRelation("l[Foo ✓ Bar]....")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r3)
	assert.Equal(t, "Foo ✓ Bar", r3.text)
	assert.Equal(t, 4, r3.size)
	assert.Equal(t, Left, r3.direction)
	assert.Equal(t, 0, r3.arrowLocation)
	assert.Equal(t, 0, r3.arrowTypeLeft)
	assert.Equal(t, Dotted, r3.kind)
	assert.Equal(t, 0, r2.arrowTypeRight)

	r4, ok := IsRelation("u[]   ")
	assert.Equal(t, true, ok)
	assert.NotNil(t, r4)
	assert.Equal(t, "", r4.text)
	assert.Equal(t, 3, r4.size)
	assert.Equal(t, Up, r4.direction)
	assert.Equal(t, 0, r4.arrowLocation)
	assert.Equal(t, 0, r4.arrowTypeLeft)
	assert.Equal(t, Empty, r4.kind)
	assert.Equal(t, 0, r4.arrowTypeRight)

	r5, ok := IsRelation("u[abc]==|v")
	assert.Equal(t, false, ok)
	assert.Nil(t, r5)
}

func TestNewRelation(t *testing.T) {
	r, err := NewRelation("<u--[Test]---|>")
	assert.NotNil(t, r)
	assert.Nil(t, err)
	assert.Equal(t, Up, r.direction)
	assert.Equal(t, Both, r.arrowLocation)
	assert.Equal(t, Regular, r.arrowTypeLeft)
	assert.Equal(t, Filled, r.arrowTypeRight)
	assert.Equal(t, 5, r.size)
	assert.Equal(t, "Test", r.text)

	r1, err := NewRelation("<u-l-[Test]---|>")
	assert.Nil(t, r1)
	assert.Equal(t, err, errors.New("<u-l-[Test]---|> is not a valid relation"))
}
<|endoftext|>