<commit_before>package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"
	"syscall"
)

var buildDate = "development"
var buildCommit = "development"
var buildVersion = "development"
var versionString = fmt.Sprintf(strings.TrimSpace(`
Version:     %s
Go version:  %s
Build date:  %s
Git commit:  %s
`),
	buildVersion,
	runtime.Version(),
	buildDate,
	buildCommit,
)

var usage = `envdir.

Run a command with environment variables
specified by the files in a directory.

Usage:
  envdir --version
  envdir --help
  envdir [-i] <directory> <command> [<arguments>...]

Arguments:
  <directory>  The directory of files representing environment variables.
  <command>    The command to run.
  <arguments>  The arguments of the command to run.

Options:
  -i, --ignore-environment  Start with an empty environment.
  --version  Show version.
  --help     Show help.

Interface:
  Each filename in <directory> is the name of an environment variable.
  The contents of the file is the value of the environment variable.
  The last newline of each file is ignored.
  If the file is empty (containing only 0 bytes or 1 newline),
    that environment variable is unset.

  envdir exits 111 if:
   * The directory's files can't be read
   * A filename contains "="
   * A file contains the null character
   * The command can't be run
`

const exitCodeUnsuccessful = 111

type environment map[string]string

func (e environment) Strings() []string {
	result := make([]string, len(e))
	index := 0
	for key, value := range e {
		result[index] = fmt.Sprintf("%s=%s", key, value)
		index++
	}
	return result
}

func makeEnvironmentMap(pairs []string) environment {
	environmentMap := make(environment)
	for _, pair := range pairs {
		keyValue := strings.SplitN(pair, "=", 2)
		key := strings.Join(keyValue[:1], "")
		value := strings.Join(keyValue[1:], "=")
		environmentMap[key] = value
	}
	return environmentMap
}

func main() {
	arguments, _ := docopt.Parse(usage, nil, true, versionString, true)
	freshEnvironment := arguments["--ignore-environment"].(bool)
	directory := arguments["<directory>"].(string)
	commandName := arguments["<command>"].(string)
	commandArguments := arguments["<arguments>"].([]string)
	environmentMap := getEnvironmentVariables(directory, freshEnvironment)
	environmentList := environmentMap.Strings()
	runCommand(commandName, commandArguments, environmentList)
}

func runCommand(
	commandName string,
	commandArguments []string,
	environmentList []string,
) {
	command := exec.Command(commandName, commandArguments...)
	command.Stdin = os.Stdin
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	command.Env = environmentList
	if err := command.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus := exitError.Sys().(syscall.WaitStatus)
			os.Exit(waitStatus.ExitStatus())
		} else {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(exitCodeUnsuccessful)
		}
	}
	os.Exit(0)
}

func getEnvironmentVariables(directory string, freshEnvironment bool) environment {
	var environmentMap environment
	if freshEnvironment {
		environmentMap = make(environment)
	} else {
		environmentMap = makeEnvironmentMap(os.Environ())
	}
	contents, err := ioutil.ReadDir(directory)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(exitCodeUnsuccessful)
	}
	for _, fileInfo := range contents {
		if fileInfo.IsDir() {
			continue
		}
		fileName := fileInfo.Name()
		if strings.ContainsRune(fileName, '=') {
			fmt.Fprintf(os.Stderr, "Error: Filenames in the environment directory must not contain \"=\": %s\n", fileName)
			os.Exit(exitCodeUnsuccessful)
		}
		if fileInfo.Size() == 0 {
			delete(environmentMap, fileName)
			continue
		}
		fileLocation := path.Join(directory, fileName)
		fileData, err := ioutil.ReadFile(fileLocation)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(exitCodeUnsuccessful)
		}
		fileString := string(fileData)
		if stringHasNullCharacter(fileString) {
			fmt.Fprintf(os.Stderr, "Error: %s contains a null character\n", fileName)
			os.Exit(exitCodeUnsuccessful)
		}
		fileString = trimLastNewline(fileString)
		if len(fileString) == 0 {
			delete(environmentMap, fileName)
			continue
		}
		environmentMap[fileName] = fileString
	}
	return environmentMap
}

func stringHasNullCharacter(s string) bool {
	i := strings.IndexByte(s, '\x00')
	return i != -1
}

func trimLastNewline(s string) string {
	if strings.HasSuffix(s, "\r\n") {
		return s[:len(s)-2]
	}
	if strings.HasSuffix(s, "\n") || strings.HasSuffix(s, "\r") {
		return s[:len(s)-1]
	}
	return s
}
<commit_msg>Implement following symlinks<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"syscall"

	"github.com/docopt/docopt-go"
)

var buildDate = "development"
var buildCommit = "development"
var buildVersion = "development"
var versionString = fmt.Sprintf(strings.TrimSpace(`
Version:     %s
Go version:  %s
Build date:  %s
Git commit:  %s
`),
	buildVersion,
	runtime.Version(),
	buildDate,
	buildCommit,
)

var usage = `envdir.

Run a command with environment variables
specified by the files in a directory.

Usage:
  envdir --version
  envdir --help
  envdir [-i] <directory> <command> [<arguments>...]

Arguments:
  <directory>  The directory of files representing environment variables.
  <command>    The command to run.
  <arguments>  The arguments of the command to run.

Options:
  -i, --ignore-environment  Start with an empty environment.
  --version  Show version.
  --help     Show help.

Interface:
  Each filename in <directory> is the name of an environment variable.
  The contents of the file is the value of the environment variable.
  The last newline of each file is ignored.
  If the file is empty (containing only 0 bytes or 1 newline),
    that environment variable is unset.

  envdir exits 111 if:
   * The directory's files can't be read
   * A filename contains "="
   * A file contains the null character
   * The command can't be run
`

const exitCodeUnsuccessful = 111

var envNameRegex = regexp.MustCompile(`^[a-zA-Z_]+[a-zA-Z0-9_]*$`)

type environment map[string]string

func (e environment) Strings() []string {
	result := make([]string, len(e))
	index := 0
	for key, value := range e {
		result[index] = fmt.Sprintf("%s=%s", key, value)
		index++
	}
	return result
}

func makeEnvironmentMap(pairs []string) environment {
	environmentMap := make(environment)
	for _, pair := range pairs {
		keyValue := strings.SplitN(pair, "=", 2)
		key := strings.Join(keyValue[:1], "")
		value := strings.Join(keyValue[1:], "=")
		environmentMap[key] = value
	}
	return environmentMap
}

func main() {
	arguments, _ := docopt.Parse(usage, nil, true, versionString, true)
	freshEnvironment := arguments["--ignore-environment"].(bool)
	directory := arguments["<directory>"].(string)
	commandName := arguments["<command>"].(string)
	commandArguments := arguments["<arguments>"].([]string)
	environmentMap := getEnvironmentVariables(directory, freshEnvironment)
	environmentList := environmentMap.Strings()
	runCommand(commandName, commandArguments, environmentList)
}

func runCommand(
	commandName string,
	commandArguments []string,
	environmentList []string,
) {
	command := exec.Command(commandName, commandArguments...)
	command.Stdin = os.Stdin
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	command.Env = environmentList
	if err := command.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus := exitError.Sys().(syscall.WaitStatus)
			os.Exit(waitStatus.ExitStatus())
		} else {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(exitCodeUnsuccessful)
		}
	}
	os.Exit(0)
}

func getEnvironmentVariables(directory string, freshEnvironment bool) environment {
	var environmentMap environment
	if freshEnvironment {
		environmentMap = make(environment)
	} else {
		environmentMap = makeEnvironmentMap(os.Environ())
	}
	contents, err := ioutil.ReadDir(directory)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(exitCodeUnsuccessful)
	}
	for _, fileInfo := range contents {
		if fileInfo.IsDir() {
			continue
		}

		fileName := fileInfo.Name()

		// ensure the name
		if !envNameRegex.MatchString(fileName) {
			continue
		}

		// ensure the size
		if fileInfo.Size() == 0 {
			delete(environmentMap, fileName)
			continue
		}

		fileLocation := path.Join(directory, fileName)

		// if symlink, then try following
		if fileInfo.Mode()&os.ModeSymlink != 0 {
			fileLocation, err = os.Readlink(fileLocation)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: Cannot read symlink: \"%s\"\n", fileLocation)
				os.Exit(exitCodeUnsuccessful)
			}

			if !filepath.IsAbs(fileLocation) {
				fileLocation = path.Join(directory, fileLocation)
			}

			fileInfo, err = os.Stat(fileLocation)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: Failed to call os.Stat of %s\n", fileLocation)
				os.Exit(exitCodeUnsuccessful)
			}

			if fileInfo.IsDir() {
				continue
			}
		}

		fileData, err := ioutil.ReadFile(fileLocation)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(exitCodeUnsuccessful)
		}
		fileString := string(fileData)
		if stringHasNullCharacter(fileString) {
			fmt.Fprintf(os.Stderr, "Error: %s contains a null character\n", fileName)
			os.Exit(exitCodeUnsuccessful)
		}
		fileString = trimLastNewline(fileString)
		if len(fileString) == 0 {
			delete(environmentMap, fileName)
			continue
		}
		environmentMap[fileName] = fileString
	}
	return environmentMap
}

func stringHasNullCharacter(s string) bool {
	i := strings.IndexByte(s, '\x00')
	return i != -1
}

func trimLastNewline(s string) string {
	if strings.HasSuffix(s, "\r\n") {
		return s[:len(s)-2]
	}
	if strings.HasSuffix(s, "\n") || strings.HasSuffix(s, "\r") {
		return s[:len(s)-1]
	}
	return s
}
<|endoftext|>


<commit_before>package horizon

import (
	"github.com/jagregory/halgo"
	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render"
	"github.com/stellar/go-horizon/render/problem"
	"github.com/zenazn/goji/web"
	"net/http"
)

type AccountResource struct {
	halgo.Links
	Id       string `json:"id"`
	Address  string `json:"address"`
	Sequence int64  `json:"sequence"`
}

// sse.Event methods

func (r AccountResource) SseData() interface{} { return r }
func (r AccountResource) Err() error           { return nil }
func (r AccountResource) SseId() string        { return r.Id }

func (r AccountResource) FromRecord(record db.CoreAccountRecord) AccountResource {
	r.Id = record.Accountid
	r.Address = record.Accountid
	r.Sequence = record.Seqnum
	return r
}

func accountShowAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	app := ah.App()
	address := ah.GetString("id")
	if ah.Err() != nil {
		problem.Render(app.ctx, w, problem.NotFound)
		return
	}

	q := db.CoreAccountByAddressQuery{
		app.CoreQuery(),
		address,
	}

	render.Single(w, r, q, func(r db.Record) (render.Resource, error) {
		return AccountResource{}.FromRecord(r.(db.CoreAccountRecord)), nil
	})
}
<commit_msg>Add links to accounts<commit_after>package horizon

import (
	"github.com/jagregory/halgo"
	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render"
	"github.com/stellar/go-horizon/render/problem"
	"github.com/zenazn/goji/web"
	"net/http"
)

type AccountResource struct {
	halgo.Links
	Id       string `json:"id"`
	Address  string `json:"address"`
	Sequence int64  `json:"sequence"`
}

// sse.Event methods

func (r AccountResource) SseData() interface{} { return r }
func (r AccountResource) Err() error           { return nil }
func (r AccountResource) SseId() string        { return r.Id }

func NewAccountResource(in db.CoreAccountRecord) AccountResource {
	return AccountResource{
		Links: halgo.Links{}.
			Self("/accounts/"+in.Accountid).
			Link("transactions", "/accounts/"+in.Accountid+"/transactions{?after}{?limit}{?order}").
			Link("operations", "/accounts/"+in.Accountid+"/operations{?after}{?limit}{?order}").
			Link("effects", "/accounts/"+in.Accountid+"/effects{?after}{?limit}{?order}"),
		Id:       in.Accountid,
		Address:  in.Accountid,
		Sequence: in.Seqnum,
	}
}

func accountShowAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	app := ah.App()
	address := ah.GetString("id")
	if ah.Err() != nil {
		problem.Render(app.ctx, w, problem.NotFound)
		return
	}

	q := db.CoreAccountByAddressQuery{
		app.CoreQuery(),
		address,
	}

	render.Single(w, r, q, func(r db.Record) (render.Resource, error) {
		return NewAccountResource(r.(db.CoreAccountRecord)), nil
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Gravitational, Inc.

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 trace

import (
	"crypto/x509"
	"fmt"
	"net"
	"net/url"
	"os"
)

// NotFound returns new instance of not found error
func NotFound(message string, args ...interface{}) error {
	return wrap(&NotFoundError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// NotFoundError indicates that object has not been found
type NotFoundError struct {
	Message string `json:"message"`
}

// IsNotFoundError returns true to indicate that is NotFoundError
func (e *NotFoundError) IsNotFoundError() bool {
	return true
}

// Error returns log friendly description of an error
func (e *NotFoundError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "object not found"
}

// OrigError returns original error (in this case this is the error itself)
func (e *NotFoundError) OrigError() error {
	return e
}

// IsNotFound returns whether this error indicates that the object is not found
func IsNotFound(e error) bool {
	type nf interface {
		IsNotFoundError() bool
	}
	_, ok := Unwrap(e).(nf)
	return ok
}

// AlreadyExists returns new AlreadyExists error
func AlreadyExists(message string, args ...interface{}) error {
	return wrap(&AlreadyExistsError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// AlreadyExistsError indicates that there's a duplicate object that already
// exists in the storage/system
type AlreadyExistsError struct {
	// Message is user-friendly error message
	Message string `json:"message"`
}

// Error returns log-friendly error description
func (n *AlreadyExistsError) Error() string {
	if n.Message != "" {
		return n.Message
	}
	return "object already exists"
}

// IsAlreadyExistsError indicates that this error is of AlreadyExists kind
func (AlreadyExistsError) IsAlreadyExistsError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (e *AlreadyExistsError) OrigError() error {
	return e
}

// IsAlreadyExists returns if this is error indicating that object
// already exists
func IsAlreadyExists(e error) bool {
	type ae interface {
		IsAlreadyExistsError() bool
	}
	_, ok := Unwrap(e).(ae)
	return ok
}

// BadParameter returns a new instance of BadParameterError
func BadParameter(message string, args ...interface{}) error {
	return wrap(&BadParameterError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// BadParameterError indicates that something is wrong with passed
// parameter to API method
type BadParameterError struct {
	Message string `json:"message"`
}

// Error returrns debug friendly message
func (b *BadParameterError) Error() string {
	return b.Message
}

// OrigError returns original error (in this case this is the error itself)
func (b *BadParameterError) OrigError() error {
	return b
}

// IsBadParameterError indicates that error is of bad parameter type
func (b *BadParameterError) IsBadParameterError() bool {
	return true
}

// IsBadParameter detects if this error is of BadParameter kind
func IsBadParameter(e error) bool {
	type bp interface {
		IsBadParameterError() bool
	}
	_, ok := Unwrap(e).(bp)
	return ok
}

// CompareFailed returns new instance of CompareFailed error
func CompareFailed(message string, args ...interface{}) error {
	return wrap(&CompareFailedError{Message: fmt.Sprintf(message, args...)}, 2)
}

// CompareFailedError indicates that compare failed (e.g wrong password or hash)
type CompareFailedError struct {
	// Message is user-friendly error message
	Message string `json:"message"`
}

// Error is debug - friendly message
func (e *CompareFailedError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "compare failed"
}

// OrigError returns original error (in this case this is the error itself)
func (e *CompareFailedError) OrigError() error {
	return e
}

// IsCompareFailedError indicates that this is compare failed error
func (e *CompareFailedError) IsCompareFailedError() bool {
	return true
}

// IsCompareFailed detects if this error is of CompareFailed kind
func IsCompareFailed(e error) bool {
	type cf interface {
		IsCompareFailedError() bool
	}
	_, ok := Unwrap(e).(cf)
	return ok
}

// AccessDenied returns new access denied error
func AccessDenied(message string, args ...interface{}) error {
	return wrap(&AccessDeniedError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// AccessDeniedError indicates denied access
type AccessDeniedError struct {
	Message string `json:"message"`
}

// Error is debug - friendly error message
func (e *AccessDeniedError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "access denied"
}

// IsAccessDeniedError indicates that this error is of AccessDenied type
func (e *AccessDeniedError) IsAccessDeniedError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (e *AccessDeniedError) OrigError() error {
	return e
}

// IsAccessDenied detects if this error is of AccessDeniedError
func IsAccessDenied(e error) bool {
	type ad interface {
		IsAccessDeniedError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// ConvertSystemError converts system error to appropriate teleport error
// if it is possible, otherwise, returns original error
func ConvertSystemError(err error) error {
	innerError := Unwrap(err)

	if os.IsNotExist(innerError) {
		return wrap(&NotFoundError{Message: innerError.Error()}, 2)
	}
	if os.IsPermission(innerError) {
		return wrap(&AccessDeniedError{Message: innerError.Error()}, 2)
	}
	switch realErr := innerError.(type) {
	case *net.OpError:
		return wrap(&ConnectionProblemError{
			Message: fmt.Sprintf("failed to connect to server %v", realErr.Addr),
			Err:     realErr}, 2)
	case *os.PathError:
		return wrap(&AccessDeniedError{
			Message: fmt.Sprintf("failed to execute command %v error:  %v", realErr.Path, realErr.Err),
		}, 2)
	case x509.SystemRootsError, x509.UnknownAuthorityError:
		return wrap(&TrustError{Err: innerError}, 2)
	default:
		return err
	}
}

// ConnectionProblem returns ConnectionProblem
func ConnectionProblem(err error, message string, args ...interface{}) error {
	return wrap(&ConnectionProblemError{
		Message: fmt.Sprintf(message, args...),
		Err:     err,
	}, 2)
}

// ConnectionProblemError indicates any network error that has occured
type ConnectionProblemError struct {
	Message string `json:"message"`
	Err     error  `json:"-"`
}

// Error is debug - friendly error message
func (c *ConnectionProblemError) Error() string {
	return fmt.Sprintf("%v: %v", c.Message, c.Err)
}

// IsConnectionProblemError indicates that this error is of ConnectionProblem
func (c *ConnectionProblemError) IsConnectionProblemError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (c *ConnectionProblemError) OrigError() error {
	return c
}

// IsConnectionProblem detects if this error is of ConnectionProblemError
func IsConnectionProblem(e error) bool {
	type ad interface {
		IsConnectionProblemError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// LimitExceeded returns new limit exceeded error
func LimitExceeded(message string, args ...interface{}) error {
	return wrap(&LimitExceededError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// LimitExceededError indicates rate limit or connection limit problem
type LimitExceededError struct {
	Message string `json:"message"`
}

// Error is debug - friendly error message
func (c *LimitExceededError) Error() string {
	return c.Message
}

// IsLimitExceededError indicates that this error is of ConnectionProblem
func (c *LimitExceededError) IsLimitExceededError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (c *LimitExceededError) OrigError() error {
	return c
}

// IsLimitExceeded detects if this error is of LimitExceededError
func IsLimitExceeded(e error) bool {
	type ad interface {
		IsLimitExceededError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// TrustError means that we can not trust remote party
type TrustError struct {
	// Err is original error
	Err     error `json:"error"`
	Message string
}

// Error returns log-friendly error description
func (t *TrustError) Error() string {
	return t.Err.Error()
}

// IsTrustError indicates that this error is of trust error kind
func (*TrustError) IsTrustError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (t *TrustError) OrigError() error {
	return t
}

// IsTrustError returns if this is a trust error
func IsTrustError(e error) bool {
	type te interface {
		IsTrustError() bool
	}
	_, ok := Unwrap(e).(te)
	return ok
}

// OAuth2 returns OAuth2 related error
func OAuth2(code, message string, query url.Values) Error {
	return wrap(&OAuth2Error{
		Code:    code,
		Message: message,
		Query:   query,
	}, 2)
}

// OAuth2Error is error returned during OAuth2 authentication
// currently used in OIDC (OpenID Connect flow)
type OAuth2Error struct {
	Code    string     `json:"code"`
	Message string     `json:"message"`
	Query   url.Values `json:"query"`
}

// Error returns debug friendly error message
func (o *OAuth2Error) Error() string {
	return fmt.Sprintf("OAuth2 error code=%v, message=%v", o.Code, o.Message)
}

// IsOAuth2Error indicates that this error of OAuth2 type
func (o *OAuth2Error) IsOAuth2Error() bool {
	return true
}

// IsOAuth2 returns if this is a OAuth2-related error
func IsOAuth2(e error) bool {
	type oe interface {
		IsOAuth2Error() bool
	}
	_, ok := Unwrap(e).(oe)
	return ok
}
<commit_msg>update comments<commit_after>/*
Copyright 2015 Gravitational, Inc.

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 trace

import (
	"crypto/x509"
	"fmt"
	"net"
	"net/url"
	"os"
)

// NotFound returns new instance of not found error
func NotFound(message string, args ...interface{}) error {
	return wrap(&NotFoundError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// NotFoundError indicates that object has not been found
type NotFoundError struct {
	Message string `json:"message"`
}

// IsNotFoundError returns true to indicate that is NotFoundError
func (e *NotFoundError) IsNotFoundError() bool {
	return true
}

// Error returns log friendly description of an error
func (e *NotFoundError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "object not found"
}

// OrigError returns original error (in this case this is the error itself)
func (e *NotFoundError) OrigError() error {
	return e
}

// IsNotFound returns whether this error is of NotFoundError type
func IsNotFound(e error) bool {
	type nf interface {
		IsNotFoundError() bool
	}
	_, ok := Unwrap(e).(nf)
	return ok
}

// AlreadyExists returns a new instance of AlreadyExists error
func AlreadyExists(message string, args ...interface{}) error {
	return wrap(&AlreadyExistsError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// AlreadyExistsError indicates that there's a duplicate object that already
// exists in the storage/system
type AlreadyExistsError struct {
	// Message is user-friendly error message
	Message string `json:"message"`
}

// Error returns log friendly description of an error
func (n *AlreadyExistsError) Error() string {
	if n.Message != "" {
		return n.Message
	}
	return "object already exists"
}

// IsAlreadyExistsError indicates that this error of the AlreadyExistsError type
func (AlreadyExistsError) IsAlreadyExistsError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (e *AlreadyExistsError) OrigError() error {
	return e
}

// IsAlreadyExists returns whether this is error indicating that object
// already exists
func IsAlreadyExists(e error) bool {
	type ae interface {
		IsAlreadyExistsError() bool
	}
	_, ok := Unwrap(e).(ae)
	return ok
}

// BadParameter returns a new instance of BadParameterError
func BadParameter(message string, args ...interface{}) error {
	return wrap(&BadParameterError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// BadParameterError indicates that something is wrong with passed
// parameter to API method
type BadParameterError struct {
	Message string `json:"message"`
}

// Error returns log friendly description of an error
func (b *BadParameterError) Error() string {
	return b.Message
}

// OrigError returns original error (in this case this is the error itself)
func (b *BadParameterError) OrigError() error {
	return b
}

// IsBadParameterError indicates that this error is of BadParameterError type
func (b *BadParameterError) IsBadParameterError() bool {
	return true
}

// IsBadParameter returns whether this error is of BadParameterType
func IsBadParameter(e error) bool {
	type bp interface {
		IsBadParameterError() bool
	}
	_, ok := Unwrap(e).(bp)
	return ok
}

// CompareFailed returns new instance of CompareFailedError
func CompareFailed(message string, args ...interface{}) error {
	return wrap(&CompareFailedError{Message: fmt.Sprintf(message, args...)}, 2)
}

// CompareFailedError indicates a failed comparison (e.g. bad password or hash)
type CompareFailedError struct {
	// Message is user-friendly error message
	Message string `json:"message"`
}

// Error is debug - friendly message
func (e *CompareFailedError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "compare failed"
}

// OrigError returns original error (in this case this is the error itself)
func (e *CompareFailedError) OrigError() error {
	return e
}

// IsCompareFailedError indicates that this is CompareFailedError
func (e *CompareFailedError) IsCompareFailedError() bool {
	return true
}

// IsCompareFailed detects if this error is of CompareFailed type
func IsCompareFailed(e error) bool {
	type cf interface {
		IsCompareFailedError() bool
	}
	_, ok := Unwrap(e).(cf)
	return ok
}

// AccessDenied returns new instance of AccessDeniedError
func AccessDenied(message string, args ...interface{}) error {
	return wrap(&AccessDeniedError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// AccessDeniedError indicates denied access
type AccessDeniedError struct {
	Message string `json:"message"`
}

// Error is debug - friendly error message
func (e *AccessDeniedError) Error() string {
	if e.Message != "" {
		return e.Message
	}
	return "access denied"
}

// IsAccessDeniedError indicates that this error is of AccessDeniedError type
func (e *AccessDeniedError) IsAccessDeniedError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (e *AccessDeniedError) OrigError() error {
	return e
}

// IsAccessDenied detects if this error is of AccessDeniedError type
func IsAccessDenied(e error) bool {
	type ad interface {
		IsAccessDeniedError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// ConvertSystemError converts system error to appropriate trace error
// if it is possible, otherwise, returns original error
func ConvertSystemError(err error) error {
	innerError := Unwrap(err)

	if os.IsNotExist(innerError) {
		return wrap(&NotFoundError{Message: innerError.Error()}, 2)
	}
	if os.IsPermission(innerError) {
		return wrap(&AccessDeniedError{Message: innerError.Error()}, 2)
	}
	switch realErr := innerError.(type) {
	case *net.OpError:
		return wrap(&ConnectionProblemError{
			Message: fmt.Sprintf("failed to connect to server %v", realErr.Addr),
			Err:     realErr}, 2)
	case *os.PathError:
		return wrap(&AccessDeniedError{
			Message: fmt.Sprintf("failed to execute command %v error:  %v", realErr.Path, realErr.Err),
		}, 2)
	case x509.SystemRootsError, x509.UnknownAuthorityError:
		return wrap(&TrustError{Err: innerError}, 2)
	default:
		return err
	}
}

// ConnectionProblem returns new instance of ConnectionProblemError
func ConnectionProblem(err error, message string, args ...interface{}) error {
	return wrap(&ConnectionProblemError{
		Message: fmt.Sprintf(message, args...),
		Err:     err,
	}, 2)
}

// ConnectionProblemError indicates a network related problem
type ConnectionProblemError struct {
	Message string `json:"message"`
	Err     error  `json:"-"`
}

// Error is debug - friendly error message
func (c *ConnectionProblemError) Error() string {
	return fmt.Sprintf("%v: %v", c.Message, c.Err)
}

// IsConnectionProblemError indicates that this error is of ConnectionProblemError type
func (c *ConnectionProblemError) IsConnectionProblemError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (c *ConnectionProblemError) OrigError() error {
	return c
}

// IsConnectionProblem returns whether this error is of ConnectionProblemError
func IsConnectionProblem(e error) bool {
	type ad interface {
		IsConnectionProblemError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// LimitExceeded returns whether new instance of LimitExceededError
func LimitExceeded(message string, args ...interface{}) error {
	return wrap(&LimitExceededError{
		Message: fmt.Sprintf(message, args...),
	}, 2)
}

// LimitExceededError indicates rate limit or connection limit problem
type LimitExceededError struct {
	Message string `json:"message"`
}

// Error is debug - friendly error message
func (c *LimitExceededError) Error() string {
	return c.Message
}

// IsLimitExceededError indicates that this error is of ConnectionProblem
func (c *LimitExceededError) IsLimitExceededError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (c *LimitExceededError) OrigError() error {
	return c
}

// IsLimitExceeded detects if this error is of LimitExceededError
func IsLimitExceeded(e error) bool {
	type ad interface {
		IsLimitExceededError() bool
	}
	_, ok := Unwrap(e).(ad)
	return ok
}

// TrustError indicates trust-related validation error (e.g. untrusted cert)
type TrustError struct {
	// Err is original error
	Err     error `json:"error"`
	Message string
}

// Error returns log-friendly error description
func (t *TrustError) Error() string {
	return t.Err.Error()
}

// IsTrustError indicates that this error is of TrustError type
func (*TrustError) IsTrustError() bool {
	return true
}

// OrigError returns original error (in this case this is the error itself)
func (t *TrustError) OrigError() error {
	return t
}

// IsTrustError returns if this is a trust error
func IsTrustError(e error) bool {
	type te interface {
		IsTrustError() bool
	}
	_, ok := Unwrap(e).(te)
	return ok
}

// OAuth2 returns new instance of OAuth2Error
func OAuth2(code, message string, query url.Values) Error {
	return wrap(&OAuth2Error{
		Code:    code,
		Message: message,
		Query:   query,
	}, 2)
}

// OAuth2Error defined an error used in OpenID Connect Flow (OIDC)
type OAuth2Error struct {
	Code    string     `json:"code"`
	Message string     `json:"message"`
	Query   url.Values `json:"query"`
}

//Error returns log friendly description of an error
func (o *OAuth2Error) Error() string {
	return fmt.Sprintf("OAuth2 error code=%v, message=%v", o.Code, o.Message)
}

// IsOAuth2Error returns whether this error of OAuth2Error type
func (o *OAuth2Error) IsOAuth2Error() bool {
	return true
}

// IsOAuth2 returns if this is a OAuth2-related error
func IsOAuth2(e error) bool {
	type oe interface {
		IsOAuth2Error() bool
	}
	_, ok := Unwrap(e).(oe)
	return ok
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"github.com/airdispatch/dpl"
	"github.com/robfig/revel"
	"html/template"
	"melange/app/models"
	"melange/app/routes"
	"melange/mailserver"
	"net/http"
	"time"
)

type Dispatch struct {
	GorpController
}

func (c Dispatch) Init() revel.Result {
	if c.Session["user"] == "" {
		return c.Redirect(routes.App.Login())
	}

	// Function to load user apps
	apps, err := models.GetUserApps(c.Txn, c.Session)
	if err != nil {
		panic(err)
	}

	c.RenderArgs["apps"] = apps

	mailserver.InitRouter()

	c.RenderArgs["news"] = func(m dpl.Message) template.HTML {
		return "hello"
	}

	return nil
}

func (d Dispatch) Dashboard() revel.Result {
	// Download all recents from subscribed, download all recents from alerts, sort them chronologically
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(u.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}
	if len(id) == 0 {
		panic("Not enough IDs")
	}

	msgs, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		u.(*models.User),
		true, true, true,
		time.Now().Add(-7*24*time.Hour).Unix())
	if err != nil {
		panic(err)
	}

	var apps []*models.UserApp
	_, err = d.Txn.Select(&apps, "select * from dispatch_app where userid = $1", GetUserId(d.Session))
	var loadedApps []*dpl.PluginInstance = make([]*dpl.PluginInstance, len(apps))
	for i, v := range apps {
		resp, err := http.Get(v.AppURL)
		if err != nil {
			// Couldn't load that application
			continue
		}
		o, err := dpl.ParseDPLStream(resp.Body)
		if err != nil {
			// Couldn't parse that application
			resp.Body.Close()
			continue
		}

		plugin := o.CreateInstance(&PluginHost{
			User: u.(*models.User),
			Txn:  d.Txn,
			R:    mailserver.LookupRouter,
		}, nil)
		loadedApps[i] = plugin
		resp.Body.Close()
	}

	type DisplayMessage struct {
		mailserver.MelangeMessage
		Display template.HTML
	}
	recents := make([]DisplayMessage, 0)
	for _, v := range msgs {
		rendered := false
		for _, a := range loadedApps {
			for _, t := range a.Tag {
				if t.FeedAction != "" {
					match := true
					for _, f := range t.Fields {
						if !v.Has(f.Name) && !f.Optional {
							match = false
						}
					}
					if match {
						// Do Something
					}
				}
			}
		}
		if !rendered {
			t, _ := template.New("").Parse(`{{ range .Components }}<p><strong>{{ .Key }}</strong> {{ .String }}</p>{{ end }}`)
			var b bytes.Buffer
			t.Execute(&b, v)
			recents = append(recents, DisplayMessage{v, template.HTML(b.String())})
		}
	}

	return d.Render(recents)
}

func (d Dispatch) Profile() revel.Result {
	user, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(user.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}

	messages, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		user.(*models.User),
		false, false, true,
		time.Now().Add(-7*24*time.Hour).Unix())
	if err != nil {
		panic(err)
	}

	return d.Render(messages, user)
}

func (d Dispatch) All() revel.Result {
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(u.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}
	if len(id) == 0 {
		panic("Not enough IDs")
	}

	recents, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		u.(*models.User),
		true, true, true,
		0)
	if err != nil {
		panic(err)
	}

	return d.Render(recents)
}

func (d Dispatch) Applications() revel.Result {
	return d.Render()
}

func (d Dispatch) AddApplication(url string) revel.Result {
	resp, err := http.Get(url)
	if err != nil {
		d.Flash.Error("Unable to download application via supplied url.")
		return d.Redirect(routes.Dispatch.Applications())
	}
	defer resp.Body.Close()

	plugin, err := dpl.ParseDPLStream(resp.Body)
	if err != nil {
		d.Flash.Error("Plugin is not valid.")
		return d.Redirect(routes.Dispatch.Applications())
	}

	in := &models.UserApp{
		UserId: GetUserId(d.Session),
		AppURL: url,
		Name:   plugin.Name,
		Path:   plugin.Path,
	}
	err = d.Txn.Insert(in)
	if err != nil {
		panic(err)
	}

	return d.Redirect(routes.Loader.LoadAppDefault(plugin.Name))
}

func (d Dispatch) UninstallApplication(app string) revel.Result {
	u := GetUserId(d.Session)

	var apps []*models.UserApp
	_, err := d.Txn.Select(&apps, "select * from dispatch_app where userid = $1 and UPPER(name) = UPPER($2)", u, app)
	if err != nil {
		panic(err)
	}
	if len(apps) != 1 {
		panic(len(apps))
	}

	toDelete := apps[0]
	count, err := d.Txn.Delete(toDelete)
	if err != nil || count != 1 {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Applications())
}

func (c Dispatch) Account() revel.Result {
	if c.Session["user"] == "" {
		return c.Redirect(routes.App.Login())
	}
	var users []*models.User

	_, err := c.Txn.Select(&users, "select * from dispatch_user where userid = $1", GetUserId(c.Session))
	if err != nil {
		panic(err)
	}
	user := users[0]

	var subscriptions []*models.UserSubscription
	_, err = c.Txn.Select(&subscriptions, "select * from dispatch_subscription where userid = $1", user.UserId)
	if err != nil {
		panic(err)
	}

	var identities []*models.Identity
	_, err = c.Txn.Select(&identities, "select * from dispatch_identity where userid = $1", user.UserId)
	if err != nil {
		panic(err)
	}

	return c.Render(user, subscriptions, identities)
}

func (c Dispatch) AddSubscription(address string) revel.Result {
	// TODO: Verify the Address Somehow...
	mailserver.InitRouter()
	_, err := mailserver.LookupRouter.LookupAlias(address)
	if err != nil {
		c.Flash.Error("Unable to find that address. It has not been added.")
		return c.Redirect(routes.Dispatch.Account())
	}

	user := GetUserId(c.Session)
	newSub := &models.UserSubscription{
		UserId:  user,
		Address: address,
	}

	err = c.Txn.Insert(newSub)
	if err != nil {
		panic(err)
	}

	return c.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) RemoveSubscription(id int) revel.Result {
	u := GetUserId(d.Session)

	var apps []*models.UserSubscription
	_, err := d.Txn.Select(&apps, "select * from dispatch_subscription where subscriptionid = $1 and userid = $2", id, u)
	if err != nil {
		panic(err)
	}
	if len(apps) != 1 {
		panic(len(apps))
	}

	toDelete := apps[0]
	count, err := d.Txn.Delete(toDelete)
	if err != nil || count != 1 {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) RegisterIdentity(id int) revel.Result {
	u := GetUserId(d.Session)

	var ids []*models.Identity
	_, err := d.Txn.Select(&ids, "select * from dispatch_identity where identityid = $1 and userid = $2", id, u)
	if err != nil {
		panic(err)
	}
	if len(ids) != 1 {
		panic(len(ids))
	}

	toRegister := ids[0]

	mailserver.InitRouter()
	did, err := toRegister.ToDispatch()
	if err != nil {
		panic(err)
	}
	did.SetLocation(revel.Config.StringDefault("server.location", ""))

	err = mailserver.RegistrationRouter.Register(did, toRegister.Alias)
	if err != nil {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) ProcessAccount(name string, username string, password1 string, password2 string, password string) revel.Result {
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	user := u.(*models.User)
	user.Name = name

	if user.VerifyPassword(password) {
		if password1 == password2 {
			user.UpdatePassword(password1)
		} else {
			d.Flash.Error("New passwords do not match.")
		}
	} else {
		if password != "" {
			d.Flash.Error("Current Password is not correct. Did not update username or password.")
		}
	}

	user.Save(d.Txn)
	return d.Redirect(routes.Dispatch.Account())
}
<commit_msg>Launching Newsfeed per Application<commit_after>package controllers

import (
	"bytes"
	"github.com/airdispatch/dpl"
	"github.com/robfig/revel"
	"html/template"
	"melange/app/models"
	"melange/app/routes"
	"melange/mailserver"
	"net/http"
	"time"
)

type Dispatch struct {
	GorpController
}

func (c Dispatch) Init() revel.Result {
	if c.Session["user"] == "" {
		return c.Redirect(routes.App.Login())
	}

	// Function to load user apps
	apps, err := models.GetUserApps(c.Txn, c.Session)
	if err != nil {
		panic(err)
	}

	c.RenderArgs["apps"] = apps

	mailserver.InitRouter()

	c.RenderArgs["news"] = func(m dpl.Message) template.HTML {
		return "hello"
	}

	return nil
}

func (d Dispatch) Dashboard() revel.Result {
	// Download all recents from subscribed, download all recents from alerts, sort them chronologically
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(u.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}
	if len(id) == 0 {
		panic("Not enough IDs")
	}

	msgs, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		u.(*models.User),
		true, true, true,
		time.Now().Add(-7*24*time.Hour).Unix())
	if err != nil {
		panic(err)
	}

	var apps []*models.UserApp
	_, err = d.Txn.Select(&apps, "select * from dispatch_app where userid = $1", GetUserId(d.Session))
	var loadedApps []*dpl.PluginInstance = make([]*dpl.PluginInstance, len(apps))
	for i, v := range apps {
		resp, err := http.Get(v.AppURL)
		if err != nil {
			// Couldn't load that application
			continue
		}
		o, err := dpl.ParseDPLStream(resp.Body)
		if err != nil {
			// Couldn't parse that application
			resp.Body.Close()
			continue
		}

		plugin := o.CreateInstance(&PluginHost{
			User: u.(*models.User),
			Txn:  d.Txn,
			R:    mailserver.LookupRouter,
		}, nil)
		loadedApps[i] = plugin
		resp.Body.Close()
	}

	type DisplayMessage struct {
		mailserver.MelangeMessage
		Display template.HTML
	}
	recents := make([]DisplayMessage, 0)
	for _, v := range msgs {
		rendered := false
		for _, a := range loadedApps {
			for _, t := range a.Tag {
				if t.FeedAction != "" {
					match := true
					for _, f := range t.Fields {
						if !v.Has(f.Name) && !f.Optional {
							match = false
						}
					}
					if match {
						// Do Something
						d, err := a.RunActionWithContext(t.FeedAction, v, nil)
						if err != nil {
							continue
						}
						rendered = true
						recents = append(recents, DisplayMessage{v, d})
					}
				}
			}
		}
		if !rendered {
			t, _ := template.New("").Parse(`{{ range .Components }}<p><strong>{{ .Key }}</strong> {{ .String }}</p>{{ end }}`)
			var b bytes.Buffer
			t.Execute(&b, v)
			recents = append(recents, DisplayMessage{v, template.HTML(b.String())})
		}
	}

	return d.Render(recents)
}

func (d Dispatch) Profile() revel.Result {
	user, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(user.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}

	messages, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		user.(*models.User),
		false, false, true,
		time.Now().Add(-7*24*time.Hour).Unix())
	if err != nil {
		panic(err)
	}

	return d.Render(messages, user)
}

func (d Dispatch) All() revel.Result {
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	id, err := models.UserIdentities(u.(*models.User), d.Txn)
	if err != nil {
		panic(err)
	}
	if len(id) == 0 {
		panic("Not enough IDs")
	}

	recents, err := mailserver.Messages(mailserver.LookupRouter,
		d.Txn,
		id[0],
		u.(*models.User),
		true, true, true,
		0)
	if err != nil {
		panic(err)
	}

	return d.Render(recents)
}

func (d Dispatch) Applications() revel.Result {
	return d.Render()
}

func (d Dispatch) AddApplication(url string) revel.Result {
	resp, err := http.Get(url)
	if err != nil {
		d.Flash.Error("Unable to download application via supplied url.")
		return d.Redirect(routes.Dispatch.Applications())
	}
	defer resp.Body.Close()

	plugin, err := dpl.ParseDPLStream(resp.Body)
	if err != nil {
		d.Flash.Error("Plugin is not valid.")
		return d.Redirect(routes.Dispatch.Applications())
	}

	in := &models.UserApp{
		UserId: GetUserId(d.Session),
		AppURL: url,
		Name:   plugin.Name,
		Path:   plugin.Path,
	}
	err = d.Txn.Insert(in)
	if err != nil {
		panic(err)
	}

	return d.Redirect(routes.Loader.LoadAppDefault(plugin.Name))
}

func (d Dispatch) UninstallApplication(app string) revel.Result {
	u := GetUserId(d.Session)

	var apps []*models.UserApp
	_, err := d.Txn.Select(&apps, "select * from dispatch_app where userid = $1 and UPPER(name) = UPPER($2)", u, app)
	if err != nil {
		panic(err)
	}
	if len(apps) != 1 {
		panic(len(apps))
	}

	toDelete := apps[0]
	count, err := d.Txn.Delete(toDelete)
	if err != nil || count != 1 {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Applications())
}

func (c Dispatch) Account() revel.Result {
	if c.Session["user"] == "" {
		return c.Redirect(routes.App.Login())
	}
	var users []*models.User

	_, err := c.Txn.Select(&users, "select * from dispatch_user where userid = $1", GetUserId(c.Session))
	if err != nil {
		panic(err)
	}
	user := users[0]

	var subscriptions []*models.UserSubscription
	_, err = c.Txn.Select(&subscriptions, "select * from dispatch_subscription where userid = $1", user.UserId)
	if err != nil {
		panic(err)
	}

	var identities []*models.Identity
	_, err = c.Txn.Select(&identities, "select * from dispatch_identity where userid = $1", user.UserId)
	if err != nil {
		panic(err)
	}

	return c.Render(user, subscriptions, identities)
}

func (c Dispatch) AddSubscription(address string) revel.Result {
	// TODO: Verify the Address Somehow...
	mailserver.InitRouter()
	_, err := mailserver.LookupRouter.LookupAlias(address)
	if err != nil {
		c.Flash.Error("Unable to find that address. It has not been added.")
		return c.Redirect(routes.Dispatch.Account())
	}

	user := GetUserId(c.Session)
	newSub := &models.UserSubscription{
		UserId:  user,
		Address: address,
	}

	err = c.Txn.Insert(newSub)
	if err != nil {
		panic(err)
	}

	return c.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) RemoveSubscription(id int) revel.Result {
	u := GetUserId(d.Session)

	var apps []*models.UserSubscription
	_, err := d.Txn.Select(&apps, "select * from dispatch_subscription where subscriptionid = $1 and userid = $2", id, u)
	if err != nil {
		panic(err)
	}
	if len(apps) != 1 {
		panic(len(apps))
	}

	toDelete := apps[0]
	count, err := d.Txn.Delete(toDelete)
	if err != nil || count != 1 {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) RegisterIdentity(id int) revel.Result {
	u := GetUserId(d.Session)

	var ids []*models.Identity
	_, err := d.Txn.Select(&ids, "select * from dispatch_identity where identityid = $1 and userid = $2", id, u)
	if err != nil {
		panic(err)
	}
	if len(ids) != 1 {
		panic(len(ids))
	}

	toRegister := ids[0]

	mailserver.InitRouter()
	did, err := toRegister.ToDispatch()
	if err != nil {
		panic(err)
	}
	did.SetLocation(revel.Config.StringDefault("server.location", ""))

	err = mailserver.RegistrationRouter.Register(did, toRegister.Alias)
	if err != nil {
		panic(err)
	}

	return d.Redirect(routes.Dispatch.Account())
}

func (d Dispatch) ProcessAccount(name string, username string, password1 string, password2 string, password string) revel.Result {
	u, err := d.Txn.Get(&models.User{}, GetUserId(d.Session))
	if err != nil {
		panic(err)
	}

	user := u.(*models.User)
	user.Name = name

	if user.VerifyPassword(password) {
		if password1 == password2 {
			user.UpdatePassword(password1)
		} else {
			d.Flash.Error("New passwords do not match.")
		}
	} else {
		if password != "" {
			d.Flash.Error("Current Password is not correct. Did not update username or password.")
		}
	}

	user.Save(d.Txn)
	return d.Redirect(routes.Dispatch.Account())
}
<|endoftext|>


<commit_before>package errors

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
)

type _errorh struct {
	ErrMessage string `json:"message"`
	ErrCode    int    `json:"code"`
	*stack     `json:"-"`
}

func (e _errorh) Error() string { return e.ErrMessage }

func (e _errorh) Code() int { return e.ErrCode }

func (e _errorh) Message() string { return e.ErrMessage }

func (e _errorh) JSONError() error {
	b, _ := json.Marshal(e)
	return errors.New(string(b))
}

func (e _errorh) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, e.ErrMessage)
			fmt.Fprintf(s, "%+v", e.StackTrace())
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, e.ErrMessage)
	}
}

// New returns an error with the supplied message.
func Newh(code int, message string) error {
	return _errorh{
		message,
		code,
		callers(),
	}
}

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorhf(code int, format string, args ...interface{}) error {
	return _errorh{
		fmt.Sprintf(format, args...),
		code,
		callers(),
	}
}

func ParseJSON(err string) _errorh {
	e := _errorh{}
	errr := json.Unmarshal([]byte(err), &e)
	if errr != nil {
		e.ErrMessage = errr.Error()
		e.ErrCode = 500
		e.stack = callers()
	}

	e.stack = callers()
	return e
}

func BadRequest(message string) error {
	return &_errorh{
		message,
		400,
		callers(),
	}
}

func Unauthorized(message string) error {
	return &_errorh{
		message,
		401,
		callers(),
	}
}

func Forbidden(message string) error {
	return &_errorh{
		message,
		403,
		callers(),
	}
}

func NotFound(message string) error {
	return &_errorh{
		message,
		404,
		callers(),
	}
}

func InternalServerError(message string) error {
	return &_errorh{
		message,
		500,
		callers(),
	}
}

type httpStatus interface {
	Code() int
	Error() string
}

type microStatus interface {
	StatusCode() int32
	Error() string
}

func ErrorStatus(err error) (int, error) {
	if err == nil {
		return 0, nil
	}

	switch wrapErr := Cause(err).(type) {
	case httpStatus:
		return wrapErr.Code(), wrapErr
	case microStatus:
		return int(wrapErr.StatusCode()), wrapErr
	default:
		return 500, wrapErr
	}
}

func IsNotFound(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 404 {
		return true
	}

	return false
}

func IsInternalError(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 500 {
		return true
	}

	return false
}

func IsBadRequest(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 400 {
		return true
	}

	return false
}

func IsUnauthorized(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 401 {
		return true
	}

	return false
}

func IsForbidden(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 403 {
		return true
	}

	return false
}
<commit_msg>add err<commit_after>package errors

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
)

type _errorh struct {
	ErrMessage string `json:"message"`
	ErrCode    int    `json:"code"`
	*stack     `json:"-"`
}

func (e _errorh) Error() string { return e.ErrMessage }

func (e _errorh) Code() int { return e.ErrCode }

func (e _errorh) Message() string { return e.ErrMessage }

func (e _errorh) JSONError() error {
	b, _ := json.Marshal(e)
	return errors.New(string(b))
}

func (e _errorh) Format(s fmt.State, verb rune) {
	switch verb {
	case 'v':
		if s.Flag('+') {
			io.WriteString(s, e.ErrMessage)
			fmt.Fprintf(s, "%+v", e.StackTrace())
			return
		}
		fallthrough
	case 's':
		io.WriteString(s, e.ErrMessage)
	}
}

// New returns an error with the supplied message.
func Newh(code int, message string) error {
	return _errorh{
		message,
		code,
		callers(),
	}
}

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorhf(code int, format string, args ...interface{}) error {
	return _errorh{
		fmt.Sprintf(format, args...),
		code,
		callers(),
	}
}

func ParseJSON(err string) _errorh {
	e := _errorh{}
	errr := json.Unmarshal([]byte(err), &e)
	if errr != nil {
		e.ErrMessage = errr.Error()
		e.ErrCode = 500
		e.stack = callers()
	}

	e.stack = callers()
	return e
}

func BadRequest(message string) error {
	return &_errorh{
		message,
		400,
		callers(),
	}
}

func Unauthorized(message string) error {
	return &_errorh{
		message,
		401,
		callers(),
	}
}

func Forbidden(message string) error {
	return &_errorh{
		message,
		403,
		callers(),
	}
}

func NotFound(message string) error {
	return &_errorh{
		message,
		404,
		callers(),
	}
}

func InternalServerError(message string) error {
	return &_errorh{
		message,
		500,
		callers(),
	}
}

type httpStatus interface {
	Code() int
	Error() string
}

type microStatus interface {
	StatusCode() int32
	Error() string
}

func ErrorStatus(err error) (int, error) {
	if err == nil {
		return 0, nil
	}

	switch wrapErr := Cause(err).(type) {
	case httpStatus:
		return wrapErr.Code(), wrapErr
	case microStatus:
		return int(wrapErr.StatusCode()), wrapErr
	default:
		return 500, wrapErr
	}
}

func IsNotFound(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 404 {
		return true
	}

	return false
}

func IsInternalError(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 500 {
		return true
	}

	return false
}

func IsBadRequest(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 400 {
		return true
	}

	return false
}

func IsUnauthorized(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 401 {
		return true
	}

	return false
}

func IsForbidden(err error) bool {
	if err == nil {
		return false
	}
	status, _ := ErrorStatus(err)
	if status == 403 {
		return true
	}

	return false
}

func BadRequestErr(err error) error {
	if err != nil {
		return nil
	}

	return &_errorh{
		err.Error(),
		400,
		callers(),
	}
}

func UnauthorizedErr(err error) error {
	if err != nil {
		return nil
	}

	return &_errorh{
		err.Error(),
		401,
		callers(),
	}
}

func ForbiddenErr(err error) error {
	if err != nil {
		return nil
	}

	return &_errorh{
		err.Error(),
		403,
		callers(),
	}
}

func NotFoundErr(err error) error {
	if err != nil {
		return nil
	}

	return &_errorh{
		err.Error(),
		404,
		callers(),
	}
}

func InternalServerErrorErr(err error) error {
	if err != nil {
		return nil
	}

	return &_errorh{
		err.Error(),
		500,
		callers(),
	}
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2013 Jeremy Torres, https://github.com/jeremytorres/jpegextract

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Command utilizing the rawparser library for extracting jpegs from RAW iles.
// The embedded JPEGs are extracted and optionally:
// (1) rotated via oritenation provided in RawFile EXIF info;
//
// Usage:
//     jpgextract --raws "NEF,CR2" --dest-dir "/path_to/output_dir"
//                --src-dirs "/path_to/source1,/path_to/source2"
//                [--num-routines "8" --quality "80" --rotate]
package main

import (
	"github.com/codegangsta/cli"
	"github.com/jeremytorres/rawparser"
	"log"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// RawFileParserPair is a struct for containing a list of files
// for a specific parser.
type RawFileParserPair struct {
	file   string
	parser rawparser.RawParser
}

const (
	// RawTypesKey is the constant representing the command line argument for the RAW file
	// types to be processed.
	RawTypesKey = "raws"

	// SrcDirKey is the constant representing the command line argument for the source directories
	// containing the source RawFiles.
	SrcDirKey = "src-dirs"
	// DestDirKey is a constant representing the command line argument for the destination directory
	// where extracted jpegs shall be placed.
	DestDirKey = "dest-dir"
	// NumRoutinesKey is the constant representing the command line argument for the max number of
	// go routines to be processed.  As this utility is mostly file IO bound, it is important
	// not to use too many routines ("too many files open..." errors can occur from OS).  Therefore,
	// if this value is greater than the logical cores, a warning is logged and the value is set to
	// the number of logical cores.
	NumRoutinesKey = "num-routines"
	// QualityKey is the constant representing the command line argument for the JPEG quality used
	// when processing the embedded JPEG in a RawFile.
	QualityKey = "quality"
	// RotateKey is the constant representing the command line argument indicating rotation of
	// JPEGs should occur based on the EXIF info embedded within the RawFile.  ImageMagic's 'convert'
	// utility is used and is checked at startup for existence.
	RotateKey = "rotate"
	// AppVersionKey is the constant defining the current version of this command utility.
	AppVersionKey = "1.0"
	// ImageMagicConvertBin is the constant representing ImageMagic's 'convert' utility.
	ImageMagicConvertBin = "convert"
)

var (
	destDir, sqlLiteDb     string
	rawFileExts, srcDirs   []string
	numOfRoutines, quality int
	rotate                 bool
	parsers                *rawparser.RawParsers
	// validParserKeys is a slice of RAW file parsers supported by this implementation.
	validParserKeys = []string{
		rawparser.NefParserKey,
		rawparser.Cr2ParserKey,
	}
)

// processFilesConcurrent processes RawFiles concurrently, based on the number goroutines
// specified.
func processFilesConcurrent(rp *RawFileParserPair, c chan<- bool) {

	go func(rp *RawFileParserPair, c chan<- bool) {
		rawfile, err := rp.parser.ProcessFile(&rawparser.RawFileInfo{rp.file, destDir, quality, numOfRoutines})
		if err != nil {
			log.Printf("Error processing file: '%s' error: %v\n", rp.file, err)
		} else {
			if rotate && rawfile.JpegOrientation != 0.0 {
				// rotate jpeg
				go func(fileName string, radiansCw float64) {
					degrees := radiansCw * (180 / math.Pi)
					log.Printf("Rotating image %f degrees for jpeg: '%s'\n", degrees, fileName)
					cmd := exec.Command(ImageMagicConvertBin, "-rotate", strconv.FormatFloat(degrees, 'f', 2, 64), fileName, fileName)
					err := cmd.Start()
					if err != nil {
						log.Fatal(err)
					}
					err = cmd.Wait()
					if err != nil {
						log.Printf("Command finished with error: %v", err)
					}
				}(rawfile.JpegPath, rawfile.JpegOrientation)
			}
		}
		// signal completion of work
		c <- true
	}(rp, c)
}

func isRawFileExtValid(ext string) bool {
	for _, validExt := range validParserKeys {
		if ext == validExt {
			return true
		}
	}
	return false
}

// processCli parses command line arguments and checks for validity of user-specified
// values.
func processCli() bool {
	var processed = false

	app := cli.NewApp()
	app.Name = "jpgextract"
	app.Usage = "Processes RAW files and extracts JPEGs and optionally create a SQLite database."
	app.Version = AppVersionKey
	app.Author = "Jeremy Torres"
	app.Flags = []cli.Flag{
		cli.StringFlag{RawTypesKey, "", "comma-separated list of RAW file extensions to process.  Current supported " +
			"RAW files: [NEF | CR2]"},
		cli.StringFlag{SrcDirKey, "", "comma-separated list of full paths to the directories containing RawFiles " +
			"(e.g., /path_to/dir1,/path_to/dir2..."},
		cli.StringFlag{DestDirKey, "", "the full path to the directory containing extracted jpegs"},
		cli.IntFlag{NumRoutinesKey, 2, "the number of concurrent files to be processed"},
		cli.IntFlag{QualityKey, 80, "JPEG encoding quality used for extracted jpegs"},
		cli.BoolFlag{RotateKey, "ImageMagic's 'convert' command will be used to rotate jpegs based on EXIF info from RawFile.  'convert' must be in PATH"},
	}
	app.Action = func(c *cli.Context) {
		rawExts := strings.TrimSpace(c.String(RawTypesKey))
		srcDir := strings.TrimSpace(c.String(SrcDirKey))
		destDir = strings.TrimSpace(c.String(DestDirKey))
		numOfRoutines = c.Int(NumRoutinesKey)
		quality = c.Int(QualityKey)
		rotate = c.Bool(RotateKey)

		// src and dest dirs required; remaing args have sane defaults
		if rawExts == "" || srcDir == "" || destDir == "" {
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		if rotate && !isImagicConvertInPath(ImageMagicConvertBin) {
			log.Fatal("Rotation of jpegs was enables, but ImageMagic's 'convert' is not in path!")
			exitWithErr()
		}

		// verify RAW file extensions
		rawFileExts = strings.Split(rawExts, ",")
		for i, ext := range rawFileExts {
			rawFileExts[i] = strings.ToUpper(strings.TrimSpace(ext))
			if !isRawFileExtValid(rawFileExts[i]) {
				log.Printf("Error: Invalid Raw File extension: %s\n", rawFileExts[i])
				exitWithErr()
			}
		}

		// verify user-provided src dirs
		srcDirs = strings.Split(srcDir, ",")
		//log.Printf("SrcDirs: %s", srcDirs)
		for i, dir := range srcDirs {
			srcDirs[i] = strings.TrimSpace(dir)
			// ensure directory ends with '/'
			if !strings.HasSuffix(dir, "/") {
				srcDirs[i] += "/"
			}
			isValid, errStr := validateUserDir(srcDirs[i])
			if !isValid {
				log.Println("Error: ", errStr)
				exitWithErr()
			}
		}

		// verify user-provided dest dir
		isValid, errStr := validateUserDir(destDir)
		if !isValid {
			log.Println(errStr)
			exitWithErr()
		}
		// ensure directory ends with '/'
		if !strings.HasSuffix(destDir, "/") {
			destDir += "/"
		}

		processed = true
	}

	app.Run(os.Args)

	return processed
}

func initParsers() {
	parsers = rawparser.NewRawParsers()
	cr2Parser, cr2Key := rawparser.NewCr2Parser(isHostLittleEndian())
	parsers.Register(cr2Key, cr2Parser)

	nefParser, nefKey := rawparser.NewNefParser(isHostLittleEndian())
	parsers.Register(nefKey, nefParser)
}

func doProcess() int {
	log.Printf("RawTypes: %v SourceDirs: %v DestinationDir: %s JPEG Quality: %d Rotate Images: %v\n",
		rawFileExts, srcDirs, destDir, quality, rotate)

	total := 0
	done := make(chan bool)

	// process all src dirs
	for _, dir := range srcDirs {
		// process all raw file types
		for i, rawType := range rawFileExts {
			globPattern := dir + "*." + rawType
			files, _ := getFilesForExt(globPattern)
			fileCnt := len(files)

			if fileCnt > 0 {
				log.Printf("Raw Type: %s ==> Processing '%s' %d files with %d NumCPU:\n",
					rawFileExts[i], dir, len(files), runtime.NumCPU())

				drainCnt := 1
				routinesActive := 0

				for j := 0; j < fileCnt; j++ {
					// keep the specified number of go routines active
					if routinesActive == numOfRoutines {
						// Completion of routines occur in any order.  Count the completion signals
						// by draining channel after launching routines.
						// Drain the channel.
						for c := 0; c < drainCnt; c++ {
							<-done // wait for task to complete
							routinesActive--
						}
					}

					processFilesConcurrent(&RawFileParserPair{files[j], parsers.GetParser(rawType)}, done)
					routinesActive++
				}
				total += fileCnt
			}
		}
	}

	close(done)

	return total
}

func setup() {
	success := processCli()
	if success {
		runtime.GOMAXPROCS(numOfRoutines)
		initParsers()
	} else {
		exitWithErr()
	}
}

func main() {
	t0 := time.Now()

	setup()

	cnt := doProcess()

	duration := time.Since(t0)

	log.Printf("jpgextract processed %d files in %02f mintues (%02f seconds)\n",
		cnt, duration.Minutes(), duration.Seconds())
}
<commit_msg>Changes made due to RawFileInfo change.<commit_after>/*
 Copyright (c) 2013 Jeremy Torres, https://github.com/jeremytorres/jpegextract

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Command utilizing the rawparser library for extracting jpegs from RAW iles.
// The embedded JPEGs are extracted and optionally:
// (1) rotated via oritenation provided in RawFile EXIF info;
//
// Usage:
//     jpgextract --raws "NEF,CR2" --dest-dir "/path_to/output_dir"
//                --src-dirs "/path_to/source1,/path_to/source2"
//                [--num-routines "8" --quality "80" --rotate]
package main

import (
	"github.com/codegangsta/cli"
	"github.com/jeremytorres/rawparser"
	"log"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// RawFileParserPair is a struct for containing a list of files
// for a specific parser.
type RawFileParserPair struct {
	file   string
	parser rawparser.RawParser
}

const (
	// RawTypesKey is the constant representing the command line argument for the RAW file
	// types to be processed.
	RawTypesKey = "raws"

	// SrcDirKey is the constant representing the command line argument for the source directories
	// containing the source RawFiles.
	SrcDirKey = "src-dirs"
	// DestDirKey is a constant representing the command line argument for the destination directory
	// where extracted jpegs shall be placed.
	DestDirKey = "dest-dir"
	// NumRoutinesKey is the constant representing the command line argument for the max number of
	// go routines to be processed.  As this utility is mostly file IO bound, it is important
	// not to use too many routines ("too many files open..." errors can occur from OS).  Therefore,
	// if this value is greater than the logical cores, a warning is logged and the value is set to
	// the number of logical cores.
	NumRoutinesKey = "num-routines"
	// QualityKey is the constant representing the command line argument for the JPEG quality used
	// when processing the embedded JPEG in a RawFile.
	QualityKey = "quality"
	// RotateKey is the constant representing the command line argument indicating rotation of
	// JPEGs should occur based on the EXIF info embedded within the RawFile.  ImageMagic's 'convert'
	// utility is used and is checked at startup for existence.
	RotateKey = "rotate"
	// AppVersionKey is the constant defining the current version of this command utility.
	AppVersionKey = "1.0"
	// ImageMagicConvertBin is the constant representing ImageMagic's 'convert' utility.
	ImageMagicConvertBin = "convert"
)

var (
	destDir, sqlLiteDb     string
	rawFileExts, srcDirs   []string
	numOfRoutines, quality int
	rotate                 bool
	parsers                *rawparser.RawParsers
	// validParserKeys is a slice of RAW file parsers supported by this implementation.
	validParserKeys = []string{
		rawparser.NefParserKey,
		rawparser.Cr2ParserKey,
	}
)

// processFilesConcurrent processes RawFiles concurrently, based on the number goroutines
// specified.
func processFilesConcurrent(rp *RawFileParserPair, c chan<- bool) {

	go func(rp *RawFileParserPair, c chan<- bool) {
		rawfile, err := rp.parser.ProcessFile(&rawparser.RawFileInfo{rp.file, destDir, quality})
		if err != nil {
			log.Printf("Error processing file: '%s' error: %v\n", rp.file, err)
		} else {
			if rotate && rawfile.JpegOrientation != 0.0 {
				// rotate jpeg
				go func(fileName string, radiansCw float64) {
					degrees := radiansCw * (180 / math.Pi)
					log.Printf("Rotating image %f degrees for jpeg: '%s'\n", degrees, fileName)
					cmd := exec.Command(ImageMagicConvertBin, "-rotate", strconv.FormatFloat(degrees, 'f', 2, 64), fileName, fileName)
					err := cmd.Start()
					if err != nil {
						log.Fatal(err)
					}
					err = cmd.Wait()
					if err != nil {
						log.Printf("Command finished with error: %v", err)
					}
				}(rawfile.JpegPath, rawfile.JpegOrientation)
			}
		}
		// signal completion of work
		c <- true
	}(rp, c)
}

func isRawFileExtValid(ext string) bool {
	for _, validExt := range validParserKeys {
		if ext == validExt {
			return true
		}
	}
	return false
}

// processCli parses command line arguments and checks for validity of user-specified
// values.
func processCli() bool {
	var processed = false

	app := cli.NewApp()
	app.Name = "jpgextract"
	app.Usage = "Processes RAW files and extracts JPEGs and optionally create a SQLite database."
	app.Version = AppVersionKey
	app.Author = "Jeremy Torres"
	app.Flags = []cli.Flag{
		cli.StringFlag{RawTypesKey, "", "comma-separated list of RAW file extensions to process.  Current supported " +
			"RAW files: [NEF | CR2]"},
		cli.StringFlag{SrcDirKey, "", "comma-separated list of full paths to the directories containing RawFiles " +
			"(e.g., /path_to/dir1,/path_to/dir2..."},
		cli.StringFlag{DestDirKey, "", "the full path to the directory containing extracted jpegs"},
		cli.IntFlag{NumRoutinesKey, 2, "the number of concurrent files to be processed"},
		cli.IntFlag{QualityKey, 80, "JPEG encoding quality used for extracted jpegs"},
		cli.BoolFlag{RotateKey, "ImageMagic's 'convert' command will be used to rotate jpegs based on EXIF info from RawFile.  'convert' must be in PATH"},
	}
	app.Action = func(c *cli.Context) {
		rawExts := strings.TrimSpace(c.String(RawTypesKey))
		srcDir := strings.TrimSpace(c.String(SrcDirKey))
		destDir = strings.TrimSpace(c.String(DestDirKey))
		numOfRoutines = c.Int(NumRoutinesKey)
		quality = c.Int(QualityKey)
		rotate = c.Bool(RotateKey)

		// src and dest dirs required; remaing args have sane defaults
		if rawExts == "" || srcDir == "" || destDir == "" {
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		if rotate && !isImagicConvertInPath(ImageMagicConvertBin) {
			log.Fatal("Rotation of jpegs was enables, but ImageMagic's 'convert' is not in path!")
			exitWithErr()
		}

		// verify RAW file extensions
		rawFileExts = strings.Split(rawExts, ",")
		for i, ext := range rawFileExts {
			rawFileExts[i] = strings.ToUpper(strings.TrimSpace(ext))
			if !isRawFileExtValid(rawFileExts[i]) {
				log.Printf("Error: Invalid Raw File extension: %s\n", rawFileExts[i])
				exitWithErr()
			}
		}

		// verify user-provided src dirs
		srcDirs = strings.Split(srcDir, ",")
		//log.Printf("SrcDirs: %s", srcDirs)
		for i, dir := range srcDirs {
			srcDirs[i] = strings.TrimSpace(dir)
			// ensure directory ends with '/'
			if !strings.HasSuffix(dir, "/") {
				srcDirs[i] += "/"
			}
			isValid, errStr := validateUserDir(srcDirs[i])
			if !isValid {
				log.Println("Error: ", errStr)
				exitWithErr()
			}
		}

		// verify user-provided dest dir
		isValid, errStr := validateUserDir(destDir)
		if !isValid {
			log.Println(errStr)
			exitWithErr()
		}
		// ensure directory ends with '/'
		if !strings.HasSuffix(destDir, "/") {
			destDir += "/"
		}

		processed = true
	}

	app.Run(os.Args)

	return processed
}

func initParsers() {
	parsers = rawparser.NewRawParsers()
	cr2Parser, cr2Key := rawparser.NewCr2Parser(isHostLittleEndian())
	parsers.Register(cr2Key, cr2Parser)

	nefParser, nefKey := rawparser.NewNefParser(isHostLittleEndian())
	parsers.Register(nefKey, nefParser)
}

func doProcess() int {
	log.Printf("RawTypes: %v SourceDirs: %v DestinationDir: %s JPEG Quality: %d Rotate Images: %v\n",
		rawFileExts, srcDirs, destDir, quality, rotate)

	total := 0
	done := make(chan bool)

	// process all src dirs
	for _, dir := range srcDirs {
		// process all raw file types
		for i, rawType := range rawFileExts {
			globPattern := dir + "*." + rawType
			files, _ := getFilesForExt(globPattern)
			fileCnt := len(files)

			if fileCnt > 0 {
				log.Printf("Raw Type: %s ==> Processing '%s' %d files with %d NumCPU:\n",
					rawFileExts[i], dir, len(files), runtime.NumCPU())

				drainCnt := 1
				routinesActive := 0

				for j := 0; j < fileCnt; j++ {
					// keep the specified number of go routines active
					if routinesActive == numOfRoutines {
						// Completion of routines occur in any order.  Count the completion signals
						// by draining channel after launching routines.
						// Drain the channel.
						for c := 0; c < drainCnt; c++ {
							<-done // wait for task to complete
							routinesActive--
						}
					}

					processFilesConcurrent(&RawFileParserPair{files[j], parsers.GetParser(rawType)}, done)
					routinesActive++
				}
				total += fileCnt
			}
		}
	}

	close(done)

	return total
}

func setup() {
	success := processCli()
	if success {
		runtime.GOMAXPROCS(numOfRoutines)
		initParsers()
	} else {
		exitWithErr()
	}
}

func main() {
	t0 := time.Now()

	setup()

	cnt := doProcess()

	duration := time.Since(t0)

	log.Printf("jpgextract processed %d files in %02f mintues (%02f seconds)\n",
		cnt, duration.Minutes(), duration.Seconds())
}
<|endoftext|>


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

// We used to used this code for Darwin, but according to issue #19314
// waitid returns if the process is stopped, even when using WEXITED.

// +build linux

package os

import (
	"runtime"
	"syscall"
	"unsafe"
)

const _P_PID = 1

// blockUntilWaitable attempts to block until a call to p.Wait will
// succeed immediately, and returns whether it has done so.
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
	// The waitid system call expects a pointer to a siginfo_t,
	// which is 128 bytes on all GNU/Linux systems.
	// On Darwin, it requires greater than or equal to 64 bytes
	// for darwin/{386,arm} and 104 bytes for darwin/amd64.
	// We don't care about the values it returns.
	var siginfo [128]byte
	psig := &siginfo[0]
	_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
	runtime.KeepAlive(p)
	if e != 0 {
		// waitid has been available since Linux 2.6.9, but
		// reportedly is not available in Ubuntu on Windows.
		// See issue 16610.
		if e == syscall.ENOSYS {
			return false, nil
		}
		return false, NewSyscallError("waitid", e)
	}
	return true, nil
}
<commit_msg>os: align siginfo argument to waitid<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// We used to used this code for Darwin, but according to issue #19314
// waitid returns if the process is stopped, even when using WEXITED.

// +build linux

package os

import (
	"runtime"
	"syscall"
	"unsafe"
)

const _P_PID = 1

// blockUntilWaitable attempts to block until a call to p.Wait will
// succeed immediately, and returns whether it has done so.
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
	// The waitid system call expects a pointer to a siginfo_t,
	// which is 128 bytes on all GNU/Linux systems.
	// On Darwin, it requires greater than or equal to 64 bytes
	// for darwin/{386,arm} and 104 bytes for darwin/amd64.
	// We don't care about the values it returns.
	var siginfo [16]uint64
	psig := &siginfo[0]
	_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
	runtime.KeepAlive(p)
	if e != 0 {
		// waitid has been available since Linux 2.6.9, but
		// reportedly is not available in Ubuntu on Windows.
		// See issue 16610.
		if e == syscall.ENOSYS {
			return false, nil
		}
		return false, NewSyscallError("waitid", e)
	}
	return true, nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"code.google.com/p/go-sqlite/go1/sqlite3"
	"github.com/SlyMarbo/rss"
)

/* RSS feed's */
var RSS = map[string]string{
	"miau":    "http://www.lets-hack.it/feed/",
	"marmaro": "http://marmaro.de/lue/feed.rss",
	"kuchen":  "https://kuchen.io/feed",
	"g0tmi1k": "https://blog.g0tmi1k.com/atom.xml",
}

var cursor *sqlite3.Conn

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

func initSQL() {
	cursor, _ = sqlite3.Open("feedme.db")

	query := "CREATE TABLE IF NOT EXISTS feed(" +
		"id        INTEGER PRIMARY KEY," +
		"site      TEXT," +
		"title     TEXT UNIQUE," +
		"link      TEXT," +
		"date      INTEGER," +
		"read      INTEGER);"

	cursor.Exec(query)
}

func insertSQL(site string, title string, link string, date time.Time, read bool) {
	query := "INSERT INTO feed (site, title, link, date, read) " +
		"VALUES ($site, $title, $link, $date, $read);"

	sql := sqlite3.NamedArgs{
		"$site":  site,
		"$title": title,
		"$link":  link,
		"$date":  date,
		"$read":  read,
	}

	cursor.Exec(query, sql)
}

func main() {
	// initialize SQL database
	initSQL()

	for _, url := range RSS {
		feed, err := rss.Fetch(url)
		checkErr(err)

		err = feed.Update()
		checkErr(err)

		for _, element := range feed.Items {
			insertSQL(feed.Title, element.Title, element.Link,
				element.Date, element.Read)
		}
	}
}

/* vim: set noet sw=4 sts=4: */
<commit_msg>Add const to ffetch.go<commit_after>// ffetch.go - fetch and store content to SQL
package main

import (
	"time"

	"code.google.com/p/go-sqlite/go1/sqlite3"
	"github.com/SlyMarbo/rss"
)

/* RSS feed's */
var RSS = map[string]string{
	"miau":    "http://www.lets-hack.it/feed/",
	"marmaro": "http://marmaro.de/lue/feed.rss",
	"kuchen":  "https://kuchen.io/feed",
	"g0tmi1k": "https://blog.g0tmi1k.com/atom.xml",
}

// Default SQL Database
const (
	SQLDatabase = "feedme.db"
)

var cursor *sqlite3.Conn

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

func initSQL() {
	cursor, _ = sqlite3.Open(SQLDatabase)

	query := "CREATE TABLE IF NOT EXISTS feed(" +
		"id        INTEGER PRIMARY KEY," +
		"site      TEXT," +
		"title     TEXT UNIQUE," +
		"link      TEXT," +
		"date      INTEGER," +
		"read      INTEGER);"

	cursor.Exec(query)
}

func insertSQL(site string, title string, link string, date time.Time, read bool) {
	query := "INSERT INTO feed (site, title, link, date, read) " +
		"VALUES ($site, $title, $link, $date, $read);"

	sql := sqlite3.NamedArgs{
		"$site":  site,
		"$title": title,
		"$link":  link,
		"$date":  date,
		"$read":  read,
	}

	cursor.Exec(query, sql)
}

func main() {
	// initialize SQL database
	initSQL()

	for _, url := range RSS {
		feed, err := rss.Fetch(url)
		checkErr(err)

		err = feed.Update()
		checkErr(err)

		for _, element := range feed.Items {
			insertSQL(feed.Title, element.Title, element.Link,
				element.Date, element.Read)
		}
	}
}

/* vim: set noet sw=4 sts=4: */
<|endoftext|>


<commit_before>// Package action implements all the different actions an alert can take should
// its condition be found to be true
package action

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/levenlabs/go-llog"
	"github.com/levenlabs/thumper/config"
	"github.com/levenlabs/thumper/context"
	"github.com/mitchellh/mapstructure"
)

// Actioner describes an action type. There all multiple action types, but they
// all simply attempt to perform one action and that's it
type Actioner interface {

	// Do takes in the alert context, and possibly returnes an error if the
	// action failed
	Do(context.Context) error
}

// Action is a wrapper around an Actioner which contains some type information
type Action struct {
	Type string
	Actioner
}

// ToActioner takes in some arbitrary data (hopefully a map[string]interface{},
// looks at its "type" key, and any other fields necessary based on that type,
// and returns an Actioner (or an error)
func ToActioner(in interface{}) (Action, error) {
	min, ok := in.(map[string]interface{})
	if !ok {
		return Action{}, errors.New("action definition is not an object")
	}

	var a Actioner
	typ, _ := min["type"].(string)
	typ = strings.ToLower(typ)
	switch typ {
	case "log":
		a = &Log{}
	case "http":
		a = &HTTP{}
	case "pagerduty":
		a = &PagerDuty{}
	default:
		return Action{}, fmt.Errorf("unknown action type: %q", typ)
	}

	if err := mapstructure.Decode(min, a); err != nil {
		return Action{}, err
	}
	return Action{Type: typ, Actioner: a}, nil
}

// Log is an action which does nothing but print a log message. Useful when
// testing alerts and you don't want to set up any actions yet
type Log struct {
	Message string `mapstructure:"message"`
}

// Do logs the Log's message. It doesn't actually need any context
func (l *Log) Do(_ context.Context) error {
	llog.Info("doing log action", llog.KV{"message": l.Message})
	return nil
}

// HTTP is an action which performs a single http request. If the request's
// response doesn't have a 2xx response code then it's considered an error
type HTTP struct {
	Method  string            `mapstructure:"method"`
	URL     string            `mapstructure:"url"`
	Headers map[string]string `mapstructure:"headers"`
	Body    string            `mapstructure:"body"`
}

// Do performs the actual http request. It doesn't need the alert context
func (h *HTTP) Do(_ context.Context) error {
	r, err := http.NewRequest(h.Method, h.URL, bytes.NewBufferString(h.Body))
	if err != nil {
		return err
	}

	if h.Headers != nil {
		for k, v := range h.Headers {
			r.Header.Set(k, v)
		}
	}

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		return fmt.Errorf("non 2xx response code returned: %d", resp.StatusCode)
	}

	return nil
}

// PagerDuty submits a trigger to a pagerduty endpoint
type PagerDuty struct {
	Key         string                 `mapstructure:"incident_key"`
	Description string                 `mapstructure:"description"`
	Details     map[string]interface{} `mapstructure:"details"`
}

// Do performs the actual trigger request to the pagerduty api
func (p *PagerDuty) Do(c context.Context) error {
	if config.PagerDutyKey == "" {
		return errors.New("pagerduty key not set in config")
	}
	if p.Key == "" {
		p.Key = c.Name
	}

	body := map[string]interface{}{
		"service_key":  config.PagerDutyKey,
		"event_type":   "trigger",
		"description":  p.Description,
		"incident_key": p.Key,
		"details":      p.Details,
	}
	bodyb, err := json.Marshal(&body)
	if err != nil {
		return err
	}

	u := "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
	r, err := http.NewRequest("POST", u, bytes.NewBuffer(bodyb))
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}

// OpsGenie submits an alert to an opsgenie endpoint
type OpsGenie struct {
	APIKey  string `json:"apiKey"`
	Message string `json:"message" mapstructure:"message"`
	// Optional Params
	Teams       []string          `json:"teams" mapstructure:"teams"`
	Alias       string            `json:"alias" mapstructure:"alias"`
	Description string            `json:"description" mapstructure:"description"`
	Recipients  []string          `json:"recipients" mapstructure:"recipients"`
	Actions     string            `json:"actions" mapstructure:"actions"`
	Source      string            `json:"source" mapstructure:"source"`
	Tags        string            `json:"tags" mapstructure:"tags"`
	Details     map[string]string `json:"details" mapstructure:"details"`
	User        string            `json:"user" mapstructure:"user"`
	Note        string            `json:"note" mapstructure:"note"`
}

// Do performs the actual alert request to the opsgenie api
func (o *OpsGenie) Do(c context.Context) error {
	if config.OpsGenieKey == "" {
		return errors.New("opsgenie key not set in config")
	}
	o.APIKey = config.OpsGenieKey

	if o.Alias == "" {
		o.Alias = c.Name
	}

	if p.Message == "" {
		return errors.New("missing required field messages in OpsGenie")
	}

	bodyb, err := json.Marshal(&o)
	if err != nil {
		return err
	}

	u := "https://api.opsgenie.com/v1/json/alert"
	r, err := http.NewRequest("POST", u, bytes.NewBuffer(bodyb))
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}
<commit_msg>I'm stupid and my vim setup changed<commit_after>// Package action implements all the different actions an alert can take should
// its condition be found to be true
package action

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/levenlabs/go-llog"
	"github.com/levenlabs/thumper/config"
	"github.com/levenlabs/thumper/context"
	"github.com/mitchellh/mapstructure"
)

// Actioner describes an action type. There all multiple action types, but they
// all simply attempt to perform one action and that's it
type Actioner interface {

	// Do takes in the alert context, and possibly returnes an error if the
	// action failed
	Do(context.Context) error
}

// Action is a wrapper around an Actioner which contains some type information
type Action struct {
	Type string
	Actioner
}

// ToActioner takes in some arbitrary data (hopefully a map[string]interface{},
// looks at its "type" key, and any other fields necessary based on that type,
// and returns an Actioner (or an error)
func ToActioner(in interface{}) (Action, error) {
	min, ok := in.(map[string]interface{})
	if !ok {
		return Action{}, errors.New("action definition is not an object")
	}

	var a Actioner
	typ, _ := min["type"].(string)
	typ = strings.ToLower(typ)
	switch typ {
	case "log":
		a = &Log{}
	case "http":
		a = &HTTP{}
	case "pagerduty":
		a = &PagerDuty{}
	default:
		return Action{}, fmt.Errorf("unknown action type: %q", typ)
	}

	if err := mapstructure.Decode(min, a); err != nil {
		return Action{}, err
	}
	return Action{Type: typ, Actioner: a}, nil
}

// Log is an action which does nothing but print a log message. Useful when
// testing alerts and you don't want to set up any actions yet
type Log struct {
	Message string `mapstructure:"message"`
}

// Do logs the Log's message. It doesn't actually need any context
func (l *Log) Do(_ context.Context) error {
	llog.Info("doing log action", llog.KV{"message": l.Message})
	return nil
}

// HTTP is an action which performs a single http request. If the request's
// response doesn't have a 2xx response code then it's considered an error
type HTTP struct {
	Method  string            `mapstructure:"method"`
	URL     string            `mapstructure:"url"`
	Headers map[string]string `mapstructure:"headers"`
	Body    string            `mapstructure:"body"`
}

// Do performs the actual http request. It doesn't need the alert context
func (h *HTTP) Do(_ context.Context) error {
	r, err := http.NewRequest(h.Method, h.URL, bytes.NewBufferString(h.Body))
	if err != nil {
		return err
	}

	if h.Headers != nil {
		for k, v := range h.Headers {
			r.Header.Set(k, v)
		}
	}

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		return fmt.Errorf("non 2xx response code returned: %d", resp.StatusCode)
	}

	return nil
}

// PagerDuty submits a trigger to a pagerduty endpoint
type PagerDuty struct {
	Key         string                 `mapstructure:"incident_key"`
	Description string                 `mapstructure:"description"`
	Details     map[string]interface{} `mapstructure:"details"`
}

// Do performs the actual trigger request to the pagerduty api
func (p *PagerDuty) Do(c context.Context) error {
	if config.PagerDutyKey == "" {
		return errors.New("pagerduty key not set in config")
	}
	if p.Key == "" {
		p.Key = c.Name
	}

	body := map[string]interface{}{
		"service_key":  config.PagerDutyKey,
		"event_type":   "trigger",
		"description":  p.Description,
		"incident_key": p.Key,
		"details":      p.Details,
	}
	bodyb, err := json.Marshal(&body)
	if err != nil {
		return err
	}

	u := "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
	r, err := http.NewRequest("POST", u, bytes.NewBuffer(bodyb))
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}

// OpsGenie submits an alert to an opsgenie endpoint
type OpsGenie struct {
	APIKey  string `json:"apiKey"`
	Message string `json:"message" mapstructure:"message"`
	// Optional Params
	Teams       []string          `json:"teams" mapstructure:"teams"`
	Alias       string            `json:"alias" mapstructure:"alias"`
	Description string            `json:"description" mapstructure:"description"`
	Recipients  []string          `json:"recipients" mapstructure:"recipients"`
	Actions     string            `json:"actions" mapstructure:"actions"`
	Source      string            `json:"source" mapstructure:"source"`
	Tags        string            `json:"tags" mapstructure:"tags"`
	Details     map[string]string `json:"details" mapstructure:"details"`
	User        string            `json:"user" mapstructure:"user"`
	Note        string            `json:"note" mapstructure:"note"`
}

// Do performs the actual alert request to the opsgenie api
func (o *OpsGenie) Do(c context.Context) error {
	if config.OpsGenieKey == "" {
		return errors.New("opsgenie key not set in config")
	}
	o.APIKey = config.OpsGenieKey

	if o.Alias == "" {
		o.Alias = c.Name
	}

	if o.Message == "" {
		return errors.New("missing required field messages in OpsGenie")
	}

	bodyb, err := json.Marshal(&o)
	if err != nil {
		return err
	}

	u := "https://api.opsgenie.com/v1/json/alert"
	r, err := http.NewRequest("POST", u, bytes.NewBuffer(bodyb))
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}
<|endoftext|>


<commit_before>package kafka

import (
	"errors"
	"testing"
	"time"

	"github.com/optiopay/kafka/proto"
)

type fetcher struct {
	messages []*proto.Message
	errors   []error
}

func (f *fetcher) Consume() (*proto.Message, error) {
	// sleep a bit to let the other's work
	time.Sleep(time.Microsecond * 50)

	if len(f.messages) > 0 {
		msg := f.messages[0]
		f.messages = f.messages[1:]
		return msg, nil
	}
	if len(f.errors) > 0 {
		err := f.errors[0]
		f.errors = f.errors[1:]
		return nil, err
	}
	panic("not implemented")
}

func TestMultiplexerConsume(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{
			messages: []*proto.Message{
				&proto.Message{Value: []byte("first")},
				&proto.Message{Value: []byte("second")},
			},
			errors: []error{
				errors.New("e first"),
				errors.New("e second"),
				errors.New("e third"),
			},
		},
		&fetcher{
			messages: []*proto.Message{
				&proto.Message{Value: []byte("1")},
				&proto.Message{Value: []byte("2")},
			},
			errors: []error{
				errors.New("e 1"),
				errors.New("e 2"),
				errors.New("e 3"),
			},
		},
	}

	results := make(map[string]bool)

	mx := Merge(fetchers...)
	defer mx.Close()

	for i := 0; i < 8; i++ {
		msg, err := mx.Consume()
		if err != nil {
			results[err.Error()] = true
		} else {
			results[string(msg.Value)] = true
		}
	}

	expected := []string{
		"first", "second", "e first", "e second",
		"1", "2", "e 1", "e 2",
	}

	// expected 4 messages and 2 errors
	if len(results) != len(expected) {
		t.Errorf("expected %d results, got %d", len(expected), len(results))
	}
	for _, name := range expected {
		if results[name] != true {
			t.Errorf("%q not found: %#v", name, results)
		}
	}
}

func TestClosingMultiplexer(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{errors: []error{errors.New("a1")}},
		&fetcher{errors: []error{errors.New("b1")}},
		&fetcher{errors: []error{errors.New("c1")}},
	}
	mx := Merge(fetchers...)

	// closing more than once should be fine
	for i := 0; i < 4; i++ {
		go mx.Close()
	}
	mx.Close()
	mx.Close()

	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}

type blockingFetcher struct {
	stop chan struct{}
}

func (f *blockingFetcher) Consume() (*proto.Message, error) {
	<-f.stop
	return nil, errors.New("blocking fetcher is done")
}

func (f *blockingFetcher) Close() {
	close(f.stop)
}

func TestClosingMultiplexerWithBlockingWorkers(t *testing.T) {
	f1 := &blockingFetcher{make(chan struct{})}
	defer f1.Close()
	f2 := &blockingFetcher{make(chan struct{})}
	defer f2.Close()

	mx := Merge(f1, f2)
	// close should be instant - without waiting for workers to finish
	mx.Close()

	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}

func TestErrNoDataCloseMultiplexer(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{errors: []error{ErrNoData}},
		&fetcher{errors: []error{ErrNoData}, messages: []*proto.Message{&proto.Message{}}},
		&fetcher{errors: []error{ErrNoData}},
	}
	mx := Merge(fetchers...)

	if _, err := mx.Consume(); err != nil {
		t.Fatalf("first consume should succeed, got %s", err)
	}
	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}
<commit_msg>tests fixed<commit_after>package kafka

import (
	"errors"
	"testing"
	"time"

	"github.com/optiopay/kafka/proto"
)

type fetcher struct {
	messages []*proto.Message
	errors   []error
}

func (f *fetcher) Consume() (*proto.Message, error) {
	// sleep a bit to let the other's work
	time.Sleep(time.Microsecond * 500)

	if len(f.messages) > 0 {
		msg := f.messages[0]
		f.messages = f.messages[1:]
		return msg, nil
	}
	if len(f.errors) > 0 {
		err := f.errors[0]
		f.errors = f.errors[1:]
		return nil, err
	}
	panic("not implemented")
}

func TestMultiplexerConsume(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{
			messages: []*proto.Message{
				&proto.Message{Value: []byte("first")},
				&proto.Message{Value: []byte("second")},
			},
			errors: []error{
				errors.New("e first"),
				errors.New("e second"),
				errors.New("e third"),
			},
		},
		&fetcher{
			messages: []*proto.Message{
				&proto.Message{Value: []byte("1")},
				&proto.Message{Value: []byte("2")},
			},
			errors: []error{
				errors.New("e 1"),
				errors.New("e 2"),
				errors.New("e 3"),
			},
		},
	}

	results := make(map[string]bool)

	mx := Merge(fetchers...)
	defer mx.Close()

	for i := 0; i < 8; i++ {
		msg, err := mx.Consume()
		if err != nil {
			results[err.Error()] = true
		} else {
			results[string(msg.Value)] = true
		}
	}

	expected := []string{
		"first", "second", "e first", "e second",
		"1", "2", "e 1", "e 2",
	}

	// expected 4 messages and 2 errors
	if len(results) != len(expected) {
		t.Errorf("expected %d results, got %d", len(expected), len(results))
	}
	for _, name := range expected {
		if results[name] != true {
			t.Errorf("%q not found: %#v", name, results)
		}
	}
}

func TestClosingMultiplexer(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{errors: []error{errors.New("a1")}},
		&fetcher{errors: []error{errors.New("b1")}},
		&fetcher{errors: []error{errors.New("c1")}},
	}
	mx := Merge(fetchers...)

	// closing more than once should be fine
	for i := 0; i < 4; i++ {
		go mx.Close()
	}
	mx.Close()
	mx.Close()

	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}

type blockingFetcher struct {
	stop chan struct{}
}

func (f *blockingFetcher) Consume() (*proto.Message, error) {
	<-f.stop
	return nil, errors.New("blocking fetcher is done")
}

func (f *blockingFetcher) Close() {
	close(f.stop)
}

func TestClosingMultiplexerWithBlockingWorkers(t *testing.T) {
	f1 := &blockingFetcher{make(chan struct{})}
	defer f1.Close()
	f2 := &blockingFetcher{make(chan struct{})}
	defer f2.Close()

	mx := Merge(f1, f2)
	// close should be instant - without waiting for workers to finish
	mx.Close()

	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}

func TestErrNoDataCloseMultiplexer(t *testing.T) {
	fetchers := []Consumer{
		&fetcher{errors: []error{ErrNoData}},
		&fetcher{errors: []error{ErrNoData}, messages: []*proto.Message{&proto.Message{}}},
		&fetcher{errors: []error{ErrNoData}},
	}
	mx := Merge(fetchers...)

	if _, err := mx.Consume(); err != nil {
		t.Fatalf("first consume should succeed, got %s", err)
	}
	if _, err := mx.Consume(); err != ErrMxClosed {
		t.Fatalf("expected %s, got %s", ErrMxClosed, err)
	}
}
<|endoftext|>


<commit_before>package fs

// Version of rclone
var Version = "v1.43"
<commit_msg>Start v1.43-DEV development<commit_after>package fs

// Version of rclone
var Version = "v1.43-DEV"
<|endoftext|>