<commit_before>// +build go1.7

package docker

import (
	"context"
	"crypto/tls"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/fnproject/fn/api/common"
	"github.com/fsouza/go-dockerclient"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
	"github.com/sirupsen/logrus"
)

const (
	retryTimeout = 10 * time.Minute
	pauseTimeout = 5 * time.Second
)

// wrap docker client calls so we can retry 500s, kind of sucks but fsouza doesn't
// bake in retries we can use internally, could contribute it at some point, would
// be much more convenient if we didn't have to do this, but it's better than ad hoc retries.
// also adds timeouts to many operations, varying by operation
// TODO could generate this, maybe not worth it, may not change often
type dockerClient interface {
	// Each of these are github.com/fsouza/go-dockerclient methods

	AttachToContainerNonBlocking(ctx context.Context, opts docker.AttachToContainerOptions) (docker.CloseWaiter, error)
	WaitContainerWithContext(id string, ctx context.Context) (int, error)
	StartContainerWithContext(id string, hostConfig *docker.HostConfig, ctx context.Context) error
	CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error)
	RemoveContainer(opts docker.RemoveContainerOptions) error
	PauseContainer(id string, ctx context.Context) error
	UnpauseContainer(id string, ctx context.Context) error
	PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
	InspectImage(ctx context.Context, name string) (*docker.Image, error)
	InspectContainerWithContext(container string, ctx context.Context) (*docker.Container, error)
	Stats(opts docker.StatsOptions) error
	Info(ctx context.Context) (*docker.DockerInfo, error)
}

// TODO: switch to github.com/docker/engine-api
func newClient() dockerClient {
	// TODO this was much easier, don't need special settings at the moment
	// docker, err := docker.NewClient(conf.Docker)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create docker client")
	}

	t := &http.Transport{
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 1 * time.Minute,
		}).Dial,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(8192),
		},
		TLSHandshakeTimeout:   10 * time.Second,
		MaxIdleConnsPerHost:   512,
		Proxy:                 http.ProxyFromEnvironment,
		MaxIdleConns:          512,
		IdleConnTimeout:       90 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	client.HTTPClient = &http.Client{Transport: t}

	if err := client.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to docker daemon")
	}

	client.SetTimeout(120 * time.Second)

	// get 2 clients, one with a small timeout, one with no timeout to use contexts

	clientNoTimeout, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create other docker client")
	}

	clientNoTimeout.HTTPClient = &http.Client{Transport: t}

	if err := clientNoTimeout.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to other docker daemon")
	}

	return &dockerWrap{client, clientNoTimeout}
}

type dockerWrap struct {
	docker          *docker.Client
	dockerNoTimeout *docker.Client
}

func (d *dockerWrap) retry(ctx context.Context, f func() error) error {
	var i int
	var err error
	span := opentracing.SpanFromContext(ctx)
	defer func() { span.LogFields(log.Int("docker_call_retries", i)) }()

	logger := common.Logger(ctx)
	var b common.Backoff
	// 10 retries w/o change to backoff is ~13s if ops take ~0 time
	for ; i < 10; i++ {
		select {
		case <-ctx.Done():
			span.LogFields(log.String("task", "fail.docker"))
			logger.WithError(ctx.Err()).Warnf("docker call timed out")
			return ctx.Err()
		default:
		}

		err = filter(ctx, f())
		if common.IsTemporary(err) || isDocker50x(err) {
			logger.WithError(err).Warn("docker temporary error, retrying")
			b.Sleep(ctx)
			span.LogFields(log.String("task", "tmperror.docker"))
			continue
		}
		if err != nil {
			span.LogFields(log.String("task", "error.docker"))
		}
		return err
	}
	return err // TODO could return context.DeadlineExceeded which ~makes sense
}

func isDocker50x(err error) bool {
	derr, ok := err.(*docker.Error)
	return ok && derr.Status >= 500
}

// implement common.Temporary()
type temporary struct {
	error
}

func (t *temporary) Temporary() bool { return true }

func temp(err error) error {
	return &temporary{err}
}

// some 500s are totally cool
func filter(ctx context.Context, err error) error {
	log := common.Logger(ctx)
	// "API error (500): {\"message\":\"service endpoint with name task-57d722ecdecb9e7be16aff17 already exists\"}\n" -> ok since container exists
	switch {
	default:
		return err
	case err == nil:
		return err
	case strings.Contains(err.Error(), "service endpoint with name"):
	}
	log.WithError(err).Warn("filtering error")
	return nil
}

func filterNoSuchContainer(ctx context.Context, err error) error {
	log := common.Logger(ctx)
	if err == nil {
		return nil
	}
	_, containerNotFound := err.(*docker.NoSuchContainer)
	dockerErr, ok := err.(*docker.Error)
	if containerNotFound || (ok && dockerErr.Status == 404) {
		log.WithError(err).Error("filtering error")
		return nil
	}
	return err
}

func (d *dockerWrap) Info(ctx context.Context) (info *docker.DockerInfo, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_server_version")
	defer span.Finish()

	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		info, err = d.docker.Info()
		return err
	})
	return info, err
}

func (d *dockerWrap) AttachToContainerNonBlocking(ctx context.Context, opts docker.AttachToContainerOptions) (w docker.CloseWaiter, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_attach_container")
	defer span.Finish()

	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		w, err = d.docker.AttachToContainerNonBlocking(opts)
		if err != nil {
			// always retry if attach errors, task is running, we want logs!
			err = temp(err)
		}
		return err
	})
	return w, err
}

func (d *dockerWrap) WaitContainerWithContext(id string, ctx context.Context) (code int, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_wait_container")
	defer span.Finish()
	err = d.retry(ctx, func() error {
		code, err = d.dockerNoTimeout.WaitContainerWithContext(id, ctx)
		return err
	})
	return code, filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) StartContainerWithContext(id string, hostConfig *docker.HostConfig, ctx context.Context) (err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_start_container")
	defer span.Finish()
	err = d.retry(ctx, func() error {
		err = d.dockerNoTimeout.StartContainerWithContext(id, hostConfig, ctx)
		if _, ok := err.(*docker.NoSuchContainer); ok {
			// for some reason create will sometimes return successfully then say no such container here. wtf. so just retry like normal
			return temp(err)
		}
		return err
	})
	return err
}

func (d *dockerWrap) CreateContainer(opts docker.CreateContainerOptions) (c *docker.Container, err error) {
	span, ctx := opentracing.StartSpanFromContext(opts.Context, "docker_create_container")
	defer span.Finish()
	err = d.retry(ctx, func() error {
		c, err = d.dockerNoTimeout.CreateContainer(opts)
		return err
	})
	return c, err
}

func (d *dockerWrap) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) (err error) {
	span, ctx := opentracing.StartSpanFromContext(opts.Context, "docker_pull_image")
	defer span.Finish()
	err = d.retry(ctx, func() error {
		err = d.dockerNoTimeout.PullImage(opts, auth)
		return err
	})
	return err
}

func (d *dockerWrap) RemoveContainer(opts docker.RemoveContainerOptions) (err error) {
	// extract the span, but do not keep the context, since the enclosing context
	// may be timed out, and we still want to remove the container. TODO in caller? who cares?
	span, _ := opentracing.StartSpanFromContext(opts.Context, "docker_remove_container")
	defer span.Finish()
	ctx := opentracing.ContextWithSpan(context.Background(), span)

	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		err = d.docker.RemoveContainer(opts)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) PauseContainer(id string, ctx context.Context) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "docker_pause_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, pauseTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		err = d.docker.PauseContainer(id)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) UnpauseContainer(id string, ctx context.Context) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "docker_unpause_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, pauseTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		err = d.docker.UnpauseContainer(id)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) InspectImage(ctx context.Context, name string) (i *docker.Image, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_inspect_image")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		i, err = d.docker.InspectImage(name)
		return err
	})
	return i, err
}

func (d *dockerWrap) InspectContainerWithContext(container string, ctx context.Context) (c *docker.Container, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_inspect_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, func() error {
		c, err = d.docker.InspectContainerWithContext(container, ctx)
		return err
	})
	return c, err
}

func (d *dockerWrap) Stats(opts docker.StatsOptions) (err error) {
	// we can't retry this one this way since the callee closes the
	// stats chan, need a fancier retry mechanism where we can swap out
	// channels, but stats isn't crucial so... be lazy for now
	return d.docker.Stats(opts)

	//err = d.retry(func() error {
	//err = d.docker.Stats(opts)
	//return err
	//})
	//return err
}
<commit_msg>fn: add docker command info to retry when logging errors (#795)<commit_after>// +build go1.7

package docker

import (
	"context"
	"crypto/tls"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/fnproject/fn/api/common"
	"github.com/fsouza/go-dockerclient"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
	"github.com/sirupsen/logrus"
)

const (
	retryTimeout = 10 * time.Minute
	pauseTimeout = 5 * time.Second
)

// wrap docker client calls so we can retry 500s, kind of sucks but fsouza doesn't
// bake in retries we can use internally, could contribute it at some point, would
// be much more convenient if we didn't have to do this, but it's better than ad hoc retries.
// also adds timeouts to many operations, varying by operation
// TODO could generate this, maybe not worth it, may not change often
type dockerClient interface {
	// Each of these are github.com/fsouza/go-dockerclient methods

	AttachToContainerNonBlocking(ctx context.Context, opts docker.AttachToContainerOptions) (docker.CloseWaiter, error)
	WaitContainerWithContext(id string, ctx context.Context) (int, error)
	StartContainerWithContext(id string, hostConfig *docker.HostConfig, ctx context.Context) error
	CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error)
	RemoveContainer(opts docker.RemoveContainerOptions) error
	PauseContainer(id string, ctx context.Context) error
	UnpauseContainer(id string, ctx context.Context) error
	PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error
	InspectImage(ctx context.Context, name string) (*docker.Image, error)
	InspectContainerWithContext(container string, ctx context.Context) (*docker.Container, error)
	Stats(opts docker.StatsOptions) error
	Info(ctx context.Context) (*docker.DockerInfo, error)
}

// TODO: switch to github.com/docker/engine-api
func newClient() dockerClient {
	// TODO this was much easier, don't need special settings at the moment
	// docker, err := docker.NewClient(conf.Docker)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create docker client")
	}

	t := &http.Transport{
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 1 * time.Minute,
		}).Dial,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(8192),
		},
		TLSHandshakeTimeout:   10 * time.Second,
		MaxIdleConnsPerHost:   512,
		Proxy:                 http.ProxyFromEnvironment,
		MaxIdleConns:          512,
		IdleConnTimeout:       90 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	client.HTTPClient = &http.Client{Transport: t}

	if err := client.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to docker daemon")
	}

	client.SetTimeout(120 * time.Second)

	// get 2 clients, one with a small timeout, one with no timeout to use contexts

	clientNoTimeout, err := docker.NewClientFromEnv()
	if err != nil {
		logrus.WithError(err).Fatal("couldn't create other docker client")
	}

	clientNoTimeout.HTTPClient = &http.Client{Transport: t}

	if err := clientNoTimeout.Ping(); err != nil {
		logrus.WithError(err).Fatal("couldn't connect to other docker daemon")
	}

	return &dockerWrap{client, clientNoTimeout}
}

type dockerWrap struct {
	docker          *docker.Client
	dockerNoTimeout *docker.Client
}

func (d *dockerWrap) retry(ctx context.Context, logger logrus.FieldLogger, f func() error) error {
	var i int
	var err error
	span := opentracing.SpanFromContext(ctx)
	defer func() { span.LogFields(log.Int("docker_call_retries", i)) }()

	var b common.Backoff
	// 10 retries w/o change to backoff is ~13s if ops take ~0 time
	for ; i < 10; i++ {
		select {
		case <-ctx.Done():
			span.LogFields(log.String("task", "fail.docker"))
			logger.WithError(ctx.Err()).Warnf("docker call timed out")
			return ctx.Err()
		default:
		}

		err = filter(ctx, f())
		if common.IsTemporary(err) || isDocker50x(err) {
			logger.WithError(err).Warn("docker temporary error, retrying")
			b.Sleep(ctx)
			span.LogFields(log.String("task", "tmperror.docker"))
			continue
		}
		if err != nil {
			span.LogFields(log.String("task", "error.docker"))
		}
		return err
	}
	return err // TODO could return context.DeadlineExceeded which ~makes sense
}

func isDocker50x(err error) bool {
	derr, ok := err.(*docker.Error)
	return ok && derr.Status >= 500
}

// implement common.Temporary()
type temporary struct {
	error
}

func (t *temporary) Temporary() bool { return true }

func temp(err error) error {
	return &temporary{err}
}

// some 500s are totally cool
func filter(ctx context.Context, err error) error {
	log := common.Logger(ctx)
	// "API error (500): {\"message\":\"service endpoint with name task-57d722ecdecb9e7be16aff17 already exists\"}\n" -> ok since container exists
	switch {
	default:
		return err
	case err == nil:
		return err
	case strings.Contains(err.Error(), "service endpoint with name"):
	}
	log.WithError(err).Warn("filtering error")
	return nil
}

func filterNoSuchContainer(ctx context.Context, err error) error {
	log := common.Logger(ctx)
	if err == nil {
		return nil
	}
	_, containerNotFound := err.(*docker.NoSuchContainer)
	dockerErr, ok := err.(*docker.Error)
	if containerNotFound || (ok && dockerErr.Status == 404) {
		log.WithError(err).Error("filtering error")
		return nil
	}
	return err
}

func (d *dockerWrap) Info(ctx context.Context) (info *docker.DockerInfo, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_server_version")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "DockerInfo")
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, logger, func() error {
		info, err = d.docker.Info()
		return err
	})
	return info, err
}

func (d *dockerWrap) AttachToContainerNonBlocking(ctx context.Context, opts docker.AttachToContainerOptions) (w docker.CloseWaiter, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_attach_container")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "AttachContainer")
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()
	err = d.retry(ctx, logger, func() error {
		w, err = d.docker.AttachToContainerNonBlocking(opts)
		if err != nil {
			// always retry if attach errors, task is running, we want logs!
			err = temp(err)
		}
		return err
	})
	return w, err
}

func (d *dockerWrap) WaitContainerWithContext(id string, ctx context.Context) (code int, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_wait_container")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "WaitContainer")
	err = d.retry(ctx, logger, func() error {
		code, err = d.dockerNoTimeout.WaitContainerWithContext(id, ctx)
		return err
	})
	return code, filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) StartContainerWithContext(id string, hostConfig *docker.HostConfig, ctx context.Context) (err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_start_container")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "StartContainer")
	err = d.retry(ctx, logger, func() error {
		err = d.dockerNoTimeout.StartContainerWithContext(id, hostConfig, ctx)
		if _, ok := err.(*docker.NoSuchContainer); ok {
			// for some reason create will sometimes return successfully then say no such container here. wtf. so just retry like normal
			return temp(err)
		}
		return err
	})
	return err
}

func (d *dockerWrap) CreateContainer(opts docker.CreateContainerOptions) (c *docker.Container, err error) {
	span, ctx := opentracing.StartSpanFromContext(opts.Context, "docker_create_container")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "CreateContainer")
	err = d.retry(ctx, logger, func() error {
		c, err = d.dockerNoTimeout.CreateContainer(opts)
		return err
	})
	return c, err
}

func (d *dockerWrap) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) (err error) {
	span, ctx := opentracing.StartSpanFromContext(opts.Context, "docker_pull_image")
	defer span.Finish()

	logger := common.Logger(ctx).WithField("docker_cmd", "PullImage")
	err = d.retry(ctx, logger, func() error {
		err = d.dockerNoTimeout.PullImage(opts, auth)
		return err
	})
	return err
}

func (d *dockerWrap) RemoveContainer(opts docker.RemoveContainerOptions) (err error) {
	// extract the span, but do not keep the context, since the enclosing context
	// may be timed out, and we still want to remove the container. TODO in caller? who cares?
	span, _ := opentracing.StartSpanFromContext(opts.Context, "docker_remove_container")
	defer span.Finish()
	ctx := opentracing.ContextWithSpan(context.Background(), span)

	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()

	logger := common.Logger(ctx).WithField("docker_cmd", "RemoveContainer")
	err = d.retry(ctx, logger, func() error {
		err = d.docker.RemoveContainer(opts)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) PauseContainer(id string, ctx context.Context) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "docker_pause_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, pauseTimeout)
	defer cancel()

	logger := common.Logger(ctx).WithField("docker_cmd", "PauseContainer")
	err = d.retry(ctx, logger, func() error {
		err = d.docker.PauseContainer(id)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) UnpauseContainer(id string, ctx context.Context) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "docker_unpause_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, pauseTimeout)
	defer cancel()

	logger := common.Logger(ctx).WithField("docker_cmd", "UnpauseContainer")
	err = d.retry(ctx, logger, func() error {
		err = d.docker.UnpauseContainer(id)
		return err
	})
	return filterNoSuchContainer(ctx, err)
}

func (d *dockerWrap) InspectImage(ctx context.Context, name string) (i *docker.Image, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_inspect_image")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()

	logger := common.Logger(ctx).WithField("docker_cmd", "InspectImage")
	err = d.retry(ctx, logger, func() error {
		i, err = d.docker.InspectImage(name)
		return err
	})
	return i, err
}

func (d *dockerWrap) InspectContainerWithContext(container string, ctx context.Context) (c *docker.Container, err error) {
	span, ctx := opentracing.StartSpanFromContext(ctx, "docker_inspect_container")
	defer span.Finish()
	ctx, cancel := context.WithTimeout(ctx, retryTimeout)
	defer cancel()

	logger := common.Logger(ctx).WithField("docker_cmd", "InspectContainer")
	err = d.retry(ctx, logger, func() error {
		c, err = d.docker.InspectContainerWithContext(container, ctx)
		return err
	})
	return c, err
}

func (d *dockerWrap) Stats(opts docker.StatsOptions) (err error) {
	// we can't retry this one this way since the callee closes the
	// stats chan, need a fancier retry mechanism where we can swap out
	// channels, but stats isn't crucial so... be lazy for now
	return d.docker.Stats(opts)

	//err = d.retry(func() error {
	//err = d.docker.Stats(opts)
	//return err
	//})
	//return err
}
<|endoftext|>


<commit_before>package gomarathon

// RequestOptions passed for query api
type RequestOptions struct {
	Method string
	Path   string
	Datas  interface{}
	Params *Parameters
}

// Parameters to build url query
type Parameters struct {
	Cmd         string
	Host        string
	Scale       bool
	CallbackURL string
	Embed       string
}

// Response representation of a full marathon response
type Response struct {
	Code         int
	Apps         []*Application `json:"apps,omitempty"`
	App          *Application   `json:"app,omitempty"`
	Versions     []string       `json:",omitempty"`
	Tasks        []*Task        `json:"tasks,omitempty"`
	DeploymentId string         `json:"deployment_id,omitempty"`
	Version      string         `json:"version,omitempty"`
}

// Application marathon application see :
// https://github.com/mesosphere/marathon/blob/master/REST.md#apps
type Application struct {
	ID                    string            `json:"id"`
	Cmd                   string            `json:"cmd,omitempty"`
	Constraints           [][]string        `json:"constraints,omitempty"`
	Container             *Container        `json:"container,omitempty"`
	CPUs                  float32           `json:"cpus,omitempty"`
	Deployments           []*Deployment     `json:"deployments,omitempty"`
	Env                   map[string]string `json:"env,omitempty"`
	Executor              string            `json:"executor,omitempty"`
	HealthChecks          []*HealthCheck    `json:"healthChecks,omitempty"`
	Instances             int               `json:"instances,omitemptys"`
	Mem                   float32           `json:"mem,omitempty"`
	Tasks                 []*Task           `json:"tasks,omitempty"`
	Ports                 []int             `json:"ports,omitempty"`
	RequirePorts          bool              `json:"requirePorts,omitempty"`
	BackoffSeconds        int               `json:"backoffSeconds,omitempty"`
	BackoffFactor         float32           `json:"backoffFactor,omitempty"`
	MaxLaunchDelaySeconds float32           `json:"maxLaunchDelaySeconds,omitempty"`
	TasksRunning          int               `json:"tasksRunning,omitempty"`
	TasksStaged           int               `json:"tasksStaged,omitempty"`
	UpgradeStrategy       *UpgradeStrategy  `json:"upgradeStrategy,omitempty"`
	Uris                  []string          `json:"uris,omitempty"`
	Version               string            `json:"version,omitempty"`
	Labels                map[string]string `json:"labels,omitempty"`
	TaskStats             *TaskStats        `json:"taskStats,omitempty"`
}

type TaskStats struct {
	StartedAfterLastScaling *TaskStatWrapper `json:"startedAfterLastScaling"`
	WithLatestConfig        *TaskStatWrapper `json:"withLatestConfig"`
	totalSummary            *TaskStatWrapper `json:"totalSummary"`
}

type TaskStatWrapper struct {
	Stats *TaskStat `json:"stats"`
}

type TaskStat struct {
	Counts   *TaskCounts   `json:"counts"`
	LifeTime *TaskLifetime `json:"lifeTime"`
}

type TaskCounts struct {
	Staged    int `json:"staged"`
	Running   int `json:"running"`
	Healthy   int `json:"healthy"`
	Unhealthy int `json:"unhealthy"`
}

type TaskLifetime struct {
	AverageSeconds float32 `json:"averageSeconds"`
	MedianSeconds  float32 `json:"medianSeconds"`
}

// Container is docker parameters
type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes []*Volume `json:"volumes,omitempty"`
}

// Docker options
type Docker struct {
	Image        string         `json:"image,omitempty"`
	Network      string         `json:"network,omitempty"`
	PortMappings []*PortMapping `json:"portMappings,omitempty"`
	Privileged   bool           `json:"privileged`
	Parameters   []*DockerParam  `json:"parameters,omitempty"`
}
type DockerParam struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Volume is used for mounting a host directory as a container volume
type Volume struct {
	ContainerPath string `json:"containerPath,omitempty"`
	HostPath      string `json:"hostPath,omitempty"`
	Mode          string `json:"mode,omitempty"`
}

// Container PortMappings
type PortMapping struct {
	ContainerPort int    `json:"containerPort,omitempty"`
	HostPort      int    `json:"hostPort,omitempty"`
	ServicePort   int    `json:"servicePort,omitempty"`
	Protocol      string `json:"protocol,omitempty"`
}

// UpgradeStrategy has a minimumHealthCapacity which defines the minimum number of healty nodes
type UpgradeStrategy struct {
	MinimumHealthCapacity float32 `json:"minimumHealthCapacity,omitempty"`
}

// HealthCheck is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#healthchecks
type HealthCheck struct {
	Protocol               string `json:"protocol,omitempty"`
	Path                   string `json:"path,omitempty"`
	GracePeriodSeconds     int    `json:"gracePeriodSeconds,omitempty"`
	IntervalSeconds        int    `json:"intervalSeconds,omitempty"`
	PortIndex              int    `json:"portIndex,omitempty"`
	TimeoutSeconds         int    `json:"timeoutSeconds,omitempty"`
	MaxConsecutiveFailures int    `json:"maxConsecutiveFailures"`
}

type HealthCheckResult struct {
	Alive               bool   `json:"alive,omitempty"`
	ConsecutiveFailures int    `json:"consecutiveFailures,omitempty"`
	FirstSuccess        string `json:"firstSuccess,omitempty"`
	LastFailure         string `json:"lastFailure,omitempty"`
	LastSuccess         string `json:"lastSuccess,omitempty"`
	TaskID              string `json:"taskId,omitempty"`
}

// Task is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#tasks
type Task struct {
	AppID              string               `json:"appId"`
	Host               string               `json:"host"`
	ID                 string               `json:"id"`
	Ports              []int                `json:"ports"`
	StagedAt           string               `json:"stagedAt"`
	StartedAt          string               `json:"startedAt"`
	Version            string               `json:"version"`
	HealthCheckResults []*HealthCheckResult `json:"healthCheckResults"`
}

// Deployment is described here:
// https://mesosphere.github.io/marathon/docs/rest-api.html#get-/v2/deployments
type Deployment struct {
	AffectedApps   []string          `json:"affectedApps"`
	ID             string            `json:"id"`
	Steps          []*DeploymentStep `json:"steps"`
	CurrentActions []*DeploymentStep `json:"currentActions"`
	CurrentStep    int               `json:"currentStep"`
	TotalSteps     int               `json:"totalSteps"`
	Version        string            `json:"version"`
}

// Deployment steps
type DeploymentStep struct {
	Action string `json:"action"`
	App    string `json:"app"`
}

// EventSubscription is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#event-subscriptions
type EventSubscription struct {
	CallbackURL  string   `json:"CallbackUrl"`
	ClientIP     string   `json:"ClientIp"`
	EventType    string   `json:"eventType"`
	CallbackURLs []string `json:"CallbackUrls"`
}
<commit_msg>Add tasksHealthy and tasksUnhealthy fields<commit_after>package gomarathon

// RequestOptions passed for query api
type RequestOptions struct {
	Method string
	Path   string
	Datas  interface{}
	Params *Parameters
}

// Parameters to build url query
type Parameters struct {
	Cmd         string
	Host        string
	Scale       bool
	CallbackURL string
	Embed       string
}

// Response representation of a full marathon response
type Response struct {
	Code         int
	Apps         []*Application `json:"apps,omitempty"`
	App          *Application   `json:"app,omitempty"`
	Versions     []string       `json:",omitempty"`
	Tasks        []*Task        `json:"tasks,omitempty"`
	DeploymentId string         `json:"deployment_id,omitempty"`
	Version      string         `json:"version,omitempty"`
}

// Application marathon application see :
// https://github.com/mesosphere/marathon/blob/master/REST.md#apps
type Application struct {
	ID                    string            `json:"id"`
	Cmd                   string            `json:"cmd,omitempty"`
	Constraints           [][]string        `json:"constraints,omitempty"`
	Container             *Container        `json:"container,omitempty"`
	CPUs                  float32           `json:"cpus,omitempty"`
	Deployments           []*Deployment     `json:"deployments,omitempty"`
	Env                   map[string]string `json:"env,omitempty"`
	Executor              string            `json:"executor,omitempty"`
	HealthChecks          []*HealthCheck    `json:"healthChecks,omitempty"`
	Instances             int               `json:"instances,omitemptys"`
	Mem                   float32           `json:"mem,omitempty"`
	Tasks                 []*Task           `json:"tasks,omitempty"`
	Ports                 []int             `json:"ports,omitempty"`
	RequirePorts          bool              `json:"requirePorts,omitempty"`
	BackoffSeconds        int               `json:"backoffSeconds,omitempty"`
	BackoffFactor         float32           `json:"backoffFactor,omitempty"`
	MaxLaunchDelaySeconds float32           `json:"maxLaunchDelaySeconds,omitempty"`
	TasksHealthy          int               `json:"tasksHealthy,omitempty"`
	TasksUnhealthy        int               `json:"tasksUnhealthy,omitempty"`
	TasksRunning          int               `json:"tasksRunning,omitempty"`
	TasksStaged           int               `json:"tasksStaged,omitempty"`
	UpgradeStrategy       *UpgradeStrategy  `json:"upgradeStrategy,omitempty"`
	Uris                  []string          `json:"uris,omitempty"`
	Version               string            `json:"version,omitempty"`
	Labels                map[string]string `json:"labels,omitempty"`
	TaskStats             *TaskStats        `json:"taskStats,omitempty"`
}

type TaskStats struct {
	StartedAfterLastScaling *TaskStatWrapper `json:"startedAfterLastScaling"`
	WithLatestConfig        *TaskStatWrapper `json:"withLatestConfig"`
	totalSummary            *TaskStatWrapper `json:"totalSummary"`
}

type TaskStatWrapper struct {
	Stats *TaskStat `json:"stats"`
}

type TaskStat struct {
	Counts   *TaskCounts   `json:"counts"`
	LifeTime *TaskLifetime `json:"lifeTime"`
}

type TaskCounts struct {
	Staged    int `json:"staged"`
	Running   int `json:"running"`
	Healthy   int `json:"healthy"`
	Unhealthy int `json:"unhealthy"`
}

type TaskLifetime struct {
	AverageSeconds float32 `json:"averageSeconds"`
	MedianSeconds  float32 `json:"medianSeconds"`
}

// Container is docker parameters
type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes []*Volume `json:"volumes,omitempty"`
}

// Docker options
type Docker struct {
	Image        string         `json:"image,omitempty"`
	Network      string         `json:"network,omitempty"`
	PortMappings []*PortMapping `json:"portMappings,omitempty"`
	Privileged   bool           `json:"privileged`
	Parameters   []*DockerParam  `json:"parameters,omitempty"`
}
type DockerParam struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Volume is used for mounting a host directory as a container volume
type Volume struct {
	ContainerPath string `json:"containerPath,omitempty"`
	HostPath      string `json:"hostPath,omitempty"`
	Mode          string `json:"mode,omitempty"`
}

// Container PortMappings
type PortMapping struct {
	ContainerPort int    `json:"containerPort,omitempty"`
	HostPort      int    `json:"hostPort,omitempty"`
	ServicePort   int    `json:"servicePort,omitempty"`
	Protocol      string `json:"protocol,omitempty"`
}

// UpgradeStrategy has a minimumHealthCapacity which defines the minimum number of healty nodes
type UpgradeStrategy struct {
	MinimumHealthCapacity float32 `json:"minimumHealthCapacity,omitempty"`
}

// HealthCheck is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#healthchecks
type HealthCheck struct {
	Protocol               string `json:"protocol,omitempty"`
	Path                   string `json:"path,omitempty"`
	GracePeriodSeconds     int    `json:"gracePeriodSeconds,omitempty"`
	IntervalSeconds        int    `json:"intervalSeconds,omitempty"`
	PortIndex              int    `json:"portIndex,omitempty"`
	TimeoutSeconds         int    `json:"timeoutSeconds,omitempty"`
	MaxConsecutiveFailures int    `json:"maxConsecutiveFailures"`
}

type HealthCheckResult struct {
	Alive               bool   `json:"alive,omitempty"`
	ConsecutiveFailures int    `json:"consecutiveFailures,omitempty"`
	FirstSuccess        string `json:"firstSuccess,omitempty"`
	LastFailure         string `json:"lastFailure,omitempty"`
	LastSuccess         string `json:"lastSuccess,omitempty"`
	TaskID              string `json:"taskId,omitempty"`
}

// Task is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#tasks
type Task struct {
	AppID              string               `json:"appId"`
	Host               string               `json:"host"`
	ID                 string               `json:"id"`
	Ports              []int                `json:"ports"`
	StagedAt           string               `json:"stagedAt"`
	StartedAt          string               `json:"startedAt"`
	Version            string               `json:"version"`
	HealthCheckResults []*HealthCheckResult `json:"healthCheckResults"`
}

// Deployment is described here:
// https://mesosphere.github.io/marathon/docs/rest-api.html#get-/v2/deployments
type Deployment struct {
	AffectedApps   []string          `json:"affectedApps"`
	ID             string            `json:"id"`
	Steps          []*DeploymentStep `json:"steps"`
	CurrentActions []*DeploymentStep `json:"currentActions"`
	CurrentStep    int               `json:"currentStep"`
	TotalSteps     int               `json:"totalSteps"`
	Version        string            `json:"version"`
}

// Deployment steps
type DeploymentStep struct {
	Action string `json:"action"`
	App    string `json:"app"`
}

// EventSubscription is described here:
// https://github.com/mesosphere/marathon/blob/master/REST.md#event-subscriptions
type EventSubscription struct {
	CallbackURL  string   `json:"CallbackUrl"`
	ClientIP     string   `json:"ClientIp"`
	EventType    string   `json:"eventType"`
	CallbackURLs []string `json:"CallbackUrls"`
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"sync"

	"./mqttadapterY"

	"./datamodel"
	"./serialport"
)

const (
	CHANNEL_SIZE int = 100
)

func main() {

	var usb_port, mqtt_address, mqtt_topic string
	var interval int

	flag.StringVar(&usb_port, "usb", "/dev/ttyUSB0", "USB/Serial port")
	flag.StringVar(&mqtt_address, "mqtt_address", "localhost:1883", "MQTT Host and Port")
	flag.StringVar(&mqtt_topic, "mqtt_topic", "dev.sample.topic", "Topic name where Serial data needs to be sent")
	flag.IntVar(&interval, "interval", 60, "message interval in seconds. default60")

	flag.Parse()

	var wg sync.WaitGroup

	wg.Add(2)

	telegram_channel := make(chan datamodel.P1Telegram, CHANNEL_SIZE)

	go serialport.ReadSerial(usb_port, telegram_channel, wg)

	go mqttadapterY.MQTTy(mqtt_address, "smartmeter-reader", mqtt_topic, telegram_channel, wg, interval)

	wg.Wait()

}
<commit_msg>added mqtt cred file option<commit_after>package main

import (
	"flag"
	"sync"

	"./mqttadapterY"

	"./datamodel"
	"./serialport"
)

const (
	CHANNEL_SIZE int = 100
)

func main() {

	var usb_port, mqtt_address, mqtt_topic, mqtt_cred_file string
	var interval int

	flag.StringVar(&usb_port, "usb", "/dev/ttyUSB0", "USB/Serial port")
	flag.StringVar(&mqtt_address, "mqtt_address", "localhost:1883", "MQTT Host and Port")
	flag.StringVar(&mqtt_topic, "mqtt_topic", "dev.sample.topic", "Topic name where Serial data needs to be sent")
	flag.IntVar(&interval, "interval", 60, "message interval in seconds. default is 60")
	flag.StringVar(&mqtt_cred_file, "mqtt_cred_file", "", "path of mqtt cred file default is blank, file should be in properties format")

	flag.Parse()

	var wg sync.WaitGroup

	wg.Add(2)

	telegram_channel := make(chan datamodel.P1Telegram, CHANNEL_SIZE)

	go serialport.ReadSerial(usb_port, telegram_channel, wg)

	go mqttadapterY.MQTTy(mqtt_address, "smartmeter-reader", mqtt_topic, mqtt_cred_file, telegram_channel, wg, interval)

	wg.Wait()

}
<|endoftext|>


<commit_before>package tripeg

import (
	"crypto/sha1"
	"fmt"
	"io"
	"math"
	"math/rand"
	"time"

	"github.com/fatih/color"
)

//Hole struct that contains information
//about a hole in the board, its location
//and whether or not it has a peg in it.
type Hole struct {
	Row    int //max of 5
	Col    int //max of 9
	Peg    bool
	Status int
}

const (
	//Dormant short hand for a row/col location that's not involved in a jump move
	Dormant = iota
	//Source shorthand for the source peg row/col for a jump move
	Source
	//Target the empty row/col the source peg will land in for a jump move.
	Target
)

func (b Board) showMove(m, o, t Hole) Board {
	result := Board{}
	result.Rows = b.Rows
	for k, v := range b.Holes {
		b.Holes[k].Status = Dormant
		if v.Row == m.Row && v.Col == m.Col {
			b.Holes[k].Status = Source
		}
		if v.Row == t.Row && v.Col == t.Col {
			b.Holes[k].Status = Target
		}
	}
	result.Holes = b.Holes
	return result

}

//Jump from the Board struct type
func (b Board) Jump(m, o Hole) (Board, Hole, error) {
	result := Board{}
	result.SolveMoves = b.SolveMoves
	result.Rows = b.Rows
	thole := Hole{}
	for _, r := range b.Holes {
		result.Holes = append(result.Holes, r)
	}
	if !m.Peg {
		//If there is no peg in the moveHole, no jump possible
		return result, thole, fmt.Errorf("No Peg in move hole %d,%d\n", o.Row, o.Col)
	}
	if !o.Peg {
		//If there is no peg in the overHole, no jump possible
		return result, thole, fmt.Errorf("No Peg in over hole %d,%d\n", o.Row, o.Col)
	}
	rDif := m.Row - o.Row
	cDif := o.Col - m.Col
	if cDif == 0 && rDif == 0 {
		//Holes are the same, not valid
		return result, thole, fmt.Errorf("Jump peg and over hole are the same\n")
	}
	if math.Abs(float64(rDif)) > 1 {
		//You can't jump over more than 1 row horizontally
		return result, thole, fmt.Errorf("Invalid horizonal movement %d\n", rDif)
	}
	if rDif > 0 && math.Abs(float64(cDif)) > 1 {
		//You can't jump over more than 1 col vertically
		return result, thole, fmt.Errorf("Invalid vertical movement %d\n", cDif)
	}
	if rDif == 0 && math.Abs(float64(cDif)) > 2 {
		return result, thole, fmt.Errorf("Invalid horizantal movement %d\n", rDif)
		//You can't jump more than 2 cols horizontally
	}
	targetR := 0
	targetC := 0
	if rDif == 0 {
		//This is a horizontal jump
		targetR = m.Row
	}
	if rDif > 0 {
		targetR = o.Row - 1
		//This is an up jump
	}
	if rDif < 0 {
		targetR = o.Row + 1
		//This is a jump down
	}
	if cDif < 0 {
		x := 1
		if rDif == 0 {
			x = 2
		}
		targetC = o.Col - x
		//This is a jump left
	}
	if cDif > 0 {
		x := 1
		if rDif == 0 {
			x = 2
		}
		targetC = o.Col + x
		//This is a jump right
	}
	targetHole, err := b.GetHole(targetR, targetC)
	if err != nil {
		return result, thole, fmt.Errorf("Target hole(%d,%d) does not exist\n", targetR, targetC)
	}
	if targetHole.Peg {
		return result, thole, fmt.Errorf("Target hole(%d,%d) has a peg in it\n", targetHole.Row, targetHole.Col)
	}
	for k, bh := range result.Holes {
		if bh.Row == m.Row && bh.Col == m.Col {
			result.Holes[k].Peg = false
		}
		if bh.Row == o.Row && bh.Col == o.Col {
			result.Holes[k].Peg = false
		}
		if bh.Row == targetHole.Row && bh.Col == targetHole.Col {
			result.Holes[k].Peg = true
		}
	}
	return result, targetHole, nil
}

//Board contains all the holes that contain the pegs
type Board struct {
	Holes      []Hole
	MoveChart  []string
	SolveMoves int
	Rows       int
}

//Hash returns a hash value for the board
func (b Board) Hash() string {
	raw := ""
	for _, v := range b.Holes {
		raw += fmt.Sprintf("%v-%v-%v", v.Row, v.Col, v.Peg)
	}
	h := sha1.New()
	io.WriteString(h, raw)
	return fmt.Sprintf("%x", h.Sum(nil))
}

//GetHole gets a pointer to a hole based on the row,col coordinates
func (b Board) GetHole(r, c int) (Hole, error) {
	if r < 0 || r > b.Rows+1 || c < 0 || c > b.Rows+(b.Rows-1) {
		return Hole{}, fmt.Errorf("Hole %d,%d does not exist\n", r, c)
	}
	for _, v := range b.Holes {
		if v.Col == c && v.Row == r {
			return v, nil
		}
	}
	return Hole{}, fmt.Errorf("Hole %d,%d does not exist\n", r, c)
}

//BuildBoard makes a board of peg holes.
//All holes have a peg except one.
func BuildBoard(rows, empty int) (Board, error) {
	var b Board
	if rows < 5 {
		return b, fmt.Errorf("Invalid rows valid %d, it must be greater than 4\n", rows)
	}
	if rows > 6 {
		//return b, fmt.Errorf("We're going to need a better algorithm before we get to %d rows...\n", rows)
	}
	max := 0
	for i := 1; i < rows+1; i++ {
		max += i
	}
	b.SolveMoves = max - 2
	b.Rows = rows

	if empty < 0 || empty > max {
		return b, fmt.Errorf("1st parameter must be >=0 or <=%d, you supplied %d", max, empty)
	}
	s2 := rand.NewSource(time.Now().UnixNano())
	r2 := rand.New(s2)
	if empty == 0 {
		empty = r2.Intn(max)
	} else {
		empty--
	}
	for r := 1; r < rows+1; r++ {
		for c := 1; c < r+1; c++ {
			offset := 1
			col := rows + (c * 2) - offset - r
			h := Hole{Row: r, Col: col, Peg: true}
			if empty == len(b.Holes) {
				h.Peg = false
			}
			b.Holes = append(b.Holes, h)
		}
	}
	return b, nil
}

type move struct {
	H Hole
	O Hole
	T Hole
}

func (m move) String() string {
	return fmt.Sprintf("[%d,%d] over [%d,%d] to [%d,%d]", m.H.Row, m.H.Col, m.O.Row, m.O.Col, m.T.Row, m.T.Col)
}

//ErrorArray an array of errors that also implements the error interface
type ErrorArray struct {
	Errors []error
}

func (ea ErrorArray) Error() string {
	r := ""
	m := len(ea.Errors)
	c := m
	if m > 11 {
		m = 11
		ea.Errors[10] = fmt.Errorf("Too many errors! Count: %v", c-1)
	}
	for _, v := range ea.Errors[0:m] {
		r += v.Error() + "\n"
	}
	return r[0 : len(r)-1]
}

//Add takes an argument of the error interface and adds it to the array
func (ea *ErrorArray) Add(err error) {
	ea.Errors = append(ea.Errors, err)
}

//Solve does a brute force solving of the game
func (b *Board) Solve() []error {
	ngMap := map[string]string{}
	high := 0
	s2 := rand.NewSource(time.Now().UnixNano())
	r2 := rand.New(s2)
	var newBoard = b
	var solved = false
	var solveErrors = ErrorArray{}
	validMove := 0
	for {
		func() {
			aMoves := []move{}
			o := Hole{}
			var err error
			for _, v := range newBoard.Holes {
				/*
					Go through all of the holes on the board.
					If the hole doesn't have a peg, it can't
					have a legal move, so skip it.
					If it doesn't have a peg, just to see if it has
					a legal move by jumping left, right, up left, up right, down left or down right.
					If any of these moves are legal, add it to the array of available moves.
					Do this for each hole on the board.
					Randomly select a legal move, color the board and return the new color coded board.
					Keep doing this until we've done SolveMoves legal moves or we run out of availaable moves.
					If no legal moves left, start over and hope for the best.
					If SolveMoves legal moves, then we've solved it, return out of here.
				*/
				if v.Peg {
					//upleft
					o, err = newBoard.GetHole(v.Row-1, v.Col-1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//upright
					o, err = newBoard.GetHole(v.Row-1, v.Col+1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//left
					o, err = newBoard.GetHole(v.Row, v.Col-2)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}
					//right
					o, err = newBoard.GetHole(v.Row, v.Col+2)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//downleft
					o, err = newBoard.GetHole(v.Row+1, v.Col-1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//downright
					o, err = newBoard.GetHole(v.Row+1, v.Col+1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}
				}
			}
			if len(aMoves) == 0 {
				//No legal moves left
				ngMap[newBoard.Hash()] = fmt.Sprintf("%s", newBoard)
				newBoard = b
				validMove = 0
				b.MoveChart = []string{}
				return
			}
			available := r2.Intn(len(aMoves))
			avs := aMoves[available].H
			avo := aMoves[available].O
			cBoard, th, errN := newBoard.Jump(avs, avo)
			cBoard.Rows = b.Rows
			if errN != nil {
				solveErrors.Add(errN)
			}
			validMove++
			if validMove > high {
				high = validMove
				// fmt.Println(b.SolveMoves, high, b.SolveMoves-high)
			}
			b.MoveChart = append(b.MoveChart, fmt.Sprintf("%v", newBoard.showMove(avs, avo, th)))

			newBoard = &cBoard
			if validMove == b.SolveMoves {
				solved = true
				return
			}
		}()
		if solved {
			break
		}
	}
	return nil
}

func (b Board) String() string {
	result := "\n"
	tar := color.New(color.FgRed).SprintFunc()
	src := color.New(color.FgGreen).SprintFunc()
	dor := color.New(color.FgWhite).SprintFunc()
	offset := 1
	for r := 1; r < b.Rows+1; r++ {
		for c := 1; c < b.Rows*2+offset; c++ {
			h, err := b.GetHole(r, c)
			mark := " "
			if err == nil {
				mark = "O"
				if h.Peg {
					mark = "*"
				}
			}
			switch h.Status {
			case Source:
				result += fmt.Sprintf("%s", src(mark))
			case Target:
				result += fmt.Sprintf("%s", tar(mark))
			case Dormant:
				result += fmt.Sprintf("%s", dor(mark))
			}
		}
		result += "\n"
	}
	return result
}
<commit_msg>don't need colors, it's easier to share solutions just using text<commit_after>package tripeg

import (
	"crypto/sha1"
	"fmt"
	"io"
	"math"
	"math/rand"
	"time"
)

//Hole struct that contains information
//about a hole in the board, its location
//and whether or not it has a peg in it.
type Hole struct {
	Row    int //max of 5
	Col    int //max of 9
	Peg    bool
	Status int
}

const (
	//Dormant short hand for a row/col location that's not involved in a jump move
	Dormant = iota
	//Source shorthand for the source peg row/col for a jump move
	Source
	//Target the empty row/col the source peg will land in for a jump move.
	Target
)

func (b Board) showMove(m, o, t Hole) Board {
	result := Board{}
	result.Rows = b.Rows
	for k, v := range b.Holes {
		b.Holes[k].Status = Dormant
		if v.Row == m.Row && v.Col == m.Col {
			b.Holes[k].Status = Source
		}
		if v.Row == t.Row && v.Col == t.Col {
			b.Holes[k].Status = Target
		}
	}
	result.Holes = b.Holes
	return result

}

//Jump from the Board struct type
func (b Board) Jump(m, o Hole) (Board, Hole, error) {
	result := Board{}
	result.SolveMoves = b.SolveMoves
	result.Rows = b.Rows
	thole := Hole{}
	for _, r := range b.Holes {
		result.Holes = append(result.Holes, r)
	}
	if !m.Peg {
		//If there is no peg in the moveHole, no jump possible
		return result, thole, fmt.Errorf("No Peg in move hole %d,%d\n", o.Row, o.Col)
	}
	if !o.Peg {
		//If there is no peg in the overHole, no jump possible
		return result, thole, fmt.Errorf("No Peg in over hole %d,%d\n", o.Row, o.Col)
	}
	rDif := m.Row - o.Row
	cDif := o.Col - m.Col
	if cDif == 0 && rDif == 0 {
		//Holes are the same, not valid
		return result, thole, fmt.Errorf("Jump peg and over hole are the same\n")
	}
	if math.Abs(float64(rDif)) > 1 {
		//You can't jump over more than 1 row horizontally
		return result, thole, fmt.Errorf("Invalid horizonal movement %d\n", rDif)
	}
	if rDif > 0 && math.Abs(float64(cDif)) > 1 {
		//You can't jump over more than 1 col vertically
		return result, thole, fmt.Errorf("Invalid vertical movement %d\n", cDif)
	}
	if rDif == 0 && math.Abs(float64(cDif)) > 2 {
		return result, thole, fmt.Errorf("Invalid horizantal movement %d\n", rDif)
		//You can't jump more than 2 cols horizontally
	}
	targetR := 0
	targetC := 0
	if rDif == 0 {
		//This is a horizontal jump
		targetR = m.Row
	}
	if rDif > 0 {
		targetR = o.Row - 1
		//This is an up jump
	}
	if rDif < 0 {
		targetR = o.Row + 1
		//This is a jump down
	}
	if cDif < 0 {
		x := 1
		if rDif == 0 {
			x = 2
		}
		targetC = o.Col - x
		//This is a jump left
	}
	if cDif > 0 {
		x := 1
		if rDif == 0 {
			x = 2
		}
		targetC = o.Col + x
		//This is a jump right
	}
	targetHole, err := b.GetHole(targetR, targetC)
	if err != nil {
		return result, thole, fmt.Errorf("Target hole(%d,%d) does not exist\n", targetR, targetC)
	}
	if targetHole.Peg {
		return result, thole, fmt.Errorf("Target hole(%d,%d) has a peg in it\n", targetHole.Row, targetHole.Col)
	}
	for k, bh := range result.Holes {
		if bh.Row == m.Row && bh.Col == m.Col {
			result.Holes[k].Peg = false
		}
		if bh.Row == o.Row && bh.Col == o.Col {
			result.Holes[k].Peg = false
		}
		if bh.Row == targetHole.Row && bh.Col == targetHole.Col {
			result.Holes[k].Peg = true
		}
	}
	return result, targetHole, nil
}

//Board contains all the holes that contain the pegs
type Board struct {
	Holes      []Hole
	MoveChart  []string
	SolveMoves int
	Rows       int
}

//Hash returns a hash value for the board
func (b Board) Hash() string {
	raw := ""
	for _, v := range b.Holes {
		raw += fmt.Sprintf("%v-%v-%v", v.Row, v.Col, v.Peg)
	}
	h := sha1.New()
	io.WriteString(h, raw)
	return fmt.Sprintf("%x", h.Sum(nil))
}

//GetHole gets a pointer to a hole based on the row,col coordinates
func (b Board) GetHole(r, c int) (Hole, error) {
	if r < 0 || r > b.Rows+1 || c < 0 || c > b.Rows+(b.Rows-1) {
		return Hole{}, fmt.Errorf("Hole %d,%d does not exist\n", r, c)
	}
	for _, v := range b.Holes {
		if v.Col == c && v.Row == r {
			return v, nil
		}
	}
	return Hole{}, fmt.Errorf("Hole %d,%d does not exist\n", r, c)
}

//BuildBoard makes a board of peg holes.
//All holes have a peg except one.
func BuildBoard(rows, empty int) (Board, error) {
	var b Board
	if rows < 5 {
		return b, fmt.Errorf("Invalid rows valid %d, it must be greater than 4\n", rows)
	}
	if rows > 6 {
		//return b, fmt.Errorf("We're going to need a better algorithm before we get to %d rows...\n", rows)
	}
	max := 0
	for i := 1; i < rows+1; i++ {
		max += i
	}
	b.SolveMoves = max - 2
	b.Rows = rows

	if empty < 0 || empty > max {
		return b, fmt.Errorf("1st parameter must be >=0 or <=%d, you supplied %d", max, empty)
	}
	s2 := rand.NewSource(time.Now().UnixNano())
	r2 := rand.New(s2)
	if empty == 0 {
		empty = r2.Intn(max)
	} else {
		empty--
	}
	for r := 1; r < rows+1; r++ {
		for c := 1; c < r+1; c++ {
			offset := 1
			col := rows + (c * 2) - offset - r
			h := Hole{Row: r, Col: col, Peg: true}
			if empty == len(b.Holes) {
				h.Peg = false
			}
			b.Holes = append(b.Holes, h)
		}
	}
	return b, nil
}

type move struct {
	H Hole
	O Hole
	T Hole
}

func (m move) String() string {
	return fmt.Sprintf("[%d,%d] over [%d,%d] to [%d,%d]", m.H.Row, m.H.Col, m.O.Row, m.O.Col, m.T.Row, m.T.Col)
}

//ErrorArray an array of errors that also implements the error interface
type ErrorArray struct {
	Errors []error
}

func (ea ErrorArray) Error() string {
	r := ""
	m := len(ea.Errors)
	c := m
	if m > 11 {
		m = 11
		ea.Errors[10] = fmt.Errorf("Too many errors! Count: %v", c-1)
	}
	for _, v := range ea.Errors[0:m] {
		r += v.Error() + "\n"
	}
	return r[0 : len(r)-1]
}

//Add takes an argument of the error interface and adds it to the array
func (ea *ErrorArray) Add(err error) {
	ea.Errors = append(ea.Errors, err)
}

//Solve does a brute force solving of the game
func (b *Board) Solve() []error {
	ngMap := map[string]string{}
	high := 0
	s2 := rand.NewSource(time.Now().UnixNano())
	r2 := rand.New(s2)
	var newBoard = b
	var solved = false
	var solveErrors = ErrorArray{}
	validMove := 0
	for {
		func() {
			aMoves := []move{}
			o := Hole{}
			var err error
			for _, v := range newBoard.Holes {
				/*
					Go through all of the holes on the board.
					If the hole doesn't have a peg, it can't
					have a legal move, so skip it.
					If it doesn't have a peg, just to see if it has
					a legal move by jumping left, right, up left, up right, down left or down right.
					If any of these moves are legal, add it to the array of available moves.
					Do this for each hole on the board.
					Randomly select a legal move, color the board and return the new color coded board.
					Keep doing this until we've done SolveMoves legal moves or we run out of availaable moves.
					If no legal moves left, start over and hope for the best.
					If SolveMoves legal moves, then we've solved it, return out of here.
				*/
				if v.Peg {
					//upleft
					o, err = newBoard.GetHole(v.Row-1, v.Col-1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//upright
					o, err = newBoard.GetHole(v.Row-1, v.Col+1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//left
					o, err = newBoard.GetHole(v.Row, v.Col-2)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}
					//right
					o, err = newBoard.GetHole(v.Row, v.Col+2)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//downleft
					o, err = newBoard.GetHole(v.Row+1, v.Col-1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}

					//downright
					o, err = newBoard.GetHole(v.Row+1, v.Col+1)
					if err == nil {
						pboard, t, errJ := newBoard.Jump(v, o)
						if errJ == nil {
							if _, ok := ngMap[pboard.Hash()]; !ok {
								aMoves = append(aMoves, move{H: v, O: o, T: t})
							}
						}
					}
				}
			}
			if len(aMoves) == 0 {
				//No legal moves left
				ngMap[newBoard.Hash()] = fmt.Sprintf("%s", newBoard)
				newBoard = b
				validMove = 0
				b.MoveChart = []string{}
				return
			}
			available := r2.Intn(len(aMoves))
			avs := aMoves[available].H
			avo := aMoves[available].O
			cBoard, th, errN := newBoard.Jump(avs, avo)
			cBoard.Rows = b.Rows
			if errN != nil {
				solveErrors.Add(errN)
			}
			validMove++
			if validMove > high {
				high = validMove
				// fmt.Println(b.SolveMoves, high, b.SolveMoves-high)
			}
			b.MoveChart = append(b.MoveChart, fmt.Sprintf("%v", newBoard.showMove(avs, avo, th)))

			newBoard = &cBoard
			if validMove == b.SolveMoves {
				solved = true
				return
			}
		}()
		if solved {
			break
		}
	}
	return nil
}

func (b Board) String() string {
	result := "\n"
	offset := 1
	for r := 1; r < b.Rows+1; r++ {
		for c := 1; c < b.Rows*2+offset; c++ {
			h, err := b.GetHole(r, c)
			mark := " "
			if err == nil {
				mark = "O"
				if h.Peg {
					mark = "*"
				}
			}
			switch h.Status {
			case Source:
				result += "+"
			case Target:
				result += "0"
			case Dormant:
				result += mark
			}
		}
		result += "\n"
	}
	return result
}
<|endoftext|>


<commit_before>package api

import (
	"net/http"
	"reflect"

	"github.com/gorilla/schema"
	"github.com/octavore/naga/service"
	"github.com/octavore/nagax/logger"
	router2 "github.com/octavore/nagax/router"
	"github.com/xenolf/lego/acme"

	"github.com/ketchuphq/ketchup/db"
	"github.com/ketchuphq/ketchup/proto/ketchup/api"
	"github.com/ketchuphq/ketchup/proto/ketchup/models"
	"github.com/ketchuphq/ketchup/proto/ketchup/packages"
	"github.com/ketchuphq/ketchup/server/config"
	"github.com/ketchuphq/ketchup/server/content"
	"github.com/ketchuphq/ketchup/server/content/templates"
	"github.com/ketchuphq/ketchup/server/files"
	"github.com/ketchuphq/ketchup/server/router"
	"github.com/ketchuphq/ketchup/server/tls"
	"github.com/ketchuphq/ketchup/server/users"
)

type mockableTemplateModule interface {
	CheckThemeForUpdate(name string) (bool, string, string, error)
	GetTemplate(theme, template string) (*models.ThemeTemplate, error)
	GetTheme(name string) (*models.Theme, string, error)
	InstallThemeFromPackage(p *packages.Package) error
	ListThemes() ([]*models.Theme, error)
	Registry() (*packages.Registry, error)
	SearchRegistry(themeName string) (*packages.Package, error)
	UpdateTheme(name, ref string) error
	GetRegistryURL() string
}

type mockableTLSModule interface {
	// CleanUp(domain, token, keyAuth string) error
	GetAllRegisteredDomains() ([]string, error)
	GetRegistration(domain string, withPrivateKey bool) (*tls.Registration, error)
	LoadCertResource(domain string) (*acme.CertificateResource, error)
	ObtainCert(email, domain string) error
	// Present(domain, token, keyAuth string) error
	// SaveRegistration(r *Registration) error
	// ServeHTTP(rw http.ResponseWriter, req *http.Request)
}

type Module struct {
	Router    *router.Module
	DB        *db.Module
	Auth      *users.Module
	Templates *templates.Module
	Content   *content.Module
	Config    *config.Module
	TLS       *tls.Module
	Logger    *logger.Module
	Files     *files.Module

	decoder *schema.Decoder
	version string

	// for tests
	templates mockableTemplateModule
	tls       mockableTLSModule
}

const (
	methodGet    = "GET"
	methodPost   = "POST"
	methodDelete = "DELETE"
)

func (m *Module) Init(c *service.Config) {
	c.Setup = func() error {
		m.templates = m.Templates
		m.tls = m.TLS
		m.decoder = schema.NewDecoder()
		m.decoder.SetAliasTag("json")
		m.decoder.IgnoreUnknownKeys(true)
		m.decoder.RegisterConverter(
			api.ListPageRequest_all,
			func(val string) reflect.Value {
				v := api.ListPageRequest_ListPageFilter_value[val]
				return reflect.ValueOf(v)
			})
		auth := m.Auth.Auth.MustWithAuth
		routes := []struct {
			path, method string
			handle       router2.Handle
		}{
			{"/api/v1/pages/:uuid", methodGet, m.GetPage},
			{"/api/v1/pages/:uuid/contents", methodGet, m.GetRenderedPage},
			{"/api/v1/pages/:uuid/routes", methodGet, m.ListRoutesByPage},
			{"/api/v1/data/:key", methodGet, m.GetData},
			{"/api/v1/pages", methodGet, m.ListPages},
			{"/api/v1/routes", methodGet, m.ListRoutes},
			{"/api/v1/data", methodGet, auth(m.ListData)},

			{"/api/v1/user", methodGet, auth(m.GetUser)},
			{"/api/v1/settings/info", methodGet, auth(m.GetInfo)},
			{"/api/v1/settings/tls", methodGet, auth(m.GetTLS)},
			{"/api/v1/settings/tls", methodPost, auth(m.EnableTLS)},

			{"/api/v1/themes", methodGet, auth(m.ListThemes)},
			{"/api/v1/themes/:name", methodGet, auth(m.GetTheme)},
			{"/api/v1/themes/:name/updates", methodGet, auth(m.CheckThemeForUpdate)},
			{"/api/v1/themes/:name/update", methodPost, auth(m.UpdateTheme)},
			{"/api/v1/themes/:name/templates/:template", methodGet, auth(m.GetTemplate)},
			{"/api/v1/theme-registry", methodGet, auth(m.ThemeRegistry)},
			{"/api/v1/theme-install", methodPost, auth(m.InstallTheme)},

			{"/api/v1/pages", methodPost, auth(m.UpdatePage)},
			{"/api/v1/pages/:uuid", methodDelete, auth(m.DeletePage)},
			{"/api/v1/pages/:uuid/routes", methodPost, auth(m.UpdateRoutesByPage)},
			{"/api/v1/pages/:uuid/publish", methodPost, auth(m.PublishPage)},
			{"/api/v1/pages/:uuid/unpublish", methodPost, auth(m.UnpublishPage)},

			{"/api/v1/routes", methodPost, auth(m.UpdateRoute)},
			{"/api/v1/routes/:uuid", methodDelete, auth(m.DeleteRoute)},

			{"/api/v1/data", methodPost, auth(m.UpdateData)},
			{"/api/v1/data/:key", methodDelete, auth(m.DeleteData)},

			{"/api/v1/files", methodGet, auth(m.ListFiles)},
			{"/api/v1/files", methodPost, auth(m.UploadFile)},
			{"/api/v1/files/:uuid", methodGet, auth(m.GetFile)},
			{"/api/v1/files/:uuid", methodDelete, auth(m.DeleteFile)},

			{"/api/v1/download-backup", methodGet, auth(m.GetBackup)},
			{"/api/v1/debug", methodGet, auth(m.Debug)},
			{"/api/v1/logout", methodGet, auth(m.Logout)},
		}
		for _, route := range routes {
			m.Router.WrappedHandle(route.method, route.path, route.handle)
		}
		return nil
	}
}

func (m *Module) Debug(rw http.ResponseWriter, req *http.Request, par router2.Params) error {
	return m.DB.Debug(rw)
}
<commit_msg>server: Reorganize public and private routes.<commit_after>package api

import (
	"net/http"
	"reflect"

	"github.com/gorilla/schema"
	"github.com/octavore/naga/service"
	"github.com/octavore/nagax/logger"
	router2 "github.com/octavore/nagax/router"
	"github.com/xenolf/lego/acme"

	"github.com/ketchuphq/ketchup/db"
	"github.com/ketchuphq/ketchup/proto/ketchup/api"
	"github.com/ketchuphq/ketchup/proto/ketchup/models"
	"github.com/ketchuphq/ketchup/proto/ketchup/packages"
	"github.com/ketchuphq/ketchup/server/config"
	"github.com/ketchuphq/ketchup/server/content"
	"github.com/ketchuphq/ketchup/server/content/templates"
	"github.com/ketchuphq/ketchup/server/files"
	"github.com/ketchuphq/ketchup/server/router"
	"github.com/ketchuphq/ketchup/server/tls"
	"github.com/ketchuphq/ketchup/server/users"
)

type mockableTemplateModule interface {
	CheckThemeForUpdate(name string) (bool, string, string, error)
	GetTemplate(theme, template string) (*models.ThemeTemplate, error)
	GetTheme(name string) (*models.Theme, string, error)
	InstallThemeFromPackage(p *packages.Package) error
	ListThemes() ([]*models.Theme, error)
	Registry() (*packages.Registry, error)
	SearchRegistry(themeName string) (*packages.Package, error)
	UpdateTheme(name, ref string) error
	GetRegistryURL() string
}

type mockableTLSModule interface {
	// CleanUp(domain, token, keyAuth string) error
	GetAllRegisteredDomains() ([]string, error)
	GetRegistration(domain string, withPrivateKey bool) (*tls.Registration, error)
	LoadCertResource(domain string) (*acme.CertificateResource, error)
	ObtainCert(email, domain string) error
	// Present(domain, token, keyAuth string) error
	// SaveRegistration(r *Registration) error
	// ServeHTTP(rw http.ResponseWriter, req *http.Request)
}

type Module struct {
	Router    *router.Module
	DB        *db.Module
	Auth      *users.Module
	Templates *templates.Module
	Content   *content.Module
	Config    *config.Module
	TLS       *tls.Module
	Logger    *logger.Module
	Files     *files.Module

	decoder *schema.Decoder
	version string

	// for tests
	templates mockableTemplateModule
	tls       mockableTLSModule
}

const (
	methodGet    = "GET"
	methodPost   = "POST"
	methodDelete = "DELETE"
)

func (m *Module) Init(c *service.Config) {
	c.Setup = func() error {
		m.templates = m.Templates
		m.tls = m.TLS
		m.decoder = schema.NewDecoder()
		m.decoder.SetAliasTag("json")
		m.decoder.IgnoreUnknownKeys(true)
		m.decoder.RegisterConverter(
			api.ListPageRequest_all,
			func(val string) reflect.Value {
				v := api.ListPageRequest_ListPageFilter_value[val]
				return reflect.ValueOf(v)
			})
		auth := m.Auth.Auth.MustWithAuth

		// THESE ROUTES ARE PUBLIC
		// todo: fine-grained toggle
		publicRoutes := []struct {
			path, method string
			handle       router2.Handle
		}{
			{"/api/v1/pages/:uuid", methodGet, m.GetPage},
			{"/api/v1/pages/:uuid/contents", methodGet, m.GetRenderedPage},
			{"/api/v1/pages/:uuid/routes", methodGet, m.ListRoutesByPage},
			{"/api/v1/data/:key", methodGet, m.GetData},
			{"/api/v1/pages", methodGet, m.ListPages},
			{"/api/v1/routes", methodGet, m.ListRoutes},
		}
		for _, route := range publicRoutes {
			m.Router.WrappedHandle(route.method, route.path, route.handle)
		}

		privateRoutes := []struct {
			path, method string
			handle       router2.Handle
		}{
			{"/api/v1/data", methodGet, m.ListData},

			{"/api/v1/user", methodGet, m.GetUser},
			{"/api/v1/settings/info", methodGet, m.GetInfo},
			{"/api/v1/settings/tls", methodGet, m.GetTLS},
			{"/api/v1/settings/tls", methodPost, m.EnableTLS},

			{"/api/v1/themes", methodGet, m.ListThemes},
			{"/api/v1/themes/:name", methodGet, m.GetTheme},
			{"/api/v1/themes/:name/updates", methodGet, m.CheckThemeForUpdate},
			{"/api/v1/themes/:name/update", methodPost, m.UpdateTheme},
			{"/api/v1/themes/:name/templates/:template", methodGet, m.GetTemplate},
			{"/api/v1/theme-registry", methodGet, m.ThemeRegistry},
			{"/api/v1/theme-install", methodPost, m.InstallTheme},

			{"/api/v1/pages", methodPost, m.UpdatePage},
			{"/api/v1/pages/:uuid", methodDelete, m.DeletePage},
			{"/api/v1/pages/:uuid/routes", methodPost, m.UpdateRoutesByPage},
			{"/api/v1/pages/:uuid/publish", methodPost, m.PublishPage},
			{"/api/v1/pages/:uuid/unpublish", methodPost, m.UnpublishPage},

			{"/api/v1/routes", methodPost, m.UpdateRoute},
			{"/api/v1/routes/:uuid", methodDelete, m.DeleteRoute},

			{"/api/v1/data", methodPost, m.UpdateData},
			{"/api/v1/data/:key", methodDelete, m.DeleteData},

			{"/api/v1/files", methodGet, m.ListFiles},
			{"/api/v1/files", methodPost, m.UploadFile},
			{"/api/v1/files/:uuid", methodGet, m.GetFile},
			{"/api/v1/files/:uuid", methodDelete, m.DeleteFile},

			{"/api/v1/download-backup", methodGet, m.GetBackup},
			{"/api/v1/debug", methodGet, m.Debug},
			{"/api/v1/logout", methodGet, m.Logout},
		}
		for _, route := range privateRoutes {
			m.Router.WrappedHandle(route.method, route.path, auth(route.handle))
		}
		return nil
	}
}

func (m *Module) Debug(rw http.ResponseWriter, req *http.Request, par router2.Params) error {
	return m.DB.Debug(rw)
}
<|endoftext|>


<commit_before>// Copyright 2016 Apcera Inc. All rights reserved.

package server

import (
	"flag"
	"github.com/nats-io/go-stan"
	"github.com/nats-io/stan-server/stores"
	"os"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var storeType string

func benchCleanupDatastore(b *testing.B, dir string) {
	if err := os.RemoveAll(dir); err != nil {
		stackFatalf(b, "Error cleaning up datastore: %v", err)
	}
}

func benchRunServer(b *testing.B) *StanServer {
	opts := GetDefaultOptions()
	opts.StoreType = storeType
	if storeType == stores.TypeFile {
		opts.FilestoreDir = defaultDataStore
	}
	s := RunServerWithOpts(opts, nil)
	return s
}

func BenchmarkPublish(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		if err := sc.Publish("foo", hw); err != nil {
			b.Fatalf("Got error on publish: %v\n", err)
		}
	}

	b.StopTimer()
}

func BenchmarkPublishAsync(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	ch := make(chan bool)
	received := int32(0)

	ah := func(guid string, err error) {
		if err != nil {
			b.Fatalf("Received an error in ack callback: %v\n", err)
		}
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		if _, err := sc.PublishAsync("foo", hw, ah); err != nil {
			b.Fatalf("Error from PublishAsync: %v\n", err)
		}
	}

	err := WaitTime(ch, 10*time.Second)
	if err != nil {
		b.Fatal("Timed out waiting for ack messages")
	} else if atomic.LoadInt32(&received) != int32(b.N) {
		b.Fatalf("Received: %d", received)
	}

	b.StopTimer()
}

func BenchmarkSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")
	pch := make(chan bool)

	// Queue up all the messages. Keep this outside of the timing.
	for i := 0; i < b.N; i++ {
		if i == b.N-1 {
			// last one
			sc.PublishAsync("foo", hw, func(lguid string, err error) {
				if err != nil {
					b.Fatalf("Got an error from ack handler, %v", err)
				}
				pch <- true
			})
		} else {
			sc.PublishAsync("foo", hw, nil)
		}
	}

	// Wait for published to finish
	if err := WaitTime(pch, 10*time.Second); err != nil {
		b.Fatalf("Error waiting for publish to finish\n")
	}

	ch := make(chan bool)
	received := int32(0)

	b.StartTimer()

	sc.Subscribe("foo", func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}, stan.DeliverAllAvailable())

	err := WaitTime(ch, 10*time.Second)
	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}

	b.StopTimer()
}

func BenchmarkQueueSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")
	pch := make(chan bool)

	// Queue up all the messages. Keep this outside of the timing.
	for i := 0; i < b.N; i++ {
		if i == b.N-1 {
			// last one
			sc.PublishAsync("foo", hw, func(lguid string, err error) {
				if err != nil {
					b.Fatalf("Got an error from ack handler, %v", err)
				}
				pch <- true
			})
		} else {
			sc.PublishAsync("foo", hw, nil)
		}
	}

	// Wait for published to finish
	if err := WaitTime(pch, 10*time.Second); err != nil {
		b.Fatalf("Error waiting for publish to finish\n")
	}

	ch := make(chan bool)
	received := int32(0)

	b.StartTimer()

	mcb := func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}

	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())

	err := WaitTime(ch, 20*time.Second)
	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}

	b.StopTimer()
}

func BenchmarkPublishSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	ch := make(chan bool)
	received := int32(0)

	// Subscribe callback, counts msgs received.
	_, err := sc.Subscribe("foo", func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}, stan.DeliverAllAvailable())

	if err != nil {
		b.Fatalf("Error subscribing, %v", err)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		_, err := sc.PublishAsync("foo", hw, func(guid string, err error) {
			if err != nil {
				b.Fatalf("Received an error in publish ack callback: %v\n", err)
			}
		})
		if err != nil {
			b.Fatalf("Error publishing %v\n", err)
		}
	}

	err = WaitTime(ch, 30*time.Second)
	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}

	b.StopTimer()
}

func TestMain(m *testing.M) {
	storeType = stores.TypeMemory
	var st string
	flag.StringVar(&st, "store", "", "store type to test: \"file\" for File stores")
	flag.Parse()
	if strings.ToLower(st) == "file" {
		storeType = stores.TypeFile
	}
	os.Exit(m.Run())
}
<commit_msg>Move start/stop of timer closer to what should be measured<commit_after>// Copyright 2016 Apcera Inc. All rights reserved.

package server

import (
	"flag"
	"github.com/nats-io/go-stan"
	"github.com/nats-io/stan-server/stores"
	"os"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var storeType string

func benchCleanupDatastore(b *testing.B, dir string) {
	if err := os.RemoveAll(dir); err != nil {
		stackFatalf(b, "Error cleaning up datastore: %v", err)
	}
}

func benchRunServer(b *testing.B) *StanServer {
	opts := GetDefaultOptions()
	opts.StoreType = storeType
	if storeType == stores.TypeFile {
		opts.FilestoreDir = defaultDataStore
	}
	s := RunServerWithOpts(opts, nil)
	return s
}

func BenchmarkPublish(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		if err := sc.Publish("foo", hw); err != nil {
			b.Fatalf("Got error on publish: %v\n", err)
		}
	}

	b.StopTimer()
}

func BenchmarkPublishAsync(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	ch := make(chan bool)
	received := int32(0)

	ah := func(guid string, err error) {
		if err != nil {
			b.Fatalf("Received an error in ack callback: %v\n", err)
		}
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		if _, err := sc.PublishAsync("foo", hw, ah); err != nil {
			b.Fatalf("Error from PublishAsync: %v\n", err)
		}
	}

	err := WaitTime(ch, 10*time.Second)

	b.StopTimer()

	if err != nil {
		b.Fatal("Timed out waiting for ack messages")
	} else if atomic.LoadInt32(&received) != int32(b.N) {
		b.Fatalf("Received: %d", received)
	}
}

func BenchmarkSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")
	pch := make(chan bool)

	// Queue up all the messages. Keep this outside of the timing.
	for i := 0; i < b.N; i++ {
		if i == b.N-1 {
			// last one
			sc.PublishAsync("foo", hw, func(lguid string, err error) {
				if err != nil {
					b.Fatalf("Got an error from ack handler, %v", err)
				}
				pch <- true
			})
		} else {
			sc.PublishAsync("foo", hw, nil)
		}
	}

	// Wait for published to finish
	if err := WaitTime(pch, 10*time.Second); err != nil {
		b.Fatalf("Error waiting for publish to finish\n")
	}

	ch := make(chan bool)
	received := int32(0)

	b.StartTimer()

	sc.Subscribe("foo", func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}, stan.DeliverAllAvailable())

	err := WaitTime(ch, 10*time.Second)

	b.StopTimer()

	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}
}

func BenchmarkQueueSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")
	pch := make(chan bool)

	// Queue up all the messages. Keep this outside of the timing.
	for i := 0; i < b.N; i++ {
		if i == b.N-1 {
			// last one
			sc.PublishAsync("foo", hw, func(lguid string, err error) {
				if err != nil {
					b.Fatalf("Got an error from ack handler, %v", err)
				}
				pch <- true
			})
		} else {
			sc.PublishAsync("foo", hw, nil)
		}
	}

	// Wait for published to finish
	if err := WaitTime(pch, 10*time.Second); err != nil {
		b.Fatalf("Error waiting for publish to finish\n")
	}

	ch := make(chan bool)
	received := int32(0)

	mcb := func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}

	b.StartTimer()

	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())
	sc.QueueSubscribe("foo", "bar", mcb, stan.DeliverAllAvailable())

	err := WaitTime(ch, 20*time.Second)

	b.StopTimer()

	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}
}

func BenchmarkPublishSubscribe(b *testing.B) {
	b.StopTimer()

	benchCleanupDatastore(b, defaultDataStore)
	defer benchCleanupDatastore(b, defaultDataStore)

	s := benchRunServer(b)
	defer s.Shutdown()

	sc := NewDefaultConnection(b)
	defer sc.Close()

	hw := []byte("Hello World")

	ch := make(chan bool)
	received := int32(0)

	// Subscribe callback, counts msgs received.
	_, err := sc.Subscribe("foo", func(m *stan.Msg) {
		if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) {
			ch <- true
		}
	}, stan.DeliverAllAvailable())

	if err != nil {
		b.Fatalf("Error subscribing, %v", err)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		_, err := sc.PublishAsync("foo", hw, func(guid string, err error) {
			if err != nil {
				b.Fatalf("Received an error in publish ack callback: %v\n", err)
			}
		})
		if err != nil {
			b.Fatalf("Error publishing %v\n", err)
		}
	}

	err = WaitTime(ch, 30*time.Second)

	b.StopTimer()

	nr := atomic.LoadInt32(&received)
	if err != nil {
		b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N)
	} else if nr != int32(b.N) {
		b.Fatalf("Only Received: %d of %d", received, b.N)
	}
}

func TestMain(m *testing.M) {
	storeType = stores.TypeMemory
	var st string
	flag.StringVar(&st, "store", "", "store type to test: \"file\" for File stores")
	flag.Parse()
	if strings.ToLower(st) == "file" {
		storeType = stores.TypeFile
	}
	os.Exit(m.Run())
}
<|endoftext|>


<commit_before>package dondeestas

import (
	"time"
)

type Person struct {
	Id       string `json:"id"`
	Name     string `json:"name"`
	Position struct {
		Tov       time.Time `json:"tov"`
		Latitude  float32   `json:"latitude"`
		Longitude float32   `json:"longitude"`
		Elevation float32   `json:"elevation"`
	} `json:"position"`
	Visible   bool  `json:"visible"`
	Whitelist []int `json:"whitelist"`
	Following []int `json:"following"`
}
<commit_msg>Forgot the lists<commit_after>package dondeestas

import (
	"time"
)

type Person struct {
	Id       string `json:"id"`
	Name     string `json:"name"`
	Position struct {
		Tov       time.Time `json:"tov"`
		Latitude  float32   `json:"latitude"`
		Longitude float32   `json:"longitude"`
		Elevation float32   `json:"elevation"`
	} `json:"position"`
	Visible   bool     `json:"visible"`
	Whitelist []string `json:"whitelist"`
	Following []string `json:"following"`
}
<|endoftext|>