<commit_before>// Package cfg handles working with the Glide configuration files.
//
// The cfg package contains the ability to parse (unmarshal) and write (marshal)
// glide.yaml and glide.lock files. These files contains the details about
// projects managed by Glide.
//
// To convert yaml into a cfg.Config instance use the cfg.ConfigFromYaml function.
// The yaml, typically in a glide.yaml file, has the following structure.
//
//     package: github.com/Masterminds/glide
//     homepage: https://masterminds.github.io/glide
//     license: MIT
//     owners:
//     - name: Matt Butcher
//       email: technosophos@gmail.com
//       homepage: http://technosophos.com
//     - name: Matt Farina
//       email: matt@mattfarina.com
//       homepage: https://www.mattfarina.com
//     ignore:
//     - appengine
//     import:
//     - package: gopkg.in/yaml.v2
//     - package: github.com/Masterminds/vcs
//       version: ^1.2.0
//       repo:    git@github.com:Masterminds/vcs
//       vcs:     git
//     - package: github.com/codegangsta/cli
//     - package: github.com/Masterminds/semver
//       version: ^1.0.0
//
// These elements are:
// - package: The top level package is the location in the GOPATH. This is used
//   for things such as making sure an import isn't also importing the top level
//   package.
// - homepage: To find the place where you can find details about the package or
//   applications. For example, http://k8s.io
// - license: The license is either an SPDX license string or the filepath to the
//   license. This allows automation and consumers to easily identify the license.
// - owners: The owners is a list of one or more owners for the project. This
//   can be a person or organization and is useful for things like notifying the
//   owners of a security issue without filing a public bug.
// - ignore: A list of packages for Glide to ignore importing. These are package
//   names to ignore rather than directories.
// - import: A list of packages to import. Each package can include:
//     - package: The name of the package to import and the only non-optional item.
//     - version: A semantic version, semantic version range, branch, tag, or
//       commit id to use.
//     - repo: If the package name isn't the repo location or this is a private
//       repository it can go here. The package will be checked out from the
//       repo and put where the package name specifies. This allows using forks.
//     - vcs: A VCS to use such as git, hg, bzr, or svn. This is only needed
//       when the type cannot be detected from the name. For example, a repo
//       ending in .git or on GitHub can be detected to be Git. For a repo on
//       Bitbucket we can contact the API to discover the type.
// - devImport: A list of development packages. Each package has the same details
//   as those lised under import.
package cfg
<commit_msg>Fixing cfg docs for better presentation on godoc.org<commit_after>// Package cfg handles working with the Glide configuration files.
//
// The cfg package contains the ability to parse (unmarshal) and write (marshal)
// glide.yaml and glide.lock files. These files contains the details about
// projects managed by Glide.
//
// To convert yaml into a cfg.Config instance use the cfg.ConfigFromYaml function.
// The yaml, typically in a glide.yaml file, has the following structure.
//
//     package: github.com/Masterminds/glide
//     homepage: https://masterminds.github.io/glide
//     license: MIT
//     owners:
//     - name: Matt Butcher
//       email: technosophos@gmail.com
//       homepage: http://technosophos.com
//     - name: Matt Farina
//       email: matt@mattfarina.com
//       homepage: https://www.mattfarina.com
//     ignore:
//     - appengine
//     import:
//     - package: gopkg.in/yaml.v2
//     - package: github.com/Masterminds/vcs
//       version: ^1.2.0
//       repo:    git@github.com:Masterminds/vcs
//       vcs:     git
//     - package: github.com/codegangsta/cli
//     - package: github.com/Masterminds/semver
//       version: ^1.0.0
//
// These elements are:
//
//    - package: The top level package is the location in the GOPATH. This is used
//      for things such as making sure an import isn't also importing the top level
//      package.
//    - homepage: To find the place where you can find details about the package or
//      applications. For example, http://k8s.io
//    - license: The license is either an SPDX license string or the filepath to the
//      license. This allows automation and consumers to easily identify the license.
//    - owners: The owners is a list of one or more owners for the project. This
//      can be a person or organization and is useful for things like notifying the
//      owners of a security issue without filing a public bug.
//    - ignore: A list of packages for Glide to ignore importing. These are package
//      names to ignore rather than directories.
//    - import: A list of packages to import. Each package can include:
//        - package: The name of the package to import and the only non-optional item.
//        - version: A semantic version, semantic version range, branch, tag, or
//          commit id to use.
//        - repo: If the package name isn't the repo location or this is a private
//          repository it can go here. The package will be checked out from the
//          repo and put where the package name specifies. This allows using forks.
//        - vcs: A VCS to use such as git, hg, bzr, or svn. This is only needed
//          when the type cannot be detected from the name. For example, a repo
//          ending in .git or on GitHub can be detected to be Git. For a repo on
//          Bitbucket we can contact the API to discover the type.
//    - devImport: A list of development packages. Each package has the same details
//      as those lised under import.
package cfg
<|endoftext|>


<commit_before>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

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

import (
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"golang.org/x/net/context"
)

var (
	errAlreadyListening = errors.New("channel already listening")
)

const (
	ephemeralHostPort = "0.0.0.0:0"
)

// ChannelOptions are used to control parameters on a create a TChannel
type ChannelOptions struct {
	// Default Connection options
	DefaultConnectionOptions ConnectionOptions

	// The name of the process, for logging and reporting to peers
	ProcessName string

	// The logger to use for this channel
	Logger Logger
}

// A Channel is a bi-directional connection to the peering and routing network.
// Applications can use a Channel to make service calls to remote peers via
// BeginCall, or to listen for incoming calls from peers.  Applications that
// want to receive requests should call one of Serve or ListenAndServe
// TODO(prashant): Shutdown all subchannels + peers when channel is closed.
type Channel struct {
	log               Logger
	connectionOptions ConnectionOptions
	handlers          *handlerMap
	peers             *PeerList

	// mutable contains all the members of Channel which are mutable.
	mutable struct {
		mut         sync.RWMutex // protects members of the mutable struct.
		closed      bool
		peerInfo    LocalPeerInfo // May be ephemeral if this is a client only channel
		l           net.Listener  // May be nil if this is a client only channel
		subChannels map[string]*SubChannel
	}
}

// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.
func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if opts == nil {
		opts = &ChannelOptions{}
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	ch := &Channel{
		connectionOptions: opts.DefaultConnectionOptions,
		log:               logger,
		handlers:          &handlerMap{},
	}
	ch.mutable.peerInfo = LocalPeerInfo{
		PeerInfo: PeerInfo{
			ProcessName: processName,
			HostPort:    ephemeralHostPort,
		},
		ServiceName: serviceName,
	}
	ch.mutable.subChannels = make(map[string]*SubChannel)
	ch.peers = newPeerList(ch)
	ch.connectionOptions.ChecksumType = ChecksumTypeCrc32
	return ch, nil
}

// Serve serves incoming requests using the provided listener.
// The local peer info is set synchronously, but the actual socket listening is done in
// a separate goroutine.
func (ch *Channel) Serve(l net.Listener) error {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	if mutable.l != nil {
		return errAlreadyListening
	}

	mutable.l = l
	mutable.peerInfo.HostPort = l.Addr().String()

	peerInfo := mutable.peerInfo
	ch.log.Debugf("%v (%v) listening on %v", peerInfo.ProcessName, peerInfo.ServiceName, peerInfo.HostPort)
	go ch.serve()
	return nil
}

// ListenAndServe listens on the given address and serves incoming requests.
// The port may be 0, in which case the channel will use an OS assigned port
// This method does not block as the handling of connections is done in a goroutine.
func (ch *Channel) ListenAndServe(hostPort string) error {
	mutable := &ch.mutable
	mutable.mut.RLock()

	if mutable.l != nil {
		mutable.mut.RUnlock()
		return errAlreadyListening
	}

	l, err := net.Listen("tcp", hostPort)
	if err != nil {
		mutable.mut.RUnlock()
		return err
	}

	mutable.mut.RUnlock()
	return ch.Serve(l)
}

// Register registers a handler for a service+operation pair
func (ch *Channel) Register(h Handler, operationName string) {
	ch.handlers.register(h, ch.PeerInfo().ServiceName, operationName)
}

// PeerInfo returns the current peer info for the channel
func (ch *Channel) PeerInfo() LocalPeerInfo {
	ch.mutable.mut.RLock()
	defer ch.mutable.mut.RUnlock()

	return ch.mutable.peerInfo
}

func (ch *Channel) registerNewSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	// Recheck for the subchannel under the write lock.
	if sc, ok := mutable.subChannels[serviceName]; ok {
		return sc
	}

	sc := newSubChannel(serviceName, ch.peers)
	mutable.subChannels[serviceName] = sc
	return sc
}

// GetSubChannel returns a SubChannel for the given service name. If the subchannel does not
// exist, it is created.
func (ch *Channel) GetSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.RLock()

	if sc, ok := mutable.subChannels[serviceName]; ok {
		mutable.mut.RUnlock()
		return sc
	}

	mutable.mut.RUnlock()
	return ch.registerNewSubChannel(serviceName)
}

// Peers returns the PeerList for the channel.
func (ch *Channel) Peers() *PeerList {
	ch.mutable.mut.RLock()
	defer ch.mutable.mut.RUnlock()

	return ch.peers
}

// BeginCall starts a new call to a remote peer, returning an OutboundCall that can
// be used to write the arguments of the call.
func (ch *Channel) BeginCall(ctx context.Context, hostPort, serviceName, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	p := ch.peers.GetOrAdd(hostPort)
	return p.BeginCall(ctx, serviceName, operationName, callOptions)
}

// serve runs the listener to accept and manage new incoming connections, blocking
// until the channel is closed.
func (ch *Channel) serve() {
	acceptBackoff := 0 * time.Millisecond

	for {
		netConn, err := ch.mutable.l.Accept()
		if err != nil {
			// Backoff from new accepts if this is a temporary error
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if acceptBackoff == 0 {
					acceptBackoff = 5 * time.Millisecond
				} else {
					acceptBackoff *= 2
				}
				if max := 1 * time.Second; acceptBackoff > max {
					acceptBackoff = max
				}
				ch.log.Warnf("accept error: %v; retrying in %v", err, acceptBackoff)
				time.Sleep(acceptBackoff)
				continue
			} else {
				// Only log an error if we are not shutdown.
				if ch.Closed() {
					return
				}
				ch.log.Fatalf("unrecoverable accept error: %v; closing server", err)
				return
			}
		}

		acceptBackoff = 0

		// Register the connection in the peer once the channel is set up.
		onActive := func(c *Connection) {
			ch.log.Debugf("Add connection as an active peer for %v", c.remotePeerInfo.HostPort)
			p := ch.peers.GetOrAdd(c.remotePeerInfo.HostPort)
			p.AddConnection(c)
		}
		_, err = newInboundConnection(netConn, ch.handlers, ch.PeerInfo(), ch.log, onActive, &ch.connectionOptions)
		if err != nil {
			// Server is getting overloaded - begin rejecting new connections
			ch.log.Errorf("could not create new TChannelConnection for incoming conn: %v", err)
			netConn.Close()
			continue
		}
	}
}

// Logger returns the logger for this channel.
func (ch *Channel) Logger() Logger {
	return ch.log
}

// Closed returns whether this channel has been closed with .Close()
func (ch *Channel) Closed() bool {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()
	return ch.mutable.closed
}

// Close closes the channel including all connections to any active peers.
func (ch *Channel) Close() {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()

	ch.mutable.closed = true
	if ch.mutable.l != nil {
		ch.mutable.l.Close()
	}
	ch.peers.Close()
}
<commit_msg>Peers() does not need a mutex<commit_after>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

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

import (
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"golang.org/x/net/context"
)

var (
	errAlreadyListening = errors.New("channel already listening")
)

const (
	ephemeralHostPort = "0.0.0.0:0"
)

// ChannelOptions are used to control parameters on a create a TChannel
type ChannelOptions struct {
	// Default Connection options
	DefaultConnectionOptions ConnectionOptions

	// The name of the process, for logging and reporting to peers
	ProcessName string

	// The logger to use for this channel
	Logger Logger
}

// A Channel is a bi-directional connection to the peering and routing network.
// Applications can use a Channel to make service calls to remote peers via
// BeginCall, or to listen for incoming calls from peers.  Applications that
// want to receive requests should call one of Serve or ListenAndServe
// TODO(prashant): Shutdown all subchannels + peers when channel is closed.
type Channel struct {
	log               Logger
	connectionOptions ConnectionOptions
	handlers          *handlerMap
	peers             *PeerList

	// mutable contains all the members of Channel which are mutable.
	mutable struct {
		mut         sync.RWMutex // protects members of the mutable struct.
		closed      bool
		peerInfo    LocalPeerInfo // May be ephemeral if this is a client only channel
		l           net.Listener  // May be nil if this is a client only channel
		subChannels map[string]*SubChannel
	}
}

// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.
func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if opts == nil {
		opts = &ChannelOptions{}
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	ch := &Channel{
		connectionOptions: opts.DefaultConnectionOptions,
		log:               logger,
		handlers:          &handlerMap{},
	}
	ch.mutable.peerInfo = LocalPeerInfo{
		PeerInfo: PeerInfo{
			ProcessName: processName,
			HostPort:    ephemeralHostPort,
		},
		ServiceName: serviceName,
	}
	ch.mutable.subChannels = make(map[string]*SubChannel)
	ch.peers = newPeerList(ch)
	ch.connectionOptions.ChecksumType = ChecksumTypeCrc32
	return ch, nil
}

// Serve serves incoming requests using the provided listener.
// The local peer info is set synchronously, but the actual socket listening is done in
// a separate goroutine.
func (ch *Channel) Serve(l net.Listener) error {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	if mutable.l != nil {
		return errAlreadyListening
	}

	mutable.l = l
	mutable.peerInfo.HostPort = l.Addr().String()

	peerInfo := mutable.peerInfo
	ch.log.Debugf("%v (%v) listening on %v", peerInfo.ProcessName, peerInfo.ServiceName, peerInfo.HostPort)
	go ch.serve()
	return nil
}

// ListenAndServe listens on the given address and serves incoming requests.
// The port may be 0, in which case the channel will use an OS assigned port
// This method does not block as the handling of connections is done in a goroutine.
func (ch *Channel) ListenAndServe(hostPort string) error {
	mutable := &ch.mutable
	mutable.mut.RLock()

	if mutable.l != nil {
		mutable.mut.RUnlock()
		return errAlreadyListening
	}

	l, err := net.Listen("tcp", hostPort)
	if err != nil {
		mutable.mut.RUnlock()
		return err
	}

	mutable.mut.RUnlock()
	return ch.Serve(l)
}

// Register registers a handler for a service+operation pair
func (ch *Channel) Register(h Handler, operationName string) {
	ch.handlers.register(h, ch.PeerInfo().ServiceName, operationName)
}

// PeerInfo returns the current peer info for the channel
func (ch *Channel) PeerInfo() LocalPeerInfo {
	ch.mutable.mut.RLock()
	defer ch.mutable.mut.RUnlock()

	return ch.mutable.peerInfo
}

func (ch *Channel) registerNewSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	// Recheck for the subchannel under the write lock.
	if sc, ok := mutable.subChannels[serviceName]; ok {
		return sc
	}

	sc := newSubChannel(serviceName, ch.peers)
	mutable.subChannels[serviceName] = sc
	return sc
}

// GetSubChannel returns a SubChannel for the given service name. If the subchannel does not
// exist, it is created.
func (ch *Channel) GetSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.RLock()

	if sc, ok := mutable.subChannels[serviceName]; ok {
		mutable.mut.RUnlock()
		return sc
	}

	mutable.mut.RUnlock()
	return ch.registerNewSubChannel(serviceName)
}

// Peers returns the PeerList for the channel.
func (ch *Channel) Peers() *PeerList {
	return ch.peers
}

// BeginCall starts a new call to a remote peer, returning an OutboundCall that can
// be used to write the arguments of the call.
func (ch *Channel) BeginCall(ctx context.Context, hostPort, serviceName, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	p := ch.peers.GetOrAdd(hostPort)
	return p.BeginCall(ctx, serviceName, operationName, callOptions)
}

// serve runs the listener to accept and manage new incoming connections, blocking
// until the channel is closed.
func (ch *Channel) serve() {
	acceptBackoff := 0 * time.Millisecond

	for {
		netConn, err := ch.mutable.l.Accept()
		if err != nil {
			// Backoff from new accepts if this is a temporary error
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if acceptBackoff == 0 {
					acceptBackoff = 5 * time.Millisecond
				} else {
					acceptBackoff *= 2
				}
				if max := 1 * time.Second; acceptBackoff > max {
					acceptBackoff = max
				}
				ch.log.Warnf("accept error: %v; retrying in %v", err, acceptBackoff)
				time.Sleep(acceptBackoff)
				continue
			} else {
				// Only log an error if we are not shutdown.
				if ch.Closed() {
					return
				}
				ch.log.Fatalf("unrecoverable accept error: %v; closing server", err)
				return
			}
		}

		acceptBackoff = 0

		// Register the connection in the peer once the channel is set up.
		onActive := func(c *Connection) {
			ch.log.Debugf("Add connection as an active peer for %v", c.remotePeerInfo.HostPort)
			p := ch.peers.GetOrAdd(c.remotePeerInfo.HostPort)
			p.AddConnection(c)
		}
		_, err = newInboundConnection(netConn, ch.handlers, ch.PeerInfo(), ch.log, onActive, &ch.connectionOptions)
		if err != nil {
			// Server is getting overloaded - begin rejecting new connections
			ch.log.Errorf("could not create new TChannelConnection for incoming conn: %v", err)
			netConn.Close()
			continue
		}
	}
}

// Logger returns the logger for this channel.
func (ch *Channel) Logger() Logger {
	return ch.log
}

// Closed returns whether this channel has been closed with .Close()
func (ch *Channel) Closed() bool {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()
	return ch.mutable.closed
}

// Close closes the channel including all connections to any active peers.
func (ch *Channel) Close() {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()

	ch.mutable.closed = true
	if ch.mutable.l != nil {
		ch.mutable.l.Close()
	}
	ch.peers.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	id3 "github.com/mikkyang/id3-go"
	kingpin "gopkg.in/alecthomas/kingpin.v1"
	"net/url"
	"os"
	"path/filepath"
)

const (
	Header   = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
	iTunesNs = "http://www.itunes.com/dtds/podcast-1.0.dtd"
)

type Rss struct {
	XMLName xml.Name `xml:"rss"`
	Channel Channel  `xml:"channel"`
	Version string   `xml:"version,attr"`
	NS      string   `xml:"xmlns:itunes,attr"`
}

type Channel struct {
	Title       string `xml:"title"`
	Link        string `xml:"link"`
	Description string `xml:"description"`
	Items       []Item `xml:"item"`
}

type Item struct {
	Title       string    `xml:"title"`
	Description string    `xml:"description"`
	Enclosure   Enclosure `xml:"enclosure"`
	Guid        string    `xml:"guid"`
	Subtitle    string    `xml:"itunes:subtitle"`
}

type Enclosure struct {
	Url    string `xml:"url,attr"`
	Length int64  `xml:"length,attr"`
	Type   string `xml:"type,attr"`
}

func fileUrl(relativePath string, baseUrl string) string {
	Url, _ := url.Parse(baseUrl)
	Url.Path += relativePath
	return Url.String()
}

func addMeta(path string, f os.FileInfo, item *Item) {
	fd, err := id3.Open(path)
	if err != nil {
		item.Title = f.Name()
	} else {
		title := fd.Title()
		author := fd.Artist()
		if len(title) > 0 {
			item.Title = title
		} else {
			item.Title = author
			if len(author) > 0 {
				item.Title += " - "
			}
			item.Title += f.Name()
		}
		item.Subtitle = author
	}
}

func visitFiles(workDir string, channel *Channel, publicUrl string) filepath.WalkFunc {
	return func(path string, f os.FileInfo, err error) error {

		if err != nil {
			return err
		}

		if !!f.IsDir() {
			return nil
		}

		matched, _ := filepath.Match("*.mp3", f.Name())

		if matched {
			relativePath := path[len(workDir)-1:]
			url := fileUrl(relativePath, publicUrl)

			enclosure := Enclosure{Length: f.Size(), Type: "audio/mpeg",
				Url: url}
			item := Item{Enclosure: enclosure, Guid: enclosure.Url}
			addMeta(path, f, &item)
			channel.Items = append(channel.Items, item)
		}

		return nil

	}
}

var (
	baseUrl     = kingpin.Flag("server", "hostname (and path) to the root e.g. http://myserver.com/rss").Short('s').Default("http://localhost").URL()
	title       = kingpin.Flag("title", "RSS channel title").Short('t').Default("RSS FEED").String()
	description = kingpin.Flag("description", "RSS channel description").Short('d').String()
	path        = kingpin.Arg("directory", "directory to read files relative from").Required().ExistingDir()
)

func main() {

	kingpin.Version("0.0.1")
	kingpin.Parse()

	channel := &Channel{Title: *title, Link: (*baseUrl).String(), Description: *description}
	err := filepath.Walk(*path, visitFiles(*path, channel, (*baseUrl).String()))

	if err != nil {
		fmt.Printf("%s: %v\n", os.Args[0], err)
	} else {
		output, err := xml.MarshalIndent(
			&Rss{Channel: *channel, Version: "2.0", NS: iTunesNs}, "", "  ")
		if err != nil {
			fmt.Printf("error: %v\n", err)
		} else {
			os.Stdout.WriteString(Header)
			os.Stdout.Write(output)
		}
	}

}
<commit_msg>inline, avoid local variables<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	id3 "github.com/mikkyang/id3-go"
	kingpin "gopkg.in/alecthomas/kingpin.v1"
	"net/url"
	"os"
	"path/filepath"
)

const (
	Header   = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
	iTunesNs = "http://www.itunes.com/dtds/podcast-1.0.dtd"
)

type Rss struct {
	XMLName xml.Name `xml:"rss"`
	Channel Channel  `xml:"channel"`
	Version string   `xml:"version,attr"`
	NS      string   `xml:"xmlns:itunes,attr"`
}

type Channel struct {
	Title       string `xml:"title"`
	Link        string `xml:"link"`
	Description string `xml:"description"`
	Items       []Item `xml:"item"`
}

type Item struct {
	Title       string    `xml:"title"`
	Description string    `xml:"description"`
	Enclosure   Enclosure `xml:"enclosure"`
	Guid        string    `xml:"guid"`
	Subtitle    string    `xml:"itunes:subtitle"`
}

type Enclosure struct {
	Url    string `xml:"url,attr"`
	Length int64  `xml:"length,attr"`
	Type   string `xml:"type,attr"`
}

func fileUrl(relativePath string, baseUrl string) string {
	Url, _ := url.Parse(baseUrl)
	Url.Path += relativePath
	return Url.String()
}

func addMeta(path string, f os.FileInfo, item *Item) {
	fd, err := id3.Open(path)
	if err != nil {
		item.Title = f.Name()
	} else {
		title := fd.Title()
		author := fd.Artist()
		if len(title) > 0 {
			item.Title = title
		} else {
			item.Title = author
			if len(author) > 0 {
				item.Title += " - "
			}
			item.Title += f.Name()
		}
		item.Subtitle = author
	}
}

func visitFiles(workDir string, channel *Channel, publicUrl string) filepath.WalkFunc {
	return func(path string, f os.FileInfo, err error) error {

		if err != nil {
			return err
		}

		if !!f.IsDir() {
			return nil
		}

		matched, _ := filepath.Match("*.mp3", f.Name())
		if matched {
			url := fileUrl(path[len(workDir)-1:], publicUrl)
			item := Item{Enclosure: Enclosure{Length: f.Size(), Type: "audio/mpeg",
				Url: url}, Guid: url}
			addMeta(path, f, &item)
			channel.Items = append(channel.Items, item)
		}

		return nil

	}
}

var (
	baseUrl     = kingpin.Flag("server", "hostname (and path) to the root e.g. http://myserver.com/rss").Short('s').Default("http://localhost").URL()
	title       = kingpin.Flag("title", "RSS channel title").Short('t').Default("RSS FEED").String()
	description = kingpin.Flag("description", "RSS channel description").Short('d').String()
	path        = kingpin.Arg("directory", "directory to read files relative from").Required().ExistingDir()
)

func main() {

	kingpin.Version("0.0.1")
	kingpin.Parse()

	channel := &Channel{Title: *title, Link: (*baseUrl).String(), Description: *description}
	err := filepath.Walk(*path, visitFiles(*path, channel, (*baseUrl).String()))

	if err != nil {
		fmt.Printf("%s: %v\n", os.Args[0], err)
	} else {
		output, err := xml.MarshalIndent(
			&Rss{Channel: *channel, Version: "2.0", NS: iTunesNs}, "", "  ")
		if err != nil {
			fmt.Printf("error: %v\n", err)
		} else {
			os.Stdout.WriteString(Header)
			os.Stdout.Write(output)
		}
	}

}
<|endoftext|>


<commit_before>package spf

import (
	"errors"
	"net"
)

const spfPrefix = "spf1"

func matchingResult(qualifier tokenType) (SPFResult, error) {
	if !qualifier.isQualifier() {
		return SPFEnd, errors.New("Not a Qualifier")
	}

	switch qualifier {
	case qPlus:
		return Pass, nil
	case qMinus:
		return Fail, nil
	case qQuestionMark:
		return Neutral, nil
	case qTilde:
		return Softfail, nil
	}
	return Permerror, nil
}

type Parser struct {
	Sender      string
	Domain      string
	Ip          net.IP
	Query       string
	Mechanisms  []*Token
	Explanation *Token
	Redirect    *Token
}

func NewParser(sender, domain string, ip net.IP, query string) *Parser {
	return &Parser{sender, domain, ip, query, nil, nil, nil}
}

func (p *Parser) Parse() (SPFResult, error) {
	var result SPFResult
	tokens := Lex(p.Query)

	if err := p.sortTokens(tokens); err != nil {
		return Permerror, err
	}

	for _, token := range p.Mechanisms {
		switch token.Mechanism {
		/*
			case tVersion:
				result = p.parseVersion(token)
			case tAll:
				result = p.parseAll(token)
			case tA:
				result = p.parseA(token)
			case tIp4:
				result = p.parseIp4(token)
			case tIp6:
				result = p.parseIp6(token)
			case tMX:
				result = p.parseMX(token)
			case tPTR:
				result = p.parsePTR(token)
			case tInclude:
				result = p.parseInclude(token)
		*/
		}

	}
	return result, nil
}

func (p *Parser) sortTokens(tokens []*Token) error {

	for _, token := range tokens {
		if token.Mechanism.isMechanism() {
			p.Mechanisms = append(p.Mechanisms, token)

			if token.Mechanism == tAll {
				p.Redirect = nil // cleaning just in case
				return nil
			}
		} else {

			if token.Mechanism == tRedirect && p.Redirect != nil {
				return errors.New("Modifier redirect musn't appear more than once")
			} else {
				p.Redirect = token
			}

			if token.Mechanism == tExp && p.Explanation != nil {
				return errors.New("Modifier exp/explanation musn't appear more than once")
			} else {
				p.Explanation = token
			}
		}
	}
	return nil
}

func (p *Parser) parseVersion(t *Token) (bool, SPFResult) {
	if t.Value == spfPrefix {
		return true, None
	}
	return true, Permerror
}

func (p *Parser) parseAll(t *Token) (bool, SPFResult) {
	if result, err := matchingResult(t.Qualifier); err != nil {
		return true, Permerror
	} else {
		return true, result
	}
}

func (p *Parser) parseIp4(t *Token) (bool, SPFResult) {
	result, _ := matchingResult(t.Qualifier)

	if _, ipnet, err := net.ParseCIDR(t.Value); err == nil {
		return ipnet.Contains(p.Ip), result
	} else {
		ip := net.ParseIP(t.Value)
		return ip.Equal(p.Ip), result
	}
}
<commit_msg>Fix NewParser, create slice of tokens.<commit_after>package spf

import (
	"errors"
	"net"
)

const spfPrefix = "spf1"

func matchingResult(qualifier tokenType) (SPFResult, error) {
	if !qualifier.isQualifier() {
		return SPFEnd, errors.New("Not a Qualifier")
	}

	switch qualifier {
	case qPlus:
		return Pass, nil
	case qMinus:
		return Fail, nil
	case qQuestionMark:
		return Neutral, nil
	case qTilde:
		return Softfail, nil
	}
	return Permerror, nil
}

type Parser struct {
	Sender      string
	Domain      string
	Ip          net.IP
	Query       string
	Mechanisms  []*Token
	Explanation *Token
	Redirect    *Token
}

func NewParser(sender, domain string, ip net.IP, query string) *Parser {
	return &Parser{sender, domain, ip, query, make([]*Token, 0, 10), nil, nil}
}

func (p *Parser) Parse() (SPFResult, error) {
	var result SPFResult
	tokens := Lex(p.Query)

	if err := p.sortTokens(tokens); err != nil {
		return Permerror, err
	}

	for _, token := range p.Mechanisms {
		switch token.Mechanism {
		/*
			case tVersion:
				result = p.parseVersion(token)
			case tAll:
				result = p.parseAll(token)
			case tA:
				result = p.parseA(token)
			case tIp4:
				result = p.parseIp4(token)
			case tIp6:
				result = p.parseIp6(token)
			case tMX:
				result = p.parseMX(token)
			case tPTR:
				result = p.parsePTR(token)
			case tInclude:
				result = p.parseInclude(token)
		*/
		}

	}
	return result, nil
}

func (p *Parser) sortTokens(tokens []*Token) error {

	for _, token := range tokens {
		if token.Mechanism.isMechanism() {
			p.Mechanisms = append(p.Mechanisms, token)

			if token.Mechanism == tAll {
				p.Redirect = nil // cleaning just in case
				return nil
			}
		} else {

			if token.Mechanism == tRedirect && p.Redirect != nil {
				return errors.New("Modifier redirect musn't appear more than once")
			} else {
				p.Redirect = token
			}

			if token.Mechanism == tExp && p.Explanation != nil {
				return errors.New("Modifier exp/explanation musn't appear more than once")
			} else {
				p.Explanation = token
			}
		}
	}
	return nil
}

func (p *Parser) parseVersion(t *Token) (bool, SPFResult) {
	if t.Value == spfPrefix {
		return true, None
	}
	return true, Permerror
}

func (p *Parser) parseAll(t *Token) (bool, SPFResult) {
	if result, err := matchingResult(t.Qualifier); err != nil {
		return true, Permerror
	} else {
		return true, result
	}
}

func (p *Parser) parseIp4(t *Token) (bool, SPFResult) {
	result, _ := matchingResult(t.Qualifier)

	if _, ipnet, err := net.ParseCIDR(t.Value); err == nil {
		return ipnet.Contains(p.Ip), result
	} else {
		ip := net.ParseIP(t.Value)
		return ip.Equal(p.Ip), result
	}
}
<|endoftext|>


<commit_before>package capabilities

import (
	"net/http"
	"os"
	"strings"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"context"
	"google.golang.org/api/container/v1"
	"io/ioutil"
	"io"
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
	"github.com/rancher/kontainer-engine/service"
	"sync"
)

const (
	defaultCredentialEnv = "GOOGLE_APPLICATION_CREDENTIALS"
)

var mutex = service.Drivers["gke"].(sync.Locker)

func NewGKECapabilitiesHandler() *gkeVersionHandler {
	return &gkeVersionHandler{}
}

type gkeVersionHandler struct {
}

type errorResponse struct {
	Error string `json:"error"`
}

type requestBody struct {
	Credentials string `json:"credentials"`
	Zone        string `json:"zone"`
	ProjectId   string `json:"projectId"`
}

func (g *gkeVersionHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
	if req.Method != http.MethodPost {
		writer.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	writer.Header().Set("Content-Type", "application/json")

	raw, err := ioutil.ReadAll(req.Body)

	var body requestBody
	err = json.Unmarshal(raw, &body)

	if err != nil {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("cannot parse request body: "+err.Error()))
		return
	}

	credentials := body.Credentials
	projectId := body.ProjectId
	zone := body.Zone

	if projectId == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid projectId"))
		return
	}

	if zone == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid zone"))
		return
	}

	if credentials == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid credentials"))
		return
	}

	client, err := g.getServiceClient(context.Background(), credentials)

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	result, err := client.Projects.Zones.GetServerconfig(projectId, zone).Do()

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	serialized, err := json.Marshal(result)

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	writer.Write(serialized)
}

func (g *gkeVersionHandler) handleErr(writer http.ResponseWriter, originalErr error) {
	resp := errorResponse{originalErr.Error()}

	asJson, err := json.Marshal(resp)

	if err != nil {
		logrus.Error("error while marshalling error message '" + originalErr.Error() + "' error was '" + err.Error() + "'")
		writer.Write([]byte(err.Error()))
		return
	}

	writer.Write([]byte(asJson))
}

func (g *gkeVersionHandler) getServiceClient(ctx context.Context, credentialContent string) (*container.Service, error) {
	// The google SDK has no sane way to pass in a TokenSource give all the different types (user, service account, etc)
	// So we actually set an environment variable and then unset it
	mutex.Lock()
	locked := true
	setEnv := false
	cleanup := func() {
		if setEnv {
			os.Unsetenv(defaultCredentialEnv)
		}

		if locked {
			mutex.Unlock()
			locked = false
		}
	}
	defer cleanup()

	file, err := ioutil.TempFile("", "credential-file")
	if err != nil {
		return nil, err
	}
	defer os.Remove(file.Name())
	defer file.Close()

	if _, err := io.Copy(file, strings.NewReader(credentialContent)); err != nil {
		return nil, err
	}

	setEnv = true
	os.Setenv(defaultCredentialEnv, file.Name())

	ts, err := google.DefaultTokenSource(ctx, container.CloudPlatformScope)
	if err != nil {
		return nil, err
	}

	// Unlocks
	cleanup()

	client := oauth2.NewClient(ctx, ts)
	service, err := container.New(client)

	if err != nil {
		return nil, err
	}
	return service, nil
}
<commit_msg>Revert "Fixing race condition by syncing to gke driver mutex in capabilities get code"<commit_after>package capabilities

import (
	"net/http"
	"os"
	"strings"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"context"
	"google.golang.org/api/container/v1"
	"sync"
	"io/ioutil"
	"io"
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
)

const (
	defaultCredentialEnv = "GOOGLE_APPLICATION_CREDENTIALS"
)

var mutex = &sync.Mutex{}

func NewGKECapabilitiesHandler() *gkeVersionHandler {
	return &gkeVersionHandler{}
}

type gkeVersionHandler struct {
}

type errorResponse struct {
	Error string `json:"error"`
}

type requestBody struct {
	Credentials string `json:"credentials"`
	Zone        string `json:"zone"`
	ProjectId   string `json:"projectId"`
}

func (g *gkeVersionHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
	if req.Method != http.MethodPost {
		writer.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	writer.Header().Set("Content-Type", "application/json")

	raw, err := ioutil.ReadAll(req.Body)

	var body requestBody
	err = json.Unmarshal(raw, &body)

	if err != nil {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("cannot parse request body: "+err.Error()))
		return
	}

	credentials := body.Credentials
	projectId := body.ProjectId
	zone := body.Zone

	if projectId == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid projectId"))
		return
	}

	if zone == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid zone"))
		return
	}

	if credentials == "" {
		writer.WriteHeader(http.StatusBadRequest)
		g.handleErr(writer, fmt.Errorf("invalid credentials"))
		return
	}

	client, err := g.getServiceClient(context.Background(), credentials)

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	result, err := client.Projects.Zones.GetServerconfig(projectId, zone).Do()

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	serialized, err := json.Marshal(result)

	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		g.handleErr(writer, err)
		return
	}

	writer.Write(serialized)
}

func (g *gkeVersionHandler) handleErr(writer http.ResponseWriter, originalErr error) {
	resp := errorResponse{originalErr.Error()}

	asJson, err := json.Marshal(resp)

	if err != nil {
		logrus.Error("error while marshalling error message '" + originalErr.Error() + "' error was '" + err.Error() + "'")
		writer.Write([]byte(err.Error()))
		return
	}

	writer.Write([]byte(asJson))
}

func (g *gkeVersionHandler) getServiceClient(ctx context.Context, credentialContent string) (*container.Service, error) {
	// The google SDK has no sane way to pass in a TokenSource give all the different types (user, service account, etc)
	// So we actually set an environment variable and then unset it
	mutex.Lock()
	locked := true
	setEnv := false
	cleanup := func() {
		if setEnv {
			os.Unsetenv(defaultCredentialEnv)
		}

		if locked {
			mutex.Unlock()
			locked = false
		}
	}
	defer cleanup()

	file, err := ioutil.TempFile("", "credential-file")
	if err != nil {
		return nil, err
	}
	defer os.Remove(file.Name())
	defer file.Close()

	if _, err := io.Copy(file, strings.NewReader(credentialContent)); err != nil {
		return nil, err
	}

	setEnv = true
	os.Setenv(defaultCredentialEnv, file.Name())

	ts, err := google.DefaultTokenSource(ctx, container.CloudPlatformScope)
	if err != nil {
		return nil, err
	}

	// Unlocks
	cleanup()

	client := oauth2.NewClient(ctx, ts)
	service, err := container.New(client)

	if err != nil {
		return nil, err
	}
	return service, nil
}
<|endoftext|>


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

package doc

import (
	"archive/zip"
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"regexp"
	"strings"

	"github.com/Unknwon/com"
	"github.com/Unknwon/gowalker/utils"
	"github.com/Unknwon/hv"
)

// TODO: specify with command line flag
const repoRoot = "/tmp/gw"

var urlTemplates = []struct {
	re       *regexp.Regexp
	template string
	lineFmt  string
}{
	{
		regexp.MustCompile(`^git\.gitorious\.org/(?P<repo>[^/]+/[^/]+)$`),
		"https://gitorious.org/{repo}/blobs/{tag}/{dir}{0}",
		"#line%d",
	},
	{
		regexp.MustCompile(`^camlistore\.org/r/p/(?P<repo>[^/]+)$`),
		"http://camlistore.org/code/?p={repo}.git;hb={tag};f={dir}{0}",
		"#l%d",
	},
}

// lookupURLTemplate finds an expand() template, match map and line number
// format for well known repositories.
func lookupURLTemplate(repo, dir, tag string) (string, map[string]string, string) {
	if strings.HasPrefix(dir, "/") {
		dir = dir[1:] + "/"
	}
	for _, t := range urlTemplates {
		if m := t.re.FindStringSubmatch(repo); m != nil {
			match := map[string]string{
				"dir": dir,
				"tag": tag,
			}
			for i, name := range t.re.SubexpNames() {
				if name != "" {
					match[name] = m[i]
				}
			}
			return t.template, match, t.lineFmt
		}
	}
	return "", nil, ""
}

type vcsCmd struct {
	schemes  []string
	download func([]string, string, string) (string, string, error)
}

var vcsCmds = map[string]*vcsCmd{
	"git": &vcsCmd{
		schemes:  []string{"http", "https", "git"},
		download: downloadGit,
	},
}

var lsremoteRe = regexp.MustCompile(`(?m)^([0-9a-f]{40})\s+refs/(?:tags|heads)/(.+)$`)

func downloadGit(schemes []string, repo, savedEtag string) (string, string, error) {
	var p []byte
	var scheme string
	for i := range schemes {
		cmd := exec.Command("git", "ls-remote", "--heads", "--tags", schemes[i]+"://"+repo+".git")
		log.Println(strings.Join(cmd.Args, " "))
		var err error
		p, err = cmd.Output()
		if err == nil {
			scheme = schemes[i]
			break
		}
	}

	if scheme == "" {
		return "", "", com.NotFoundError{"VCS not found"}
	}

	tags := make(map[string]string)
	for _, m := range lsremoteRe.FindAllSubmatch(p, -1) {
		tags[string(m[2])] = string(m[1])
	}

	tag, commit, err := bestTag(tags, "master")
	if err != nil {
		return "", "", err
	}

	etag := scheme + "-" + commit

	if etag == savedEtag {
		return "", "", errNotModified
	}

	dir := path.Join(repoRoot, repo+".git")
	p, err = ioutil.ReadFile(path.Join(dir, ".git/HEAD"))
	switch {
	case err != nil:
		if err := os.MkdirAll(dir, 0777); err != nil {
			return "", "", err
		}
		cmd := exec.Command("git", "clone", scheme+"://"+repo, dir)
		log.Println(strings.Join(cmd.Args, " "))
		if err := cmd.Run(); err != nil {
			return "", "", err
		}
	case string(bytes.TrimRight(p, "\n")) == commit:
		return tag, etag, nil
	default:
		cmd := exec.Command("git", "fetch")
		log.Println(strings.Join(cmd.Args, " "))
		cmd.Dir = dir
		if err := cmd.Run(); err != nil {
			return "", "", err
		}
	}

	cmd := exec.Command("git", "checkout", "--detach", "--force", commit)
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		return "", "", err
	}

	return tag, etag, nil
}

var vcsPattern = regexp.MustCompile(`^(?P<repo>(?:[a-z0-9.\-]+\.)+[a-z0-9.\-]+(?::[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn)(?P<dir>/[A-Za-z0-9_.\-/]*)?$`)

func getVCSDoc(client *http.Client, match map[string]string, etagSaved string) (*hv.Package, error) {
	cmd := vcsCmds[match["vcs"]]
	if cmd == nil {
		return nil, com.NotFoundError{com.Expand("VCS not supported: {vcs}", match)}
	}

	scheme := match["scheme"]
	if scheme == "" {
		i := strings.Index(etagSaved, "-")
		if i > 0 {
			scheme = etagSaved[:i]
		}
	}

	schemes := cmd.schemes
	if scheme != "" {
		for i := range cmd.schemes {
			if cmd.schemes[i] == scheme {
				schemes = cmd.schemes[i : i+1]
				break
			}
		}
	}

	// Download and checkout.

	tag, _, err := cmd.download(schemes, match["repo"], etagSaved)
	if err != nil {
		return nil, err
	}

	// Find source location.

	urlTemplate, urlMatch, lineFmt := lookupURLTemplate(match["repo"], match["dir"], tag)

	// Slurp source files.

	d := path.Join(repoRoot, com.Expand("{repo}.{vcs}", match), match["dir"])
	f, err := os.Open(d)
	if err != nil {
		if os.IsNotExist(err) {
			err = com.NotFoundError{err.Error()}
		}
		return nil, err
	}
	fis, err := f.Readdir(-1)
	if err != nil {
		return nil, err
	}

	// Get source file data.
	var files []com.RawFile
	for _, fi := range fis {
		if fi.IsDir() || !utils.IsDocFile(fi.Name()) {
			continue
		}
		b, err := ioutil.ReadFile(path.Join(d, fi.Name()))
		if err != nil {
			return nil, err
		}
		files = append(files, &hv.Source{
			SrcName:   fi.Name(),
			BrowseUrl: com.Expand(urlTemplate, urlMatch, fi.Name()),
			SrcData:   b,
		})
	}

	// Start generating data.
	w := &hv.Walker{
		LineFmt: lineFmt,
		Pdoc: &hv.Package{
			PkgInfo: &hv.PkgInfo{
				ImportPath:  match["importPath"],
				ProjectName: match["repo"],
			},
		},
	}

	srcs := make([]*hv.Source, 0, len(files))
	for _, f := range files {
		s, _ := f.(*hv.Source)
		srcs = append(srcs, s)
	}

	return w.Build(&hv.WalkRes{
		WalkDepth: hv.WD_All,
		WalkType:  hv.WT_Memory,
		WalkMode:  hv.WM_All,
		Srcs:      srcs,
	})
}

var defaultTags = map[string]string{"git": "master", "hg": "default", "svn": "trunk"}

func bestTag(tags map[string]string, defaultTag string) (string, string, error) {
	if commit, ok := tags["go1"]; ok {
		return "go1", commit, nil
	}
	if commit, ok := tags[defaultTag]; ok {
		return defaultTag, commit, nil
	}
	return "", "", com.NotFoundError{"Tag or branch not found."}
}

// checkDir checks if directory has been appended to slice.
func checkDir(dir string, dirs []string) bool {
	for _, d := range dirs {
		if dir == d {
			return true
		}
	}
	return false
}

// Only support .zip.
func getRepoByArchive(match map[string]string, downloadPath string) (bool, string, []com.RawFile, []string, error) {
	stdout, _, err := com.ExecCmd("curl", downloadPath)
	if err != nil {
		return false, "", nil, nil, err
	}
	p := []byte(stdout)

	r, err := zip.NewReader(bytes.NewReader(p), int64(len(p)))
	if err != nil {
		return false, "", nil, nil, errors.New(downloadPath + " -> new zip: " + err.Error())
	}

	if len(r.File) == 0 {
		return false, "", nil, nil, nil
	}

	nameLen := strings.Index(r.File[0].Name, "/")
	dirPrefix := match["dir"]
	if len(dirPrefix) != 0 {
		dirPrefix = dirPrefix[1:] + "/"
	}
	preLen := len(dirPrefix)
	isGoPro := false

	// for k, v := range match {
	// 	println(k, v)
	// }
	comment := r.Comment

	files := make([]com.RawFile, 0, 5)
	dirs := make([]string, 0, 5)
	for _, f := range r.File {
		fileName := f.Name[nameLen+1:]
		// Skip directories and files in wrong directories, get them later.
		if strings.HasSuffix(fileName, "/") || !strings.HasPrefix(fileName, dirPrefix) {
			continue
		}
		//fmt.Println(fileName)

		// Get files and check if directories have acceptable files.
		if d, fn := path.Split(fileName); utils.IsDocFile(fn) &&
			utils.FilterDirName(d) {
			// Check if it's a Go file.
			if !isGoPro && strings.HasSuffix(fn, ".go") {
				isGoPro = true
			}

			// Check if file is in the directory that is corresponding to import path.
			if d == dirPrefix {
				// Yes.
				if !isGoPro && strings.HasSuffix(fn, ".go") {
					isGoPro = true
				}
				// Get file from archive.
				rc, err := f.Open()
				if err != nil {
					return isGoPro, comment, files, dirs,
						errors.New(downloadPath + " -> open file: " + err.Error())
				}

				p := make([]byte, f.FileInfo().Size())
				rc.Read(p)
				if err != nil {
					return isGoPro, comment, files, dirs,
						errors.New(downloadPath + " -> read file: " + err.Error())
				}
				fmt.Println(com.Expand(match["browserUrlTpl"], match, fn))
				files = append(files, &hv.Source{
					SrcName:   fn,
					BrowseUrl: com.Expand(match["browserUrlTpl"], match, fn),
					RawSrcUrl: com.Expand(match["rawSrcUrlTpl"], match, fileName[preLen:]),
					SrcData:   p,
				})

			} else {
				sd, _ := path.Split(d[preLen:])
				sd = strings.TrimSuffix(sd, "/")
				if !checkDir(sd, dirs) {
					dirs = append(dirs, sd)
				}
			}
		}
	}
	return isGoPro, comment, files, dirs, nil
}

func generateHv(importPath string, srcMap map[string]*hv.Source) error {
	w := &hv.Walker{
		Pdoc: &hv.Package{
			PkgInfo: &hv.PkgInfo{
				ImportPath: importPath,
			},
		},
		SrcFiles: srcMap,
	}
	hvs, err := w.Render()
	if err != nil {
		return errors.New("doc.generateHv(" + importPath + ") -> Fail to render: " + err.Error())
	}

	buf := new(bytes.Buffer)
	for name, data := range hvs {
		filePath := "." + utils.HvJsPath + importPath + "/" + name + ".js"
		buf.Reset()
		buf.WriteString("document.write(\"")
		buf.Write(com.Html2JS(data))
		buf.WriteString("\")")

		if _, err := com.SaveFile(filePath, buf.Bytes()); err != nil {
			return errors.New("doc.generateHv(" + importPath + ") -> Save hv: " + err.Error())
		}
	}
	return nil
}
<commit_msg>v1.0.0<commit_after>// Copyright 2012 Gary Burd
// Copyright 2013 Unknown
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package doc

import (
	"archive/zip"
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"regexp"
	"strings"

	"github.com/Unknwon/com"
	"github.com/Unknwon/gowalker/utils"
	"github.com/Unknwon/hv"
)

// TODO: specify with command line flag
const repoRoot = "/tmp/gw"

var urlTemplates = []struct {
	re       *regexp.Regexp
	template string
	lineFmt  string
}{
	{
		regexp.MustCompile(`^git\.gitorious\.org/(?P<repo>[^/]+/[^/]+)$`),
		"https://gitorious.org/{repo}/blobs/{tag}/{dir}{0}",
		"#line%d",
	},
	{
		regexp.MustCompile(`^camlistore\.org/r/p/(?P<repo>[^/]+)$`),
		"http://camlistore.org/code/?p={repo}.git;hb={tag};f={dir}{0}",
		"#l%d",
	},
}

// lookupURLTemplate finds an expand() template, match map and line number
// format for well known repositories.
func lookupURLTemplate(repo, dir, tag string) (string, map[string]string, string) {
	if strings.HasPrefix(dir, "/") {
		dir = dir[1:] + "/"
	}
	for _, t := range urlTemplates {
		if m := t.re.FindStringSubmatch(repo); m != nil {
			match := map[string]string{
				"dir": dir,
				"tag": tag,
			}
			for i, name := range t.re.SubexpNames() {
				if name != "" {
					match[name] = m[i]
				}
			}
			return t.template, match, t.lineFmt
		}
	}
	return "", nil, ""
}

type vcsCmd struct {
	schemes  []string
	download func([]string, string, string) (string, string, error)
}

var vcsCmds = map[string]*vcsCmd{
	"git": &vcsCmd{
		schemes:  []string{"http", "https", "git"},
		download: downloadGit,
	},
}

var lsremoteRe = regexp.MustCompile(`(?m)^([0-9a-f]{40})\s+refs/(?:tags|heads)/(.+)$`)

func downloadGit(schemes []string, repo, savedEtag string) (string, string, error) {
	var p []byte
	var scheme string
	for i := range schemes {
		cmd := exec.Command("git", "ls-remote", "--heads", "--tags", schemes[i]+"://"+repo+".git")
		log.Println(strings.Join(cmd.Args, " "))
		var err error
		p, err = cmd.Output()
		if err == nil {
			scheme = schemes[i]
			break
		}
	}

	if scheme == "" {
		return "", "", com.NotFoundError{"VCS not found"}
	}

	tags := make(map[string]string)
	for _, m := range lsremoteRe.FindAllSubmatch(p, -1) {
		tags[string(m[2])] = string(m[1])
	}

	tag, commit, err := bestTag(tags, "master")
	if err != nil {
		return "", "", err
	}

	etag := scheme + "-" + commit

	if etag == savedEtag {
		return "", "", errNotModified
	}

	dir := path.Join(repoRoot, repo+".git")
	p, err = ioutil.ReadFile(path.Join(dir, ".git/HEAD"))
	switch {
	case err != nil:
		if err := os.MkdirAll(dir, 0777); err != nil {
			return "", "", err
		}
		cmd := exec.Command("git", "clone", scheme+"://"+repo, dir)
		log.Println(strings.Join(cmd.Args, " "))
		if err := cmd.Run(); err != nil {
			return "", "", err
		}
	case string(bytes.TrimRight(p, "\n")) == commit:
		return tag, etag, nil
	default:
		cmd := exec.Command("git", "fetch")
		log.Println(strings.Join(cmd.Args, " "))
		cmd.Dir = dir
		if err := cmd.Run(); err != nil {
			return "", "", err
		}
	}

	cmd := exec.Command("git", "checkout", "--detach", "--force", commit)
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		return "", "", err
	}

	return tag, etag, nil
}

var vcsPattern = regexp.MustCompile(`^(?P<repo>(?:[a-z0-9.\-]+\.)+[a-z0-9.\-]+(?::[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn)(?P<dir>/[A-Za-z0-9_.\-/]*)?$`)

func getVCSDoc(client *http.Client, match map[string]string, etagSaved string) (*hv.Package, error) {
	cmd := vcsCmds[match["vcs"]]
	if cmd == nil {
		return nil, com.NotFoundError{com.Expand("VCS not supported: {vcs}", match)}
	}

	scheme := match["scheme"]
	if scheme == "" {
		i := strings.Index(etagSaved, "-")
		if i > 0 {
			scheme = etagSaved[:i]
		}
	}

	schemes := cmd.schemes
	if scheme != "" {
		for i := range cmd.schemes {
			if cmd.schemes[i] == scheme {
				schemes = cmd.schemes[i : i+1]
				break
			}
		}
	}

	// Download and checkout.

	tag, _, err := cmd.download(schemes, match["repo"], etagSaved)
	if err != nil {
		return nil, err
	}

	// Find source location.

	urlTemplate, urlMatch, lineFmt := lookupURLTemplate(match["repo"], match["dir"], tag)

	// Slurp source files.

	d := path.Join(repoRoot, com.Expand("{repo}.{vcs}", match), match["dir"])
	f, err := os.Open(d)
	if err != nil {
		if os.IsNotExist(err) {
			err = com.NotFoundError{err.Error()}
		}
		return nil, err
	}
	fis, err := f.Readdir(-1)
	if err != nil {
		return nil, err
	}

	// Get source file data.
	var files []com.RawFile
	for _, fi := range fis {
		if fi.IsDir() || !utils.IsDocFile(fi.Name()) {
			continue
		}
		b, err := ioutil.ReadFile(path.Join(d, fi.Name()))
		if err != nil {
			return nil, err
		}
		files = append(files, &hv.Source{
			SrcName:   fi.Name(),
			BrowseUrl: com.Expand(urlTemplate, urlMatch, fi.Name()),
			SrcData:   b,
		})
	}

	// Start generating data.
	w := &hv.Walker{
		LineFmt: lineFmt,
		Pdoc: &hv.Package{
			PkgInfo: &hv.PkgInfo{
				ImportPath:  match["importPath"],
				ProjectName: match["repo"],
			},
		},
	}

	srcs := make([]*hv.Source, 0, len(files))
	for _, f := range files {
		s, _ := f.(*hv.Source)
		srcs = append(srcs, s)
	}

	return w.Build(&hv.WalkRes{
		WalkDepth: hv.WD_All,
		WalkType:  hv.WT_Memory,
		WalkMode:  hv.WM_All,
		Srcs:      srcs,
	})
}

var defaultTags = map[string]string{"git": "master", "hg": "default", "svn": "trunk"}

func bestTag(tags map[string]string, defaultTag string) (string, string, error) {
	if commit, ok := tags["go1"]; ok {
		return "go1", commit, nil
	}
	if commit, ok := tags[defaultTag]; ok {
		return defaultTag, commit, nil
	}
	return "", "", com.NotFoundError{"Tag or branch not found."}
}

// checkDir checks if directory has been appended to slice.
func checkDir(dir string, dirs []string) bool {
	for _, d := range dirs {
		if dir == d {
			return true
		}
	}
	return false
}

// Only support .zip.
func getRepoByArchive(match map[string]string, downloadPath string) (bool, string, []com.RawFile, []string, error) {
	stdout, _, err := com.ExecCmd("curl", downloadPath)
	if err != nil {
		return false, "", nil, nil, err
	}
	p := []byte(stdout)

	r, err := zip.NewReader(bytes.NewReader(p), int64(len(p)))
	if err != nil {
		return false, "", nil, nil, errors.New(downloadPath + " -> new zip: " + err.Error())
	}

	if len(r.File) == 0 {
		return false, "", nil, nil, nil
	}

	nameLen := strings.Index(r.File[0].Name, "/")
	dirPrefix := match["dir"]
	if len(dirPrefix) != 0 {
		dirPrefix = dirPrefix[1:] + "/"
	}
	preLen := len(dirPrefix)
	isGoPro := false

	// for k, v := range match {
	// 	println(k, v)
	// }
	comment := r.Comment

	files := make([]com.RawFile, 0, 5)
	dirs := make([]string, 0, 5)
	for _, f := range r.File {
		fileName := f.Name[nameLen+1:]
		// Skip directories and files in wrong directories, get them later.
		if strings.HasSuffix(fileName, "/") || !strings.HasPrefix(fileName, dirPrefix) {
			continue
		}
		//fmt.Println(fileName)

		// Get files and check if directories have acceptable files.
		if d, fn := path.Split(fileName); utils.IsDocFile(fn) &&
			utils.FilterDirName(d) {
			// Check if it's a Go file.
			if !isGoPro && strings.HasSuffix(fn, ".go") {
				isGoPro = true
			}

			// Check if file is in the directory that is corresponding to import path.
			if d == dirPrefix {
				// Yes.
				if !isGoPro && strings.HasSuffix(fn, ".go") {
					isGoPro = true
				}
				// Get file from archive.
				rc, err := f.Open()
				if err != nil {
					return isGoPro, comment, files, dirs,
						errors.New(downloadPath + " -> open file: " + err.Error())
				}

				p := make([]byte, f.FileInfo().Size())
				rc.Read(p)
				if err != nil {
					return isGoPro, comment, files, dirs,
						errors.New(downloadPath + " -> read file: " + err.Error())
				}
				//fmt.Println(com.Expand(match["browserUrlTpl"], match, fn))
				files = append(files, &hv.Source{
					SrcName:   fn,
					BrowseUrl: com.Expand(match["browserUrlTpl"], match, fn),
					RawSrcUrl: com.Expand(match["rawSrcUrlTpl"], match, fileName[preLen:]),
					SrcData:   p,
				})

			} else {
				sd, _ := path.Split(d[preLen:])
				sd = strings.TrimSuffix(sd, "/")
				if !checkDir(sd, dirs) {
					dirs = append(dirs, sd)
				}
			}
		}
	}
	return isGoPro, comment, files, dirs, nil
}

func generateHv(importPath string, srcMap map[string]*hv.Source) error {
	w := &hv.Walker{
		Pdoc: &hv.Package{
			PkgInfo: &hv.PkgInfo{
				ImportPath: importPath,
			},
		},
		SrcFiles: srcMap,
	}
	hvs, err := w.Render()
	if err != nil {
		return errors.New("doc.generateHv(" + importPath + ") -> Fail to render: " + err.Error())
	}

	buf := new(bytes.Buffer)
	for name, data := range hvs {
		filePath := "." + utils.HvJsPath + importPath + "/" + name + ".js"
		buf.Reset()
		buf.WriteString("document.write(\"")
		buf.Write(com.Html2JS(data))
		buf.WriteString("\")")

		if _, err := com.SaveFile(filePath, buf.Bytes()); err != nil {
			return errors.New("doc.generateHv(" + importPath + ") -> Save hv: " + err.Error())
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package common

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"errors"
	"fmt"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/packer/communicator/ssh"
)

// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name.
func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, error) {
	return func(state map[string]interface{}) (string, error) {
		for j := 0; j < 2; j++ {
			var host string
			i := state["instance"].(*ec2.Instance)
			if i.DNSName != "" {
				host = i.DNSName
			} else if i.VpcId == "" {
				host = i.PrivateIpAddress
			}

			if host != "" {
				return fmt.Sprintf("%s:%d", host, port), nil
			}

			r, err := e.Instances([]string{i.InstanceId}, ec2.NewFilter())
			if err != nil {
				return "", err
			}

			if len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
				return "", fmt.Errorf("instance not found: %s", i.InstanceId)
			}

			state["instance"] = &r.Reservations[0].Instances[0]
		}

		return "", errors.New("couldn't determine IP address for instance")
	}
}

// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
	return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
		privateKey := state["privateKey"].(string)

		keyring := new(ssh.SimpleKeychain)
		if err := keyring.AddPEMKey(privateKey); err != nil {
			return nil, fmt.Errorf("Error setting up SSH config: %s", err)
		}

		return &gossh.ClientConfig{
			User: username,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		}, nil
	}
}
<commit_msg>builder/amazon/common: sleep between API calls for SSHAddr<commit_after>package common

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"errors"
	"fmt"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/packer/communicator/ssh"
	"time"
)

// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name.
func SSHAddress(e *ec2.EC2, port int) func(map[string]interface{}) (string, error) {
	return func(state map[string]interface{}) (string, error) {
		for j := 0; j < 2; j++ {
			var host string
			i := state["instance"].(*ec2.Instance)
			if i.DNSName != "" {
				host = i.DNSName
			} else if i.VpcId == "" {
				host = i.PrivateIpAddress
			}

			if host != "" {
				return fmt.Sprintf("%s:%d", host, port), nil
			}

			r, err := e.Instances([]string{i.InstanceId}, ec2.NewFilter())
			if err != nil {
				return "", err
			}

			if len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 {
				return "", fmt.Errorf("instance not found: %s", i.InstanceId)
			}

			state["instance"] = &r.Reservations[0].Instances[0]
			time.Sleep(1 * time.Second)
		}

		return "", errors.New("couldn't determine IP address for instance")
	}
}

// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
	return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
		privateKey := state["privateKey"].(string)

		keyring := new(ssh.SimpleKeychain)
		if err := keyring.AddPEMKey(privateKey); err != nil {
			return nil, fmt.Errorf("Error setting up SSH config: %s", err)
		}

		return &gossh.ClientConfig{
			User: username,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		}, nil
	}
}
<|endoftext|>


<commit_before>package rpg

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"time"

	"golang.org/x/image/colornames"

	"github.com/aerth/rpg/assets"
	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
)

var DefaultSpriteRectangle = pixel.R(-16, -16, 16, 16)

type ObjectType int

const (
	O_NONE ObjectType = iota
	O_TILE
	O_BLOCK
	O_INVISIBLE
	O_SPECIAL
	O_WIN
	O_DYNAMIC // loot, doors
)

//var DefaultSpriteRectangle = pixel.R(-16, 0, 16, 32)
//var DefaultSpriteRectangle = pixel.R(-16, 0, 16, 32)

func init() {
	rand.Seed(time.Now().UnixNano())
}

type Object struct {
	Loc       pixel.Vec        `json:"L"`
	Rect      pixel.Rect       `json:"-"`
	Type      ObjectType       `json:"T,ObjectType"`
	P         ObjectProperties `json:",omitempty"`
	SpriteNum int              `json:"S,omitempty"`
	Sprite    *pixel.Sprite    `json:"-"`
	W         *World           `json:"-"`
	//	Contains  []Item           `json:"-"`
}

func (o Object) String() string {
	return fmt.Sprintf("%s %s %s %v", o.Loc, o.Rect, o.Type, o.SpriteNum)
}

type ObjectProperties struct {
	Invisible bool `json:",omitempty"`
	//	Tile      bool `json:",omitempty"`
	//	Block     bool `json:",omitempty"`
	Special bool `json:",omitempty"`
}

func NewTile(loc pixel.Vec) Object {
	return Object{
		Loc:  loc,
		Rect: pixel.Rect{loc.Sub(pixel.V(16, 16)), loc.Add(pixel.V(16, 16))},
		Type: O_TILE,
	}
}
func NewBlock(loc pixel.Vec) Object {
	return Object{
		Loc:  loc,
		Rect: pixel.Rect{loc.Sub(pixel.V(16, 16)), loc.Add(pixel.V(16, 16))},
		Type: O_BLOCK,
	}
}

func NewTileBox(rect pixel.Rect) Object {
	return Object{
		Rect: rect,
		Type: O_TILE,
	}
}
func NewBlockBox(rect pixel.Rect) Object {
	return Object{
		Rect: rect,
		Type: O_BLOCK,
	}
}

var TransparentBlue = pixel.ToRGBA(colornames.Blue).Scaled(0.4)
var TransparentRed = pixel.ToRGBA(colornames.Red).Scaled(0.4)
var TransparentPurple = pixel.ToRGBA(colornames.Purple).Scaled(0.4)

func (o Object) Highlight(win pixel.Target, color pixel.RGBA) {
	imd := imdraw.New(nil)
	imd.Color = color
	imd.Push(o.Rect.Min, o.Rect.Max)
	imd.Rectangle(1)
	imd.Draw(win)
}
func (o Object) Draw(win pixel.Target, spritesheet pixel.Picture, sheetFrames []*pixel.Sprite) {
	//	r := pixel.Rect{o.Loc, o.w.Char.Rect.Center()}
	//	sz := r.Size()
	//	if sz.X > 1000 || sz.Y > 1000 {
	//		return
	//	}
	if o.P.Invisible {
		return
	}
	if o.Sprite == nil && o.Type != O_DYNAMIC {
		if 0 > o.SpriteNum || o.SpriteNum > len(sheetFrames) {
			log.Printf("unloadable sprite: %v/%v", o.SpriteNum, len(sheetFrames))
			return
		}
		o.Sprite = sheetFrames[o.SpriteNum]
	}
	if o.Sprite == nil && o.Type == O_DYNAMIC {
		o.Sprite = sheetFrames[0]
	}
	//	if o.Loc == pixel.ZV && o.Rect.Size().Y != 32 {
	//		log.Println(o.Rect.Size(), "cool rectangle", o.SpriteNum)
	//		DrawPattern(win, o.Sprite, o.Rect, 0)
	//	} else {
	o.Sprite.Draw(win, pixel.IM.Moved(o.Loc))
	//	}

}
func (w *World) LoadMapFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return w.loadmap(b)
}
func (w *World) LoadMap(path string) error {
	b, err := assets.Asset(path)
	if err != nil {
		return err
	}
	return w.loadmap(b)
}
func (w *World) loadmap(b []byte) error {
	var things = []Object{}
	err := json.Unmarshal(b, &things)
	if err != nil {
		return fmt.Errorf("invalid map: %v", err)
	}
	total := len(things)
	for i, t := range things {
		t.W = w
		t.Rect = DefaultSpriteRectangle.Moved(t.Loc)
		switch t.SpriteNum {
		case 53: // water
			t.Type = O_BLOCK
		default:
		}

		switch t.Type {
		case O_BLOCK:
			//log.Printf("%v/%v block object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
			w.Blocks = append(w.Blocks, t)
		case O_TILE:
			//log.Printf("%v/%v tile object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
			w.Tiles = append(w.Tiles, t)

		default: //
			log.Printf("%v/%v skipping bad object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
		}
	}
	log.Printf("map has %v blocks, %v tiles", len(w.Blocks), len(w.Tiles))
	if len(w.Blocks) == 0 && len(w.Tiles) == 0 {
		return fmt.Errorf("invalid map")
	}
	return nil
}

// assumes only tiles are given
func FindRandomTile(os []Object) pixel.Vec {
	if len(os) == 0 {
		panic("no objects")
	}
	ob := os[rand.Intn(len(os))]
	if ob.Loc != pixel.ZV && ob.SpriteNum != 0 && ob.Type == O_TILE {
		return ob.Rect.Center()
	}
	return FindRandomTile(os)
}

func GetObjects(objects []Object, position pixel.Vec) []Object {
	var good []Object
	for _, o := range objects {
		if o.Rect.Contains(position) {
			good = append(good, o)
		}
	}
	return good
}

func GetTiles(objects []Object) []Object {
	var tiles []Object
	for _, o := range objects {
		if o.Type == O_TILE {
			tiles = append(tiles, o)
		}
	}
	return tiles
}

func TilesAt(objects []Object, position pixel.Vec) []Object {
	var good []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if DefaultSpriteRectangle.Moved(o.Loc).Contains(position) && o.Type == O_TILE {
				good = append(good, o)
			}

		}
	}
	return good

}
func GetObjectsAt(objects []Object, position pixel.Vec) []Object {
	var good []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if DefaultSpriteRectangle.Moved(o.Loc).Contains(position) {
				good = append(good, o)
			}

		}
	}
	return good

}

func GetBlocks(objects []Object, position pixel.Vec) []Object {
	var bad []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if o.Type == O_BLOCK {
				bad = append(bad, o)
			}

		}
	}
	return bad
}

// GetNeighbors gets the neighboring tiles
func (o Object) GetNeighbors() []Object {
	neighbors := []Object{}
	of := 32.0
	for _, offset := range [][]float64{
		{-of, 0},
		{of, 0},
		{0, -of},
		{0, of},
	} {
		if n := o.W.Tile(pixel.V(o.Rect.Center().X+offset[0], o.Rect.Center().Y+offset[1])); n.Type == o.Type {
			neighbors = append(neighbors, n)
		}
	}
	return neighbors

}
func (w *World) drawTiles(path string) error {
	spritesheet, spritemap := LoadSpriteSheet(path)
	// layers (TODO: slice?)
	// batch sprite drawing
	globebatch := pixel.NewBatch(&pixel.TrianglesData{}, spritesheet)
	// water world 67 wood, 114 117 182 special, 121 135 dirt, 128 blank, 20 grass
	//      rpg.DrawPattern(batch, spritemap[53], pixel.R(-3000, -3000, 3000, 3000), 100)

	globebatch.Clear()
	// draw it on to canvasglobe
	for _, o := range w.Tiles {
		o.Draw(globebatch, spritesheet, spritemap)
	}
	for _, o := range w.Blocks {
		o.Draw(globebatch, spritesheet, spritemap)
	}
	w.Batches[EntityType(-1)] = globebatch
	return nil
}

func TileNear(all []Object, loc pixel.Vec) Object {
	tile := TilesAt(all, loc)
	snap := 32.00
	loc.X = float64(int(loc.X/snap)) * snap
	loc.Y = float64(int(loc.Y/snap)) * snap
	radius := 1.00
	oloc := loc
	if len(tile) > 0 {
		oloc = tile[0].Loc
	}
	log.Println("looking for loc:", loc)
	for i := 0; i < len(all); i++ {
		if loc == oloc {
			loc.X += 16
			continue
		}
		//log.Println("Checking loc", loc)
		os := TilesAt(all, loc)
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}
		os = TilesAt(all, loc.Scaled(-2))
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}

		loc.X += radius * 16
		loc.Y += radius * 16
		if i%4 == 1 {
			radius++
		}
	}
	return Object{Type: O_NONE}

}
<commit_msg>improve (but not fix) TileNear()<commit_after>package rpg

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"time"

	"golang.org/x/image/colornames"

	"github.com/aerth/rpg/assets"
	"github.com/faiface/pixel"
	"github.com/faiface/pixel/imdraw"
)

var DefaultSpriteRectangle = pixel.R(-16, -16, 16, 16)

type ObjectType int

const (
	O_NONE ObjectType = iota
	O_TILE
	O_BLOCK
	O_INVISIBLE
	O_SPECIAL
	O_WIN
	O_DYNAMIC // loot, doors
)

//var DefaultSpriteRectangle = pixel.R(-16, 0, 16, 32)
//var DefaultSpriteRectangle = pixel.R(-16, 0, 16, 32)

func init() {
	rand.Seed(time.Now().UnixNano())
}

type Object struct {
	Loc       pixel.Vec        `json:"L"`
	Rect      pixel.Rect       `json:"-"`
	Type      ObjectType       `json:"T,ObjectType"`
	P         ObjectProperties `json:",omitempty"`
	SpriteNum int              `json:"S,omitempty"`
	Sprite    *pixel.Sprite    `json:"-"`
	W         *World           `json:"-"`
	//	Contains  []Item           `json:"-"`
}

func (o Object) String() string {
	return fmt.Sprintf("%s %s %s %v", o.Loc, o.Rect, o.Type, o.SpriteNum)
}

type ObjectProperties struct {
	Invisible bool `json:",omitempty"`
	//	Tile      bool `json:",omitempty"`
	//	Block     bool `json:",omitempty"`
	Special bool `json:",omitempty"`
}

func NewTile(loc pixel.Vec) Object {
	return Object{
		Loc:  loc,
		Rect: pixel.Rect{loc.Sub(pixel.V(16, 16)), loc.Add(pixel.V(16, 16))},
		Type: O_TILE,
	}
}
func NewBlock(loc pixel.Vec) Object {
	return Object{
		Loc:  loc,
		Rect: pixel.Rect{loc.Sub(pixel.V(16, 16)), loc.Add(pixel.V(16, 16))},
		Type: O_BLOCK,
	}
}

func NewTileBox(rect pixel.Rect) Object {
	return Object{
		Rect: rect,
		Type: O_TILE,
	}
}
func NewBlockBox(rect pixel.Rect) Object {
	return Object{
		Rect: rect,
		Type: O_BLOCK,
	}
}

var TransparentBlue = pixel.ToRGBA(colornames.Blue).Scaled(0.4)
var TransparentRed = pixel.ToRGBA(colornames.Red).Scaled(0.4)
var TransparentPurple = pixel.ToRGBA(colornames.Purple).Scaled(0.4)

func (o Object) Highlight(win pixel.Target, color pixel.RGBA) {
	imd := imdraw.New(nil)
	imd.Color = color
	imd.Push(o.Rect.Min, o.Rect.Max)
	imd.Rectangle(1)
	imd.Draw(win)
}
func (o Object) Draw(win pixel.Target, spritesheet pixel.Picture, sheetFrames []*pixel.Sprite) {
	//	r := pixel.Rect{o.Loc, o.w.Char.Rect.Center()}
	//	sz := r.Size()
	//	if sz.X > 1000 || sz.Y > 1000 {
	//		return
	//	}
	if o.P.Invisible {
		return
	}
	if o.Sprite == nil && o.Type != O_DYNAMIC {
		if 0 > o.SpriteNum || o.SpriteNum > len(sheetFrames) {
			log.Printf("unloadable sprite: %v/%v", o.SpriteNum, len(sheetFrames))
			return
		}
		o.Sprite = sheetFrames[o.SpriteNum]
	}
	if o.Sprite == nil && o.Type == O_DYNAMIC {
		o.Sprite = sheetFrames[0]
	}
	//	if o.Loc == pixel.ZV && o.Rect.Size().Y != 32 {
	//		log.Println(o.Rect.Size(), "cool rectangle", o.SpriteNum)
	//		DrawPattern(win, o.Sprite, o.Rect, 0)
	//	} else {
	o.Sprite.Draw(win, pixel.IM.Moved(o.Loc))
	//	}

}
func (w *World) LoadMapFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return w.loadmap(b)
}
func (w *World) LoadMap(path string) error {
	b, err := assets.Asset(path)
	if err != nil {
		return err
	}
	return w.loadmap(b)
}
func (w *World) loadmap(b []byte) error {
	var things = []Object{}
	err := json.Unmarshal(b, &things)
	if err != nil {
		return fmt.Errorf("invalid map: %v", err)
	}
	total := len(things)
	for i, t := range things {
		t.W = w
		t.Rect = DefaultSpriteRectangle.Moved(t.Loc)
		switch t.SpriteNum {
		case 53: // water
			t.Type = O_BLOCK
		default:
		}

		switch t.Type {
		case O_BLOCK:
			//log.Printf("%v/%v block object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
			w.Blocks = append(w.Blocks, t)
		case O_TILE:
			//log.Printf("%v/%v tile object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
			w.Tiles = append(w.Tiles, t)

		default: //
			log.Printf("%v/%v skipping bad object: %s %v %s", i, total, t.Loc, t.SpriteNum, t.Type)
		}
	}
	log.Printf("map has %v blocks, %v tiles", len(w.Blocks), len(w.Tiles))
	if len(w.Blocks) == 0 && len(w.Tiles) == 0 {
		return fmt.Errorf("invalid map")
	}
	return nil
}

// assumes only tiles are given
func FindRandomTile(os []Object) pixel.Vec {
	if len(os) == 0 {
		panic("no objects")
	}
	ob := os[rand.Intn(len(os))]
	if ob.Loc != pixel.ZV && ob.SpriteNum != 0 && ob.Type == O_TILE {
		return ob.Rect.Center()
	}
	return FindRandomTile(os)
}

func GetObjects(objects []Object, position pixel.Vec) []Object {
	var good []Object
	for _, o := range objects {
		if o.Rect.Contains(position) {
			good = append(good, o)
		}
	}
	return good
}

func GetTiles(objects []Object) []Object {
	var tiles []Object
	for _, o := range objects {
		if o.Type == O_TILE {
			tiles = append(tiles, o)
		}
	}
	return tiles
}

func TilesAt(objects []Object, position pixel.Vec) []Object {
	var good []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if DefaultSpriteRectangle.Moved(o.Loc).Contains(position) && o.Type == O_TILE {
				good = append(good, o)
			}

		}
	}
	return good

}
func GetObjectsAt(objects []Object, position pixel.Vec) []Object {
	var good []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if DefaultSpriteRectangle.Moved(o.Loc).Contains(position) {
				good = append(good, o)
			}

		}
	}
	return good

}

func GetBlocks(objects []Object, position pixel.Vec) []Object {
	var bad []Object
	all := GetObjects(objects, position)
	if len(all) > 0 {
		for _, o := range all {
			if o.Type == O_BLOCK {
				bad = append(bad, o)
			}

		}
	}
	return bad
}

// GetNeighbors gets the neighboring tiles
func (o Object) GetNeighbors() []Object {
	neighbors := []Object{}
	of := 32.0
	for _, offset := range [][]float64{
		{-of, 0},
		{of, 0},
		{0, -of},
		{0, of},
	} {
		if n := o.W.Tile(pixel.V(o.Rect.Center().X+offset[0], o.Rect.Center().Y+offset[1])); n.Type == o.Type {
			neighbors = append(neighbors, n)
		}
	}
	return neighbors

}
func (w *World) drawTiles(path string) error {
	spritesheet, spritemap := LoadSpriteSheet(path)
	// layers (TODO: slice?)
	// batch sprite drawing
	globebatch := pixel.NewBatch(&pixel.TrianglesData{}, spritesheet)
	// water world 67 wood, 114 117 182 special, 121 135 dirt, 128 blank, 20 grass
	//      rpg.DrawPattern(batch, spritemap[53], pixel.R(-3000, -3000, 3000, 3000), 100)

	globebatch.Clear()
	// draw it on to canvasglobe
	for _, o := range w.Tiles {
		o.Draw(globebatch, spritesheet, spritemap)
	}
	for _, o := range w.Blocks {
		o.Draw(globebatch, spritesheet, spritemap)
	}
	w.Batches[EntityType(-1)] = globebatch
	return nil
}

func TileNear(all []Object, loc pixel.Vec) Object {
	tile := TilesAt(all, loc)
	snap := 32.00
	loc.X = float64(int(loc.X/snap)) * snap
	loc.Y = float64(int(loc.Y/snap)) * snap
	radius := 1.00
	oloc := loc
	if len(tile) > 0 {
		oloc = tile[0].Loc
	}
	log.Println("looking for loc:", loc)
	for i := 0; i < len(all); i++ {
		loc.X += radius * 16
		loc.Y += radius * 16
		if loc == oloc {
			continue
		}
		log.Println("Checking loc", loc)
		os := TilesAt(all, loc)
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}
		loc2 := loc
		loc2.X = -loc.X
		os = TilesAt(all, loc.Scaled(-1))
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}
		os = TilesAt(all, loc2.Scaled(1))
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}

		os = TilesAt(all, loc2.Scaled(-1))
		if len(os) > 0 {
			if os[0].Loc == pixel.ZV || os[0].Loc == oloc {
				continue
			}
			return os[0]
		}

		if i%4 == 0 {
			radius++
			loc.X += 16
		}
	}
	log.Println("not found")
	return Object{Type: O_NONE}

}
<|endoftext|>


<commit_before>package main

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"time"
)

func checkErr(err error) {
	if err != nil {
		log.Fatalln("Error:", err)
	}
}

type Backend struct {
	Upstream string `json:"backend"`
	Local    string `json:"local"`
	input    chan []byte
	quit     chan struct{}
}

type Listener struct {
	Address string `json:"address"`
	quit    chan struct{}
}

type udproxyConfig struct {
	Backends map[string]Backend `json:"backends,inline"`
	Listen   []Listener         `json:"listen"`
	Clients  map[string]string  `json:"clients"`
}

func backend(local, remote string, quit chan struct{}, input chan []byte) {
	laddr, err := net.ResolveUDPAddr("udp", local)
	checkErr(err)

	raddr, err := net.ResolveUDPAddr("udp", remote)
	checkErr(err)

	conn, err := net.DialUDP("udp", laddr, raddr)
	checkErr(err)

	defer conn.Close()

	log.Println("Backend connection ready for action", local, remote)

	for {
		select {
		case <-quit:
			return
		case msg := <-input:
			_, err := conn.Write(msg)
			checkErr(err)
		}
	}
}

func spawnBackend(local, remote string) (chan struct{}, chan []byte) {
	quit := make(chan struct{})
	input := make(chan []byte)

	go backend(local, remote, quit, input)

	return quit, input
}

func listener(listen string, quit chan struct{}) {
	buf := make([]byte, 65535)

	laddr, err := net.ResolveUDPAddr("udp", listen)
	checkErr(err)

	conn, err := net.ListenUDP("udp", laddr)
	checkErr(err)

	defer conn.Close()
	log.Println("Listener ready for action", listen)

	for {
		select {
		case <-quit:
			return
		default:
			conn.SetReadDeadline(time.Now().Add(90 * time.Millisecond))
			n, addr, err := conn.ReadFromUDP(buf)
			if err, ok := err.(net.Error); ok && err.Timeout() {
				continue
			}
			if err != nil {
				log.Println("Error:", err)
			}
			log.Print("Received |", string(buf[0:n]), "| from ", addr)
		}
	}
}

func spawnListener(listen string) chan struct{} {
	quit := make(chan struct{})

	go listener(listen, quit)

	return quit
}

func main() {
	var config udproxyConfig
	quit := make(chan struct{}, 1)

	if len(os.Args) < 2 {
		log.Fatalln("Usage:", os.Args[0], "<config file>")
	}

	data, err := ioutil.ReadFile(os.Args[1])
	checkErr(err)

	err = yaml.Unmarshal(data, &config)
	checkErr(err)

	data, err = yaml.Marshal(config)
	checkErr(err)
	log.Print("Parsed configuration:\n", string(data))

	for name, backend := range config.Backends {
		quit, input := spawnBackend(backend.Local, backend.Upstream)
		config.Backends[name] = Backend{
			Upstream: backend.Upstream,
			Local:    backend.Local,
			input:    input,
			quit:     quit,
		}
	}

	for i, listen := range config.Listen {
		quit := spawnListener(listen.Address)
		config.Listen[i] = Listener{
			Address: listen.Address,
			quit:    quit,
		}
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt)

		<-c
		log.Println("Shutting down!")
		for name, backend := range config.Backends {
			log.Println("Stopping backend", name)
			backend.quit <- struct{}{}
		}

		for _, listen := range config.Listen {
			log.Println("Stopping listen socket", listen.Address)
			listen.quit <- struct{}{}
		}

		log.Println("Writing config!")
		data, err = yaml.Marshal(config)
		checkErr(err)

		err = ioutil.WriteFile(os.Args[1], data, 0600)
		checkErr(err)

		log.Println("Finally stopping!")
		quit <- struct{}{}
	}()

	<-quit
}
<commit_msg>Dispatch messages and save mappings.<commit_after>package main

import (
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"sync"
	"time"
)

func checkErr(err error) {
	if err != nil {
		log.Fatalln("Error:", err)
	}
}

type Backend struct {
	Upstream string `json:"backend"`
	Local    string `json:"local"`
	input    chan []byte
	quit     chan struct{}
}

type Listener struct {
	Address string `json:"address"`
	quit    chan struct{}
}

type udproxyConfig struct {
	Backends map[string]Backend `json:"backends,inline"`
	Listen   []Listener         `json:"listen"`
	Clients  map[string]string  `json:"clients"`
}

func backend(local, remote string, quit chan struct{}, input chan []byte) {
	laddr, err := net.ResolveUDPAddr("udp", local)
	checkErr(err)

	raddr, err := net.ResolveUDPAddr("udp", remote)
	checkErr(err)

	conn, err := net.DialUDP("udp", laddr, raddr)
	checkErr(err)

	defer conn.Close()

	log.Println("Backend connection ready for action", local, remote)

	for {
		select {
		case <-quit:
			return
		case msg := <-input:
			_, err := conn.Write(msg)
			if err != nil {
				log.Println("Couldn't send message:", err)
			}
		}
	}
}

func spawnBackend(local, remote string) (chan struct{}, chan []byte) {
	quit := make(chan struct{})
	input := make(chan []byte)

	go backend(local, remote, quit, input)

	return quit, input
}

func listener(listen string, quit chan struct{}, dispatcher func(net.IP, []byte)) {
	buf := make([]byte, 32765)

	laddr, err := net.ResolveUDPAddr("udp", listen)
	checkErr(err)

	conn, err := net.ListenUDP("udp", laddr)
	checkErr(err)

	defer conn.Close()
	log.Println("Listener ready for action", listen)

	for {
		select {
		case <-quit:
			return
		default:
			conn.SetReadDeadline(time.Now().Add(90 * time.Millisecond))
			n, addr, err := conn.ReadFromUDP(buf)
			if err, ok := err.(net.Error); ok && err.Timeout() {
				continue
			}
			if err != nil {
				log.Println("Error:", err)
			}
			log.Print("Received |", string(buf[0:n]), "| from ", addr)
			dispatcher(addr.IP, buf)
		}
	}
}

func spawnListener(listen string, dispatcher func(net.IP, []byte)) chan struct{} {
	quit := make(chan struct{})

	go listener(listen, quit, dispatcher)

	return quit
}

func main() {
	var config udproxyConfig
	var configLock sync.Mutex
	var backends []string
	quit := make(chan struct{}, 1)

	if len(os.Args) < 2 {
		log.Fatalln("Usage:", os.Args[0], "<config file>")
	}

	data, err := ioutil.ReadFile(os.Args[1])
	checkErr(err)

	err = yaml.Unmarshal(data, &config)
	checkErr(err)

	data, err = yaml.Marshal(config)
	checkErr(err)
	log.Print("Parsed configuration:\n", string(data))

	rand.Seed(time.Now().UnixNano())

	for name, backend := range config.Backends {
		backends = append(backends, name)
		quit, input := spawnBackend(backend.Local, backend.Upstream)
		config.Backends[name] = Backend{
			Upstream: backend.Upstream,
			Local:    backend.Local,
			input:    input,
			quit:     quit,
		}
	}

	dispatcher := func(ip net.IP, buf []byte) {
		configLock.Lock()
		defer configLock.Unlock()
		if _, ok := config.Clients[ip.String()]; ok {
			config.Backends[config.Clients[ip.String()]].input <- buf
		} else {
			backend := backends[rand.Intn(len(backends))]
			log.Println("Client", ip, "not found in map, mapping to backend", backend)
			config.Clients[ip.String()] = backend
			config.Backends[backend].input <- buf
		}
	}

	for i, listen := range config.Listen {
		quit := spawnListener(listen.Address, dispatcher)
		config.Listen[i] = Listener{
			Address: listen.Address,
			quit:    quit,
		}
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt)

		<-c
		log.Println("Shutting down!")
		for name, backend := range config.Backends {
			log.Println("Stopping backend", name)
			backend.quit <- struct{}{}
		}

		for _, listen := range config.Listen {
			log.Println("Stopping listen socket", listen.Address)
			listen.quit <- struct{}{}
		}

		log.Println("Writing config!")
		configLock.Lock()
		defer configLock.Unlock()
		data, err = yaml.Marshal(config)
		checkErr(err)

		err = ioutil.WriteFile(os.Args[1], data, 0600)
		checkErr(err)

		log.Println("Finally stopping!")
		quit <- struct{}{}
	}()

	<-quit
}
<|endoftext|>


<commit_before>package unicreds

import (
	"testing"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/versent/unicreds/mocks"
)

var (
	Table       = "credential-store"
	dsPlainText = []byte{
		0x6a, 0xcf, 0xeb, 0xd6, 0xe9, 0xa6, 0x19, 0xc1,
		0x38, 0xb9, 0xfc, 0x2d, 0x53, 0x23, 0x4d, 0x78,
		0x85, 0x48, 0x96, 0xd6, 0xd2, 0xf6, 0xf4, 0x42,
		0x99, 0x9d, 0x8e, 0xa9, 0xed, 0xf0, 0xb3, 0xf2,
	}

	itemsFixture = []map[string]*dynamodb.AttributeValue{
		{
			"name":     &dynamodb.AttributeValue{S: aws.String("test")},
			"version":  &dynamodb.AttributeValue{S: aws.String("1")},
			"contents": &dynamodb.AttributeValue{S: aws.String("o8we1zr9GD+KstVv3x2YTeT2")},
			"hmac":     &dynamodb.AttributeValue{S: aws.String("1e2d485cf52ec57d9db5c05eda678b45eee8d3dabcc6c1ee7c0999712026f6aa")},
		},
	}
)

func init() {
	log.SetHandler(cli.Default)
}

func TestCredential(t *testing.T) {
	c := &Credential{}

	assert.Equal(t, c.CreatedAtDate(), CreatedAtNotAvailable)

	c.CreatedAt = 1458117788

	assert.NotEqual(t, c.CreatedAtDate(), CreatedAtNotAvailable)
}

func TestSetup(t *testing.T) {

	dsMock, _ := configureMock()

	dsMock.On("CreateTable",
		mock.AnythingOfType("*dynamodb.CreateTableInput")).Return(nil, nil)

	dto := &dynamodb.DescribeTableOutput{
		Table: &dynamodb.TableDescription{TableStatus: aws.String("ACTIVE")},
	}

	dsMock.On("DescribeTable",
		mock.AnythingOfType("*dynamodb.DescribeTableInput")).Return(dto, nil)

	err := Setup(&Table)

	assert.Nil(t, err)
}

func TestGetSecretNotFound(t *testing.T) {

	dsMock, _ := configureMock()

	qi := &dynamodb.QueryOutput{
		Items: []map[string]*dynamodb.AttributeValue{},
	}

	dsMock.On("Query", mock.AnythingOfType("*dynamodb.QueryInput")).Return(qi, nil)

	ds, err := GetSecret(&Table, "test")

	assert.Error(t, err, "Secret Not Found")
	assert.Nil(t, ds)
}

func TestGetSecret(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qi := &dynamodb.QueryOutput{
		Items: itemsFixture,
	}

	ki := &kms.DecryptOutput{Plaintext: dsPlainText}

	dsMock.On("Query", mock.AnythingOfType("*dynamodb.QueryInput")).Return(qi, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(ki, nil)

	ds, err := GetSecret(&Table, "test")

	assert.Nil(t, err)
	assert.Equal(t, ds.Secret, "something test 123")
}

func TestGetAllSecrets(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	ki := &kms.DecryptOutput{Plaintext: dsPlainText}

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(ki, nil)

	ds, err := GetAllSecrets(&Table, false)

	assert.Nil(t, err)
	assert.Len(t, ds, 1)
}

func TestGetAllSecretsDecryptFailed(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	awsErr := awserr.New("AccessDeniedException", "KMS access denied", nil)

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(nil, awsErr)

	ds, err := GetAllSecrets(&Table, true)

	assert.Nil(t, err)
	assert.Len(t, ds, 0)
}

func TestListSecrets(t *testing.T) {

	dsMock, _ := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)

	ds, err := ListSecrets(&Table, true)

	assert.Nil(t, err)
	assert.Len(t, ds, 1)
}

func configureMock() (*mocks.DynamoDBAPI, *mocks.KMSAPI) {
	dsMock := &mocks.DynamoDBAPI{}
	kmsMock := &mocks.KMSAPI{}

	dynamoSvc = dsMock
	kmsSvc = kmsMock

	return dsMock, kmsMock
}
<commit_msg>Update table name in the tests as well.<commit_after>package unicreds

import (
	"testing"

	"github.com/apex/log"
	"github.com/apex/log/handlers/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/versent/unicreds/mocks"
)

var (
	tableName   = "credential-store"
	dsPlainText = []byte{
		0x6a, 0xcf, 0xeb, 0xd6, 0xe9, 0xa6, 0x19, 0xc1,
		0x38, 0xb9, 0xfc, 0x2d, 0x53, 0x23, 0x4d, 0x78,
		0x85, 0x48, 0x96, 0xd6, 0xd2, 0xf6, 0xf4, 0x42,
		0x99, 0x9d, 0x8e, 0xa9, 0xed, 0xf0, 0xb3, 0xf2,
	}

	itemsFixture = []map[string]*dynamodb.AttributeValue{
		{
			"name":     &dynamodb.AttributeValue{S: aws.String("test")},
			"version":  &dynamodb.AttributeValue{S: aws.String("1")},
			"contents": &dynamodb.AttributeValue{S: aws.String("o8we1zr9GD+KstVv3x2YTeT2")},
			"hmac":     &dynamodb.AttributeValue{S: aws.String("1e2d485cf52ec57d9db5c05eda678b45eee8d3dabcc6c1ee7c0999712026f6aa")},
		},
	}
)

func init() {
	log.SetHandler(cli.Default)
}

func TestCredential(t *testing.T) {
	c := &Credential{}

	assert.Equal(t, c.CreatedAtDate(), CreatedAtNotAvailable)

	c.CreatedAt = 1458117788

	assert.NotEqual(t, c.CreatedAtDate(), CreatedAtNotAvailable)
}

func TestSetup(t *testing.T) {

	dsMock, _ := configureMock()

	dsMock.On("CreateTable",
		mock.AnythingOfType("*dynamodb.CreateTableInput")).Return(nil, nil)

	dto := &dynamodb.DescribeTableOutput{
		Table: &dynamodb.TableDescription{TableStatus: aws.String("ACTIVE")},
	}

	dsMock.On("DescribeTable",
		mock.AnythingOfType("*dynamodb.DescribeTableInput")).Return(dto, nil)

	err := Setup(&tableName)

	assert.Nil(t, err)
}

func TestGetSecretNotFound(t *testing.T) {

	dsMock, _ := configureMock()

	qi := &dynamodb.QueryOutput{
		Items: []map[string]*dynamodb.AttributeValue{},
	}

	dsMock.On("Query", mock.AnythingOfType("*dynamodb.QueryInput")).Return(qi, nil)

	ds, err := GetSecret(&tableName, "test")

	assert.Error(t, err, "Secret Not Found")
	assert.Nil(t, ds)
}

func TestGetSecret(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qi := &dynamodb.QueryOutput{
		Items: itemsFixture,
	}

	ki := &kms.DecryptOutput{Plaintext: dsPlainText}

	dsMock.On("Query", mock.AnythingOfType("*dynamodb.QueryInput")).Return(qi, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(ki, nil)

	ds, err := GetSecret(&tableName, "test")

	assert.Nil(t, err)
	assert.Equal(t, ds.Secret, "something test 123")
}

func TestGetAllSecrets(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	ki := &kms.DecryptOutput{Plaintext: dsPlainText}

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(ki, nil)

	ds, err := GetAllSecrets(&tableName, false)

	assert.Nil(t, err)
	assert.Len(t, ds, 1)
}

func TestGetAllSecretsDecryptFailed(t *testing.T) {

	dsMock, kmsMock := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	awsErr := awserr.New("AccessDeniedException", "KMS access denied", nil)

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)
	kmsMock.On("Decrypt", mock.AnythingOfType("*kms.DecryptInput")).Return(nil, awsErr)

	ds, err := GetAllSecrets(&tableName, true)

	assert.Nil(t, err)
	assert.Len(t, ds, 0)
}

func TestListSecrets(t *testing.T) {

	dsMock, _ := configureMock()

	qs := &dynamodb.ScanOutput{
		Count: aws.Int64(0),
		Items: itemsFixture,
	}

	dsMock.On("Scan", mock.AnythingOfType("*dynamodb.ScanInput")).Return(qs, nil)

	ds, err := ListSecrets(&tableName, true)

	assert.Nil(t, err)
	assert.Len(t, ds, 1)
}

func configureMock() (*mocks.DynamoDBAPI, *mocks.KMSAPI) {
	dsMock := &mocks.DynamoDBAPI{}
	kmsMock := &mocks.KMSAPI{}

	dynamoSvc = dsMock
	kmsSvc = kmsMock

	return dsMock, kmsMock
}
<|endoftext|>