<commit_before>package sparkle

import (
	"net/http"
)
// ActionResults are the results returned from ActionHandlers,
// they are used to abstract away the commonalities around writting
// responses to the client
type ActionResult interface {
	Execute(http.ResponseWriter, *http.Request, *Context) error
}
// ActionHandlers are functions that are called to handle a request in
// sparkle. They recieve a pointer to a sparkle.Context and can return
// ActionResults and/or and error.
//
// When ActionHandlers return ActionResults (with no error), that ActionResult
// is later executed (in most cases) in order to write output to the client
//
// On errors, the framework executes it's configured errorHandler.
type ActionHandler func(*Context) (ActionResult, error)
// ActionWrappers are functions used to wrap action handlers in order to perform
// function prior to or after ActionHandlers.
//
// They are given a pointer to a *sparkle.Context and the ActionHandler it's wrapping.
//
// Because the ActionWrapper is responsible for calling the ActionHandler, it's possible
// for the ActionHandler to actually prevent the ActionHandler from being run.
// Since the ActionWrapper also returns an ActionResult, it's also possible for an
// ActionWrapper to change or subvert the ActionResult to be used.
type ActionWrapper func(*Context, ActionHandler) (ActionResult, error)
// Action adds an ActionHandler to be executed when incoming urls match the given pattern.
//
// By default, the pattern matching is the same as the DefaultMux used by net/http
func Action(pattern string, handler ActionHandler) {
	http.HandleFunc(pattern, createActionHandler(handler))
}

func applyActionWrapper(handler ActionHandler, wrapper ActionWrapper) ActionHandler {
	return func(c *Context) (ActionResult, error) {
		return wrapper(c, handler)
	}
}

// ApplyActionWrappers applies one or more ActionWrappers to an ActionHandler and returns
// the a result ActionHandler that will make sure the wrappers are called into.
//
// Providing that all ActionWrappers call there supplied ActionHandler, then calling
//     ApplyActionWrappers(handler, w1, w2, w3)
// Can be seen as giving a handler that will cause w3 to called, then w2, then w1 and finally handler
//
// An example of an ActionWrapper might be for logging when a certain Action is called.
//
//     func LogAction(c *Context, next ActionHandler) (ActionResult, error) {
//	       log("Action Starting")
//         res, err := next(c)
//         log("Action Complete")
//     }
//
// And this action wrapper can be applied like so:
//     func main() {
//	       sparkle.Action("/MyUrlPattern", sparkle.ApplyActionWrappers(MyHandler, LogAction))
//     }
func ApplyActionWrappers(handler ActionHandler, wrappers ...ActionWrapper) ActionHandler {
	result := handler

	for _, wrapper := range wrappers {
		result = applyActionWrapper(handler, wrapper)
	}

	return result
}
<commit_msg>Fixed up some documentation, after discovering the text had lots of errors.<commit_after>package sparkle

import (
	"net/http"
)
// ActionResults are the results returned from ActionHandlers,
// they are used to abstract away the commonalities around writting
// responses to the client
type ActionResult interface {
	Execute(http.ResponseWriter, *http.Request, *Context) error
}
// ActionHandlers are functions that are called to handle a request in
// sparkle. They recieve a pointer to a sparkle.Context and can return
// an ActionResult and/or an error.
//
// When ActionHandlers return ActionResults (with no error), that ActionResult
// is later executed (in most cases) in order to write output to the client
//
// On errors, the framework executes it's configured error handler.
type ActionHandler func(*Context) (ActionResult, error)
// ActionWrappers are functions used to wrap ActionHandlers in order to perform
// some function prior to or after ActionHandlers.
//
// They are given a pointer to a *sparkle.Context and the ActionHandler it's wrapping.
//
// Because the ActionWrapper is responsible for calling the ActionHandler, it's possible
// for the ActionWrapper to actually prevent the ActionHandler from being run.
// Since the ActionWrapper also returns an ActionResult, it's also possible for an
// ActionWrapper to change or subvert the ActionResult to be used.
type ActionWrapper func(*Context, ActionHandler) (ActionResult, error)
// Action adds an ActionHandler to be executed when incoming urls match the given pattern.
//
// By default, the pattern matching is the same as the DefaultMux used by net/http
func Action(pattern string, handler ActionHandler) {
	http.HandleFunc(pattern, createActionHandler(handler))
}

func applyActionWrapper(handler ActionHandler, wrapper ActionWrapper) ActionHandler {
	return func(c *Context) (ActionResult, error) {
		return wrapper(c, handler)
	}
}

// ApplyActionWrappers applies one or more ActionWrappers to an ActionHandler and returns
// another ActionHandler that will make sure the wrappers are called into.
//
// Providing that all ActionWrappers call their supplied ActionHandler, then calling
//     ApplyActionWrappers(handler, w1, w2, w3)
// can be seen as creating an ActionHandler that will cause w3 to called, then w2, then w1 and finally handler
//
// A simple example of an ActionWrapper might be for logging when a certain Action is called.
//
//     func LogAction(c *Context, next ActionHandler) (ActionResult, error) {
//	       log("Action Starting")
//         res, err := next(c)
//         log("Action Complete")
//         return res, err
//     }
//
// And this action wrapper can be applied like so:
//     func main() {
//	       sparkle.Action("/MyUrlPattern", sparkle.ApplyActionWrappers(MyHandler, LogAction))
//     }
func ApplyActionWrappers(handler ActionHandler, wrappers ...ActionWrapper) ActionHandler {
	result := handler

	for _, wrapper := range wrappers {
		result = applyActionWrapper(handler, wrapper)
	}

	return result
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	docker "github.com/smashwilson/go-dockerclient"
)

// OutputCollector is an io.Writer that accumulates output from a specified stream in an attached
// Docker container and appends it to the appropriate field within a SubmittedJob.
type OutputCollector struct {
	context  *Context
	job      *SubmittedJob
	isStdout bool
}

// DescribeStream returns "stdout" or "stderr" to indicate which stream this collector is consuming.
func (c OutputCollector) DescribeStream() string {
	if c.isStdout {
		return "stdout"
	}
	return "stderr"
}

// Write appends bytes to the selected stream and updates the SubmittedJob.
func (c OutputCollector) Write(p []byte) (int, error) {
	log.WithFields(log.Fields{
		"length": len(p),
		"bytes":  string(p),
		"stream": c.DescribeStream(),
	}).Debug("Received output from a job")

	if c.isStdout {
		c.job.Stdout += string(p)
	} else {
		c.job.Stderr += string(p)
	}

	if err := c.context.UpdateJob(c.job); err != nil {
		return 0, err
	}

	return len(p), nil
}

// Runner is the main entry point for the job runner goroutine.
func Runner(c *Context) {
	for {
		Claim(c)

		time.Sleep(time.Duration(c.Poll) * time.Millisecond)
	}
}

// Claim acquires the oldest single pending job and launches a goroutine to execute its command in
// a new container.
func Claim(c *Context) {
	job, err := c.ClaimJob()
	if err != nil {
		log.WithFields(log.Fields{"error": err}).Error("Unable to claim a job.")
		return
	}
	if job == nil {
		// Nothing to claim.
		return
	}
	if err := job.Validate(); err != nil {
		fields := log.Fields{
			"jid":     job.JID,
			"account": job.Account,
			"error":   err,
		}

		log.WithFields(fields).Error("Invalid job in queue.")

		job.Status = StatusError
		if err := c.UpdateJob(job); err != nil {
			fields["error"] = err
			log.WithFields(fields).Error("Unable to update job status.")
		}

		return
	}

	go Execute(c, job)
}

// Execute launches a container to process the submitted job. It passes any provided stdin data
// to the container and consumes stdout and stderr, updating Mongo as it runs. Once completed, it
// acquires the job's result from its configured source and marks the job as finished.
func Execute(c *Context, job *SubmittedJob) {
	defaultFields := log.Fields{
		"jid":     job.JID,
		"account": job.Account,
	}

	// Logging utility messages.
	debug := func(message string) {
		log.WithFields(defaultFields).Debug(message)
	}
	reportErr := func(message string, err error) {
		fs := log.Fields{}
		for k, v := range defaultFields {
			fs[k] = v
		}
		fs["err"] = err
		log.WithFields(fs).Error(message)
	}
	checkErr := func(message string, err error) bool {
		if err == nil {
			debug(fmt.Sprintf("%s: ok", message))
			return false
		}

		reportErr(fmt.Sprintf("%s: ERROR", message), err)
		return true
	}

	// Update the job model in Mongo, reporting any errors along the way.
	// This also updates our job model with any changes from Mongo, such as the kill request flag.
	updateJob := func(message string) bool {
		if err := c.UpdateJob(job); err != nil {
			reportErr(fmt.Sprintf("Unable to update the job's %s.", message), err)
			return false
		}
		return true
	}

	log.WithFields(defaultFields).Info("Launching a job.")

	job.StartedAt = StoreTime(time.Now())
	job.QueueDelay = job.StartedAt.AsTime().Sub(job.CreatedAt.AsTime()).Nanoseconds()

	image := c.DefaultImage
	if len(job.Layers) != 0 {
		image = job.Layers[0].Name
	}

	container, err := c.CreateContainer(docker.CreateContainerOptions{
		Name: job.ContainerName(),
		Config: &docker.Config{
			Image:     image,
			Cmd:       []string{"/bin/bash", "-c", job.Command},
			OpenStdin: true,
			StdinOnce: true,
		},
	})
	if checkErr("Created the job's container", err) {
		job.Status = StatusError
		updateJob("status")
		return
	}

	// Record the job's container ID.
	job.ContainerID = container.ID
	if !updateJob("start timestamp and container id") {
		return
	}

	// Include container information in this job's logging messages.
	defaultFields["container id"] = container.ID
	defaultFields["container name"] = container.Name

	// Was a kill requested between the time the job was claimed, and the time the container was
	// created? If so: transition the job to StatusKilled and jump ahead to removing the container
	// we just created. If not: continue with job execution normally.

	// If a kill was requested before the job was claimed, it would have been removed from the queue.
	// If a kill is requested after the container was created, it will have the containerID that we
	// just sent and be able to kill the running container.

	if job.KillRequested {
		job.Status = StatusKilled
	} else {
		// Prepare the input and output streams.
		stdin := bytes.NewReader(job.Stdin)
		stdout := OutputCollector{
			context:  c,
			job:      job,
			isStdout: true,
		}
		stderr := OutputCollector{
			context:  c,
			job:      job,
			isStdout: false,
		}

		go func() {
			err = c.AttachToContainer(docker.AttachToContainerOptions{
				Container:    container.ID,
				Stream:       true,
				InputStream:  stdin,
				OutputStream: stdout,
				ErrorStream:  stderr,
				Stdin:        true,
				Stdout:       true,
				Stderr:       true,
			})
			checkErr("Attached to the container", err)
		}()

		// Start the created container.
		err = c.StartContainer(container.ID, &docker.HostConfig{})
		if checkErr("Started the container", err) {
			job.Status = StatusError
			updateJob("status")
			return
		}

		// Measure the container-launch overhead here.
		overhead := time.Now()
		job.OverheadDelay = overhead.Sub(job.StartedAt.AsTime()).Nanoseconds()
		updateJob("overhead delay")

		status, err := c.WaitContainer(container.ID)
		if checkErr("Waited for the container to complete", err) {
			job.Status = StatusError
			updateJob("status")
			return
		}

		job.FinishedAt = StoreTime(time.Now())
		job.Runtime = job.FinishedAt.AsTime().Sub(overhead).Nanoseconds()
		if status == 0 {
			// Successful termination.
			job.Status = StatusDone

			// Extract the result from the job.
			if job.ResultSource == "stdout" {
				job.Result = []byte(job.Stdout)
				debug("Acquired job result from stdout: ok")
			} else if strings.HasPrefix(job.ResultSource, "file:") {
				resultPath := job.ResultSource[len("file:"):len(job.ResultSource)]

				var resultBuffer bytes.Buffer
				err = c.CopyFromContainer(docker.CopyFromContainerOptions{
					Container:    container.ID,
					Resource:     resultPath,
					OutputStream: &resultBuffer,
				})
				if checkErr(fmt.Sprintf("Acquired the job's result from the file [%s]", resultPath), err) {
					job.Status = StatusError
				} else {
					// CopyFromContainer returns the file contents as a tarball.
					var content bytes.Buffer
					r := bytes.NewReader(resultBuffer.Bytes())
					tr := tar.NewReader(r)

					for {
						_, err := tr.Next()
						if err == io.EOF {
							break
						}
						if err != nil {
							reportErr("Read tar-encoded content: ERROR", err)
							job.Status = StatusError
							break
						}

						if _, err = io.Copy(&content, tr); err != nil {
							reportErr("Copy decoded content: ERROR", err)
							job.Status = StatusError
							break
						}
					}

					job.Result = content.Bytes()
				}
			}
		} else {
			// Something went wrong.

			// See if a kill was explicitly requested. If so, transition to StatusKilled. Otherwise,
			// transition to StatusError.
			killed, err := c.JobKillRequested(job.JID)
			if err != nil {
				reportErr("Check the job kill status: ERROR", err)
				return
			}

			if killed {
				job.Status = StatusKilled
			} else {
				job.Status = StatusError
			}
		}

		// Job execution has completed successfully.
	}

	err = c.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID})
	checkErr("Removed the container", err)

	err = c.UpdateAccountUsage(job.Account, job.Runtime)
	if err != nil {
		reportErr("Update account usage: ERROR", err)
	}
	updateJob("status and final result")

	log.WithFields(log.Fields{
		"jid":      job.JID,
		"account":  job.Account,
		"status":   job.Status,
		"runtime":  job.Runtime,
		"overhead": job.OverheadDelay,
		"queue":    job.QueueDelay,
	}).Info("Job complete.")
}
<commit_msg>Log > 1 layers<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	docker "github.com/smashwilson/go-dockerclient"
)

// OutputCollector is an io.Writer that accumulates output from a specified stream in an attached
// Docker container and appends it to the appropriate field within a SubmittedJob.
type OutputCollector struct {
	context  *Context
	job      *SubmittedJob
	isStdout bool
}

// DescribeStream returns "stdout" or "stderr" to indicate which stream this collector is consuming.
func (c OutputCollector) DescribeStream() string {
	if c.isStdout {
		return "stdout"
	}
	return "stderr"
}

// Write appends bytes to the selected stream and updates the SubmittedJob.
func (c OutputCollector) Write(p []byte) (int, error) {
	log.WithFields(log.Fields{
		"length": len(p),
		"bytes":  string(p),
		"stream": c.DescribeStream(),
	}).Debug("Received output from a job")

	if c.isStdout {
		c.job.Stdout += string(p)
	} else {
		c.job.Stderr += string(p)
	}

	if err := c.context.UpdateJob(c.job); err != nil {
		return 0, err
	}

	return len(p), nil
}

// Runner is the main entry point for the job runner goroutine.
func Runner(c *Context) {
	for {
		Claim(c)

		time.Sleep(time.Duration(c.Poll) * time.Millisecond)
	}
}

// Claim acquires the oldest single pending job and launches a goroutine to execute its command in
// a new container.
func Claim(c *Context) {
	job, err := c.ClaimJob()
	if err != nil {
		log.WithFields(log.Fields{"error": err}).Error("Unable to claim a job.")
		return
	}
	if job == nil {
		// Nothing to claim.
		return
	}
	if err := job.Validate(); err != nil {
		fields := log.Fields{
			"jid":     job.JID,
			"account": job.Account,
			"error":   err,
		}

		log.WithFields(fields).Error("Invalid job in queue.")

		job.Status = StatusError
		if err := c.UpdateJob(job); err != nil {
			fields["error"] = err
			log.WithFields(fields).Error("Unable to update job status.")
		}

		return
	}

	go Execute(c, job)
}

// Execute launches a container to process the submitted job. It passes any provided stdin data
// to the container and consumes stdout and stderr, updating Mongo as it runs. Once completed, it
// acquires the job's result from its configured source and marks the job as finished.
func Execute(c *Context, job *SubmittedJob) {
	defaultFields := log.Fields{
		"jid":     job.JID,
		"account": job.Account,
	}

	// Logging utility messages.
	debug := func(message string) {
		log.WithFields(defaultFields).Debug(message)
	}
	reportErr := func(message string, err error) {
		fs := log.Fields{}
		for k, v := range defaultFields {
			fs[k] = v
		}
		fs["err"] = err
		log.WithFields(fs).Error(message)
	}
	checkErr := func(message string, err error) bool {
		if err == nil {
			debug(fmt.Sprintf("%s: ok", message))
			return false
		}

		reportErr(fmt.Sprintf("%s: ERROR", message), err)
		return true
	}

	// Update the job model in Mongo, reporting any errors along the way.
	// This also updates our job model with any changes from Mongo, such as the kill request flag.
	updateJob := func(message string) bool {
		if err := c.UpdateJob(job); err != nil {
			reportErr(fmt.Sprintf("Unable to update the job's %s.", message), err)
			return false
		}
		return true
	}

	log.WithFields(defaultFields).Info("Launching a job.")

	job.StartedAt = StoreTime(time.Now())
	job.QueueDelay = job.StartedAt.AsTime().Sub(job.CreatedAt.AsTime()).Nanoseconds()

	image := c.DefaultImage
	if len(job.Layers) != 0 {
		image = job.Layers[0].Name
		if len(job.Layers) > 1 {
			log.WithFields(log.Fields{
				"layers": job.Layers,
			}).Warn("More than one layer used")
		}

	}

	container, err := c.CreateContainer(docker.CreateContainerOptions{
		Name: job.ContainerName(),
		Config: &docker.Config{
			Image:     image,
			Cmd:       []string{"/bin/bash", "-c", job.Command},
			OpenStdin: true,
			StdinOnce: true,
		},
	})
	if checkErr("Created the job's container", err) {
		job.Status = StatusError
		updateJob("status")
		return
	}

	// Record the job's container ID.
	job.ContainerID = container.ID
	if !updateJob("start timestamp and container id") {
		return
	}

	// Include container information in this job's logging messages.
	defaultFields["container id"] = container.ID
	defaultFields["container name"] = container.Name

	// Was a kill requested between the time the job was claimed, and the time the container was
	// created? If so: transition the job to StatusKilled and jump ahead to removing the container
	// we just created. If not: continue with job execution normally.

	// If a kill was requested before the job was claimed, it would have been removed from the queue.
	// If a kill is requested after the container was created, it will have the containerID that we
	// just sent and be able to kill the running container.

	if job.KillRequested {
		job.Status = StatusKilled
	} else {
		// Prepare the input and output streams.
		stdin := bytes.NewReader(job.Stdin)
		stdout := OutputCollector{
			context:  c,
			job:      job,
			isStdout: true,
		}
		stderr := OutputCollector{
			context:  c,
			job:      job,
			isStdout: false,
		}

		go func() {
			err = c.AttachToContainer(docker.AttachToContainerOptions{
				Container:    container.ID,
				Stream:       true,
				InputStream:  stdin,
				OutputStream: stdout,
				ErrorStream:  stderr,
				Stdin:        true,
				Stdout:       true,
				Stderr:       true,
			})
			checkErr("Attached to the container", err)
		}()

		// Start the created container.
		err = c.StartContainer(container.ID, &docker.HostConfig{})
		if checkErr("Started the container", err) {
			job.Status = StatusError
			updateJob("status")
			return
		}

		// Measure the container-launch overhead here.
		overhead := time.Now()
		job.OverheadDelay = overhead.Sub(job.StartedAt.AsTime()).Nanoseconds()
		updateJob("overhead delay")

		status, err := c.WaitContainer(container.ID)
		if checkErr("Waited for the container to complete", err) {
			job.Status = StatusError
			updateJob("status")
			return
		}

		job.FinishedAt = StoreTime(time.Now())
		job.Runtime = job.FinishedAt.AsTime().Sub(overhead).Nanoseconds()
		if status == 0 {
			// Successful termination.
			job.Status = StatusDone

			// Extract the result from the job.
			if job.ResultSource == "stdout" {
				job.Result = []byte(job.Stdout)
				debug("Acquired job result from stdout: ok")
			} else if strings.HasPrefix(job.ResultSource, "file:") {
				resultPath := job.ResultSource[len("file:"):len(job.ResultSource)]

				var resultBuffer bytes.Buffer
				err = c.CopyFromContainer(docker.CopyFromContainerOptions{
					Container:    container.ID,
					Resource:     resultPath,
					OutputStream: &resultBuffer,
				})
				if checkErr(fmt.Sprintf("Acquired the job's result from the file [%s]", resultPath), err) {
					job.Status = StatusError
				} else {
					// CopyFromContainer returns the file contents as a tarball.
					var content bytes.Buffer
					r := bytes.NewReader(resultBuffer.Bytes())
					tr := tar.NewReader(r)

					for {
						_, err := tr.Next()
						if err == io.EOF {
							break
						}
						if err != nil {
							reportErr("Read tar-encoded content: ERROR", err)
							job.Status = StatusError
							break
						}

						if _, err = io.Copy(&content, tr); err != nil {
							reportErr("Copy decoded content: ERROR", err)
							job.Status = StatusError
							break
						}
					}

					job.Result = content.Bytes()
				}
			}
		} else {
			// Something went wrong.

			// See if a kill was explicitly requested. If so, transition to StatusKilled. Otherwise,
			// transition to StatusError.
			killed, err := c.JobKillRequested(job.JID)
			if err != nil {
				reportErr("Check the job kill status: ERROR", err)
				return
			}

			if killed {
				job.Status = StatusKilled
			} else {
				job.Status = StatusError
			}
		}

		// Job execution has completed successfully.
	}

	err = c.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID})
	checkErr("Removed the container", err)

	err = c.UpdateAccountUsage(job.Account, job.Runtime)
	if err != nil {
		reportErr("Update account usage: ERROR", err)
	}
	updateJob("status and final result")

	log.WithFields(log.Fields{
		"jid":      job.JID,
		"account":  job.Account,
		"status":   job.Status,
		"runtime":  job.Runtime,
		"overhead": job.OverheadDelay,
		"queue":    job.QueueDelay,
	}).Info("Job complete.")
}
<|endoftext|>


<commit_before>package model

import (
	"fmt"
	"strings"
)

type Region struct {
	Name string `yaml:"region,omitempty"`
}

func RegionForName(name string) Region {
	return Region{
		Name: name,
	}
}

func (r Region) PrivateDomainName() string {
	if r.Name == "us-east-1" {
		return "ec2.internal"
	}
	return fmt.Sprintf("%s.compute.internal", r.Name)
}

func (r Region) PublicComputeDomainName() string {
	switch r.Name {
	case "us-east-1":
		return fmt.Sprintf("compute-1.%s", r.PublicDomainName())
	default:
		return fmt.Sprintf("%s.compute.%s", r.Name, r.PublicDomainName())
	}
}

func (r Region) PublicDomainName() string {
	if r.IsChina() {
		return "amazonaws.com.cn"
	}
	return "amazonaws.com"
}

func (r Region) String() string {
	return r.Name
}

func (r Region) S3Endpoint() string {
	if r.IsChina() {
		return fmt.Sprintf("https://s3.%s.amazonaws.com.cn", r.Name)
	}
	return "https://s3.amazonaws.com"
}

func (r Region) Partition() string {
	if r.IsChina() {
		return "aws-cn"
	}
	return "aws"
}

func (r Region) IsChina() bool {
	return strings.HasPrefix(r.Name, "cn-")
}

func (r Region) IsEmpty() bool {
	return r.Name == ""
}

func (r Region) SupportsKMS() bool {
	return !r.IsChina()
}

func (r Region) SupportsNetworkLoadBalancers() bool {
	return !r.IsChina()
}
<commit_msg>Support deployment to AWS GovCloud<commit_after>package model

import (
	"fmt"
	"strings"
)

type Region struct {
	Name string `yaml:"region,omitempty"`
}

func RegionForName(name string) Region {
	return Region{
		Name: name,
	}
}

func (r Region) PrivateDomainName() string {
	if r.Name == "us-east-1" {
		return "ec2.internal"
	}
	return fmt.Sprintf("%s.compute.internal", r.Name)
}

func (r Region) PublicComputeDomainName() string {
	switch r.Name {
	case "us-east-1":
		return fmt.Sprintf("compute-1.%s", r.PublicDomainName())
	default:
		return fmt.Sprintf("%s.compute.%s", r.Name, r.PublicDomainName())
	}
}

func (r Region) PublicDomainName() string {
	if r.IsChina() {
		return "amazonaws.com.cn"
	}
	return "amazonaws.com"
}

func (r Region) String() string {
	return r.Name
}

func (r Region) S3Endpoint() string {
	if r.IsChina() {
		return fmt.Sprintf("https://s3.%s.amazonaws.com.cn", r.Name)
	}
	if r.IsGovcloud() {
		return fmt.Sprintf("https://s3-%s.amazonaws.com", r.Name)
	}
	return "https://s3.amazonaws.com"
}

func (r Region) Partition() string {
	if r.IsChina() {
		return "aws-cn"
	}
	if r.IsGovcloud() {
		return "aws-us-gov"
	}
	return "aws"
}

func (r Region) IsChina() bool {
	return strings.HasPrefix(r.Name, "cn-")
}

func (r Region) IsGovcloud() bool {
	return strings.HasPrefix(r.Name, "us-gov-")
}

func (r Region) IsEmpty() bool {
	return r.Name == ""
}

func (r Region) SupportsKMS() bool {
	return !r.IsChina()
}

func (r Region) SupportsNetworkLoadBalancers() bool {
	return !r.IsChina()
}
<|endoftext|>


<commit_before>package cachectl

const (
	Version   = "0.3.7"
	Cachectl  = "cachectl"
	Cachectld = "cachectld"
)
<commit_msg>bumped version to 0.3.8.<commit_after>package cachectl

const (
	Version   = "0.3.8"
	Cachectl  = "cachectl"
	Cachectld = "cachectld"
)
<|endoftext|>


<commit_before>/*
Package sarama provides client libraries for the Kafka 0.8 protocol. The Client, Producer and Consumer objects are the core of the high-level API. The Broker and Request/Response objects permit more precise control.

The Request/Response objects and properties are mostly undocumented, as they line up exactly with the
protocol fields documented by Kafka at https://cwiki.apache.org/confluence/display/KAFKA/A+Guide+To+The+Kafka+Protocol
*/
package sarama

import (
	"io/ioutil"
	"log"
)

// Logger is the instance of golang's log.Logger that Sarama writes connection
// management events to. By default it is set to discard all log messages via ioutil.Discard,
// but you can set it to redirect wherever you want.
var Logger = log.New(ioutil.Discard, "[Sarama] ", log.LstdFlags)

// PanicHandler is called for recovering from panics spawned internally to the library (and thus
// not recoverable by the caller's goroutine). Defaults to nil, which means panics are not recovered.
var PanicHandler func(interface{})

// MaxRequestSize is the maximum size (in bytes) of any request that Sarama will attempt to send. Trying
// to send a request larger than this will result in an EncodingError. The default of 100 MiB is aligned
// with Kafka's default `socket.request.max.bytes`, which is the largest request the broker will attempt
// to process.
var MaxRequestSize uint32 = 100 * 1024 * 1024
<commit_msg>make logger an interface<commit_after>/*
Package sarama provides client libraries for the Kafka 0.8 protocol. The Client, Producer and Consumer objects are the core of the high-level API. The Broker and Request/Response objects permit more precise control.

The Request/Response objects and properties are mostly undocumented, as they line up exactly with the
protocol fields documented by Kafka at https://cwiki.apache.org/confluence/display/KAFKA/A+Guide+To+The+Kafka+Protocol
*/
package sarama

import (
	"io/ioutil"
	"log"
)

// Logger is the instance of a StdLogger interface that Sarama writes connection
// management events to. By default it is set to discard all log messages via ioutil.Discard,
// but you can set it to redirect wherever you want.
var Logger StdLogger = log.New(ioutil.Discard, "[Sarama] ", log.LstdFlags)

// StdLogger is used to log error messages.
type StdLogger interface {
	Print(v ...interface{})
	Printf(format string, v ...interface{})
	Println(v ...interface{})
}

// PanicHandler is called for recovering from panics spawned internally to the library (and thus
// not recoverable by the caller's goroutine). Defaults to nil, which means panics are not recovered.
var PanicHandler func(interface{})

// MaxRequestSize is the maximum size (in bytes) of any request that Sarama will attempt to send. Trying
// to send a request larger than this will result in an EncodingError. The default of 100 MiB is aligned
// with Kafka's default `socket.request.max.bytes`, which is the largest request the broker will attempt
// to process.
var MaxRequestSize uint32 = 100 * 1024 * 1024
<|endoftext|>


<commit_before>package sawyer

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
)

var httpClient = &http.Client{}

type Client struct {
	HttpClient *http.Client
	Endpoint   *url.URL
	Decoders   map[string]DecoderFunc
}

type DecoderFunc func(r io.Reader) Decoder

type Decoder interface {
	Decode(v interface{}) error
}

func New(endpoint *url.URL, client *http.Client) *Client {
	if client == nil {
		client = httpClient
	}

	if len(endpoint.Path) > 0 && !strings.HasSuffix(endpoint.Path, "/") {
		endpoint.Path = endpoint.Path + "/"
	}

	decoders := map[string]DecoderFunc{
		"json": func(r io.Reader) Decoder {
			return json.NewDecoder(r)
		},
	}
	return &Client{client, endpoint, decoders}
}

func NewFromString(endpoint string, client *http.Client) (*Client, error) {
	e, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}

	return New(e, client), nil
}

func (c *Client) Get(resource interface{}, apierr interface{}, rawurl string) (*http.Response, error) {
	u, err := c.resolveReferenceString(rawurl)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return nil, err
	}

	res, err := c.HttpClient.Do(req)
	if err != nil {
		return res, err
	}
	defer res.Body.Close()

	return res, c.decode(resource, apierr, res)
}

func (c *Client) ResolveReference(u *url.URL) *url.URL {
	return c.Endpoint.ResolveReference(u)
}

func (c *Client) decode(resource interface{}, apierr interface{}, res *http.Response) error {
	// TODO: content type negotiation to find the right decoder
	dec := c.Decoders["json"](res.Body)

	if UseApiError(res.StatusCode) {
		return dec.Decode(apierr)
	}

	return dec.Decode(resource)
}

func (c *Client) resolveReferenceString(rawurl string) (string, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return c.ResolveReference(u).String(), nil
}

func UseApiError(status int) bool {
	switch {
	case status > 199 && status < 300:
		return false
	case status == 304:
		return false
	case status == 0:
		return false
	}
	return true
}
<commit_msg>extract out NewRequest() and Do() that look like core http functions<commit_after>package sawyer

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
)

var httpClient = &http.Client{}

type Client struct {
	HttpClient *http.Client
	Endpoint   *url.URL
	Decoders   map[string]DecoderFunc
}

type DecoderFunc func(r io.Reader) Decoder

type Decoder interface {
	Decode(v interface{}) error
}

func New(endpoint *url.URL, client *http.Client) *Client {
	if client == nil {
		client = httpClient
	}

	if len(endpoint.Path) > 0 && !strings.HasSuffix(endpoint.Path, "/") {
		endpoint.Path = endpoint.Path + "/"
	}

	decoders := map[string]DecoderFunc{
		"json": func(r io.Reader) Decoder {
			return json.NewDecoder(r)
		},
	}
	return &Client{client, endpoint, decoders}
}

func NewFromString(endpoint string, client *http.Client) (*Client, error) {
	e, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}

	return New(e, client), nil
}

func (c *Client) Do(resource interface{}, apierr interface{}, req *http.Request) (*http.Response, error) {
	res, err := c.HttpClient.Do(req)
	if err != nil {
		return res, err
	}
	defer res.Body.Close()

	return res, c.decode(resource, apierr, res)
}

func (c *Client) Get(resource interface{}, apierr interface{}, rawurl string) (*http.Response, error) {
	req, err := c.NewRequest("GET", rawurl, nil)
	if err != nil {
		return nil, err
	}

	return c.Do(resource, apierr, req)
}

func (c *Client) NewRequest(method string, rawurl string, body io.Reader) (*http.Request, error) {
	u, err := c.resolveReferenceString(rawurl)
	if err != nil {
		return nil, err
	}

	return http.NewRequest("GET", u, nil)
}

func (c *Client) ResolveReference(u *url.URL) *url.URL {
	return c.Endpoint.ResolveReference(u)
}

func (c *Client) decode(resource interface{}, apierr interface{}, res *http.Response) error {
	// TODO: content type negotiation to find the right decoder
	dec := c.Decoders["json"](res.Body)

	if UseApiError(res.StatusCode) {
		return dec.Decode(apierr)
	}

	return dec.Decode(resource)
}

func (c *Client) resolveReferenceString(rawurl string) (string, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}
	return c.ResolveReference(u).String(), nil
}

func UseApiError(status int) bool {
	switch {
	case status > 199 && status < 300:
		return false
	case status == 304:
		return false
	case status == 0:
		return false
	}
	return true
}
<|endoftext|>


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

package errors

import (
	"fmt"
	"strings"
)

const (
	invalidType               = "%s is an invalid type name"
	typeFail                  = "%s in %s must be of type %s"
	typeFailWithData          = "%s in %s must be of type %s: %q"
	typeFailWithError         = "%s in %s must be of type %s, because: %s"
	requiredFail              = "%s in %s is required"
	tooLongMessage            = "%s in %s should be at most %d chars long"
	tooShortMessage           = "%s in %s should be at least %d chars long"
	patternFail               = "%s in %s should match '%s'"
	enumFail                  = "%s in %s should be one of %v"
	mulitpleOfFail            = "%s in %s should be a multiple of %v"
	maxIncFail                = "%s in %s should be less than or equal to %v"
	maxExcFail                = "%s in %s should be less than %v"
	minIncFail                = "%s in %s should be greater than or equal to %v"
	minExcFail                = "%s in %s should be greater than %v"
	uniqueFail                = "%s in %s shouldn't contain duplicates"
	maxItemsFail              = "%s in %s should have at most %d items"
	minItemsFail              = "%s in %s should have at least %d items"
	typeFailNoIn              = "%s must be of type %s"
	typeFailWithDataNoIn      = "%s must be of type %s: %q"
	typeFailWithErrorNoIn     = "%s must be of type %s, because: %s"
	requiredFailNoIn          = "%s is required"
	tooLongMessageNoIn        = "%s should be at most %d chars long"
	tooShortMessageNoIn       = "%s should be at least %d chars long"
	patternFailNoIn           = "%s should match '%s'"
	enumFailNoIn              = "%s should be one of %v"
	mulitpleOfFailNoIn        = "%s should be a multiple of %v"
	maxIncFailNoIn            = "%s should be less than or equal to %v"
	maxExcFailNoIn            = "%s should be less than %v"
	minIncFailNoIn            = "%s should be greater than or equal to %v"
	minExcFailNoIn            = "%s should be greater than %v"
	uniqueFailNoIn            = "%s shouldn't contain duplicates"
	maxItemsFailNoIn          = "%s should have at most %d items"
	minItemsFailNoIn          = "%s should have at least %d items"
	noAdditionalItems         = "%s in %s can't have additional items"
	noAdditionalItemsNoIn     = "%s can't have additional items"
	tooFewProperties          = "%s in %s should have at least %d properties"
	tooFewPropertiesNoIn      = "%s should have at least %d properties"
	tooManyProperties         = "%s in %s should have at most %d properties"
	tooManyPropertiesNoIn     = "%s should have at most %d properties"
	unallowedProperty         = "%s.%s in %s is a forbidden property"
	unallowedPropertyNoIn     = "%s.%s is a forbidden property"
	failedAllPatternProps     = "%s.%s in %s failed all pattern properties"
	failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
)

// CompositeError is an error that groups several errors together
type CompositeError struct {
	Errors  []error
	code    int32
	message string
}

func (c *CompositeError) Code() int32 {
	return c.code
}

func (c *CompositeError) Error() string {
	if len(c.Errors) > 0 {
		msgs := []string{c.message + ":"}
		for _, e := range c.Errors {
			msgs = append(msgs, e.Error())
		}
		return strings.Join(msgs, "\n")
	}
	return c.message
}

// CompositeValidationError an error to wrap a bunch of other errors
func CompositeValidationError(errors ...error) *CompositeError {
	return &CompositeError{
		code:    422,
		Errors:  append([]error{}, errors...),
		message: "validation failure list",
	}
}

// FailedAllPatternProperties an error for when the property doesn't match a pattern
func FailedAllPatternProperties(name, in, key string) *Validation {
	msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
	if in == "" {
		msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   key,
		message: msg,
	}
}

// PropertyNotAllowed an error for when the property doesn't match a pattern
func PropertyNotAllowed(name, in, key string) *Validation {
	msg := fmt.Sprintf(unallowedProperty, name, key, in)
	if in == "" {
		msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   key,
		message: msg,
	}
}

// TooFewProperties an error for an object with too few properties
func TooFewProperties(name, in string, n int64) *Validation {
	msg := fmt.Sprintf(tooFewProperties, name, in, n)
	if in == "" {
		msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   n,
		message: msg,
	}
}

// TooManyProperties an error for an object with too many properties
func TooManyProperties(name, in string, n int64) *Validation {
	msg := fmt.Sprintf(tooManyProperties, name, in, n)
	if in == "" {
		msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   n,
		message: msg,
	}
}

// AdditionalItemsNotAllowed an error for invalid additional items
func AdditionalItemsNotAllowed(name, in string) *Validation {
	msg := fmt.Sprintf(noAdditionalItems, name, in)
	if in == "" {
		msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// InvalidCollectionFormat another flavor of invalid type error
func InvalidCollectionFormat(name, in, format string) *Validation {
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   format,
		message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
	}
}

// InvalidTypeName an error for when the type is invalid
func InvalidTypeName(typeName string) *Validation {
	return &Validation{
		code:    422,
		Value:   typeName,
		message: fmt.Sprintf(invalidType, typeName),
	}
}

// InvalidType creates an error for when the type is invalid
func InvalidType(name, in, typeName string, value interface{}) *Validation {
	var message string

	if in != "" {
		switch value.(type) {
		case string:
			message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
		case error:
			message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
		default:
			message = fmt.Sprintf(typeFail, name, in, typeName)
		}
	} else {
		switch value.(type) {
		case string:
			message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
		case error:
			message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
		default:
			message = fmt.Sprintf(typeFailNoIn, name, typeName)
		}
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   value,
		message: message,
	}

}

// DuplicateItems error for when an array contains duplicates
func DuplicateItems(name, in string) *Validation {
	msg := fmt.Sprintf(uniqueFail, name, in)
	if in == "" {
		msg = fmt.Sprintf(uniqueFailNoIn, name)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooManyItems error for when an array contains too many items
func TooManyItems(name, in string, max int64) *Validation {
	msg := fmt.Sprintf(maxItemsFail, name, in, max)
	if in == "" {
		msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooFewItems error for when an array contains too few items
func TooFewItems(name, in string, min int64) *Validation {
	msg := fmt.Sprintf(minItemsFail, name, in, min)
	if in == "" {
		msg = fmt.Sprintf(minItemsFailNoIn, name, min)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// ExceedsMaximum error for when maxinum validation fails
func ExceedsMaximum(name, in string, max float64, exclusive bool) *Validation {
	var message string
	if in == "" {
		m := maxIncFailNoIn
		if exclusive {
			m = maxExcFailNoIn
		}
		message = fmt.Sprintf(m, name, max)
	} else {
		m := maxIncFail
		if exclusive {
			m = maxExcFail
		}
		message = fmt.Sprintf(m, name, in, max)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   max,
		message: message,
	}
}

// ExceedsMinimum error for when maxinum validation fails
func ExceedsMinimum(name, in string, min float64, exclusive bool) *Validation {
	var message string
	if in == "" {
		m := minIncFailNoIn
		if exclusive {
			m = minExcFailNoIn
		}
		message = fmt.Sprintf(m, name, min)
	} else {
		m := minIncFail
		if exclusive {
			m = minExcFail
		}
		message = fmt.Sprintf(m, name, in, min)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   min,
		message: message,
	}
}

// NotMultipleOf error for when multiple of validation fails
func NotMultipleOf(name, in string, multiple float64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(mulitpleOfFailNoIn, name, multiple)
	} else {
		msg = fmt.Sprintf(mulitpleOfFail, name, in, multiple)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   multiple,
		message: msg,
	}
}

// EnumFail error for when an enum validation fails
func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(enumFailNoIn, name, values)
	} else {
		msg = fmt.Sprintf(enumFail, name, in, values)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   value,
		Values:  values,
		message: msg,
	}
}

// Required error for when a value is missing
func Required(name, in string) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(requiredFailNoIn, name)
	} else {
		msg = fmt.Sprintf(requiredFail, name, in)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooLong error for when a string is too long
func TooLong(name, in string, max int64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
	} else {
		msg = fmt.Sprintf(tooLongMessage, name, in, max)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooShort error for when a string is too short
func TooShort(name, in string, min int64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
	} else {
		msg = fmt.Sprintf(tooShortMessage, name, in, min)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// FailedPattern error for when a string fails a regex pattern match
// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
func FailedPattern(name, in, pattern string) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(patternFailNoIn, name, pattern)
	} else {
		msg = fmt.Sprintf(patternFail, name, in, pattern)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}
<commit_msg>cleanup and update vendor<commit_after>// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package errors

import (
	"fmt"
	"strings"
)

const (
	invalidType               = "%s is an invalid type name"
	typeFail                  = "%s in %s must be of type %s"
	typeFailWithData          = "%s in %s must be of type %s: %q"
	typeFailWithError         = "%s in %s must be of type %s, because: %s"
	requiredFail              = "%s in %s is required"
	tooLongMessage            = "%s in %s should be at most %d chars long"
	tooShortMessage           = "%s in %s should be at least %d chars long"
	patternFail               = "%s in %s should match '%s'"
	enumFail                  = "%s in %s should be one of %v"
	mulitpleOfFail            = "%s in %s should be a multiple of %v"
	maxIncFail                = "%s in %s should be less than or equal to %v"
	maxExcFail                = "%s in %s should be less than %v"
	minIncFail                = "%s in %s should be greater than or equal to %v"
	minExcFail                = "%s in %s should be greater than %v"
	uniqueFail                = "%s in %s shouldn't contain duplicates"
	maxItemsFail              = "%s in %s should have at most %d items"
	minItemsFail              = "%s in %s should have at least %d items"
	typeFailNoIn              = "%s must be of type %s"
	typeFailWithDataNoIn      = "%s must be of type %s: %q"
	typeFailWithErrorNoIn     = "%s must be of type %s, because: %s"
	requiredFailNoIn          = "%s is required"
	tooLongMessageNoIn        = "%s should be at most %d chars long"
	tooShortMessageNoIn       = "%s should be at least %d chars long"
	patternFailNoIn           = "%s should match '%s'"
	enumFailNoIn              = "%s should be one of %v"
	mulitpleOfFailNoIn        = "%s should be a multiple of %v"
	maxIncFailNoIn            = "%s should be less than or equal to %v"
	maxExcFailNoIn            = "%s should be less than %v"
	minIncFailNoIn            = "%s should be greater than or equal to %v"
	minExcFailNoIn            = "%s should be greater than %v"
	uniqueFailNoIn            = "%s shouldn't contain duplicates"
	maxItemsFailNoIn          = "%s should have at most %d items"
	minItemsFailNoIn          = "%s should have at least %d items"
	noAdditionalItems         = "%s in %s can't have additional items"
	noAdditionalItemsNoIn     = "%s can't have additional items"
	tooFewProperties          = "%s in %s should have at least %d properties"
	tooFewPropertiesNoIn      = "%s should have at least %d properties"
	tooManyProperties         = "%s in %s should have at most %d properties"
	tooManyPropertiesNoIn     = "%s should have at most %d properties"
	unallowedProperty         = "%s.%s in %s is a forbidden property"
	unallowedPropertyNoIn     = "%s.%s is a forbidden property"
	failedAllPatternProps     = "%s.%s in %s failed all pattern properties"
	failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
)

// CompositeError is an error that groups several errors together
type CompositeError struct {
	Errors  []error
	code    int32
	message string
}

// Code for this error
func (c *CompositeError) Code() int32 {
	return c.code
}

func (c *CompositeError) Error() string {
	if len(c.Errors) > 0 {
		msgs := []string{c.message + ":"}
		for _, e := range c.Errors {
			msgs = append(msgs, e.Error())
		}
		return strings.Join(msgs, "\n")
	}
	return c.message
}

// CompositeValidationError an error to wrap a bunch of other errors
func CompositeValidationError(errors ...error) *CompositeError {
	return &CompositeError{
		code:    422,
		Errors:  append([]error{}, errors...),
		message: "validation failure list",
	}
}

// FailedAllPatternProperties an error for when the property doesn't match a pattern
func FailedAllPatternProperties(name, in, key string) *Validation {
	msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
	if in == "" {
		msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   key,
		message: msg,
	}
}

// PropertyNotAllowed an error for when the property doesn't match a pattern
func PropertyNotAllowed(name, in, key string) *Validation {
	msg := fmt.Sprintf(unallowedProperty, name, key, in)
	if in == "" {
		msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   key,
		message: msg,
	}
}

// TooFewProperties an error for an object with too few properties
func TooFewProperties(name, in string, n int64) *Validation {
	msg := fmt.Sprintf(tooFewProperties, name, in, n)
	if in == "" {
		msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   n,
		message: msg,
	}
}

// TooManyProperties an error for an object with too many properties
func TooManyProperties(name, in string, n int64) *Validation {
	msg := fmt.Sprintf(tooManyProperties, name, in, n)
	if in == "" {
		msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   n,
		message: msg,
	}
}

// AdditionalItemsNotAllowed an error for invalid additional items
func AdditionalItemsNotAllowed(name, in string) *Validation {
	msg := fmt.Sprintf(noAdditionalItems, name, in)
	if in == "" {
		msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// InvalidCollectionFormat another flavor of invalid type error
func InvalidCollectionFormat(name, in, format string) *Validation {
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   format,
		message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
	}
}

// InvalidTypeName an error for when the type is invalid
func InvalidTypeName(typeName string) *Validation {
	return &Validation{
		code:    422,
		Value:   typeName,
		message: fmt.Sprintf(invalidType, typeName),
	}
}

// InvalidType creates an error for when the type is invalid
func InvalidType(name, in, typeName string, value interface{}) *Validation {
	var message string

	if in != "" {
		switch value.(type) {
		case string:
			message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
		case error:
			message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
		default:
			message = fmt.Sprintf(typeFail, name, in, typeName)
		}
	} else {
		switch value.(type) {
		case string:
			message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
		case error:
			message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
		default:
			message = fmt.Sprintf(typeFailNoIn, name, typeName)
		}
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   value,
		message: message,
	}

}

// DuplicateItems error for when an array contains duplicates
func DuplicateItems(name, in string) *Validation {
	msg := fmt.Sprintf(uniqueFail, name, in)
	if in == "" {
		msg = fmt.Sprintf(uniqueFailNoIn, name)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooManyItems error for when an array contains too many items
func TooManyItems(name, in string, max int64) *Validation {
	msg := fmt.Sprintf(maxItemsFail, name, in, max)
	if in == "" {
		msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooFewItems error for when an array contains too few items
func TooFewItems(name, in string, min int64) *Validation {
	msg := fmt.Sprintf(minItemsFail, name, in, min)
	if in == "" {
		msg = fmt.Sprintf(minItemsFailNoIn, name, min)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// ExceedsMaximum error for when maxinum validation fails
func ExceedsMaximum(name, in string, max float64, exclusive bool) *Validation {
	var message string
	if in == "" {
		m := maxIncFailNoIn
		if exclusive {
			m = maxExcFailNoIn
		}
		message = fmt.Sprintf(m, name, max)
	} else {
		m := maxIncFail
		if exclusive {
			m = maxExcFail
		}
		message = fmt.Sprintf(m, name, in, max)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   max,
		message: message,
	}
}

// ExceedsMinimum error for when maxinum validation fails
func ExceedsMinimum(name, in string, min float64, exclusive bool) *Validation {
	var message string
	if in == "" {
		m := minIncFailNoIn
		if exclusive {
			m = minExcFailNoIn
		}
		message = fmt.Sprintf(m, name, min)
	} else {
		m := minIncFail
		if exclusive {
			m = minExcFail
		}
		message = fmt.Sprintf(m, name, in, min)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   min,
		message: message,
	}
}

// NotMultipleOf error for when multiple of validation fails
func NotMultipleOf(name, in string, multiple float64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(mulitpleOfFailNoIn, name, multiple)
	} else {
		msg = fmt.Sprintf(mulitpleOfFail, name, in, multiple)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   multiple,
		message: msg,
	}
}

// EnumFail error for when an enum validation fails
func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(enumFailNoIn, name, values)
	} else {
		msg = fmt.Sprintf(enumFail, name, in, values)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		Value:   value,
		Values:  values,
		message: msg,
	}
}

// Required error for when a value is missing
func Required(name, in string) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(requiredFailNoIn, name)
	} else {
		msg = fmt.Sprintf(requiredFail, name, in)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooLong error for when a string is too long
func TooLong(name, in string, max int64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
	} else {
		msg = fmt.Sprintf(tooLongMessage, name, in, max)
	}
	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// TooShort error for when a string is too short
func TooShort(name, in string, min int64) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
	} else {
		msg = fmt.Sprintf(tooShortMessage, name, in, min)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}

// FailedPattern error for when a string fails a regex pattern match
// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
func FailedPattern(name, in, pattern string) *Validation {
	var msg string
	if in == "" {
		msg = fmt.Sprintf(patternFailNoIn, name, pattern)
	} else {
		msg = fmt.Sprintf(patternFail, name, in, pattern)
	}

	return &Validation{
		code:    422,
		Name:    name,
		In:      in,
		message: msg,
	}
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

type ChangeDirection struct {
	Index     int
	Direction Direction
	Wait      *sync.WaitGroup
}

const (
	Initializing = iota
	InProgress
	Ended
)

type Field struct {
	mu *sync.Mutex //initially used while adding players

	Height, Width int
	needed        int //number of players needed to start the game

	Gophers []*Gopher
	Board   [][]bool

	Change chan ChangeDirection
	Remove chan *Gopher

	State     int
	cycles    int
	nextCycle interface{}
}

var (
	ErrInProgress = errors.New("game is already in progress")
	ErrMaxPlayers = errors.New("cannot add more than 4 players")
)

func New(height, width int, needed int) (*Field, error) {
	if needed > 4 {
		return nil, ErrMaxPlayers
	}

	field := &Field{
		Height:    height,
		needed:    needed,
		Width:     width,
		Board:     make([][]bool, height),
		Change:    make(chan ChangeDirection),
		Remove:    make(chan *Gopher),
		mu:        new(sync.Mutex),
		State:     Initializing,
		nextCycle: time.NewTicker(100 * time.Millisecond),
	}

	for i := range field.Board {
		field.Board[i] = make([]bool, width)
	}

	return field, nil
}

func (f *Field) Add(g *Gopher) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.State == InProgress {
		return ErrInProgress
	}

	f.Gophers = append(f.Gophers, g)
	//set gopher's initial position and direction

	var initPositions = []struct {
		X int
		Y int
		D Direction
	}{
		{f.Width / 2, 0, North},
		{0, f.Height / 2, East},
		{f.Width / 2, f.Height - 1, South},
		{f.Width - 1, f.Height / 2, West},
	}
	for _, pos := range initPositions {
		if !f.Board[pos.X][pos.Y] {
			f.setPos(g, pos.X, pos.Y)
			g.Direction = pos.D
			break
		}
	}

	if len(f.Gophers) == f.needed {
		f.State = Ended
		go f.start()
	}

	return nil
}

func (f *Field) setPos(g *Gopher, X, Y int) {
	f.Board[X][Y] = true
	g.X = X
	g.Y = Y
}

func (f *Field) remove(gopher *Gopher) {
	for i, currGopher := range f.Gophers {
		if currGopher == gopher {
			f.Gophers, f.Gophers[len(f.Gophers)-1] = append(f.Gophers[:i], f.Gophers[i+1:]...), nil
		}
	}
}

func (f *Field) PrintBoard() {
	for y := f.Height - 1; y >= 0; y-- {
		for x := 0; x < f.Width; x++ {
			if f.Board[x][y] {
				fmt.Print(1)
			} else {
				fmt.Print(0)
			}
			//fmt.Printf("(%d,%d)", x, y)
		}
		fmt.Println()
	}
	fmt.Println("-----")
}

func (f *Field) increment(g *Gopher) bool {
	g.Path = append(g.Path, Coordinate{g.X, g.Y})
	switch g.Direction {
	case North:
		g.Y++
	case South:
		g.Y--
	case East:
		g.X++
	case West:
		g.X--
	}

	if g.X == f.Height || g.Y == f.Width {
		return true
	}
	if f.Board[g.X][g.Y] {
		return true
	}

	f.Board[g.X][g.Y] = true
	g.Score++

	if f.cycles > 10 {
		f.Board[g.Path[0].X][g.Path[0].Y] = false
	} else {
		f.cycles++
	}

	return false
}

func (f *Field) clearPath(g *Gopher) {
	for _, c := range g.Path {
		f.Board[c.X][c.Y] = false
	}
}

func (f *Field) start() {
	channel := make(chan struct{})

	switch f.nextCycle.(type) {
	case *time.Ticker:
		go func() {
			for {
				<-f.nextCycle.(time.Ticker).C
				channel <- struct{}{}
			}
		}()
	default:
		//testing
		go func() {
			for {
				channel <- <-f.nextCycle.(chan struct{})
			}
		}()
	}

	for {
		select {
		case dir := <-f.Change:
			f.Gophers[dir.Index].Direction = dir.Direction
			dir.Wait.Done()
		case gopher := <-f.Remove:
			f.remove(gopher)
			if len(f.Gophers) == 1 {
				f.end()
				return
			}
		case <-channel:
			for _, gopher := range f.Gophers {
				if f.increment(gopher) {
					//fmt.Println(i, " collided")
					//gopher collided, clear it's path and remove it
					//from the field
					f.clearPath(gopher)
					f.remove(gopher)

					if len(f.Gophers) == 1 {
						f.end()
						return
					}
				}
			}
			//f.PrintBoard()
		}
	}
}

func (f *Field) end() {
	f.mu.Lock()
	f.State = Ended
	f.mu.Unlock()
	if _, ok := f.nextCycle.(*time.Ticker); ok {
		f.nextCycle.(*time.Ticker).Stop()
	}
}

func (f *Field) broadcast() {

}
<commit_msg>Change New() -> NewField<commit_after>package models

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

type ChangeDirection struct {
	Index     int
	Direction Direction
	Wait      *sync.WaitGroup
}

const (
	Initializing = iota
	InProgress
	Ended
)

type Field struct {
	mu *sync.Mutex //initially used while adding players

	Height, Width int
	needed        int //number of players needed to start the game

	Gophers []*Gopher
	Board   [][]bool

	Change chan ChangeDirection
	Remove chan *Gopher

	State     int
	cycles    int
	nextCycle interface{}
}

var (
	ErrInProgress = errors.New("game is already in progress")
	ErrMaxPlayers = errors.New("cannot add more than 4 players")
)

func NewField(height, width int, needed int) (*Field, error) {
	if needed > 4 {
		return nil, ErrMaxPlayers
	}

	field := &Field{
		Height:    height,
		needed:    needed,
		Width:     width,
		Board:     make([][]bool, height),
		Change:    make(chan ChangeDirection),
		Remove:    make(chan *Gopher),
		mu:        new(sync.Mutex),
		State:     Initializing,
		nextCycle: time.NewTicker(100 * time.Millisecond),
	}

	for i := range field.Board {
		field.Board[i] = make([]bool, width)
	}

	return field, nil
}

func (f *Field) Add(g *Gopher) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	if f.State == InProgress {
		return ErrInProgress
	}

	f.Gophers = append(f.Gophers, g)
	//set gopher's initial position and direction

	var initPositions = []struct {
		X int
		Y int
		D Direction
	}{
		{f.Width / 2, 0, North},
		{0, f.Height / 2, East},
		{f.Width / 2, f.Height - 1, South},
		{f.Width - 1, f.Height / 2, West},
	}
	for _, pos := range initPositions {
		if !f.Board[pos.X][pos.Y] {
			f.setPos(g, pos.X, pos.Y)
			g.Direction = pos.D
			break
		}
	}

	if len(f.Gophers) == f.needed {
		f.State = Ended
		go f.start()
	}

	return nil
}

func (f *Field) setPos(g *Gopher, X, Y int) {
	f.Board[X][Y] = true
	g.X = X
	g.Y = Y
}

func (f *Field) remove(gopher *Gopher) {
	for i, currGopher := range f.Gophers {
		if currGopher == gopher {
			f.Gophers, f.Gophers[len(f.Gophers)-1] = append(f.Gophers[:i], f.Gophers[i+1:]...), nil
		}
	}
}

func (f *Field) PrintBoard() {
	for y := f.Height - 1; y >= 0; y-- {
		for x := 0; x < f.Width; x++ {
			if f.Board[x][y] {
				fmt.Print(1)
			} else {
				fmt.Print(0)
			}
			//fmt.Printf("(%d,%d)", x, y)
		}
		fmt.Println()
	}
	fmt.Println("-----")
}

func (f *Field) increment(g *Gopher) bool {
	g.Path = append(g.Path, Coordinate{g.X, g.Y})
	switch g.Direction {
	case North:
		g.Y++
	case South:
		g.Y--
	case East:
		g.X++
	case West:
		g.X--
	}

	if g.X == f.Height || g.Y == f.Width {
		return true
	}
	if f.Board[g.X][g.Y] {
		return true
	}

	f.Board[g.X][g.Y] = true
	g.Score++

	if f.cycles > 10 {
		f.Board[g.Path[0].X][g.Path[0].Y] = false
	} else {
		f.cycles++
	}

	return false
}

func (f *Field) clearPath(g *Gopher) {
	for _, c := range g.Path {
		f.Board[c.X][c.Y] = false
	}
}

func (f *Field) start() {
	channel := make(chan struct{})

	switch f.nextCycle.(type) {
	case *time.Ticker:
		go func() {
			for {
				<-f.nextCycle.(time.Ticker).C
				channel <- struct{}{}
			}
		}()
	default:
		//testing
		go func() {
			for {
				channel <- <-f.nextCycle.(chan struct{})
			}
		}()
	}

	for {
		select {
		case dir := <-f.Change:
			f.Gophers[dir.Index].Direction = dir.Direction
			dir.Wait.Done()
		case gopher := <-f.Remove:
			f.remove(gopher)
			if len(f.Gophers) == 1 {
				f.end()
				return
			}
		case <-channel:
			for _, gopher := range f.Gophers {
				if f.increment(gopher) {
					//fmt.Println(i, " collided")
					//gopher collided, clear it's path and remove it
					//from the field
					f.clearPath(gopher)
					f.remove(gopher)

					if len(f.Gophers) == 1 {
						f.end()
						return
					}
				}
			}
			//f.PrintBoard()
		}
	}
}

func (f *Field) end() {
	f.mu.Lock()
	f.State = Ended
	f.mu.Unlock()
	if _, ok := f.nextCycle.(*time.Ticker); ok {
		f.nextCycle.(*time.Ticker).Stop()
	}
}

func (f *Field) broadcast() {

}
<|endoftext|>


<commit_before>package gallium

/*
#cgo CFLAGS: -mmacosx-version-min=10.8
#cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
#cgo CFLAGS: -Idist/include

#include <stdlib.h>
#include "gallium/screen.h"
*/
import "C"
import "fmt"

// A screen represents a physical rectangular display. "Device coordinates"
// means a position on a screen measured from (0, 0) at the bottom left of
// the device. "Global coordinates" means the coordinate system in which
// each of the screens are positioned relative to each other. Global and
// device coordinates almost always have the same scale factor. It is
// possible for screens to overlap in global coordinates (such as when
// mirroring a display.)
type Screen struct {
	Shape        Rect // the size and position of this screen in global coords
	Usable       Rect // excludes the menubar and dock
	BitsPerPixel int  // color depth of this screen (total of all color components)
	ID           int  // unique identifier for this screen
}

func screenFromC(c *C.gallium_screen_t) Screen {
	return Screen{
		Shape:        rectFromC(C.GalliumScreenShape(c)),
		Usable:       rectFromC(C.GalliumScreenUsable(c)),
		BitsPerPixel: int(C.GalliumScreenBitsPerPixel(c)),
		ID:           int(C.GalliumScreenID(c)),
	}
}

// Screens gets a list of available screens
func Screens() []Screen {
	var screens []Screen
	n := int(C.GalliumScreenCount())
	for i := 0; i < n; i++ {
		c := C.GalliumScreen(C.int(i))
		if c == nil {
			panic(fmt.Sprintf("GalliumScreen returned nil for index %d", i))
		}
		screens = append(screens, screenFromC(c))
	}
	return screens
}

// FocussedScreen gets the screen containing the currently focussed window
func FocussedScreen() Screen {
	c := C.GalliumFocussedScreen()
	if c == nil {
		panic("GalliumFocussedScreen returned nil")
	}
	return screenFromC(c)
}
<commit_msg>fix misspelling<commit_after>package gallium

/*
#cgo CFLAGS: -mmacosx-version-min=10.8
#cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
#cgo CFLAGS: -Idist/include

#include <stdlib.h>
#include "gallium/screen.h"
*/
import "C"
import "fmt"

// A screen represents a rectangular display, normally corresponding to a
// physical display. "Device coordinates" means a position on a screen
// measured from (0, 0) at the bottom left of the device. "Global coordinates"
// means the coordinate system in which each of the screens are positioned
// relative to each other. Global and device coordinates almost always have
// the same scale factor. It is possible for screens to overlap in global
// coordinates (such as when mirroring a display.)
type Screen struct {
	Shape        Rect // the size and position of this screen in global coords
	Usable       Rect // excludes the menubar and dock
	BitsPerPixel int  // color depth of this screen (total of all color components)
	ID           int  // unique identifier for this screen
}

func screenFromC(c *C.gallium_screen_t) Screen {
	return Screen{
		Shape:        rectFromC(C.GalliumScreenShape(c)),
		Usable:       rectFromC(C.GalliumScreenUsable(c)),
		BitsPerPixel: int(C.GalliumScreenBitsPerPixel(c)),
		ID:           int(C.GalliumScreenID(c)),
	}
}

// Screens gets a list of available screens
func Screens() []Screen {
	var screens []Screen
	n := int(C.GalliumScreenCount())
	for i := 0; i < n; i++ {
		c := C.GalliumScreen(C.int(i))
		if c == nil {
			panic(fmt.Sprintf("GalliumScreen returned nil for index %d", i))
		}
		screens = append(screens, screenFromC(c))
	}
	return screens
}

// FocusedScreen gets the screen containing the currently focused window
func FocusedScreen() Screen {
	c := C.GalliumFocusedScreen()
	if c == nil {
		panic("GalliumFocusedScreen returned nil")
	}
	return screenFromC(c)
}
<|endoftext|>


<commit_before>package main

/**
 * Barista Server
 *
 * @author: Anant Bhardwaj
 * @date: 03/23/2014
 */

import "fmt"
import "barista"
import "git.apache.org/thrift.git/lib/go/thrift"
import "net"
import "strings"

const PORT = ":9000"
var ADDRS = []string {"128.52.161.243", "128.52.160.104", "128.52.161.242", "128.52.160.122", "128.52.161.24"}

func main() {
  protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
  transportFactory := thrift.NewTTransportFactory()

  addrs, err := net.InterfaceAddrs()
  addr := ""

  if err != nil || len(addrs) < 2 {
     fmt.Println("Error getting ip: ", err)
     addr = "localhost"
  } else {
     addr = strings.Split(addrs[1].String(), "/")[0]
  }

  transport, err := thrift.NewTServerSocket(addr + PORT)

  if err != nil {
    fmt.Println("Error: ", err)
    return
  }

  me := -1
  for i, server := range ADDRS {
     if addr == server {
        me = i
     }
  }

  if me == -1 {
     fmt.Println("Error: I am not listed in the servers")
     return
  }

  handler := NewBaristaHandler(ADDRS, me)
  processor := barista.NewBaristaProcessor(handler)
  server := thrift.NewTSimpleServer4(processor, transport, transportFactory, protocolFactory)

  fmt.Println("Starting the Barista server on ", addr + PORT)
  server.Serve()
}
<commit_msg>run json server<commit_after>package main

/**
 * Barista Server
 *
 * @author: Anant Bhardwaj
 * @date: 03/23/2014
 */

import "fmt"
import "barista"
import "git.apache.org/thrift.git/lib/go/thrift"
import "net"
import "strings"

const PORT_BINARY = ":9000"
const PORT_JSON = ":9090"
var ADDRS = []string {"128.52.161.243", "128.52.160.104", "128.52.161.242", "128.52.160.122", "128.52.161.24"}

func main() {
  binary_protocol_factory := thrift.NewTBinaryProtocolFactoryDefault()
  json_protocol_factory := thrift.NewTJSONProtocolFactoryDefault()
  transport_factory := thrift.NewTTransportFactory()

  addrs, err := net.InterfaceAddrs()
  addr := ""

  if err != nil || len(addrs) < 2 {
     fmt.Println("Error getting ip: ", err)
     addr = "localhost"
  } else {
     addr = strings.Split(addrs[1].String(), "/")[0]
  }

  binary_transport, err := thrift.NewTServerSocket(addr + PORT_BINARY)
  json_transport, err := thrift.NewTServerSocket(addr + PORT_JSON)

  if err != nil {
    fmt.Println("Error: ", err)
    return
  }

  me := -1
  for i, server := range ADDRS {
     if addr == server {
        me = i
     }
  }

  if me == -1 {
     fmt.Println("Error: I am not listed in the servers")
     return
  }

  handler := NewBaristaHandler(ADDRS, me)
  processor := barista.NewBaristaProcessor(handler)
  binary_server := thrift.NewTSimpleServer4(processor, binary_transport, transport_factory, binary_protocol_factory)
  json_server := thrift.NewTSimpleServer4(processor, json_transport, transport_factory, json_protocol_factory)

  fmt.Println("Starting the Barista server (Binary Mode) on ", addr + PORT_BINARY)
  binary_server.Serve()

  fmt.Println("Starting the Barista server (JSON Mode) on ", addr + PORT_JSON)
  json_server.Serve()
}
<|endoftext|>


<commit_before>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sippy_log

import (
    "fmt"
    "runtime"
    "os"
    "strings"
    "sync"
    "time"
)

type ErrorLogger interface {
    ErrorAndTraceback(interface{})
    Error(...interface{})
    Debug(...interface{})
    Errorf(string, ...interface{})
    Debugf(string, ...interface{})
}

type errorLogger struct {
    lock    sync.Mutex
}

func NewErrorLogger() *errorLogger {
    return &errorLogger{}
}

func (self *errorLogger) ErrorAndTraceback(err interface{}) {
    self.lock.Lock()
    defer self.lock.Unlock()
    self.Error(err)
    buf := make([]byte, 16384)
    runtime.Stack(buf, false)
    s := string(buf)
    for _, l := range strings.Split(s, "\n") {
        self.Error(l)
    }
}

func (self *errorLogger) Debug(params...interface{}) {
    self.write("DEBUG:", params...)
}

func (self *errorLogger) Debugf(format string, params...interface{}) {
    self.write("DEBUG:", fmt.Sprintf(format, params...))
}

func (self *errorLogger) Error(params...interface{}) {
    self.write("ERROR:", params...)
}

func (self *errorLogger) Errorf(format string, params...interface{}) {
    self.write("ERROR:", fmt.Sprintf(format, params...))
}

func (*errorLogger) Reopen() {
}

func (*errorLogger) write(prefix string, params ...interface{}) {
    t := time.Now().UTC()
    buf := []interface{}{ fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d+00", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()), " ", prefix }
    for _, it := range params {
        buf = append(buf, " ", it)
    }
    buf = append(buf, "\n")
    fmt.Fprint(os.Stderr, buf...)
}
<commit_msg>Do not dump whole 16k buffer.<commit_after>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sippy_log

import (
    "fmt"
    "runtime"
    "os"
    "strings"
    "sync"
    "time"
)

type ErrorLogger interface {
    ErrorAndTraceback(interface{})
    Error(...interface{})
    Debug(...interface{})
    Errorf(string, ...interface{})
    Debugf(string, ...interface{})
}

type errorLogger struct {
    lock    sync.Mutex
}

func NewErrorLogger() *errorLogger {
    return &errorLogger{}
}

func (self *errorLogger) ErrorAndTraceback(err interface{}) {
    self.lock.Lock()
    defer self.lock.Unlock()
    self.Error(err)
    buf := make([]byte, 16384)
    n := runtime.Stack(buf, false)
    s := string(buf[:n])
    for _, l := range strings.Split(s, "\n") {
        self.Error(l)
    }
}

func (self *errorLogger) Debug(params...interface{}) {
    self.write("DEBUG:", params...)
}

func (self *errorLogger) Debugf(format string, params...interface{}) {
    self.write("DEBUG:", fmt.Sprintf(format, params...))
}

func (self *errorLogger) Error(params...interface{}) {
    self.write("ERROR:", params...)
}

func (self *errorLogger) Errorf(format string, params...interface{}) {
    self.write("ERROR:", fmt.Sprintf(format, params...))
}

func (*errorLogger) Reopen() {
}

func (*errorLogger) write(prefix string, params ...interface{}) {
    t := time.Now().UTC()
    buf := []interface{}{ fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d+00", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()), " ", prefix }
    for _, it := range params {
        buf = append(buf, " ", it)
    }
    buf = append(buf, "\n")
    fmt.Fprint(os.Stderr, buf...)
}
<|endoftext|>


<commit_before>package cat

import (
	"bytes"
	"github.com/phyxdown/ghost/pool"
	"time"
)

var (
	sender_transaction_channel        chan Message
	sender_max_batch_size int
	sender_pool          pool.Pool
)

//cat_sender_init is internally used and only called by Cat_init_if.
func cat_sender_init() {
	sender_transaction_channel = make(chan Message, 1<<10)
	sender_max_batch_size = 1 << 8
	sender_pool, _ = pool.NewBlockingPool(3, 3, CONN_FACTORY)
	go sender_run()
}

//sender_run call sender_collect repeatedly.
//Basically, only 1 goroutine keeps this function.
func sender_run() {
	for {
		if sender_collect() {
			time.Sleep(1 << 16 * time.Microsecond)
		}
	}
}

func sender_collect() bool {
	messages := make(chan Message, sender_max_batch_size)
	var count = 0
collect:
	for count < sender_max_batch_size {
		select {
		case message := <-sender_transaction_channel:
			messages <- message
			count++
		default:
			break collect
		}
	}
	close(messages)
	if count > 0 {
		sender_encode(messages, count)
		return false
	} else {
		return true
	}
}

func sender_encode(messages <-chan Message, count int) {
	datas := make(chan []byte, count)
	for message := range messages {
		buf := bytes.NewBuffer([]byte{0, 0, 0, 0})
		NewHeader().Encode(buf)
		message.Encode(buf)
		load := int32tobytes(int32(buf.Len() - 4))
		data := buf.Bytes()
		data[0] = load[0]
		data[1] = load[1]
		data[2] = load[2]
		data[3] = load[3]
		datas <- data
	}
	close(datas)
	go sender_send(datas)
}

func sender_send(datas <-chan []byte) {
	conn, err := sender_pool.Get()
	if err != nil {
		return
	}
	defer conn.Close()
	for data := range datas {
		conn.Write(data)
	}
}
<commit_msg>go fmt<commit_after>package cat

import (
	"bytes"
	"github.com/phyxdown/ghost/pool"
	"time"
)

var (
	sender_transaction_channel chan Message
	sender_max_batch_size      int
	sender_pool                pool.Pool
)

//cat_sender_init is internally used and only called by Cat_init_if.
func cat_sender_init() {
	sender_transaction_channel = make(chan Message, 1<<10)
	sender_max_batch_size = 1 << 8
	sender_pool, _ = pool.NewBlockingPool(3, 3, CONN_FACTORY)
	go sender_run()
}

//sender_run call sender_collect repeatedly.
//Basically, only 1 goroutine keeps this function.
func sender_run() {
	for {
		if sender_collect() {
			time.Sleep(1 << 16 * time.Microsecond)
		}
	}
}

//False returned when it seems to be busy.
func sender_collect() bool {
	messages := make(chan Message, sender_max_batch_size)
	var count = 0
collect:
	for count < sender_max_batch_size {
		select {
		case message := <-sender_transaction_channel:
			messages <- message
			count++
		default:
			break collect
		}
	}
	close(messages)
	if count > 0 {
		sender_encode(messages, count)
		return false
	} else {
		return true
	}
}

func sender_encode(messages <-chan Message, count int) {
	datas := make(chan []byte, count)
	for message := range messages {
		buf := bytes.NewBuffer([]byte{0, 0, 0, 0})
		NewHeader().Encode(buf)
		message.Encode(buf)
		load := int32tobytes(int32(buf.Len() - 4))
		data := buf.Bytes()
		data[0] = load[0]
		data[1] = load[1]
		data[2] = load[2]
		data[3] = load[3]
		datas <- data
	}
	close(datas)
	go sender_send(datas)
}

func sender_send(datas <-chan []byte) {
	conn, err := sender_pool.Get()
	if err != nil {
		return
	}
	defer conn.Close()
	for data := range datas {
		conn.Write(data)
	}
}
<|endoftext|>


<commit_before>// Package server offers a simple server with logging and configs
package server

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
)

// TODO: Graceful restart would be nice - http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/

// Logger interface for a simple logger (the stdlib log pkg and the fragmenta log pkg conform)
type Logger interface {
	Printf(format string, args ...interface{})
}

// Server holds the config and logger for the app
type Server struct {
	// Our internal logger instance
	Logger Logger

	// Which port to serve on
	port int

	// Which env mode we're in, read from ENV variable
	production bool

	// Server configs - access with Config(string)
	configProduction  map[string]string
	configDevelopment map[string]string
	configTest        map[string]string
}

// New creates a new server instance
func New() (*Server, error) {

	// Check environment variable to see if we are in production mode
	prod := false
	if os.Getenv("FRAG_ENV") == "production" {
		prod = true
	}

	// Set up a new server
	s := &Server{
		port:              3000,
		production:        prod,
		configProduction:  make(map[string]string),
		configDevelopment: make(map[string]string),
		configTest:        make(map[string]string),
		Logger:            log.New(os.Stderr, "fragmenta: ", log.LstdFlags), // default to a stderr logger
	}

	err := s.readConfig()
	if err != nil {
		return s, err
	}
	err = s.readArguments()
	if err != nil {
		return s, err
	}

	return s, err
}

// Logf logs the message with the given arguments to our internal logger
func (s *Server) Logf(format string, v ...interface{}) {
	s.Logger.Printf(format, v...)
}

// Log logs the message to our internal logger
func (s *Server) Log(message string) {
	s.Logf(message)
}

// Fatalf the message with the given arguments to our internal logger, and then exits with status 1
func (s *Server) Fatalf(format string, v ...interface{}) {
	s.Logger.Printf(format, v...)

	// Now exit
	os.Exit(1)
}

// Fatal logs the message, and then exits with status 1
func (s *Server) Fatal(format string) {
	s.Fatalf(format)
}

// Timef logs a time since starting, when used with defer at the start of a function to time
// Usage: defer s.Timef("Completed %s in %s",time.Now(),args...)
func (s *Server) Timef(format string, start time.Time, v ...interface{}) {
	end := time.Since(start).String()
	var args []interface{}
	args = append(args, end)
	args = append(args, v...)
	s.Logf(format, args...)
}

// Start starts the http server on our given port
func (s *Server) Start() error {
	p := fmt.Sprintf(":%d", s.port)
	return http.ListenAndServe(p, nil)
}
<commit_msg>Support tls connections using config keys<commit_after>// Package server offers a simple server with logging and configs
package server

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"
)

// TODO: Graceful restart would be nice - http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/

// Logger interface for a simple logger (the stdlib log pkg and the fragmenta log pkg conform)
type Logger interface {
	Printf(format string, args ...interface{})
}

// Server holds the config and logger for the app
type Server struct {
	// Our internal logger instance
	Logger Logger

	// Which port to serve on
	port int

	// Which env mode we're in, read from ENV variable
	production bool

	// Server configs - access with Config(string)
	configProduction  map[string]string
	configDevelopment map[string]string
	configTest        map[string]string
}

// New creates a new server instance
func New() (*Server, error) {

	// Check environment variable to see if we are in production mode
	prod := false
	if os.Getenv("FRAG_ENV") == "production" {
		prod = true
	}

	// Set up a new server
	s := &Server{
		port:              3000,
		production:        prod,
		configProduction:  make(map[string]string),
		configDevelopment: make(map[string]string),
		configTest:        make(map[string]string),
		Logger:            log.New(os.Stderr, "fragmenta: ", log.LstdFlags), // default to a stderr logger
	}

	err := s.readConfig()
	if err != nil {
		return s, err
	}
	err = s.readArguments()
	if err != nil {
		return s, err
	}

	return s, err
}

// Logf logs the message with the given arguments to our internal logger
func (s *Server) Logf(format string, v ...interface{}) {
	s.Logger.Printf(format, v...)
}

// Log logs the message to our internal logger
func (s *Server) Log(message string) {
	s.Logf(message)
}

// Fatalf the message with the given arguments to our internal logger, and then exits with status 1
func (s *Server) Fatalf(format string, v ...interface{}) {
	s.Logger.Printf(format, v...)

	// Now exit
	os.Exit(1)
}

// Fatal logs the message, and then exits with status 1
func (s *Server) Fatal(format string) {
	s.Fatalf(format)
}

// Timef logs a time since starting, when used with defer at the start of a function to time
// Usage: defer s.Timef("Completed %s in %s",time.Now(),args...)
func (s *Server) Timef(format string, start time.Time, v ...interface{}) {
	end := time.Since(start).String()
	var args []interface{}
	args = append(args, end)
	args = append(args, v...)
	s.Logf(format, args...)
}

// Start starts an http server on the given port
func (s *Server) Start() error {
	p := fmt.Sprintf(":%d", s.port)
	return http.ListenAndServe(p, nil)
}

// StartTLS starts an https server on the given port
func (s *Server) StartTLS() error {
	port := fmt.Sprintf(":%d", s.port)
	cert := s.Config("tls_cert")
	key := s.Config("tls_key")
	return http.ListenAndServeTLS(port, cert, key, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"io/ioutil"
	"log/syslog"

	"golang.org/x/crypto/ssh"
  log "github.com/Sirupsen/logrus"
  logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
  "github.com/rifflock/lfshook"
)

func setupLogging() {
  logLevel := log.InfoLevel
  if os.Getenv("DEBUG") == "true" { logLevel = log.DebugLevel }
  log.SetLevel(logLevel)

	logrusFileHook := lfshook.NewHook(lfshook.PathMap{
	  log.InfoLevel : "/var/log/sshoney.log",
	  log.WarnLevel : "/var/log/sshoney.log",
	  log.ErrorLevel : "/var/log/sshoney.log",
	  log.FatalLevel : "/var/log/sshoney.log",
	  log.PanicLevel : "/var/log/sshoney.log",
  })
	log.AddHook(logrusFileHook)

	logrusSysLogHook, err := logrus_syslog.NewSyslogHook("", "localhost", syslog.LOG_INFO, "sshoney")
	if err != nil { log.Fatalf("Failed to add syslog logrus hook - %s", err) }
  log.AddHook(logrusSysLogHook)

	log.SetFormatter(&log.TextFormatter{DisableColors: true})
}

func main() {
  setupLogging()

	sshConfig := &ssh.ServerConfig{
		NoClientAuth: true,
	}

	privateBytes, err := ioutil.ReadFile("./host.key")
	if err != nil { log.Fatal("Failed to load private key ./host.key.  Run make gen_ssh_key") }

	private, err := ssh.ParsePrivateKey(privateBytes)
	if err != nil { log.Fatal("Failed to parse private key") }
	sshConfig.AddHostKey(private)

  port := "2222"
  if os.Getenv("PORT") != "" {
    port = os.Getenv("PORT")
  }

  portComplete := fmt.Sprintf(":%s", port)
	listener, err := net.Listen("tcp4", portComplete)
	if err != nil { log.Fatalf("failed to listen on *:%s", port) }

	log.Printf("listening on %s", port)

	for {
		tcpConn, err := listener.Accept()
		if err != nil {
			log.Debugf("failed to accept incoming connection (%s)", err)
			continue
		}

		log.Debugf("new TCP connection from %s", tcpConn.RemoteAddr())

		sshConn, _, _, err := ssh.NewServerConn(tcpConn, sshConfig)
		if err != nil {
			log.Debugf("failed to handshake (%s)", err)
			continue
		}

		log.Printf("new SSH connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion())

    sshConn.Close()
	}
}
<commit_msg>Actually threaded now!<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"io/ioutil"
	"log/syslog"

  log "github.com/Sirupsen/logrus"
  logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
	"golang.org/x/crypto/ssh"
  "github.com/rifflock/lfshook"
  // "github.com/codegangsta/cli"
)

func setupCLI() {
	// cli.NewApp().Run(os.Args)
}

func setupLogging() {
  logLevel := log.InfoLevel
  if os.Getenv("DEBUG") == "true" { logLevel = log.DebugLevel }
  log.SetLevel(logLevel)

	log.SetFormatter(&log.TextFormatter{DisableColors: true})

	setupFileLogging()
	setupSyslogLogging()
}

func setupFileLogging() {
	logrusFileHook := lfshook.NewHook(lfshook.PathMap{
	  log.InfoLevel : "/var/log/sshoney.log",
	  log.WarnLevel : "/var/log/sshoney.log",
	  log.ErrorLevel : "/var/log/sshoney.log",
	  log.FatalLevel : "/var/log/sshoney.log",
	  log.PanicLevel : "/var/log/sshoney.log",
  })
	log.AddHook(logrusFileHook)
}

func setupSyslogLogging() {
	logrusSysLogHook, err := logrus_syslog.NewSyslogHook("", "localhost", syslog.LOG_INFO, "sshoney")
	if err != nil { log.Fatalf("Failed to add syslog logrus hook - %s", err) }
	log.AddHook(logrusSysLogHook)
}

func setupSSHListener() (ssh.ServerConfig, net.Listener) {
	sshConfig := &ssh.ServerConfig{
		NoClientAuth: true,
	}

	privateBytes, err := ioutil.ReadFile("./host.key")
	if err != nil { log.Fatal("Failed to load private key ./host.key.  Run make gen_ssh_key") }

	private, err := ssh.ParsePrivateKey(privateBytes)
	if err != nil { log.Fatal("Failed to parse private key") }
	sshConfig.AddHostKey(private)

  port := "2222"
  if os.Getenv("PORT") != "" {
    port = os.Getenv("PORT")
  }

  portComplete := fmt.Sprintf(":%s", port)
	listener, err := net.Listen("tcp4", portComplete)
	if err != nil { log.Fatalf("failed to listen on *:%s", port) }

	log.Printf("listening on %s", port)

	return *sshConfig, listener;
}

func processConnections(sshConfig *ssh.ServerConfig, listener net.Listener) {
	for {
		tcpConn, err := listener.Accept()
		if err != nil {
			log.Debugf("failed to accept incoming connection (%s)", err)
			continue
		}
		go handleConnection(sshConfig, tcpConn)
	}
}

func handleConnection(sshConfig *ssh.ServerConfig, tcpConn net.Conn) {
	defer tcpConn.Close()

	log.Debugf("new TCP connection from %s", tcpConn.RemoteAddr())

	sshConn, _, _, err := ssh.NewServerConn(tcpConn, sshConfig)
	if err != nil {
		log.Debugf("failed to handshake (%s)", err)
	} else {
		log.Printf("new SSH connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion())
		sshConn.Close()
	}
}

func main() {
	setupCLI()
	setupLogging()
	sshConfig, listener := setupSSHListener()
	processConnections(&sshConfig, listener)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/clawio/service.auth/lib"
	"github.com/rs/xlog"
	"golang.org/x/net/context"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
)

const (
	dirPerm = 0755
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	if strings.ToUpper(r.Method) == "PUT" {
		s.authHandler(ctx, w, r, s.upload)
	} else if strings.ToUpper(r.Method) == "GET" {
		s.authHandler(ctx, w, r, s.download)
	} else {
		w.WriteHeader(http.StatusNotFound)
		return
	}
}

func (s *server) upload(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	idt := lib.MustFromContext(ctx)

	p := s.getFilePath(r, idt)

	tmpFn, tmpFile, err := s.tmpFile()
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	defer tmpFile.Close()

	_, err = io.CopyN(tmpFile, r.Body, r.ContentLength)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if err = os.Rename(tmpFn, p); err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
}

func (s *server) download(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	idt := lib.MustFromContext(ctx)

	p := s.getFilePath(r, idt)

	fd, err := os.Open(p)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	defer fd.Close()

	_, err = io.Copy(w, fd)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(200)
}

func (s *server) authHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
	next func(ctx context.Context, w http.ResponseWriter, r *http.Request)) {

	log := xlog.FromContext(ctx)

	idt, err := s.getIdentityFromReq(r)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	ctx = lib.NewContext(ctx, idt)
	next(ctx, w, r)
}

func (s *server) tmpFile() (string, *os.File, error) {

	file, err := ioutil.TempFile(s.p.tmpDir, serviceID)
	if err != nil {
		return "", nil, err
	}

	fn := path.Join(path.Clean(file.Name()))

	return fn, file, nil
}
<commit_msg>Fixed binary uploads<commit_after>package main

import (
	"github.com/clawio/service.auth/lib"
	"github.com/rs/xlog"
	"golang.org/x/net/context"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
)

const (
	dirPerm = 0755
)

type newServerParams struct {
	dataDir      string
	tmpDir       string
	sharedSecret string
}

func newServer(p *newServerParams) *server {
	return &server{p}
}

type server struct {
	p *newServerParams
}

func (s *server) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	if strings.ToUpper(r.Method) == "PUT" {
		s.authHandler(ctx, w, r, s.upload)
	} else if strings.ToUpper(r.Method) == "GET" {
		s.authHandler(ctx, w, r, s.download)
	} else {
		w.WriteHeader(http.StatusNotFound)
		return
	}
}

func (s *server) upload(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	idt := lib.MustFromContext(ctx)

	p := s.getFilePath(r, idt)

	tmpFn, tmpFile, err := s.tmpFile()
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof("created tmp file %s", tmpFn)

	// TODO(labkode) Sometimes ContentLength = -1 because it is a binary
	// upload with TransferEncoding: chunked.
	// Instead using Copy we shoudl use a LimitedReader with a max file upload
	// configuration value.
	_, err = io.Copy(tmpFile, r.Body)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof("copied r.body into tmp file %s", tmpFn)

	err = tmpFile.Close()
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof("closed tmp file %s", tmpFn)

	if err = os.Rename(tmpFn, p); err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Infof("renamed tmp file %s to %s", tmpFn, p)

	w.WriteHeader(http.StatusCreated)
}

func (s *server) download(ctx context.Context, w http.ResponseWriter, r *http.Request) {

	log := xlog.FromContext(ctx)
	idt := lib.MustFromContext(ctx)

	p := s.getFilePath(r, idt)

	fd, err := os.Open(p)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	defer fd.Close()

	_, err = io.Copy(w, fd)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(200)
}

func (s *server) authHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
	next func(ctx context.Context, w http.ResponseWriter, r *http.Request)) {

	log := xlog.FromContext(ctx)

	idt, err := s.getIdentityFromReq(r)
	if err != nil {
		log.Error(err)
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	ctx = lib.NewContext(ctx, idt)
	next(ctx, w, r)
}

func (s *server) tmpFile() (string, *os.File, error) {

	file, err := ioutil.TempFile(s.p.tmpDir, serviceID)
	if err != nil {
		return "", nil, err
	}

	fn := path.Join(path.Clean(file.Name()))

	return fn, file, nil
}
<|endoftext|>