<commit_before>package docker

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

type ChangeType int

const (
	ChangeModify = iota
	ChangeAdd
	ChangeDelete
)

type Change struct {
	Path string
	Kind ChangeType
}

func (change *Change) String() string {
	var kind string
	switch change.Kind {
	case ChangeModify:
		kind = "C"
	case ChangeAdd:
		kind = "A"
	case ChangeDelete:
		kind = "D"
	}
	return fmt.Sprintf("%s %s", kind, change.Path)
}

func ChangesAUFS(layers []string, rw string) ([]Change, error) {
	var changes []Change
	err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		path, err = filepath.Rel(rw, path)
		if err != nil {
			return err
		}
		path = filepath.Join("/", path)

		// Skip root
		if path == "/" {
			return nil
		}

		// Skip AUFS metadata
		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
			return err
		}

		change := Change{
			Path: path,
		}

		// Find out what kind of modification happened
		file := filepath.Base(path)
		// If there is a whiteout, then the file was removed
		if strings.HasPrefix(file, ".wh.") {
			originalFile := file[len(".wh."):]
			change.Path = filepath.Join(filepath.Dir(path), originalFile)
			change.Kind = ChangeDelete
		} else {
			// Otherwise, the file was added
			change.Kind = ChangeAdd

			// ...Unless it already existed in a top layer, in which case, it's a modification
			for _, layer := range layers {
				stat, err := os.Stat(filepath.Join(layer, path))
				if err != nil && !os.IsNotExist(err) {
					return err
				}
				if err == nil {
					// The file existed in the top layer, so that's a modification

					// However, if it's a directory, maybe it wasn't actually modified.
					// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
					if stat.IsDir() && f.IsDir() {
						if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
							// Both directories are the same, don't record the change
							return nil
						}
					}
					change.Kind = ChangeModify
					break
				}
			}
		}

		// Record change
		changes = append(changes, change)
		return nil
	})
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}
	return changes, nil
}

func ChangesDirs(newDir, oldDir string) ([]Change, error) {
	var changes []Change
	err := filepath.Walk(newDir, func(newPath string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		var newStat syscall.Stat_t
		err = syscall.Lstat(newPath, &newStat)
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(newDir, newPath)
		if err != nil {
			return err
		}
		relPath = filepath.Join("/", relPath)

		// Skip root
		if relPath == "/" || relPath == "/.docker-id" {
			return nil
		}

		change := Change{
			Path: relPath,
		}

		oldPath := filepath.Join(oldDir, relPath)

		var oldStat = &syscall.Stat_t{}
		err = syscall.Lstat(oldPath, oldStat)
		if err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			oldStat = nil
		}

		if oldStat == nil {
			change.Kind = ChangeAdd
			changes = append(changes, change)
		} else {
			if oldStat.Ino != newStat.Ino ||
				oldStat.Mode != newStat.Mode ||
				oldStat.Uid != newStat.Uid ||
				oldStat.Gid != newStat.Gid ||
				oldStat.Rdev != newStat.Rdev ||
				oldStat.Size != newStat.Size ||
				oldStat.Blocks != newStat.Blocks ||
				oldStat.Mtim != newStat.Mtim ||
				oldStat.Ctim != newStat.Ctim {
				change.Kind = ChangeModify
				changes = append(changes, change)
			}
		}

		return nil
	})
	if err != nil {
		return nil, err
	}
	err = filepath.Walk(oldDir, func(oldPath string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(oldDir, oldPath)
		if err != nil {
			return err
		}
		relPath = filepath.Join("/", relPath)

		// Skip root
		if relPath == "/" {
			return nil
		}

		change := Change{
			Path: relPath,
		}

		newPath := filepath.Join(newDir, relPath)

		var newStat = &syscall.Stat_t{}
		err = syscall.Lstat(newPath, newStat)
		if err != nil && os.IsNotExist(err) {
			change.Kind = ChangeDelete
			changes = append(changes, change)
		}

		return nil
	})
	if err != nil {
		return nil, err
	}
	return changes, nil
}
<commit_msg>Change how ChangesDirs() works<commit_after>package docker

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

type ChangeType int

const (
	ChangeModify = iota
	ChangeAdd
	ChangeDelete
)

type Change struct {
	Path string
	Kind ChangeType
}

func (change *Change) String() string {
	var kind string
	switch change.Kind {
	case ChangeModify:
		kind = "C"
	case ChangeAdd:
		kind = "A"
	case ChangeDelete:
		kind = "D"
	}
	return fmt.Sprintf("%s %s", kind, change.Path)
}

func ChangesAUFS(layers []string, rw string) ([]Change, error) {
	var changes []Change
	err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		path, err = filepath.Rel(rw, path)
		if err != nil {
			return err
		}
		path = filepath.Join("/", path)

		// Skip root
		if path == "/" {
			return nil
		}

		// Skip AUFS metadata
		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
			return err
		}

		change := Change{
			Path: path,
		}

		// Find out what kind of modification happened
		file := filepath.Base(path)
		// If there is a whiteout, then the file was removed
		if strings.HasPrefix(file, ".wh.") {
			originalFile := file[len(".wh."):]
			change.Path = filepath.Join(filepath.Dir(path), originalFile)
			change.Kind = ChangeDelete
		} else {
			// Otherwise, the file was added
			change.Kind = ChangeAdd

			// ...Unless it already existed in a top layer, in which case, it's a modification
			for _, layer := range layers {
				stat, err := os.Stat(filepath.Join(layer, path))
				if err != nil && !os.IsNotExist(err) {
					return err
				}
				if err == nil {
					// The file existed in the top layer, so that's a modification

					// However, if it's a directory, maybe it wasn't actually modified.
					// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
					if stat.IsDir() && f.IsDir() {
						if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
							// Both directories are the same, don't record the change
							return nil
						}
					}
					change.Kind = ChangeModify
					break
				}
			}
		}

		// Record change
		changes = append(changes, change)
		return nil
	})
	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}
	return changes, nil
}

type FileInfo struct {
	parent *FileInfo
	name string
	stat syscall.Stat_t
	children map[string]*FileInfo
}

func (root *FileInfo) LookUp(path string) *FileInfo {
	parent := root
	if path == "/" {
		return root
	}

	pathElements := strings.Split(path, "/")
	for _, elem := range pathElements {
		if elem != "" {
			child := parent.children[elem]
			if child == nil {
				return nil
			}
			parent = child
		}
	}
	return parent
}

func (info *FileInfo)path() string {
	if info.parent == nil {
		return "/"
	}
	return filepath.Join(info.parent.path(), info.name)
}

func (info *FileInfo)unlink() {
	if info.parent != nil {
		delete(info.parent.children, info.name)
	}
}

func (info *FileInfo)Remove(path string) bool {
	child := info.LookUp(path)
	if child != nil {
		child.unlink()
		return true
	}
	return false
}

func (info *FileInfo)isDir() bool {
	return info.parent == nil || info.stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR
}

func (info *FileInfo)addChanges(oldInfo *FileInfo, changes *[]Change) {
	if oldInfo == nil {
		// add
		change := Change{
			Path: info.path(),
			Kind: ChangeAdd,
		}
		*changes = append(*changes, change)
	}

	// We make a copy so we can modify it to detect additions
	// also, we only recurse on the old dir if the new info is a directory
	// otherwise any previous delete/change is considered recursive
	oldChildren := make(map[string]*FileInfo)
	if oldInfo != nil && info.isDir() {
		for k, v := range oldInfo.children {
			oldChildren[k] = v
		}
	}

	for name, newChild := range info.children {
		oldChild, _ := oldChildren[name]
		if oldChild != nil {
			// change?
			oldStat := &oldChild.stat
			newStat := &newChild.stat
			if oldStat.Ino != newStat.Ino ||
				oldStat.Mode != newStat.Mode ||
				oldStat.Uid != newStat.Uid ||
				oldStat.Gid != newStat.Gid ||
				oldStat.Rdev != newStat.Rdev ||
				oldStat.Size != newStat.Size ||
				oldStat.Blocks != newStat.Blocks ||
				oldStat.Mtim != newStat.Mtim ||
				oldStat.Ctim != newStat.Ctim {
				change := Change{
					Path: newChild.path(),
					Kind: ChangeModify,
				}
				*changes = append(*changes, change)
			}

			// Remove from copy so we can detect deletions
			delete(oldChildren, name)
		}

		newChild.addChanges(oldChild, changes)
	}
	for _, oldChild := range oldChildren {
		// delete
		change := Change{
			Path: oldChild.path(),
			Kind: ChangeDelete,
		}
		*changes = append(*changes, change)
	}

}

func (info *FileInfo)Changes(oldInfo *FileInfo) []Change {
	var changes []Change

	info.addChanges(oldInfo, &changes)

	return changes
}

func collectFileInfo(sourceDir string) (*FileInfo, error) {
	root := &FileInfo {
		name: "/",
		children: make(map[string]*FileInfo),
	}

	err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(sourceDir, path)
		if err != nil {
			return err
		}
		relPath = filepath.Join("/", relPath)

		if relPath == "/" {
			return nil
		}

		parent := root.LookUp(filepath.Dir(relPath))
		if parent == nil {
			return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
		}

		info := &FileInfo {
			name: filepath.Base(relPath),
			children: make(map[string]*FileInfo),
			parent: parent,
		}

		if err := syscall.Lstat(path, &info.stat); err != nil {
			return err
		}

		parent.children[info.name] = info

		return nil
	})
	if err != nil {
		return nil, err
	}
	return root, nil
}

func ChangesDirs(newDir, oldDir string) ([]Change, error) {
	oldRoot, err := collectFileInfo(oldDir)
	if err != nil {
		return nil, err
	}
	newRoot, err := collectFileInfo(newDir)
	if err != nil {
		return nil, err
	}

	// Ignore changes in .docker-id
	_ = newRoot.Remove("/.docker-id")
	_ = oldRoot.Remove("/.docker-id")

	return newRoot.Changes(oldRoot), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
)

func action(ctx *cli.Context) error {
	config, errors := makeConfig(ctx)
	if errors != nil {
		for _, err := range errors {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
		fmt.Fprintf(os.Stderr, "\n")
		cli.ShowAppHelp(ctx)
	} else {
		dependency, errors := gatherDependency(config)
		output(config, dependency, errors)
	}
	return nil
}

func output(config *Config, dependency *Dependency, errors []error) {
	for _, err := range errors {
		fmt.Fprintf(os.Stderr, err.Error()+"\n")
	}
	switch config.Format {
	case "dot":
		outputDot(config.Output, dependency)
	case "csv":
		outputCsv(config.Output, dependency)
	case "tsv":
		outputTsv(config.Output, dependency)
	case "json":
		outputJSON(config.Output, dependency)
	default:
		outputDefault(config.Output, dependency)
	}
}

func gatherDependency(config *Config) (*Dependency, []error) {
	var errors []error
	dependency := newDependency()
	for _, path := range config.Paths {
		deps, err := extract(path, config)
		if err != nil {
			errors = append(errors, err...)
		} else {
			dependency.concat(deps)
		}
	}
	return dependency, errors
}
<commit_msg>update action.go: improve error formatting<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
)

func action(ctx *cli.Context) error {
	config, errors := makeConfig(ctx)
	if errors != nil {
		hasErr := false
		for _, err := range errors {
			if err.Error() != "" {
				fmt.Fprintf(os.Stderr, err.Error()+"\n")
				hasErr = true
			}
		}
		if hasErr {
			fmt.Fprintf(os.Stderr, "\n")
		}
		cli.ShowAppHelp(ctx)
	} else {
		dependency, errors := gatherDependency(config)
		output(config, dependency, errors)
	}
	return nil
}

func output(config *Config, dependency *Dependency, errors []error) {
	for _, err := range errors {
		fmt.Fprintf(os.Stderr, err.Error()+"\n")
	}
	switch config.Format {
	case "dot":
		outputDot(config.Output, dependency)
	case "csv":
		outputCsv(config.Output, dependency)
	case "tsv":
		outputTsv(config.Output, dependency)
	case "json":
		outputJSON(config.Output, dependency)
	default:
		outputDefault(config.Output, dependency)
	}
}

func gatherDependency(config *Config) (*Dependency, []error) {
	var errors []error
	dependency := newDependency()
	for _, path := range config.Paths {
		deps, err := extract(path, config)
		if err != nil {
			errors = append(errors, err...)
		} else {
			dependency.concat(deps)
		}
	}
	return dependency, errors
}
<|endoftext|>


<commit_before>package pusher

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

// Channel represents a subscription to a Pusher channel.
type Channel interface {
	// IsSubscribed indicates if the channel is currently subscribed
	IsSubscribed() bool
	// Subscribe attempts to subscribe to the channel if the subscription is not
	// already active. Authentication will be attempted for private and presence
	// channels.
	Subscribe(...SubscribeOption) error
	// Unsubscribe attempts to unsubscribe from the channel. Note that a nil error
	// does not mean that the unsubscription was successful, just that the request
	// was sent.
	Unsubscribe() error
	// Bind returns a channel to which all the data from all matching events received
	// on the channel will be sent.
	Bind(event string) chan json.RawMessage
	// Unbind removes bindings for an event. If chans are passed, only those bindings
	// will be removed. Otherwise, all bindings for an event will be removed.
	Unbind(event string, chans ...chan json.RawMessage)
	// Trigger sends an event to the channel.
	Trigger(event string, data interface{}) error
}

// internalChannel represents the Channel interface used internally
type internalChannel interface {
	Channel

	handleEvent(event string, data json.RawMessage)
}

type chanContext struct {
	ctx    context.Context
	cancel context.CancelFunc
}

func newChanContext() chanContext {
	ctx, cancel := context.WithCancel(context.Background())
	return chanContext{ctx, cancel}
}

type boundDataChans map[chan json.RawMessage]chanContext

type channel struct {
	name        string
	boundEvents map[string]boundDataChans
	// TODO: implement global bindings
	// globalBindings boundDataChans
	client           *Client
	subscribed       bool
	subscribeSuccess chan struct{}
	// channelData is populated for authorized channels (presence and private
	// channels). It's set by sendSubscriptionRequest. The channelData is invalid
	// until subscribed is set to true.
	channelData channelData

	mutex sync.RWMutex
}

type channelData struct {
	Channel     string          `json:"channel"`
	Auth        string          `json:"auth,omitempty"`
	ChannelData json.RawMessage `json:"channel_data,omitempty"`
}

func (c *channel) IsSubscribed() bool {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	return c.subscribed
}

type subscribeOptions struct {
	successTimeout time.Duration
}

// SubscribeOption is a configuration option for subscribing to a channel
type SubscribeOption func(*subscribeOptions)

const defaultSuccessTimeout = 10 * time.Second

// WithSuccessTimeout returns a SubscribeOption that sets the time that a subscription
// request will wait for a success response from Pusher before timing out. The
// default is 10 seconds.
func WithSuccessTimeout(d time.Duration) SubscribeOption {
	return func(o *subscribeOptions) {
		o.successTimeout = d
	}
}

// ErrTimedOut is the error returned when there is a timeout waiting for a subscription
// confirmation from Pusher
var ErrTimedOut = errors.New("timed out")

func (c *channel) sendSubscriptionRequest(data channelData, o *subscribeOptions) error {
	c.mutex.Lock()
	c.subscribeSuccess = make(chan struct{})
	c.channelData = data
	c.mutex.Unlock()

	doneChan := make(chan error)

	go func() {
		var err error
		select {
		case <-c.subscribeSuccess:
			err = nil
		case <-time.After(o.successTimeout):
			err = ErrTimedOut
		}

		// try to send on the channel, but don't block if nothing is listening, such
		// as when there is an error calling SendEvent
		select {
		case doneChan <- err:
		default:
		}
	}()

	err := c.client.SendEvent(pusherSubscribe, data, "")
	if err != nil {
		return fmt.Errorf("error sending subscription request: %s", err)
	}

	return <-doneChan
}

func (c *channel) Subscribe(opts ...SubscribeOption) error {
	if c.IsSubscribed() {
		return nil
	}

	o := &subscribeOptions{
		successTimeout: defaultSuccessTimeout,
	}

	for _, opt := range opts {
		opt(o)
	}

	return c.sendSubscriptionRequest(channelData{Channel: c.name}, o)
}

func (c *channel) Unsubscribe() error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.subscribed = false
	return c.client.SendEvent(pusherUnsubscribe, channelData{
		Channel: c.name,
	}, "")
}

func (c *channel) Bind(event string) chan json.RawMessage {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	boundChan := make(chan json.RawMessage)

	if c.boundEvents[event] == nil {
		c.boundEvents[event] = boundDataChans{}
	}

	c.boundEvents[event][boundChan] = newChanContext()

	return boundChan
}

func (c *channel) Unbind(event string, chans ...chan json.RawMessage) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if len(chans) == 0 {
		for _, chanCtx := range c.boundEvents[event] {
			chanCtx.cancel()
		}
		delete(c.boundEvents, event)
		return
	}

	eventBoundChans := c.boundEvents[event]
	for _, boundChan := range chans {
		chanCtx, exists := eventBoundChans[boundChan]
		if !exists {
			continue
		}

		chanCtx.cancel()
		delete(eventBoundChans, boundChan)
	}
}

func (c *channel) handleEvent(event string, data json.RawMessage) {
	if event == pusherInternalSubSucceeded {
		// try to send on the channel, but don't block if nothing is listening
		select {
		case c.subscribeSuccess <- struct{}{}:
		default:
		}

		c.mutex.Lock()
		c.subscribed = true
		c.mutex.Unlock()

		event = pusherSubSucceeded
	}

	c.mutex.RLock()
	sendDataMessage(c.boundEvents[event], data)
	c.mutex.RUnlock()
}

func sendDataMessage(channels boundDataChans, data json.RawMessage) {
	for boundChan, chanCtx := range channels {
		go func(boundChan chan json.RawMessage, data json.RawMessage, chanCtx chanContext) {
			select {
			case boundChan <- data:
			case <-chanCtx.ctx.Done():
			}
		}(boundChan, data, chanCtx)
	}
}

func (c *channel) Trigger(event string, data interface{}) error {
	return c.client.SendEvent(event, data, c.name)
}

type privateChannel struct {
	*channel
}

// An AuthError is returned when a non-200 status code is returned in a channel
// subscription authentication request.
type AuthError struct {
	Status int
	Body   string
}

func (e AuthError) Error() string {
	return fmt.Sprintf("Auth error: status code %d, response body: %q", e.Status, e.Body)
}

func (c *privateChannel) Subscribe(opts ...SubscribeOption) error {
	if c.IsSubscribed() {
		return nil
	}

	o := &subscribeOptions{
		successTimeout: defaultSuccessTimeout,
	}

	for _, opt := range opts {
		opt(o)
	}

	body := url.Values{}
	body.Set("socket_id", c.client.socketID)
	body.Set("channel_name", c.name)
	for key, vals := range c.client.AuthParams {
		for _, val := range vals {
			body.Add(key, val)
		}
	}

	req, err := http.NewRequest(http.MethodPost, c.client.AuthURL, strings.NewReader(body.Encode()))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	for key, vals := range c.client.AuthHeaders {
		for _, val := range vals {
			req.Header.Add(key, val)
		}
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		var body []byte
		var bodyStr string
		body, err = ioutil.ReadAll(res.Body)
		if err != nil {
			bodyStr = fmt.Sprintf("Error reading response body: %s", err)
		} else {
			bodyStr = string(body)
		}

		return AuthError{
			Status: res.StatusCode,
			Body:   bodyStr,
		}
	}

	chanData := channelData{}
	if err = json.NewDecoder(res.Body).Decode(&chanData); err != nil {
		return err
	}
	chanData.Channel = c.name

	return c.sendSubscriptionRequest(chanData, o)
}
<commit_msg>use NewTimer instead of After<commit_after>package pusher

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

// Channel represents a subscription to a Pusher channel.
type Channel interface {
	// IsSubscribed indicates if the channel is currently subscribed
	IsSubscribed() bool
	// Subscribe attempts to subscribe to the channel if the subscription is not
	// already active. Authentication will be attempted for private and presence
	// channels.
	Subscribe(...SubscribeOption) error
	// Unsubscribe attempts to unsubscribe from the channel. Note that a nil error
	// does not mean that the unsubscription was successful, just that the request
	// was sent.
	Unsubscribe() error
	// Bind returns a channel to which all the data from all matching events received
	// on the channel will be sent.
	Bind(event string) chan json.RawMessage
	// Unbind removes bindings for an event. If chans are passed, only those bindings
	// will be removed. Otherwise, all bindings for an event will be removed.
	Unbind(event string, chans ...chan json.RawMessage)
	// Trigger sends an event to the channel.
	Trigger(event string, data interface{}) error
}

// internalChannel represents the Channel interface used internally
type internalChannel interface {
	Channel

	handleEvent(event string, data json.RawMessage)
}

type chanContext struct {
	ctx    context.Context
	cancel context.CancelFunc
}

func newChanContext() chanContext {
	ctx, cancel := context.WithCancel(context.Background())
	return chanContext{ctx, cancel}
}

type boundDataChans map[chan json.RawMessage]chanContext

type channel struct {
	name        string
	boundEvents map[string]boundDataChans
	// TODO: implement global bindings
	// globalBindings boundDataChans
	client           *Client
	subscribed       bool
	subscribeSuccess chan struct{}
	// channelData is populated for authorized channels (presence and private
	// channels). It's set by sendSubscriptionRequest. The channelData is invalid
	// until subscribed is set to true.
	channelData channelData

	mutex sync.RWMutex
}

type channelData struct {
	Channel     string          `json:"channel"`
	Auth        string          `json:"auth,omitempty"`
	ChannelData json.RawMessage `json:"channel_data,omitempty"`
}

func (c *channel) IsSubscribed() bool {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	return c.subscribed
}

type subscribeOptions struct {
	successTimeout time.Duration
}

// SubscribeOption is a configuration option for subscribing to a channel
type SubscribeOption func(*subscribeOptions)

const defaultSuccessTimeout = 10 * time.Second

// WithSuccessTimeout returns a SubscribeOption that sets the time that a subscription
// request will wait for a success response from Pusher before timing out. The
// default is 10 seconds.
func WithSuccessTimeout(d time.Duration) SubscribeOption {
	return func(o *subscribeOptions) {
		o.successTimeout = d
	}
}

// ErrTimedOut is the error returned when there is a timeout waiting for a subscription
// confirmation from Pusher
var ErrTimedOut = errors.New("timed out")

func (c *channel) sendSubscriptionRequest(data channelData, o *subscribeOptions) error {
	c.mutex.Lock()
	c.subscribeSuccess = make(chan struct{})
	c.channelData = data
	c.mutex.Unlock()

	doneChan := make(chan error)

	go func() {
		var err error

		timer := time.NewTimer(o.successTimeout)
		defer timer.Stop()

		select {
		case <-c.subscribeSuccess:
			err = nil
		case <-timer.C:
			err = ErrTimedOut
		}

		// try to send on the channel, but don't block if nothing is listening, such
		// as when there is an error calling SendEvent
		select {
		case doneChan <- err:
		default:
		}
	}()

	err := c.client.SendEvent(pusherSubscribe, data, "")
	if err != nil {
		return fmt.Errorf("error sending subscription request: %s", err)
	}

	return <-doneChan
}

func (c *channel) Subscribe(opts ...SubscribeOption) error {
	if c.IsSubscribed() {
		return nil
	}

	o := &subscribeOptions{
		successTimeout: defaultSuccessTimeout,
	}

	for _, opt := range opts {
		opt(o)
	}

	return c.sendSubscriptionRequest(channelData{Channel: c.name}, o)
}

func (c *channel) Unsubscribe() error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.subscribed = false
	return c.client.SendEvent(pusherUnsubscribe, channelData{
		Channel: c.name,
	}, "")
}

func (c *channel) Bind(event string) chan json.RawMessage {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	boundChan := make(chan json.RawMessage)

	if c.boundEvents[event] == nil {
		c.boundEvents[event] = boundDataChans{}
	}

	c.boundEvents[event][boundChan] = newChanContext()

	return boundChan
}

func (c *channel) Unbind(event string, chans ...chan json.RawMessage) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if len(chans) == 0 {
		for _, chanCtx := range c.boundEvents[event] {
			chanCtx.cancel()
		}
		delete(c.boundEvents, event)
		return
	}

	eventBoundChans := c.boundEvents[event]
	for _, boundChan := range chans {
		chanCtx, exists := eventBoundChans[boundChan]
		if !exists {
			continue
		}

		chanCtx.cancel()
		delete(eventBoundChans, boundChan)
	}
}

func (c *channel) handleEvent(event string, data json.RawMessage) {
	if event == pusherInternalSubSucceeded {
		// try to send on the channel, but don't block if nothing is listening
		select {
		case c.subscribeSuccess <- struct{}{}:
		default:
		}

		c.mutex.Lock()
		c.subscribed = true
		c.mutex.Unlock()

		event = pusherSubSucceeded
	}

	c.mutex.RLock()
	sendDataMessage(c.boundEvents[event], data)
	c.mutex.RUnlock()
}

func sendDataMessage(channels boundDataChans, data json.RawMessage) {
	for boundChan, chanCtx := range channels {
		go func(boundChan chan json.RawMessage, data json.RawMessage, chanCtx chanContext) {
			select {
			case boundChan <- data:
			case <-chanCtx.ctx.Done():
			}
		}(boundChan, data, chanCtx)
	}
}

func (c *channel) Trigger(event string, data interface{}) error {
	return c.client.SendEvent(event, data, c.name)
}

type privateChannel struct {
	*channel
}

// An AuthError is returned when a non-200 status code is returned in a channel
// subscription authentication request.
type AuthError struct {
	Status int
	Body   string
}

func (e AuthError) Error() string {
	return fmt.Sprintf("Auth error: status code %d, response body: %q", e.Status, e.Body)
}

func (c *privateChannel) Subscribe(opts ...SubscribeOption) error {
	if c.IsSubscribed() {
		return nil
	}

	o := &subscribeOptions{
		successTimeout: defaultSuccessTimeout,
	}

	for _, opt := range opts {
		opt(o)
	}

	body := url.Values{}
	body.Set("socket_id", c.client.socketID)
	body.Set("channel_name", c.name)
	for key, vals := range c.client.AuthParams {
		for _, val := range vals {
			body.Add(key, val)
		}
	}

	req, err := http.NewRequest(http.MethodPost, c.client.AuthURL, strings.NewReader(body.Encode()))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	for key, vals := range c.client.AuthHeaders {
		for _, val := range vals {
			req.Header.Add(key, val)
		}
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		var body []byte
		var bodyStr string
		body, err = ioutil.ReadAll(res.Body)
		if err != nil {
			bodyStr = fmt.Sprintf("Error reading response body: %s", err)
		} else {
			bodyStr = string(body)
		}

		return AuthError{
			Status: res.StatusCode,
			Body:   bodyStr,
		}
	}

	chanData := channelData{}
	if err = json.NewDecoder(res.Body).Decode(&chanData); err != nil {
		return err
	}
	chanData.Channel = c.name

	return c.sendSubscriptionRequest(chanData, o)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"testing"
)

func TestRemoveContainerWithRemovedVolume(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "losemyvolumes", "-v", "/tmp/testing:/test", "busybox", "true")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	if err := os.Remove("/tmp/testing"); err != nil {
		t.Fatal(err)
	}

	cmd = exec.Command(dockerBinary, "rm", "-v", "losemyvolumes")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - removed volume")
}

func TestRemoveContainerWithVolume(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "foo", "-v", "/srv", "busybox", "true")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	cmd = exec.Command(dockerBinary, "rm", "-v", "foo")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - volume")
}

func TestRemoveContainerRunning(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "-d", "--name", "foo", "busybox", "sleep", "300")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	// Test cannot remove running container
	cmd = exec.Command(dockerBinary, "rm", "foo")
	if _, err := runCommand(cmd); err == nil {
		t.Fatalf("Expected error, can't rm a running container")
	}

	// Remove with -f
	cmd = exec.Command(dockerBinary, "rm", "-f", "foo")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - running container")
}
<commit_msg>make TestRemoveContainerRunning handle signals<commit_after>package main

import (
	"os"
	"os/exec"
	"testing"
)

func TestRemoveContainerWithRemovedVolume(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "losemyvolumes", "-v", "/tmp/testing:/test", "busybox", "true")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	if err := os.Remove("/tmp/testing"); err != nil {
		t.Fatal(err)
	}

	cmd = exec.Command(dockerBinary, "rm", "-v", "losemyvolumes")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - removed volume")
}

func TestRemoveContainerWithVolume(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "--name", "foo", "-v", "/srv", "busybox", "true")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	cmd = exec.Command(dockerBinary, "rm", "-v", "foo")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - volume")
}

func TestRemoveContainerRunning(t *testing.T) {
	cmd := exec.Command(dockerBinary, "run", "-dt", "--name", "foo", "busybox", "top")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	// Test cannot remove running container
	cmd = exec.Command(dockerBinary, "rm", "foo")
	if _, err := runCommand(cmd); err == nil {
		t.Fatalf("Expected error, can't rm a running container")
	}

	// Remove with -f
	cmd = exec.Command(dockerBinary, "rm", "-f", "foo")
	if _, err := runCommand(cmd); err != nil {
		t.Fatal(err)
	}

	deleteAllContainers()

	logDone("rm - running container")
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/urfave/cli"
)

var createCommand = cli.Command{
	Name:  "create",
	Usage: "create a container",
	ArgsUsage: `<container-id>

Where "<container-id>" is your name for the instance of the container that you
are starting. The name you provide for the container instance must be unique on
your host.`,
	Description: `The create command creates an instance of a container for a bundle. The bundle
is a directory with a specification file named "` + specConfig + `" and a root
filesystem.

The specification file includes an args parameter. The args parameter is used
to specify command(s) that get run when the container is started. To change the
command(s) that get executed on start, edit the args parameter of the spec. See
"runc spec --help" for more explanation.`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "bundle, b",
			Value: "",
			Usage: `path to the root of the bundle directory, defaults to the current directory`,
		},
		cli.StringFlag{
			Name:  "console",
			Value: "",
			Usage: "specify the pty slave path for use with the container",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Value: "",
			Usage: "specify the file to write the process id to",
		},
		cli.BoolFlag{
			Name:  "no-pivot",
			Usage: "do not use pivot root to jail process inside rootfs.  This should be used whenever the rootfs is on top of a ramdisk",
		},
		cli.BoolFlag{
			Name:  "no-new-keyring",
			Usage: "do not create a new session keyring for the container.  This will cause the container to inherit the calling processes session key",
		},
	},
	Action: func(context *cli.Context) error {
		spec, err := setupSpec(context)
		if err != nil {
			return err
		}
		status, err := startContainer(context, spec, true)
		if err != nil {
			return err
		}
		// exit with the container's exit status so any external supervisor is
		// notified of the exit with the correct exit status.
		os.Exit(status)
		return nil
	},
}
<commit_msg>check the arguments for `runc create`<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/urfave/cli"
)

var createCommand = cli.Command{
	Name:  "create",
	Usage: "create a container",
	ArgsUsage: `<container-id>

Where "<container-id>" is your name for the instance of the container that you
are starting. The name you provide for the container instance must be unique on
your host.`,
	Description: `The create command creates an instance of a container for a bundle. The bundle
is a directory with a specification file named "` + specConfig + `" and a root
filesystem.

The specification file includes an args parameter. The args parameter is used
to specify command(s) that get run when the container is started. To change the
command(s) that get executed on start, edit the args parameter of the spec. See
"runc spec --help" for more explanation.`,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "bundle, b",
			Value: "",
			Usage: `path to the root of the bundle directory, defaults to the current directory`,
		},
		cli.StringFlag{
			Name:  "console",
			Value: "",
			Usage: "specify the pty slave path for use with the container",
		},
		cli.StringFlag{
			Name:  "pid-file",
			Value: "",
			Usage: "specify the file to write the process id to",
		},
		cli.BoolFlag{
			Name:  "no-pivot",
			Usage: "do not use pivot root to jail process inside rootfs.  This should be used whenever the rootfs is on top of a ramdisk",
		},
		cli.BoolFlag{
			Name:  "no-new-keyring",
			Usage: "do not create a new session keyring for the container.  This will cause the container to inherit the calling processes session key",
		},
	},
	Action: func(context *cli.Context) error {
		if context.NArg() != 1 {
			fmt.Printf("Incorrect Usage.\n\n")
			cli.ShowCommandHelp(context, "create")
			return fmt.Errorf("runc: \"create\" requires exactly one argument")
		}
		spec, err := setupSpec(context)
		if err != nil {
			return err
		}
		status, err := startContainer(context, spec, true)
		if err != nil {
			return err
		}
		// exit with the container's exit status so any external supervisor is
		// notified of the exit with the correct exit status.
		os.Exit(status)
		return nil
	},
}
<|endoftext|>


<commit_before>package all

import (
	_ "github.com/influxdb/telegraf/plugins/mysql"
	_ "github.com/influxdb/telegraf/plugins/postgresql"
	_ "github.com/influxdb/telegraf/plugins/redis"
	_ "github.com/influxdb/telegraf/plugins/system"
)
<commit_msg>Add memcached to the all plugins package<commit_after>package all

import (
	_ "github.com/influxdb/telegraf/plugins/memcached"
	_ "github.com/influxdb/telegraf/plugins/mysql"
	_ "github.com/influxdb/telegraf/plugins/postgresql"
	_ "github.com/influxdb/telegraf/plugins/redis"
	_ "github.com/influxdb/telegraf/plugins/system"
)
<|endoftext|>


<commit_before>// NatNet packet parsing attempt (not finished)
package natnet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

type rawFrame struct {
	frameType   uint64
	frameNumber uint64
	markerSets  []markerSet
	unidMarkers []Vector3
	rigidBodies []RigidBody
	size        int
}

type markerSet struct {
	Name    string
	Markers []Vector3
}

type Vector3 struct {
	X, Y, Z float32
}

func (v Vector3) String() string {
	return fmt.Sprintf("(%.5f, %.5f, %.5f)", v.X, v.Y, v.Z)
}

type Quaternion struct {
	X, Y, Z, W float32
}

func (v Quaternion) String() string {
	return fmt.Sprintf("(%.5f, %.5f, %.5f, %.5f)", v.X, v.Y, v.Z, v.W)
}

type Frame interface {
	RigidBodies() map[string]RigidBody
}

func (f rawFrame) RigidBodies() map[string]RigidBody {
	result := make(map[string]RigidBody, len(f.rigidBodies))
	for i := 0; i < len(f.rigidBodies); i++ {
		f.rigidBodies[i].Name = f.markerSets[i].Name
		result[f.markerSets[i].Name] = f.rigidBodies[i]
	}
	return result
}

type RigidBody struct {
	ID       int
	Name     string
	Position Vector3
	Rotation Quaternion
}

func Parse(buf []byte) (Frame, error) {
	frame, err := parsePacket(buf)
	return frame, err
}

func parsePacket(buf []byte) (rawFrame, error) {
	var packet rawFrame
	var offset int

	packet.frameType, _ = binary.Uvarint(buf[offset : offset+2])
	offset += 2
	if packet.frameType != 7 { // 7 - mocap data
		return packet, errors.New("Not mocap data packet")
	}

	//	numBytes, _ := binary.Uvarint(buf[offset : offset+2]) // unknown nature
	offset += 2
	packet.frameNumber, _ = binary.Uvarint(buf[offset : offset+4])
	offset += 4
	markerSetCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4

	// markersets
	var markerCount uint64
	for ms := 0; ms < int(markerSetCount); ms++ {
		// Reading c-string
		bb := new(bytes.Buffer)
		var i int
		for i = 0; buf[offset+i] != 0; i++ {
			bb.WriteByte(buf[offset+i])
		}
		offset += i + 1
		mSet := markerSet{Name: bb.String()}
		// fmt.Println("> ", bb.String())

		markerCount, _ = binary.Uvarint(buf[offset : offset+4])
		offset += 4
		// fmt.Println(markerCount, "markers")
		for i = 0; i < int(markerCount); i++ {
			x := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			y := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			z := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			v := Vector3{x, y, z}
			mSet.Markers = append(mSet.Markers, v)
			// fmt.Println(v)
		}
		packet.markerSets = append(packet.markerSets, mSet)
	}

	// unidentified markers
	unidMarkerCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4
	// fmt.Println("Unid #", unidMarkerCount)
	for i := 0; i < int(unidMarkerCount); i++ {
		x := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		y := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		z := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		v := Vector3{x, y, z}
		packet.unidMarkers = append(packet.unidMarkers, v)
		// fmt.Println(v)
	}

	// rigid bodies
	rigidBodyCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4
	// fmt.Println("==== Rigid bodies #", rigidBodyCount)
	for i := 0; i < int(rigidBodyCount); i++ {
		id, _ := binary.Uvarint(buf[offset : offset+4])
		offset += 4
		x := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		y := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		z := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qx := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qy := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qz := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qw := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		body := RigidBody{ID: int(id), Position: Vector3{x, y, z}, Rotation: Quaternion{qx, qy, qz, qw}}
		packet.rigidBodies = append(packet.rigidBodies, body)
		// fmt.Println(body)
	}

	packet.size = -1
	return packet, nil
}

func FloatFromBytes(bytes []byte) float32 {
	bits := binary.LittleEndian.Uint32(bytes)
	float := math.Float32frombits(bits)
	return float
}
<commit_msg>Handling panic, dumping broken packet to log<commit_after>// NatNet packet parsing attempt (not finished)
package natnet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"math"
)

type rawFrame struct {
	frameType   uint64
	frameNumber uint64
	markerSets  []markerSet
	unidMarkers []Vector3
	rigidBodies []RigidBody
	size        int
}

type markerSet struct {
	Name    string
	Markers []Vector3
}

type Vector3 struct {
	X, Y, Z float32
}

func (v Vector3) String() string {
	return fmt.Sprintf("(%.5f, %.5f, %.5f)", v.X, v.Y, v.Z)
}

type Quaternion struct {
	X, Y, Z, W float32
}

func (v Quaternion) String() string {
	return fmt.Sprintf("(%.5f, %.5f, %.5f, %.5f)", v.X, v.Y, v.Z, v.W)
}

type Frame interface {
	RigidBodies() map[string]RigidBody
}

func (f rawFrame) RigidBodies() map[string]RigidBody {
	result := make(map[string]RigidBody, len(f.rigidBodies))
	for i := 0; i < len(f.rigidBodies); i++ {
		f.rigidBodies[i].Name = f.markerSets[i].Name
		result[f.markerSets[i].Name] = f.rigidBodies[i]
	}
	return result
}

type RigidBody struct {
	ID       int
	Name     string
	Position Vector3
	Rotation Quaternion
}

func Parse(buf []byte) (f Frame, err error) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("Panicked during parsing:", r)
			log.Println(buf)
			err = r.(error)
		}
	}()
	frame, err := parsePacket(buf)
	return frame, err
}

func parsePacket(buf []byte) (rawFrame, error) {
	var packet rawFrame
	var offset int

	packet.frameType, _ = binary.Uvarint(buf[offset : offset+2])
	offset += 2
	if packet.frameType != 7 { // 7 - mocap data
		return packet, errors.New("Not mocap data packet")
	}

	//	numBytes, _ := binary.Uvarint(buf[offset : offset+2]) // unknown nature
	offset += 2
	packet.frameNumber, _ = binary.Uvarint(buf[offset : offset+4])
	offset += 4
	markerSetCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4

	// markersets
	var markerCount uint64
	for ms := 0; ms < int(markerSetCount); ms++ {
		// Reading c-string
		bb := new(bytes.Buffer)
		var i int
		for i = 0; buf[offset+i] != 0; i++ {
			bb.WriteByte(buf[offset+i])
		}
		offset += i + 1
		mSet := markerSet{Name: bb.String()}
		// fmt.Println("> ", bb.String())

		markerCount, _ = binary.Uvarint(buf[offset : offset+4])
		offset += 4
		// fmt.Println(markerCount, "markers")
		for i = 0; i < int(markerCount); i++ {
			x := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			y := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			z := FloatFromBytes(buf[offset : offset+4])
			offset += 4
			v := Vector3{x, y, z}
			mSet.Markers = append(mSet.Markers, v)
			// fmt.Println(v)
		}
		packet.markerSets = append(packet.markerSets, mSet)
	}

	// unidentified markers
	unidMarkerCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4
	// fmt.Println("Unid #", unidMarkerCount)
	for i := 0; i < int(unidMarkerCount); i++ {
		x := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		y := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		z := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		v := Vector3{x, y, z}
		packet.unidMarkers = append(packet.unidMarkers, v)
		// fmt.Println(v)
	}

	// rigid bodies
	rigidBodyCount, _ := binary.Uvarint(buf[offset : offset+4])
	offset += 4
	// fmt.Println("==== Rigid bodies #", rigidBodyCount)
	for i := 0; i < int(rigidBodyCount); i++ {
		id, _ := binary.Uvarint(buf[offset : offset+4])
		offset += 4
		x := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		y := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		z := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qx := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qy := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qz := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		qw := FloatFromBytes(buf[offset : offset+4])
		offset += 4
		body := RigidBody{ID: int(id), Position: Vector3{x, y, z}, Rotation: Quaternion{qx, qy, qz, qw}}
		packet.rigidBodies = append(packet.rigidBodies, body)
		// fmt.Println(body)
	}

	packet.size = -1
	return packet, nil
}

func FloatFromBytes(bytes []byte) float32 {
	bits := binary.LittleEndian.Uint32(bytes)
	float := math.Float32frombits(bits)
	return float
}
<|endoftext|>


<commit_before>package plugins

import (
	"regexp"
	"strings"

	"github.com/ArjenSchwarz/igor/config"
	"github.com/ArjenSchwarz/igor/slack"
)

// IgorPlugin is the interface that needs to be followed by all plugins
type IgorPlugin interface {
	Work() (slack.Response, error)
	Describe(string) map[string]string
	Name() string
	Description(string) string
	Message() string
	Config() IgorConfig
}

// IgorConfig is the interface for all plugin Configuration
type IgorConfig interface {
	Languages() map[string]config.LanguagePluginDetails
	ChosenLanguage() string
}

// GetPlugins retrieves all the plugins that are activated. It checks the
// config for a whitelist and blacklist as well.
func GetPlugins(request slack.Request, config config.Config) map[string]IgorPlugin {
	plugins := make(map[string]IgorPlugin)
	plugins["help"] = Help(request)
	//TODO should handle these errors somehow. Returning an error when the
	//plugin isn't called doesn't make a lot of sense though
	plugins["weather"], _ = Weather(request)
	plugins["tumblr"], _ = RandomTumblr(request)
	plugins["status"], _ = Status(request)
	plugins["xkcd"], _ = Xkcd(request)

	// Whitelist plugins
	if config.Whitelist != nil {
		whitelist := make(map[string]IgorPlugin)
		whitelist["help"] = Help(request) //Help is always required
		for _, allowedPlugin := range config.Whitelist {
			whitelist[allowedPlugin] = plugins[allowedPlugin]
		}
		plugins = whitelist
	}

	// Blacklist plugins
	if config.Blacklist != nil {
		for _, pluginname := range config.Blacklist {
			if pluginname != "help" { // Help is always required
				delete(plugins, pluginname)
			}
		}
	}
	return plugins
}

// NoMatchError is an error type to indicate a plugin didn't find a match
type NoMatchError struct {
	Message string
}

// Error returns a string interpretation of the NoMatchError
func (e *NoMatchError) Error() string {
	return "No match found:" + e.Message
}

// CreateNoMatchError creates a new NoMatchError instance
func CreateNoMatchError(message string) *NoMatchError {
	return &NoMatchError{Message: message}
}

func getCommandName(plugin IgorPlugin) (string, string) {
	// It's possible for a command to have substitutions
	// Therefore, this needs to be taken into account
	reMain := regexp.MustCompile("(.*) \\[")
	reCommand := regexp.MustCompile("^([^ ]*) ?")
	subCommandArray := reCommand.FindStringSubmatch(plugin.Message())
	subCommand := ""
	if subCommandArray != nil {
		subCommand = strings.ToLower(subCommandArray[1])
	}
	for language, details := range plugin.Config().Languages() {
		for name, value := range details.Commands {
			matchArray := reMain.FindStringSubmatch(value.Command)
			match := ""
			if matchArray != nil {
				match = strings.ToLower(matchArray[1])
			}
			if match != "" && match == subCommand {
				return name, language
			} else if strings.ToLower(plugin.Message()) == strings.ToLower(value.Command) {
				return name, language
			}
		}
	}
	return "", ""
}

func getCommandDetails(plugin IgorPlugin, commandName string) config.LanguagePluginCommandDetails {
	return getAllCommands(plugin, "")[commandName]
}

func getAllCommands(plugin IgorPlugin, language string) map[string]config.LanguagePluginCommandDetails {
	language = getPluginLanguage(plugin, language)
	return plugin.Config().Languages()[language].Commands
}

func getDescriptionText(plugin IgorPlugin, language string) string {
	language = getPluginLanguage(plugin, language)
	return plugin.Config().Languages()[language].Description
}

func getPluginLanguage(plugin IgorPlugin, language string) string {
	if language == "" {
		language = plugin.Config().ChosenLanguage()
	}
	if _, ok := plugin.Config().Languages()[language]; !ok {
		generalConfig, _ := config.GeneralConfig()
		language = generalConfig.DefaultLanguage
	}
	return language
}

func getPluginLanguages(pluginname string) map[string]config.LanguagePluginDetails {
	generalConfig, _ := config.GeneralConfig()
	details := make(map[string]config.LanguagePluginDetails)
	for language, langConfig := range generalConfig.Languages {
		if val, ok := langConfig.Plugins[pluginname]; ok {
			details[language] = val
		}
	}
	return details
}
<commit_msg>Complete hits are preferred over partial ones<commit_after>package plugins

import (
	"regexp"
	"strings"

	"github.com/ArjenSchwarz/igor/config"
	"github.com/ArjenSchwarz/igor/slack"
)

// IgorPlugin is the interface that needs to be followed by all plugins
type IgorPlugin interface {
	Work() (slack.Response, error)
	Describe(string) map[string]string
	Name() string
	Description(string) string
	Message() string
	Config() IgorConfig
}

// IgorConfig is the interface for all plugin Configuration
type IgorConfig interface {
	Languages() map[string]config.LanguagePluginDetails
	ChosenLanguage() string
}

// GetPlugins retrieves all the plugins that are activated. It checks the
// config for a whitelist and blacklist as well.
func GetPlugins(request slack.Request, config config.Config) map[string]IgorPlugin {
	plugins := make(map[string]IgorPlugin)
	plugins["help"] = Help(request)
	//TODO should handle these errors somehow. Returning an error when the
	//plugin isn't called doesn't make a lot of sense though
	plugins["weather"], _ = Weather(request)
	plugins["tumblr"], _ = RandomTumblr(request)
	plugins["status"], _ = Status(request)
	plugins["xkcd"], _ = Xkcd(request)

	// Whitelist plugins
	if config.Whitelist != nil {
		whitelist := make(map[string]IgorPlugin)
		whitelist["help"] = Help(request) //Help is always required
		for _, allowedPlugin := range config.Whitelist {
			whitelist[allowedPlugin] = plugins[allowedPlugin]
		}
		plugins = whitelist
	}

	// Blacklist plugins
	if config.Blacklist != nil {
		for _, pluginname := range config.Blacklist {
			if pluginname != "help" { // Help is always required
				delete(plugins, pluginname)
			}
		}
	}
	return plugins
}

// NoMatchError is an error type to indicate a plugin didn't find a match
type NoMatchError struct {
	Message string
}

// Error returns a string interpretation of the NoMatchError
func (e *NoMatchError) Error() string {
	return "No match found:" + e.Message
}

// CreateNoMatchError creates a new NoMatchError instance
func CreateNoMatchError(message string) *NoMatchError {
	return &NoMatchError{Message: message}
}

func getCommandName(plugin IgorPlugin) (string, string) {
	// It's possible for a command to have substitutions
	// Therefore, this needs to be taken into account
	reMain := regexp.MustCompile("(.*) \\[")
	reCommand := regexp.MustCompile("^([^ ]*) ?")
	subCommandArray := reCommand.FindStringSubmatch(plugin.Message())
	subCommand := ""
	if subCommandArray != nil {
		subCommand = strings.ToLower(subCommandArray[1])
	}
	for language, details := range plugin.Config().Languages() {
		for name, value := range details.Commands {
			matchArray := reMain.FindStringSubmatch(value.Command)
			match := ""
			if matchArray != nil {
				match = strings.ToLower(matchArray[1])
			}
			if strings.ToLower(plugin.Message()) == strings.ToLower(value.Command) {
				return name, language
			} else if match != "" && match == subCommand {
				return name, language
			}
		}
	}
	return "", ""
}

func getCommandDetails(plugin IgorPlugin, commandName string) config.LanguagePluginCommandDetails {
	return getAllCommands(plugin, "")[commandName]
}

func getAllCommands(plugin IgorPlugin, language string) map[string]config.LanguagePluginCommandDetails {
	language = getPluginLanguage(plugin, language)
	return plugin.Config().Languages()[language].Commands
}

func getDescriptionText(plugin IgorPlugin, language string) string {
	language = getPluginLanguage(plugin, language)
	return plugin.Config().Languages()[language].Description
}

func getPluginLanguage(plugin IgorPlugin, language string) string {
	if language == "" {
		language = plugin.Config().ChosenLanguage()
	}
	if _, ok := plugin.Config().Languages()[language]; !ok {
		generalConfig, _ := config.GeneralConfig()
		language = generalConfig.DefaultLanguage
	}
	return language
}

func getPluginLanguages(pluginname string) map[string]config.LanguagePluginDetails {
	generalConfig, _ := config.GeneralConfig()
	details := make(map[string]config.LanguagePluginDetails)
	for language, langConfig := range generalConfig.Languages {
		if val, ok := langConfig.Plugins[pluginname]; ok {
			details[language] = val
		}
	}
	return details
}
<|endoftext|>


<commit_before>package milo

import (
	"context"
	"net/http"
)

const (
	idKey       = 22
	tokenKey    = 24
	sessAuthKey = "sessauthkey"
	sessID      = "sessid"
	xUserToken  = "X-User-Token"
)

type AuthBase struct {
	*FlashBase
	ac       AuthCheck
	loginURL string
	authKey  string
	xToken   string
}

type AuthCheck interface {
	IsValid(id string) (bool, error)
	IsTokenValid(token string) (bool, error)
}

func NewAuthBase(fb *FlashBase, ac AuthCheck, loginURL string) *AuthBase {
	return &AuthBase{FlashBase: fb, ac: ac, loginURL: loginURL, authKey: sessAuthKey, xToken: xUserToken}
}

func NewAuthBaseCustom(fb *FlashBase, ac AuthCheck, loginURL string, authKey string, xToken string) *AuthBase {
	return &AuthBase{FlashBase: fb, ac: ac, loginURL: loginURL, authKey: authKey, xToken: xToken}
}

func (ab *AuthBase) AuthMiddleware(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		sess, sessErr := ab.store.Get(r, ab.authKey)
		token := r.Header.Get(ab.xToken)
		if token == "" && sessErr != nil {
			ab.SetErrorFlash(w, r, "Error: authorization required")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		id, idOk := sess.Values[sessID]
		if token == "" && !idOk {
			ab.SetErrorFlash(w, r, "Error: authorization required")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		if token != "" {
			for _, oac := range overrideAuthCheck {
				valid, err := oac.IsTokenValid(token)
				if err != nil || !valid {
					w.WriteHeader(http.StatusUnauthorized)
					return
				}
			}

			ctx := r.Context()
			ctx = contextWithToken(ctx, token)
			r = r.WithContext(ctx)
		} else {
			for _, oac := range overrideAuthCheck {
				valid, err := oac.IsValid(id.(string))
				if err != nil || !valid {
					ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
					ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
					return
				}
			}

			ctx := r.Context()
			ctx = contextWithId(ctx, id.(string))
			r = r.WithContext(ctx)
		}

		fn(w, r)
	}
}

func (ab *AuthBase) AuthMiddlewareCookie(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		sess, sessErr := ab.store.Get(r, ab.authKey)
		if sessErr != nil {
			ab.SetErrorFlash(w, r, sessErr.Error())
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		id, idOk := sess.Values[sessID]
		if !idOk {
			ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		for _, oac := range overrideAuthCheck {
			valid, err := oac.IsValid(id.(string))
			if err != nil || !valid {
				ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
				ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
				return
			}
		}

		ctx := r.Context()
		ctx = contextWithId(ctx, id.(string))
		r = r.WithContext(ctx)

		fn(w, r)
	}
}

func (ab *AuthBase) AuthMiddlewareToken(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get(ab.xToken)
		if token == "" {
			ab.RenderError(w, r, http.StatusForbidden, "Authorization required.")
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		for _, oac := range overrideAuthCheck {
			valid, err := oac.IsTokenValid(token)
			if err != nil || !valid {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
		}

		ctx := r.Context()
		ctx = contextWithId(ctx, token)
		r = r.WithContext(ctx)

		fn(w, r)
	}
}

func contextWithToken(ctx context.Context, token string) context.Context {
	return context.WithValue(ctx, tokenKey, token)
}

func TokenFromContext(ctx context.Context) (*string, bool) {
	token, ok := ctx.Value(tokenKey).(*string)
	return token, ok
}

func contextWithId(ctx context.Context, id string) context.Context {
	return context.WithValue(ctx, idKey, id)
}

func IdFromContext(ctx context.Context) (*string, bool) {
	id, ok := ctx.Value(idKey).(*string)
	return id, ok
}

func (ab *AuthBase) DoLogin(w http.ResponseWriter, r *http.Request, id string) error {
	sess, sessErr := ab.store.Get(r, ab.authKey)
	if sessErr != nil {
		return sessErr
	}
	sess.Values[sessID] = id
	sess.Options.MaxAge = 60 * 60 * 2
	sess.Save(r, w)
	return nil
}

func (ab *AuthBase) DoLogout(w http.ResponseWriter, r *http.Request) error {
	sess, sessErr := ab.store.Get(r, ab.authKey)
	if sessErr != nil {
		return sessErr
	}
	sess.Options.MaxAge = -1
	sess.Save(r, w)
	return nil
}
<commit_msg>Updated middleware to handle id & token correctly.<commit_after>package milo

import (
	"context"
	"net/http"
)

const (
	idKey       = 22
	tokenKey    = 24
	sessAuthKey = "sessauthkey"
	sessID      = "sessid"
	xUserToken  = "X-User-Token"
)

type AuthBase struct {
	*FlashBase
	ac       AuthCheck
	loginURL string
	authKey  string
	xToken   string
}

type AuthCheck interface {
	IsValid(id string) (bool, error)
	IsTokenValid(token string) (bool, error)
}

func NewAuthBase(fb *FlashBase, ac AuthCheck, loginURL string) *AuthBase {
	return &AuthBase{FlashBase: fb, ac: ac, loginURL: loginURL, authKey: sessAuthKey, xToken: xUserToken}
}

func NewAuthBaseCustom(fb *FlashBase, ac AuthCheck, loginURL string, authKey string, xToken string) *AuthBase {
	return &AuthBase{FlashBase: fb, ac: ac, loginURL: loginURL, authKey: authKey, xToken: xToken}
}

func (ab *AuthBase) AuthMiddleware(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		sess, sessErr := ab.store.Get(r, ab.authKey)
		token := r.Header.Get(ab.xToken)
		if token == "" && sessErr != nil {
			ab.SetErrorFlash(w, r, "Error: authorization required")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		id, idOk := sess.Values[sessID]
		if token == "" && !idOk {
			ab.SetErrorFlash(w, r, "Error: authorization required")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		if token != "" {
			for _, oac := range overrideAuthCheck {
				valid, err := oac.IsTokenValid(token)
				if err != nil || !valid {
					w.WriteHeader(http.StatusUnauthorized)
					return
				}
			}

			ctx := r.Context()
			ctx = contextWithToken(ctx, token)
			r = r.WithContext(ctx)
		} else {
			for _, oac := range overrideAuthCheck {
				valid, err := oac.IsValid(id.(string))
				if err != nil || !valid {
					ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
					ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
					return
				}
			}

			ctx := r.Context()
			ctx = contextWithId(ctx, id.(string))
			r = r.WithContext(ctx)
		}

		fn(w, r)
	}
}

func (ab *AuthBase) AuthMiddlewareCookie(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		sess, sessErr := ab.store.Get(r, ab.authKey)
		if sessErr != nil {
			ab.SetErrorFlash(w, r, sessErr.Error())
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		id, idOk := sess.Values[sessID]
		if !idOk {
			ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
			ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		for _, oac := range overrideAuthCheck {
			valid, err := oac.IsValid(id.(string))
			if err != nil || !valid {
				ab.SetErrorFlash(w, r, r.RequestURI+" requires authentication.")
				ab.Redirect(w, r, ab.loginURL, http.StatusSeeOther)
				return
			}
		}

		ctx := r.Context()
		ctx = contextWithId(ctx, id.(string))
		r = r.WithContext(ctx)

		fn(w, r)
	}
}

func (ab *AuthBase) AuthMiddlewareToken(fn http.HandlerFunc, overrideAuthCheck ...AuthCheck) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get(ab.xToken)
		if token == "" {
			ab.RenderError(w, r, http.StatusForbidden, "Authorization required.")
			return
		}

		if overrideAuthCheck == nil || len(overrideAuthCheck) == 0 {
			overrideAuthCheck = append(overrideAuthCheck, ab.ac)
		}

		for _, oac := range overrideAuthCheck {
			valid, err := oac.IsTokenValid(token)
			if err != nil || !valid {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
		}

		ctx := r.Context()
		ctx = contextWithId(ctx, token)
		r = r.WithContext(ctx)

		fn(w, r)
	}
}

func contextWithToken(ctx context.Context, token string) context.Context {
	return context.WithValue(ctx, tokenKey, token)
}

func TokenFromContext(ctx context.Context) (string, bool) {
	token, ok := ctx.Value(tokenKey).(string)
	return token, ok
}

func contextWithId(ctx context.Context, id string) context.Context {
	return context.WithValue(ctx, idKey, id)
}

func IdFromContext(ctx context.Context) (string, bool) {
	id, ok := ctx.Value(idKey).(string)
	return id, ok
}

func (ab *AuthBase) DoLogin(w http.ResponseWriter, r *http.Request, id string) error {
	sess, sessErr := ab.store.Get(r, ab.authKey)
	if sessErr != nil {
		return sessErr
	}
	sess.Values[sessID] = id
	sess.Options.MaxAge = 60 * 60 * 2
	sess.Save(r, w)
	return nil
}

func (ab *AuthBase) DoLogout(w http.ResponseWriter, r *http.Request) error {
	sess, sessErr := ab.store.Get(r, ab.authKey)
	if sessErr != nil {
		return sessErr
	}
	sess.Options.MaxAge = -1
	sess.Save(r, w)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/xthexder/go-jack"
)

var (
	portIn, portOut *jack.Port
	ch              chan string // for printing midi events
)

func process(nframes uint32) int {
	events := portIn.GetMidiEvents(nframes)
	buffer := portOut.MidiClearBuffer(nframes)
	for _, event := range events {
		ch <- fmt.Sprintf("%#v", event)
		portOut.MidiEventWrite(event, buffer)
	}

	return 0
}

func main() {
	ch = make(chan string, 30)

	client, status := jack.ClientOpen("Go Midi Passthrough", jack.NoStartServer)
	if status != 0 {
		fmt.Println(jack.StrError(status))
		return
	}
	defer client.Close()

	if code := client.SetProcessCallback(process); code != 0 {
		fmt.Println("Failed to set process callback: ", jack.StrError(code))
		return
	}
	client.OnShutdown(func() {
		close(ch)
	})

	if code := client.Activate(); code != 0 {
		fmt.Println("Failed to activate client: ", jack.StrError(code))
		return
	}

	portIn = client.PortRegister("midi_in", jack.DEFAULT_MIDI_TYPE, jack.PortIsInput, 0)
	portOut = client.PortRegister("midi_out", jack.DEFAULT_MIDI_TYPE, jack.PortIsOutput, 0)

	fmt.Println(client.GetName())

	str, more := "", true
	for more {
		str, more = <-ch
		fmt.Printf("Midi Event: %s\n", str)
	}
}
<commit_msg>Fix segmentation fault for midipassthrough example (#14)<commit_after>package main

import (
	"fmt"

	"github.com/xthexder/go-jack"
)

var (
	portIn, portOut *jack.Port
	ch              chan string // for printing midi events
)

func process(nframes uint32) int {
	events := portIn.GetMidiEvents(nframes)
	buffer := portOut.MidiClearBuffer(nframes)
	for _, event := range events {
		ch <- fmt.Sprintf("%#v", event)
		portOut.MidiEventWrite(event, buffer)
	}

	return 0
}

func main() {
	ch = make(chan string, 30)

	client, status := jack.ClientOpen("Go Midi Passthrough", jack.NoStartServer)
	if status != 0 {
		fmt.Println(jack.StrError(status))
		return
	}
	defer client.Close()

	portIn = client.PortRegister("midi_in", jack.DEFAULT_MIDI_TYPE, jack.PortIsInput, 0)
	portOut = client.PortRegister("midi_out", jack.DEFAULT_MIDI_TYPE, jack.PortIsOutput, 0)

	if code := client.SetProcessCallback(process); code != 0 {
		fmt.Println("Failed to set process callback: ", jack.StrError(code))
		return
	}
	client.OnShutdown(func() {
		close(ch)
	})

	if code := client.Activate(); code != 0 {
		fmt.Println("Failed to activate client: ", jack.StrError(code))
		return
	}

	fmt.Println(client.GetName())

	str, more := "", true
	for more {
		str, more = <-ch
		fmt.Printf("Midi Event: %s\n", str)
	}
}
<|endoftext|>


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

package app

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"github.com/fsouza/go-iam"
	"github.com/globocom/config"
	"io"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
	"strings"
	"text/template"
)

type s3Env struct {
	aws.Auth
	bucket             string
	endpoint           string
	locationConstraint bool
}

func (s *s3Env) empty() bool {
	return s.bucket == "" || s.AccessKey == "" || s.SecretKey == ""
}

const (
	randBytes      = 32
	s3InstanceName = "tsurus3"
)

var (
	rReader = rand.Reader
	policy  = template.Must(template.New("policy").Parse(`{
  "Statement": [
    {
      "Action": [
        "s3:CreateBucket",
        "s3:DeleteBucket",
        "s3:DeleteBucketPolicy",
        "s3:DeleteBucketWebsite",
        "s3:PutBucketLogging",
        "s3:PutBucketPolicy",
        "s3:PutBucketRequestPayment",
        "s3:PutBucketVersioning",
        "s3:PutBucketWebsite"
      ],
      "Effect": "Deny",
      "Resource": [
        "arn:aws:s3:::{{.}}/*",
        "arn:aws:s3:::{{.}}"
      ]
    },
    {
      "Action": [
        "s3:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::{{.}}/*",
        "arn:aws:s3:::{{.}}"
      ]
    }
  ]
}`))
)

func getAWSAuth() aws.Auth {
	access, err := config.GetString("aws:access-key-id")
	if err != nil {
		panic("FATAL: aws:access-key-id must be defined in configuration file.")
	}
	secret, err := config.GetString("aws:secret-access-key")
	if err != nil {
		panic("FATAL: aws:secret-access-key must be defined in configuration file.")
	}
	return aws.Auth{
		AccessKey: access,
		SecretKey: secret,
	}
}

func getS3Endpoint() *s3.S3 {
	regionName, _ := config.GetString("aws:s3:region-name")
	endpoint, err := config.GetString("aws:s3:endpoint")
	if err != nil {
		panic("FATAL: aws:s3:endpoint must be defined in configuration file.")
	}
	bucketEndpoint, _ := config.GetString("aws:s3:bucketEndpoint")
	locationConstraint, err := config.GetBool("aws:s3:location-constraint")
	if err != nil {
		panic("FATAL: aws:s3:location-constraint must be defined in configuration file.")
	}
	lowercaseBucket, err := config.GetBool("aws:s3:lowercase-bucket")
	if err != nil {
		panic("FATAL: aws:s3:lowercase-bucket must be defined in configuration file.")
	}
	region := aws.Region{
		Name:                 regionName,
		S3Endpoint:           endpoint,
		S3BucketEndpoint:     bucketEndpoint,
		S3LocationConstraint: locationConstraint,
		S3LowercaseBucket:    lowercaseBucket,
	}
	return s3.New(getAWSAuth(), region)
}

func getIAMEndpoint() *iam.IAM {
	endpoint, err := config.GetString("aws:iam:endpoint")
	if err != nil {
		panic("FATAL: aws:iam:endpoint must be defined in configuration file.")
	}
	region := aws.Region{IAMEndpoint: endpoint}
	return iam.New(getAWSAuth(), region)
}

func putBucket(appName string, bucketChan chan s3.Bucket, errChan chan error) {
	randPart := make([]byte, randBytes)
	n, err := rReader.Read(randPart)
	if err != nil {
		errChan <- err
		return
	}
	if n != randBytes {
		errChan <- io.ErrShortBuffer
		return
	}
	name := fmt.Sprintf("%s%x", appName, randPart)
	bucket := getS3Endpoint().Bucket(name)
	if err := bucket.PutBucket(s3.BucketOwnerFull); err != nil {
		errChan <- err
		return
	}
	bucketChan <- *bucket
}

func createIAMCredentials(appName string, keyChan chan iam.AccessKey, errChan chan error) {
	iamEndpoint := getIAMEndpoint()
	uResp, err := iamEndpoint.CreateUser(appName, fmt.Sprintf("/%s/", appName))
	if err != nil {
		errChan <- err
		return
	}
	kResp, err := iamEndpoint.CreateAccessKey(uResp.User.Name)
	if err != nil {
		errChan <- err
		return
	}
	keyChan <- kResp.AccessKey
}

func createBucket(app *App) (*s3Env, error) {
	var env s3Env
	appName := strings.ToLower(app.Name)
	errChan := make(chan error)
	bChan := make(chan s3.Bucket)
	kChan := make(chan iam.AccessKey)
	s := getS3Endpoint()
	go putBucket(appName, bChan, errChan)
	go createIAMCredentials(appName, kChan, errChan)
	iamEndpoint := getIAMEndpoint()
	var userName string
	for env.empty() {
		select {
		case k := <-kChan:
			env.AccessKey = k.Id
			env.SecretKey = k.Secret
			userName = k.UserName
		case bucket := <-bChan:
			env.bucket = bucket.Name
			env.locationConstraint = bucket.S3LocationConstraint
			env.endpoint = bucket.S3Endpoint
		case err := <-errChan:
			switch err.(type) {
			case *iam.Error:
				if env.bucket != "" {
					s.Bucket(env.bucket).DelBucket()
				}
			case *s3.Error:
				if userName != "" {
					iamEndpoint.DeleteUser(userName)
				}
			}
			return nil, err
		}
	}
	policyName := fmt.Sprintf("app-%s-bucket", appName)
	var buf bytes.Buffer
	policy.Execute(&buf, env.bucket)
	if _, err := iamEndpoint.PutUserPolicy(userName, policyName, buf.String()); err != nil {
		return nil, err
	}
	return &env, nil
}

func destroyBucket(app *App) error {
	appName := strings.ToLower(app.Name)
	env := app.InstanceEnv(s3InstanceName)
	accessKeyId := env["TSURU_S3_ACCESS_KEY_ID"].Value
	bucketName := env["TSURU_S3_BUCKET"].Value
	policyName := fmt.Sprintf("app-%s-bucket", appName)
	s3Endpoint := getS3Endpoint()
	iamEndpoint := getIAMEndpoint()
	if _, err := iamEndpoint.DeleteUserPolicy(appName, policyName); err != nil {
		return err
	}
	bucket := s3Endpoint.Bucket(bucketName)
	if err := bucket.DelBucket(); err != nil {
		return err
	}
	if _, err := iamEndpoint.DeleteAccessKey(accessKeyId, appName); err != nil {
		return err
	}
	_, err := iamEndpoint.DeleteUser(appName)
	return err
}
<commit_msg>api/app: make bucket and access key channels asynchronous<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"github.com/fsouza/go-iam"
	"github.com/globocom/config"
	"io"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
	"strings"
	"text/template"
)

type s3Env struct {
	aws.Auth
	bucket             string
	endpoint           string
	locationConstraint bool
}

func (s *s3Env) empty() bool {
	return s.bucket == "" || s.AccessKey == "" || s.SecretKey == ""
}

const (
	randBytes      = 32
	s3InstanceName = "tsurus3"
)

var (
	rReader = rand.Reader
	policy  = template.Must(template.New("policy").Parse(`{
  "Statement": [
    {
      "Action": [
        "s3:CreateBucket",
        "s3:DeleteBucket",
        "s3:DeleteBucketPolicy",
        "s3:DeleteBucketWebsite",
        "s3:PutBucketLogging",
        "s3:PutBucketPolicy",
        "s3:PutBucketRequestPayment",
        "s3:PutBucketVersioning",
        "s3:PutBucketWebsite"
      ],
      "Effect": "Deny",
      "Resource": [
        "arn:aws:s3:::{{.}}/*",
        "arn:aws:s3:::{{.}}"
      ]
    },
    {
      "Action": [
        "s3:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::{{.}}/*",
        "arn:aws:s3:::{{.}}"
      ]
    }
  ]
}`))
)

func getAWSAuth() aws.Auth {
	access, err := config.GetString("aws:access-key-id")
	if err != nil {
		panic("FATAL: aws:access-key-id must be defined in configuration file.")
	}
	secret, err := config.GetString("aws:secret-access-key")
	if err != nil {
		panic("FATAL: aws:secret-access-key must be defined in configuration file.")
	}
	return aws.Auth{
		AccessKey: access,
		SecretKey: secret,
	}
}

func getS3Endpoint() *s3.S3 {
	regionName, _ := config.GetString("aws:s3:region-name")
	endpoint, err := config.GetString("aws:s3:endpoint")
	if err != nil {
		panic("FATAL: aws:s3:endpoint must be defined in configuration file.")
	}
	bucketEndpoint, _ := config.GetString("aws:s3:bucketEndpoint")
	locationConstraint, err := config.GetBool("aws:s3:location-constraint")
	if err != nil {
		panic("FATAL: aws:s3:location-constraint must be defined in configuration file.")
	}
	lowercaseBucket, err := config.GetBool("aws:s3:lowercase-bucket")
	if err != nil {
		panic("FATAL: aws:s3:lowercase-bucket must be defined in configuration file.")
	}
	region := aws.Region{
		Name:                 regionName,
		S3Endpoint:           endpoint,
		S3BucketEndpoint:     bucketEndpoint,
		S3LocationConstraint: locationConstraint,
		S3LowercaseBucket:    lowercaseBucket,
	}
	return s3.New(getAWSAuth(), region)
}

func getIAMEndpoint() *iam.IAM {
	endpoint, err := config.GetString("aws:iam:endpoint")
	if err != nil {
		panic("FATAL: aws:iam:endpoint must be defined in configuration file.")
	}
	region := aws.Region{IAMEndpoint: endpoint}
	return iam.New(getAWSAuth(), region)
}

func putBucket(appName string, bucketChan chan s3.Bucket, errChan chan error) {
	randPart := make([]byte, randBytes)
	n, err := rReader.Read(randPart)
	if err != nil {
		errChan <- err
		return
	}
	if n != randBytes {
		errChan <- io.ErrShortBuffer
		return
	}
	name := fmt.Sprintf("%s%x", appName, randPart)
	bucket := getS3Endpoint().Bucket(name)
	if err := bucket.PutBucket(s3.BucketOwnerFull); err != nil {
		errChan <- err
		return
	}
	bucketChan <- *bucket
}

func createIAMCredentials(appName string, keyChan chan iam.AccessKey, errChan chan error) {
	iamEndpoint := getIAMEndpoint()
	uResp, err := iamEndpoint.CreateUser(appName, fmt.Sprintf("/%s/", appName))
	if err != nil {
		errChan <- err
		return
	}
	kResp, err := iamEndpoint.CreateAccessKey(uResp.User.Name)
	if err != nil {
		errChan <- err
		return
	}
	keyChan <- kResp.AccessKey
}

func createBucket(app *App) (*s3Env, error) {
	var env s3Env
	appName := strings.ToLower(app.Name)
	errChan := make(chan error)
	bChan := make(chan s3.Bucket, 1)
	kChan := make(chan iam.AccessKey, 1)
	s := getS3Endpoint()
	go putBucket(appName, bChan, errChan)
	go createIAMCredentials(appName, kChan, errChan)
	iamEndpoint := getIAMEndpoint()
	var userName string
	for env.empty() {
		select {
		case k := <-kChan:
			env.AccessKey = k.Id
			env.SecretKey = k.Secret
			userName = k.UserName
		case bucket := <-bChan:
			env.bucket = bucket.Name
			env.locationConstraint = bucket.S3LocationConstraint
			env.endpoint = bucket.S3Endpoint
		case err := <-errChan:
			switch err.(type) {
			case *iam.Error:
				if env.bucket != "" {
					s.Bucket(env.bucket).DelBucket()
				}
			case *s3.Error:
				if userName != "" {
					iamEndpoint.DeleteUser(userName)
				}
			}
			return nil, err
		}
	}
	policyName := fmt.Sprintf("app-%s-bucket", appName)
	var buf bytes.Buffer
	policy.Execute(&buf, env.bucket)
	if _, err := iamEndpoint.PutUserPolicy(userName, policyName, buf.String()); err != nil {
		return nil, err
	}
	return &env, nil
}

func destroyBucket(app *App) error {
	appName := strings.ToLower(app.Name)
	env := app.InstanceEnv(s3InstanceName)
	accessKeyId := env["TSURU_S3_ACCESS_KEY_ID"].Value
	bucketName := env["TSURU_S3_BUCKET"].Value
	policyName := fmt.Sprintf("app-%s-bucket", appName)
	s3Endpoint := getS3Endpoint()
	iamEndpoint := getIAMEndpoint()
	if _, err := iamEndpoint.DeleteUserPolicy(appName, policyName); err != nil {
		return err
	}
	bucket := s3Endpoint.Bucket(bucketName)
	if err := bucket.DelBucket(); err != nil {
		return err
	}
	if _, err := iamEndpoint.DeleteAccessKey(accessKeyId, appName); err != nil {
		return err
	}
	_, err := iamEndpoint.DeleteUser(appName)
	return err
}
<|endoftext|>


<commit_before>package routing

TODO SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-routing/index.js
<commit_msg>add comment '//' before note so that package routing compiles<commit_after>package routing

// TODO SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-routing/index.js
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// 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.
package main

import (
	"fmt"
	astatic "github.com/bboozzoo/q3stats/assets/static"
	"github.com/bboozzoo/q3stats/controllers"
	"github.com/bboozzoo/q3stats/controllers/match"
	"github.com/bboozzoo/q3stats/controllers/player"
	"github.com/bboozzoo/q3stats/handlers"
	"github.com/bboozzoo/q3stats/handlers/api"
	"github.com/bboozzoo/q3stats/handlers/site"
	ghandlers "github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"os"
	"path"
)

const (
	defaultListenPort = 9090

	uriApi    = "/api"
	uriStatic = "/static/"
	uriSite   = "/site/"
)

var (
	defaultListenAddr = fmt.Sprintf("localhost:%d",
		defaultListenPort)
)

type handlerRouting struct {
	prefix  string
	handler handlers.Handler
}

func setupHandlers(handlers []handlerRouting) {
	r := mux.NewRouter()

	for _, h := range handlers {
		subr := r.PathPrefix(h.prefix).Subrouter()
		h.handler.SetupHandlers(subr)
	}

	// redirect to site by default
	r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, uriSite, http.StatusFound)
	})

	// static files
	staticroot := path.Join(C.Webroot, "static")
	log.Printf("serving static files from %s", staticroot)

	filehandler := http.FileServer(astatic.FS(false))
	r.PathPrefix(uriStatic).
		Handler(http.StripPrefix(uriStatic, filehandler))

	// setup logging for all handlers
	lr := ghandlers.LoggingHandler(os.Stdout, r)

	http.Handle("/", lr)
}

func daemonMain() error {
	db := NewDB()
	if err := db.Open(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	matchctrl := match.NewController(db)
	userctrl := player.NewController(db)
	api := api.NewApi(matchctrl)
	ctrls := controllers.Controllers{
		matchctrl,
		userctrl,
	}
	site := site.NewSite(ctrls, C.Webroot)

	hrouting := []handlerRouting{
		{uriApi, api},
		{uriSite, site},
	}
	setupHandlers(hrouting)

	return http.ListenAndServe(fmt.Sprintf(":%d", C.Port), nil)
}

func runDaemon() error {
	log.Printf("listen port: %d", C.Port)

	return daemonMain()
}
<commit_msg>daemon: drop webroot<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// 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.
package main

import (
	"fmt"
	astatic "github.com/bboozzoo/q3stats/assets/static"
	"github.com/bboozzoo/q3stats/controllers"
	"github.com/bboozzoo/q3stats/controllers/match"
	"github.com/bboozzoo/q3stats/controllers/player"
	"github.com/bboozzoo/q3stats/handlers"
	"github.com/bboozzoo/q3stats/handlers/api"
	"github.com/bboozzoo/q3stats/handlers/site"
	ghandlers "github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"log"
	"net/http"
	"os"
)

const (
	defaultListenPort = 9090

	uriApi    = "/api"
	uriStatic = "/static/"
	uriSite   = "/site/"
)

var (
	defaultListenAddr = fmt.Sprintf("localhost:%d",
		defaultListenPort)
)

type handlerRouting struct {
	prefix  string
	handler handlers.Handler
}

func setupHandlers(handlers []handlerRouting) {
	r := mux.NewRouter()

	for _, h := range handlers {
		subr := r.PathPrefix(h.prefix).Subrouter()
		h.handler.SetupHandlers(subr)
	}

	// redirect to site by default
	r.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		http.Redirect(w, req, uriSite, http.StatusFound)
	})

	filehandler := http.FileServer(astatic.FS(false))
	r.PathPrefix(uriStatic).
		Handler(http.StripPrefix(uriStatic, filehandler))

	// setup logging for all handlers
	lr := ghandlers.LoggingHandler(os.Stdout, r)

	http.Handle("/", lr)
}

func daemonMain() error {
	db := NewDB()
	if err := db.Open(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	matchctrl := match.NewController(db)
	userctrl := player.NewController(db)
	api := api.NewApi(matchctrl)
	ctrls := controllers.Controllers{
		matchctrl,
		userctrl,
	}
	site := site.NewSite(ctrls, C.Webroot)

	hrouting := []handlerRouting{
		{uriApi, api},
		{uriSite, site},
	}
	setupHandlers(hrouting)

	return http.ListenAndServe(fmt.Sprintf(":%d", C.Port), nil)
}

func runDaemon() error {
	log.Printf("listen port: %d", C.Port)

	return daemonMain()
}
<|endoftext|>


<commit_before>package api

import (
	"context"

	"github.com/bytom/account"
	"github.com/bytom/asset"
	"github.com/bytom/blockchain/pseudohsm"
	"github.com/bytom/errors"
)

// POST /wallet error
func (a *API) walletError() Response {
	return NewErrorResponse(errors.New("wallet not found, please check that the wallet is open"))
}

// WalletImage hold the ziped wallet data
type WalletImage struct {
	AccountImage *account.Image      `json:"account_image"`
	AssetImage   *asset.Image        `json:"asset_image"`
	KeyImages    *pseudohsm.KeyImage `json:"key_images"`
}

func (a *API) restoreWalletImage(ctx context.Context, image WalletImage) Response {
	if err := a.wallet.Hsm.Restore(image.KeyImages); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore key images"))
	}
	if err := a.wallet.AssetReg.Restore(image.AssetImage); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore asset image"))
	}
	if err := a.wallet.AccountMgr.Restore(image.AccountImage); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore account image"))
	}
	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}

func (a *API) backupWalletImage() Response {
	keyImages, err := a.wallet.Hsm.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup key images"))
	}
	assetImage, err := a.wallet.AssetReg.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup asset image"))
	}
	accountImage, err := a.wallet.AccountMgr.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup account image"))
	}

	image := &WalletImage{
		KeyImages:    keyImages,
		AssetImage:   assetImage,
		AccountImage: accountImage,
	}
	return NewSuccessResponse(image)
}

func (a *API) rescanWallet() Response {
	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}

// WalletInfo return wallet information
type WalletInfo struct {
	BestBlockHeight uint64 `json:"best_block_height"`
	WalletHeight    uint64 `json:"wallet_height"`
}

func (a *API) getWalletInfo() Response {
	bestBlockHeight := a.chain.BestBlockHeight()
	walletStatus := a.wallet.GetWalletStatusInfo()

	return NewSuccessResponse(&WalletInfo{
		BestBlockHeight: bestBlockHeight,
		WalletHeight:    walletStatus.WorkHeight,
	})
}
<commit_msg>rescan-wallet capture rescan signal (#1102)<commit_after>package api

import (
	"context"
	"time"

	"github.com/bytom/account"
	"github.com/bytom/asset"
	"github.com/bytom/blockchain/pseudohsm"
	"github.com/bytom/errors"
)

// POST /wallet error
func (a *API) walletError() Response {
	return NewErrorResponse(errors.New("wallet not found, please check that the wallet is open"))
}

// WalletImage hold the ziped wallet data
type WalletImage struct {
	AccountImage *account.Image      `json:"account_image"`
	AssetImage   *asset.Image        `json:"asset_image"`
	KeyImages    *pseudohsm.KeyImage `json:"key_images"`
}

func (a *API) restoreWalletImage(ctx context.Context, image WalletImage) Response {
	if err := a.wallet.Hsm.Restore(image.KeyImages); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore key images"))
	}
	if err := a.wallet.AssetReg.Restore(image.AssetImage); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore asset image"))
	}
	if err := a.wallet.AccountMgr.Restore(image.AccountImage); err != nil {
		return NewErrorResponse(errors.Wrap(err, "restore account image"))
	}
	a.wallet.RescanBlocks()
	return NewSuccessResponse(nil)
}

func (a *API) backupWalletImage() Response {
	keyImages, err := a.wallet.Hsm.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup key images"))
	}
	assetImage, err := a.wallet.AssetReg.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup asset image"))
	}
	accountImage, err := a.wallet.AccountMgr.Backup()
	if err != nil {
		return NewErrorResponse(errors.Wrap(err, "backup account image"))
	}

	image := &WalletImage{
		KeyImages:    keyImages,
		AssetImage:   assetImage,
		AccountImage: accountImage,
	}
	return NewSuccessResponse(image)
}

func (a *API) rescanWallet() Response {
	a.wallet.RescanBlocks()
	for {
		time.Sleep(50 * time.Microsecond)
		walletStatus := a.wallet.GetWalletStatusInfo()
		if walletStatus.WorkHeight >= walletStatus.BestHeight {
			break
		}
	}
	return NewSuccessResponse(nil)
}

// WalletInfo return wallet information
type WalletInfo struct {
	BestBlockHeight uint64 `json:"best_block_height"`
	WalletHeight    uint64 `json:"wallet_height"`
}

func (a *API) getWalletInfo() Response {
	bestBlockHeight := a.chain.BestBlockHeight()
	walletStatus := a.wallet.GetWalletStatusInfo()

	return NewSuccessResponse(&WalletInfo{
		BestBlockHeight: bestBlockHeight,
		WalletHeight:    walletStatus.WorkHeight,
	})
}
<|endoftext|>


<commit_before>package awsping

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestAWSRegionError(t *testing.T) {
	AWSErr := errors.New("something bad")
	r := AWSRegion{Error: AWSErr}

	got := r.GetLatencyStr()
	want := AWSErr.Error()

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

type testTarget struct {
	URL string
	IP  *net.TCPAddr
}

func (r *testTarget) GetURL() string {
	return r.URL
}

// GetIP return IP for AWS target
func (r *testTarget) GetIP() (*net.TCPAddr, error) {
	return r.IP, nil
}

func TestAWSRegionCheckLatencyHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(15 * time.Millisecond)
		fmt.Fprintln(w, "X")
	}))
	defer ts.Close()

	tt := testTarget{URL: ts.URL}

	regions := GetRegions()
	service := "ec2"
	checkType := HTTPCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want+2 {
		t.Errorf("failed:\ngot=%f\nwant=%f", got, want)
	}
}

type testRequest struct {
	duration time.Duration
	err      error
}

func (d *testRequest) Do(_, _ string, _ RequestType) (time.Duration, error) {
	if d.err != nil {
		return 0, d.err
	}
	return d.duration, nil
}

func TestAWSRegionCheckLatencyTCP(t *testing.T) {
	// just random local IP
	tt := testTarget{IP: &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 67890,
	}}

	regions := GetRegions()
	service := "ec2"
	checkType := TCPCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})
	regions[0].Request = &testRequest{duration: 15 * time.Millisecond}

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want+1 {
		t.Errorf("failed:\ngot=%f\nwant=%f\nregion=%q", got, want, regions[0])
	}

	if regions[0].Error != nil {
		t.Errorf("failed: error should be empty")
	}

	// check "error"
	errTxt := "something bad"
	regions[0].Request = &testRequest{err: errors.New(errTxt)}

	wg.Add(1)
	regions[0].CheckLatency(&wg)

	if regions[0].Error == nil {
		t.Errorf("failed: error should not be empty")
	}

	if regions[0].Error.Error() != errTxt {
		t.Errorf("failed: error should be empty=%s", errTxt)
	}
}

// ---------------------------------------------

func TestAWSRegionsLen(t *testing.T) {
	regions := GetRegions()

	got := regions.Len()
	want := len(regions)

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

func TestAWSRegionsLess(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	if !regions.Less(0, 1) {
		t.Errorf("failed: not less, regions=%q", regions)
	}
}

func TestAWSRegionsSwap(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	regions.Swap(0, 3)

	if len(regions[0].Latencies) != 0 {
		t.Errorf("failed: not swapped, regions=%q", regions)
	}
}

func TestAWSRegionsSetService(t *testing.T) {
	regions := GetRegions()
	service := "ec2"

	regions.SetService(service)

	if regions[0].Service != service || regions[len(regions)-1].Service != service {
		t.Errorf("failed: not setted, regions=%q, service=%s", regions, service)
	}
}

func TestAWSRegionsSetCheckType(t *testing.T) {
	regions := GetRegions()
	checkType := HTTPCheck

	regions.SetCheckType(checkType)

	if regions[0].Type != checkType || regions[len(regions)-1].Type != checkType {
		t.Errorf("failed: not setted, regions=%q, checkType=%d", regions, checkType)
	}
}

func TestAWSRegionsSetDefaulTarget(t *testing.T) {
	regions := GetRegions()
	service := "ec2"
	checkType := HTTPSCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetDefaultTarget()

	got := regions[0].Target.GetURL()
	want := fmt.Sprintf("https://ec2.%s.amazonaws.com/ping?x=", regions[0].Code)

	if !strings.HasPrefix(got, want) {
		t.Errorf("failed: wrong url\ngot=%s\nneed=%s", got, want)
	}
}
<commit_msg>Add error case into TestAWSRegionCheckLatencyHTTP<commit_after>package awsping

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync"
	"testing"
	"time"
)

func TestAWSRegionError(t *testing.T) {
	AWSErr := errors.New("something bad")
	r := AWSRegion{Error: AWSErr}

	got := r.GetLatencyStr()
	want := AWSErr.Error()

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

type testTarget struct {
	URL string
	IP  *net.TCPAddr
}

func (r *testTarget) GetURL() string {
	return r.URL
}

// GetIP return IP for AWS target
func (r *testTarget) GetIP() (*net.TCPAddr, error) {
	return r.IP, nil
}

func TestAWSRegionCheckLatencyHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(15 * time.Millisecond)
		fmt.Fprintln(w, "X")
	}))
	defer ts.Close()

	tt := testTarget{URL: ts.URL}

	regions := GetRegions()
	service := "ec2"
	checkType := HTTPCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want+2 {
		t.Errorf("failed:\ngot=%f\nwant=%f", got, want)
	}

	// check "error"
	errTxt := "something bad"
	regions[0].Request = &testRequest{err: errors.New(errTxt)}

	wg.Add(1)
	regions[0].CheckLatency(&wg)

	if regions[0].Error == nil {
		t.Errorf("failed: error should not be empty")
	}

	if regions[0].Error.Error() != errTxt {
		t.Errorf("failed: error should be empty=%s", errTxt)
	}
}

type testRequest struct {
	duration time.Duration
	err      error
}

func (d *testRequest) Do(_, _ string, _ RequestType) (time.Duration, error) {
	if d.err != nil {
		return 0, d.err
	}
	return d.duration, nil
}

func TestAWSRegionCheckLatencyTCP(t *testing.T) {
	// just random local IP
	tt := testTarget{IP: &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 67890,
	}}

	regions := GetRegions()
	service := "ec2"
	checkType := TCPCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetTarget(func(r *AWSRegion) {
		r.Target = &tt
	})
	regions[0].Request = &testRequest{duration: 15 * time.Millisecond}

	var wg sync.WaitGroup
	wg.Add(1)
	regions[0].CheckLatency(&wg)

	got := regions[0].GetLatency()
	want := 15.0

	if got < want || got > want+1 {
		t.Errorf("failed:\ngot=%f\nwant=%f\nregion=%q", got, want, regions[0])
	}

	if regions[0].Error != nil {
		t.Errorf("failed: error should be empty")
	}

	// check "error"
	errTxt := "something bad"
	regions[0].Request = &testRequest{err: errors.New(errTxt)}

	wg.Add(1)
	regions[0].CheckLatency(&wg)

	if regions[0].Error == nil {
		t.Errorf("failed: error should not be empty")
	}

	if regions[0].Error.Error() != errTxt {
		t.Errorf("failed: error should be empty=%s", errTxt)
	}
}

// ---------------------------------------------

func TestAWSRegionsLen(t *testing.T) {
	regions := GetRegions()

	got := regions.Len()
	want := len(regions)

	if got != want {
		t.Errorf("failed:\ngot=%q\nwant=%q", got, want)
	}
}

func TestAWSRegionsLess(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	if !regions.Less(0, 1) {
		t.Errorf("failed: not less, regions=%q", regions)
	}
}

func TestAWSRegionsSwap(t *testing.T) {
	regions := GetRegions()

	regions[0].Latencies = []time.Duration{15 * time.Millisecond}
	regions[1].Latencies = []time.Duration{25 * time.Millisecond}

	regions.Swap(0, 3)

	if len(regions[0].Latencies) != 0 {
		t.Errorf("failed: not swapped, regions=%q", regions)
	}
}

func TestAWSRegionsSetService(t *testing.T) {
	regions := GetRegions()
	service := "ec2"

	regions.SetService(service)

	if regions[0].Service != service || regions[len(regions)-1].Service != service {
		t.Errorf("failed: not setted, regions=%q, service=%s", regions, service)
	}
}

func TestAWSRegionsSetCheckType(t *testing.T) {
	regions := GetRegions()
	checkType := HTTPCheck

	regions.SetCheckType(checkType)

	if regions[0].Type != checkType || regions[len(regions)-1].Type != checkType {
		t.Errorf("failed: not setted, regions=%q, checkType=%d", regions, checkType)
	}
}

func TestAWSRegionsSetDefaulTarget(t *testing.T) {
	regions := GetRegions()
	service := "ec2"
	checkType := HTTPSCheck

	regions.SetService(service)
	regions.SetCheckType(checkType)
	regions.SetDefaultTarget()

	got := regions[0].Target.GetURL()
	want := fmt.Sprintf("https://ec2.%s.amazonaws.com/ping?x=", regions[0].Code)

	if !strings.HasPrefix(got, want) {
		t.Errorf("failed: wrong url\ngot=%s\nneed=%s", got, want)
	}
}
<|endoftext|>