<commit_before>package filesystem

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"time"

	"github.com/docker/distribution/context"
	storagedriver "github.com/docker/distribution/registry/storage/driver"
	"github.com/docker/distribution/registry/storage/driver/base"
	"github.com/docker/distribution/registry/storage/driver/factory"
)

const driverName = "filesystem"
const defaultRootDirectory = "/var/lib/registry"

func init() {
	factory.Register(driverName, &filesystemDriverFactory{})
}

// filesystemDriverFactory implements the factory.StorageDriverFactory interface
type filesystemDriverFactory struct{}

func (factory *filesystemDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
	return FromParameters(parameters), nil
}

type driver struct {
	rootDirectory string
}

type baseEmbed struct {
	base.Base
}

// Driver is a storagedriver.StorageDriver implementation backed by a local
// filesystem. All provided paths will be subpaths of the RootDirectory.
type Driver struct {
	baseEmbed
}

// FromParameters constructs a new Driver with a given parameters map
// Optional Parameters:
// - rootdirectory
func FromParameters(parameters map[string]interface{}) *Driver {
	var rootDirectory = defaultRootDirectory
	if parameters != nil {
		rootDir, ok := parameters["rootdirectory"]
		if ok {
			rootDirectory = fmt.Sprint(rootDir)
		}
	}
	return New(rootDirectory)
}

// New constructs a new Driver with a given rootDirectory
func New(rootDirectory string) *Driver {
	return &Driver{
		baseEmbed: baseEmbed{
			Base: base.Base{
				StorageDriver: &driver{
					rootDirectory: rootDirectory,
				},
			},
		},
	}
}

// Implement the storagedriver.StorageDriver interface

func (d *driver) Name() string {
	return driverName
}

// GetContent retrieves the content stored at "path" as a []byte.
func (d *driver) GetContent(ctx context.Context, path string) ([]byte, error) {
	rc, err := d.ReadStream(ctx, path, 0)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	p, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, err
	}

	return p, nil
}

// PutContent stores the []byte content at a location designated by "path".
func (d *driver) PutContent(ctx context.Context, subPath string, contents []byte) error {
	if _, err := d.WriteStream(ctx, subPath, 0, bytes.NewReader(contents)); err != nil {
		return err
	}

	return os.Truncate(d.fullPath(subPath), int64(len(contents)))
}

// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
// given byte offset.
func (d *driver) ReadStream(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
	file, err := os.OpenFile(d.fullPath(path), os.O_RDONLY, 0644)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: path}
		}

		return nil, err
	}

	seekPos, err := file.Seek(int64(offset), os.SEEK_SET)
	if err != nil {
		file.Close()
		return nil, err
	} else if seekPos < int64(offset) {
		file.Close()
		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
	}

	return file, nil
}

// WriteStream stores the contents of the provided io.Reader at a location
// designated by the given path.
func (d *driver) WriteStream(ctx context.Context, subPath string, offset int64, reader io.Reader) (nn int64, err error) {
	// TODO(stevvooe): This needs to be a requirement.
	// if !path.IsAbs(subPath) {
	// 	return fmt.Errorf("absolute path required: %q", subPath)
	// }

	fullPath := d.fullPath(subPath)
	parentDir := path.Dir(fullPath)
	if err := os.MkdirAll(parentDir, 0755); err != nil {
		return 0, err
	}

	fp, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		// TODO(stevvooe): A few missing conditions in storage driver:
		//	1. What if the path is already a directory?
		//  2. Should number 1 be exposed explicitly in storagedriver?
		//	2. Can this path not exist, even if we create above?
		return 0, err
	}
	defer fp.Close()

	nn, err = fp.Seek(offset, os.SEEK_SET)
	if err != nil {
		return 0, err
	}

	if nn != offset {
		return 0, fmt.Errorf("bad seek to %v, expected %v in fp=%v", offset, nn, fp)
	}

	return io.Copy(fp, reader)
}

// Stat retrieves the FileInfo for the given path, including the current size
// in bytes and the creation time.
func (d *driver) Stat(ctx context.Context, subPath string) (storagedriver.FileInfo, error) {
	fullPath := d.fullPath(subPath)

	fi, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: subPath}
		}

		return nil, err
	}

	return fileInfo{
		path:     subPath,
		FileInfo: fi,
	}, nil
}

// List returns a list of the objects that are direct descendants of the given
// path.
func (d *driver) List(ctx context.Context, subPath string) ([]string, error) {
	fullPath := d.fullPath(subPath)

	dir, err := os.Open(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: subPath}
		}
		return nil, err
	}

	defer dir.Close()

	fileNames, err := dir.Readdirnames(0)
	if err != nil {
		return nil, err
	}

	keys := make([]string, 0, len(fileNames))
	for _, fileName := range fileNames {
		keys = append(keys, path.Join(subPath, fileName))
	}

	return keys, nil
}

// Move moves an object stored at sourcePath to destPath, removing the original
// object.
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
	source := d.fullPath(sourcePath)
	dest := d.fullPath(destPath)

	if _, err := os.Stat(source); os.IsNotExist(err) {
		return storagedriver.PathNotFoundError{Path: sourcePath}
	}

	if err := os.MkdirAll(path.Dir(dest), 0755); err != nil {
		return err
	}

	err := os.Rename(source, dest)
	return err
}

// Delete recursively deletes all objects stored at "path" and its subpaths.
func (d *driver) Delete(ctx context.Context, subPath string) error {
	fullPath := d.fullPath(subPath)

	_, err := os.Stat(fullPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	} else if err != nil {
		return storagedriver.PathNotFoundError{Path: subPath}
	}

	err = os.RemoveAll(fullPath)
	return err
}

// URLFor returns a URL which may be used to retrieve the content stored at the given path.
// May return an UnsupportedMethodErr in certain StorageDriver implementations.
func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) {
	return "", storagedriver.ErrUnsupportedMethod{}
}

// fullPath returns the absolute path of a key within the Driver's storage.
func (d *driver) fullPath(subPath string) string {
	return path.Join(d.rootDirectory, subPath)
}

type fileInfo struct {
	os.FileInfo
	path string
}

var _ storagedriver.FileInfo = fileInfo{}

// Path provides the full path of the target of this file info.
func (fi fileInfo) Path() string {
	return fi.path
}

// Size returns current length in bytes of the file. The return value can
// be used to write to the end of the file at path. The value is
// meaningless if IsDir returns true.
func (fi fileInfo) Size() int64 {
	if fi.IsDir() {
		return 0
	}

	return fi.FileInfo.Size()
}

// ModTime returns the modification time for the file. For backends that
// don't have a modification time, the creation time should be returned.
func (fi fileInfo) ModTime() time.Time {
	return fi.FileInfo.ModTime()
}

// IsDir returns true if the path is a directory.
func (fi fileInfo) IsDir() bool {
	return fi.FileInfo.IsDir()
}
<commit_msg>Relaxes filesystem driver permissions to 0777 (dirs) and 0666 (files)<commit_after>package filesystem

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"time"

	"github.com/docker/distribution/context"
	storagedriver "github.com/docker/distribution/registry/storage/driver"
	"github.com/docker/distribution/registry/storage/driver/base"
	"github.com/docker/distribution/registry/storage/driver/factory"
)

const driverName = "filesystem"
const defaultRootDirectory = "/var/lib/registry"

func init() {
	factory.Register(driverName, &filesystemDriverFactory{})
}

// filesystemDriverFactory implements the factory.StorageDriverFactory interface
type filesystemDriverFactory struct{}

func (factory *filesystemDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
	return FromParameters(parameters), nil
}

type driver struct {
	rootDirectory string
}

type baseEmbed struct {
	base.Base
}

// Driver is a storagedriver.StorageDriver implementation backed by a local
// filesystem. All provided paths will be subpaths of the RootDirectory.
type Driver struct {
	baseEmbed
}

// FromParameters constructs a new Driver with a given parameters map
// Optional Parameters:
// - rootdirectory
func FromParameters(parameters map[string]interface{}) *Driver {
	var rootDirectory = defaultRootDirectory
	if parameters != nil {
		rootDir, ok := parameters["rootdirectory"]
		if ok {
			rootDirectory = fmt.Sprint(rootDir)
		}
	}
	return New(rootDirectory)
}

// New constructs a new Driver with a given rootDirectory
func New(rootDirectory string) *Driver {
	return &Driver{
		baseEmbed: baseEmbed{
			Base: base.Base{
				StorageDriver: &driver{
					rootDirectory: rootDirectory,
				},
			},
		},
	}
}

// Implement the storagedriver.StorageDriver interface

func (d *driver) Name() string {
	return driverName
}

// GetContent retrieves the content stored at "path" as a []byte.
func (d *driver) GetContent(ctx context.Context, path string) ([]byte, error) {
	rc, err := d.ReadStream(ctx, path, 0)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	p, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, err
	}

	return p, nil
}

// PutContent stores the []byte content at a location designated by "path".
func (d *driver) PutContent(ctx context.Context, subPath string, contents []byte) error {
	if _, err := d.WriteStream(ctx, subPath, 0, bytes.NewReader(contents)); err != nil {
		return err
	}

	return os.Truncate(d.fullPath(subPath), int64(len(contents)))
}

// ReadStream retrieves an io.ReadCloser for the content stored at "path" with a
// given byte offset.
func (d *driver) ReadStream(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
	file, err := os.OpenFile(d.fullPath(path), os.O_RDONLY, 0644)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: path}
		}

		return nil, err
	}

	seekPos, err := file.Seek(int64(offset), os.SEEK_SET)
	if err != nil {
		file.Close()
		return nil, err
	} else if seekPos < int64(offset) {
		file.Close()
		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset}
	}

	return file, nil
}

// WriteStream stores the contents of the provided io.Reader at a location
// designated by the given path.
func (d *driver) WriteStream(ctx context.Context, subPath string, offset int64, reader io.Reader) (nn int64, err error) {
	// TODO(stevvooe): This needs to be a requirement.
	// if !path.IsAbs(subPath) {
	// 	return fmt.Errorf("absolute path required: %q", subPath)
	// }

	fullPath := d.fullPath(subPath)
	parentDir := path.Dir(fullPath)
	if err := os.MkdirAll(parentDir, 0777); err != nil {
		return 0, err
	}

	fp, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		// TODO(stevvooe): A few missing conditions in storage driver:
		//	1. What if the path is already a directory?
		//  2. Should number 1 be exposed explicitly in storagedriver?
		//	2. Can this path not exist, even if we create above?
		return 0, err
	}
	defer fp.Close()

	nn, err = fp.Seek(offset, os.SEEK_SET)
	if err != nil {
		return 0, err
	}

	if nn != offset {
		return 0, fmt.Errorf("bad seek to %v, expected %v in fp=%v", offset, nn, fp)
	}

	return io.Copy(fp, reader)
}

// Stat retrieves the FileInfo for the given path, including the current size
// in bytes and the creation time.
func (d *driver) Stat(ctx context.Context, subPath string) (storagedriver.FileInfo, error) {
	fullPath := d.fullPath(subPath)

	fi, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: subPath}
		}

		return nil, err
	}

	return fileInfo{
		path:     subPath,
		FileInfo: fi,
	}, nil
}

// List returns a list of the objects that are direct descendants of the given
// path.
func (d *driver) List(ctx context.Context, subPath string) ([]string, error) {
	fullPath := d.fullPath(subPath)

	dir, err := os.Open(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, storagedriver.PathNotFoundError{Path: subPath}
		}
		return nil, err
	}

	defer dir.Close()

	fileNames, err := dir.Readdirnames(0)
	if err != nil {
		return nil, err
	}

	keys := make([]string, 0, len(fileNames))
	for _, fileName := range fileNames {
		keys = append(keys, path.Join(subPath, fileName))
	}

	return keys, nil
}

// Move moves an object stored at sourcePath to destPath, removing the original
// object.
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
	source := d.fullPath(sourcePath)
	dest := d.fullPath(destPath)

	if _, err := os.Stat(source); os.IsNotExist(err) {
		return storagedriver.PathNotFoundError{Path: sourcePath}
	}

	if err := os.MkdirAll(path.Dir(dest), 0755); err != nil {
		return err
	}

	err := os.Rename(source, dest)
	return err
}

// Delete recursively deletes all objects stored at "path" and its subpaths.
func (d *driver) Delete(ctx context.Context, subPath string) error {
	fullPath := d.fullPath(subPath)

	_, err := os.Stat(fullPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	} else if err != nil {
		return storagedriver.PathNotFoundError{Path: subPath}
	}

	err = os.RemoveAll(fullPath)
	return err
}

// URLFor returns a URL which may be used to retrieve the content stored at the given path.
// May return an UnsupportedMethodErr in certain StorageDriver implementations.
func (d *driver) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) {
	return "", storagedriver.ErrUnsupportedMethod{}
}

// fullPath returns the absolute path of a key within the Driver's storage.
func (d *driver) fullPath(subPath string) string {
	return path.Join(d.rootDirectory, subPath)
}

type fileInfo struct {
	os.FileInfo
	path string
}

var _ storagedriver.FileInfo = fileInfo{}

// Path provides the full path of the target of this file info.
func (fi fileInfo) Path() string {
	return fi.path
}

// Size returns current length in bytes of the file. The return value can
// be used to write to the end of the file at path. The value is
// meaningless if IsDir returns true.
func (fi fileInfo) Size() int64 {
	if fi.IsDir() {
		return 0
	}

	return fi.FileInfo.Size()
}

// ModTime returns the modification time for the file. For backends that
// don't have a modification time, the creation time should be returned.
func (fi fileInfo) ModTime() time.Time {
	return fi.FileInfo.ModTime()
}

// IsDir returns true if the path is a directory.
func (fi fileInfo) IsDir() bool {
	return fi.FileInfo.IsDir()
}
<|endoftext|>


<commit_before>// Package route finds the shortest route between two points along a geometrical
// network (e.g., a road network). For now, all network links are assumed to be
// bi-directional (e.g., all roads are two-way).
package route

import (
	"fmt"
	"math"

	"github.com/ctessum/geom"
	"github.com/ctessum/geom/index/rtree"
	"github.com/ctessum/geom/op"
	"github.com/gonum/graph"
	"github.com/gonum/graph/path"
)

// A Network is a holder for network data (e.g., a road network)
type Network struct {
	nodes, edges   *rtree.Rtree
	neighbors      map[int]map[int]*edge
	nodeMap        map[int]*node
	maxID          int
	freeMap        map[int]struct{}
	minimizeOption MinimizeOption
	minimumSpeed   float64 // The minimum speed traveled on any link in the network.
}

// NewNetwork initializes a new Network where m determines how to choose
// the shortest route (either by Distance or Time).
func NewNetwork(m MinimizeOption) *Network {
	return &Network{
		neighbors:      make(map[int]map[int]*edge),
		nodeMap:        make(map[int]*node),
		maxID:          0,
		nodes:          rtree.NewTree(25, 50),
		edges:          rtree.NewTree(25, 50),
		minimizeOption: m,
		minimumSpeed:   math.Inf(1),
	}
}

// Has returns whether the node exists within the graph.
// It is not intended for direct use in this package.
func (net Network) Has(n graph.Node) bool {
	_, ok := net.nodeMap[n.ID()]
	return ok
}

// Nodes returns all the nodes in the graph.
// It is not intended for direct use in this package.
func (net Network) Nodes() []graph.Node {
	nodes := make([]graph.Node, len(net.nodeMap))
	i := 0
	for _, n := range net.nodeMap {
		nodes[i] = n
		i++
	}
	return nodes
}

// From returns all nodes that can be reached directly
// from the given node.
// It is not intended for direct use in this package.
func (net Network) From(n graph.Node) []graph.Node {
	if !net.Has(n) {
		return nil
	}
	neighbors := make([]graph.Node, len(net.neighbors[n.ID()]))
	i := 0
	for id := range net.neighbors[n.ID()] {
		neighbors[i] = net.nodeMap[id]
		i++
	}
	return neighbors
}

// HasEdge returns whether an edge exists between
// nodes x and y without considering direction.
// It is not intended for direct use in this package.
func (net Network) HasEdge(x, y graph.Node) bool {
	_, ok := net.neighbors[x.ID()][y.ID()]
	return ok
}

// Edge returns the edge from u to v if such an edge
// exists and nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
// It is not intended for direct use in this package.
func (net Network) Edge(u, v graph.Node) graph.Edge {
	// We don't need to check if neigh exists because
	// it's implicit in the neighbors access.
	if !net.Has(u) {
		return nil
	}
	return net.neighbors[u.ID()][v.ID()]
}

// The math package only provides explicitly sized max
// values. This ensures we get the max for the actual
// type int.
const maxInt int = int(^uint(0) >> 1)

func (net *Network) newNodeID() int {
	if net.maxID != maxInt {
		net.maxID++
		return net.maxID
	}
	// I cannot foresee this ever happening, but just in case, we check.
	if len(net.nodeMap) == maxInt {
		panic("cannot allocate node: graph too large")
	}
	// Should not happen.
	panic("cannot allocate node id: no free id found")
}

// Check if there is already a node at this location, and if there
// is return that one, otherwise create a new node.
func (net *Network) newNode(p geom.Point) *node {
	nearest := net.nodes.NearestNeighbor(p)
	if nearest != nil && op.PointEquals(p, nearest.(*node).Point) {
		return nearest.(*node)
	}
	return &node{
		Point: p,
		id:    net.newNodeID(),
	}
}

func (net *Network) addNode(n graph.Node) {
	if _, exists := net.nodeMap[n.ID()]; exists {
		panic(fmt.Sprintf("route: node ID collision: %d", n.ID()))
	}
	net.nodeMap[n.ID()] = n.(*node)
	net.neighbors[n.ID()] = make(map[int]*edge)
	net.nodes.Insert(n.(*node))
}

// AddLink adds a new link l (which is a line string) to the Network, where
// speed is the speed traveled along the link and should have units that
// are compatible with the units of l (for instance, if l is in units of
// meters, and speed is in units of m/s, the time results will be in units
// of seconds).
func (net *Network) AddLink(l geom.LineString, speed float64) {
	from := net.newNode(l[0])
	to := net.newNode(l[len(l)-1])

	length := op.Length(l)
	e := &edge{
		LineString: l,
		start:      from,
		end:        to,
		length:     length,
		speed:      speed,
		time:       length / speed,
	}
	if e.speed < net.minimumSpeed {
		net.minimumSpeed = e.speed
	}
	fid := from.ID()
	tid := to.ID()
	if fid == tid {
		panic("concrete: adding self edge")
	}
	if !net.Has(from) {
		net.addNode(from)
	}
	if !net.Has(to) {
		net.addNode(to)
	}
	net.edges.Insert(e)
	net.neighbors[fid][tid] = e
	net.neighbors[tid][fid] = e
}

// Weight returns the weight associated with this edge.
// It is not intended for direct use in this package.
func (net *Network) Weight(e graph.Edge) float64 {
	if n, ok := net.neighbors[e.From().ID()]; ok {
		if we, ok := n[e.To().ID()]; ok {
			switch net.minimizeOption {
			// If we're optimizing by time, return use the minimum speed to
			// calculate the time to ensure the heuristic is less than the actual
			// value
			case Time:
				return we.time
			case Distance:
				// If we're optimizing by distance, just return the distance.
				return we.length
			default:
				panic(fmt.Errorf("Invalid MinimizeOption %v", net.minimizeOption))
			}
		}
	}
	panic("route: attempting to find an edge that is not in the graph")
}

type edge struct {
	geom.LineString
	start, end          *node
	length, speed, time float64
}

// From gives the beginning point of this edge.
func (e edge) From() graph.Node {
	return e.start
}

// To gives the final point of this edge.
func (e edge) To() graph.Node {
	return e.end
}

type node struct {
	geom.Point
	id int
}

func (n node) ID() int {
	return n.id
}

// MinimizeOption specifies how the shortest route should be chosen.
type MinimizeOption float64

const (
	// Distance specifies that we are looking to travel the minimum distance.
	Distance MinimizeOption = iota
	// Time specifies that we are looking to travel the minimum time.
	Time
)

// ShortestRoute calculates the shortest route along the network between the
// from and to points. It returns the route ("path"), the distance traveled
// along the route ("distance"), the time it would take travel along the route
// ("time"; this does not count time spent getting to and from the network),
// the distance traveled from the starting
// point to get to the nearest node (e.g., intersection) along the route
// ("startDistance") and the distance traveled to the ending point from
// the nearest node along the route ("endDistance"). This function does
// not change the Network, so multiple function calls can be run concurrently.
func (net Network) ShortestRoute(from, to geom.Point) (
	route geom.MultiLineString, distance, time, startDistance, endDistance float64) {
	startNode := net.nodes.NearestNeighbor(from).(*node)
	endNode := net.nodes.NearestNeighbor(to).(*node)
	startDistance = op.Distance(from, startNode.Point)
	endDistance = op.Distance(to, endNode.Point)
	shortest, _ := path.AStar(startNode, endNode, net, net.costHeuristic)
	nodes, _ := shortest.To(endNode)
	for i := 0; i < len(nodes)-1; i++ {
		e, ok := net.neighbors[nodes[i].ID()][nodes[i+1].ID()]
		if !ok {
			panic("route: missing edge; this shouldn't happen")
		}
		route = append(route, e.LineString)
		distance += e.length
		time += e.time
	}
	return
}

// costHeuristic provides a cost estimate this is guaranteed to be equal
// to or less than the actual cost.
func (net *Network) costHeuristic(x, y graph.Node) float64 {
	distance := op.Distance(x.(*node).Point, y.(*node).Point)
	switch net.minimizeOption {
	// If we're optimizing by time, return use the minimum speed to
	// calculate the time to ensure the heuristic is less than the actual
	// value
	case Time:
		return distance / net.minimumSpeed
	case Distance:
		// If we're optimizing by distance, just return the distance.
		return distance
	default:
		panic(fmt.Errorf("Invalid MinimizeOption %v", net.minimizeOption))
	}
}
<commit_msg>Update route dependencies<commit_after>// Package route finds the shortest route between two points along a geometrical
// network (e.g., a road network). For now, all network links are assumed to be
// bi-directional (e.g., all roads are two-way).
package route

import (
	"fmt"
	"math"

	"github.com/ctessum/geom"
	"github.com/ctessum/geom/index/rtree"
	"github.com/ctessum/geom/op"
	"gonum.org/v1/gonum/graph"
	"gonum.org/v1/gonum/graph/path"
)

// A Network is a holder for network data (e.g., a road network)
type Network struct {
	nodes, edges   *rtree.Rtree
	neighbors      map[int64]map[int64]*edge
	nodeMap        map[int64]*node
	maxID          int
	freeMap        map[int]struct{}
	minimizeOption MinimizeOption
	minimumSpeed   float64 // The minimum speed traveled on any link in the network.
}

// NewNetwork initializes a new Network where m determines how to choose
// the shortest route (either by Distance or Time).
func NewNetwork(m MinimizeOption) *Network {
	return &Network{
		neighbors:      make(map[int64]map[int64]*edge),
		nodeMap:        make(map[int64]*node),
		maxID:          0,
		nodes:          rtree.NewTree(25, 50),
		edges:          rtree.NewTree(25, 50),
		minimizeOption: m,
		minimumSpeed:   math.Inf(1),
	}
}

// Has returns whether the node exists within the graph.
// It is not intended for direct use in this package.
func (net Network) Has(n int64) bool {
	_, ok := net.nodeMap[n]
	return ok
}

// Nodes returns all the nodes in the graph.
// It is not intended for direct use in this package.
func (net Network) Nodes() []graph.Node {
	nodes := make([]graph.Node, len(net.nodeMap))
	i := 0
	for _, n := range net.nodeMap {
		nodes[i] = n
		i++
	}
	return nodes
}

// From returns all nodes that can be reached directly
// from the given node.
// It is not intended for direct use in this package.
func (net Network) From(n int64) []graph.Node {
	if !net.Has(n) {
		return nil
	}
	neighbors := make([]graph.Node, len(net.neighbors[n]))
	i := 0
	for id := range net.neighbors[n] {
		neighbors[i] = net.nodeMap[id]
		i++
	}
	return neighbors
}

// HasEdge returns whether an edge exists between
// nodes x and y without considering direction.
// It is not intended for direct use in this package.
func (net Network) HasEdge(x, y int64) bool {
	_, ok := net.neighbors[x][y]
	return ok
}

// Edge returns the edge from u to v if such an edge
// exists and nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
// It is not intended for direct use in this package.
func (net Network) Edge(u, v int64) graph.Edge {
	// We don't need to check if neigh exists because
	// it's implicit in the neighbors access.
	if !net.Has(u) {
		return nil
	}
	return net.neighbors[u][v]
}

// The math package only provides explicitly sized max
// values. This ensures we get the max for the actual
// type int.
const maxInt int = int(^uint(0) >> 1)

func (net *Network) newNodeID() int {
	if net.maxID != maxInt {
		net.maxID++
		return net.maxID
	}
	// I cannot foresee this ever happening, but just in case, we check.
	if len(net.nodeMap) == maxInt {
		panic("cannot allocate node: graph too large")
	}
	// Should not happen.
	panic("cannot allocate node id: no free id found")
}

// Check if there is already a node at this location, and if there
// is return that one, otherwise create a new node.
func (net *Network) newNode(p geom.Point) *node {
	nearest := net.nodes.NearestNeighbor(p)
	if nearest != nil && op.PointEquals(p, nearest.(*node).Point) {
		return nearest.(*node)
	}
	return &node{
		Point: p,
		id:    net.newNodeID(),
	}
}

func (net *Network) addNode(n graph.Node) {
	if _, exists := net.nodeMap[n.ID()]; exists {
		panic(fmt.Sprintf("route: node ID collision: %d", n.ID()))
	}
	net.nodeMap[n.ID()] = n.(*node)
	net.neighbors[n.ID()] = make(map[int64]*edge)
	net.nodes.Insert(n.(*node))
}

// AddLink adds a new link l (which is a line string) to the Network, where
// speed is the speed traveled along the link and should have units that
// are compatible with the units of l (for instance, if l is in units of
// meters, and speed is in units of m/s, the time results will be in units
// of seconds).
func (net *Network) AddLink(l geom.LineString, speed float64) {
	from := net.newNode(l[0])
	to := net.newNode(l[len(l)-1])

	length := op.Length(l)
	e := &edge{
		LineString: l,
		start:      from,
		end:        to,
		length:     length,
		speed:      speed,
		time:       length / speed,
	}
	if e.speed < net.minimumSpeed {
		net.minimumSpeed = e.speed
	}
	fid := from.ID()
	tid := to.ID()
	if fid == tid {
		panic("concrete: adding self edge")
	}
	if !net.Has(from.ID()) {
		net.addNode(from)
	}
	if !net.Has(to.ID()) {
		net.addNode(to)
	}
	net.edges.Insert(e)
	net.neighbors[fid][tid] = e
	net.neighbors[tid][fid] = e
}

// Weight returns the weight associated with this edge.
// It is not intended for direct use in this package.
func (net *Network) Weight(e graph.Edge) float64 {
	if n, ok := net.neighbors[e.From().ID()]; ok {
		if we, ok := n[e.To().ID()]; ok {
			switch net.minimizeOption {
			// If we're optimizing by time, return use the minimum speed to
			// calculate the time to ensure the heuristic is less than the actual
			// value
			case Time:
				return we.time
			case Distance:
				// If we're optimizing by distance, just return the distance.
				return we.length
			default:
				panic(fmt.Errorf("Invalid MinimizeOption %v", net.minimizeOption))
			}
		}
	}
	panic("route: attempting to find an edge that is not in the graph")
}

type edge struct {
	geom.LineString
	start, end          *node
	length, speed, time float64
}

// From gives the beginning point of this edge.
func (e edge) From() graph.Node {
	return e.start
}

// To gives the final point of this edge.
func (e edge) To() graph.Node {
	return e.end
}

type node struct {
	geom.Point
	id int
}

func (n node) ID() int64 {
	return int64(n.id)
}

// MinimizeOption specifies how the shortest route should be chosen.
type MinimizeOption float64

const (
	// Distance specifies that we are looking to travel the minimum distance.
	Distance MinimizeOption = iota
	// Time specifies that we are looking to travel the minimum time.
	Time
)

// ShortestRoute calculates the shortest route along the network between the
// from and to points. It returns the route ("path"), the distance traveled
// along the route ("distance"), the time it would take travel along the route
// ("time"; this does not count time spent getting to and from the network),
// the distance traveled from the starting
// point to get to the nearest node (e.g., intersection) along the route
// ("startDistance") and the distance traveled to the ending point from
// the nearest node along the route ("endDistance"). This function does
// not change the Network, so multiple function calls can be run concurrently.
func (net Network) ShortestRoute(from, to geom.Point) (
	route geom.MultiLineString, distance, time, startDistance, endDistance float64) {
	startNode := net.nodes.NearestNeighbor(from).(*node)
	endNode := net.nodes.NearestNeighbor(to).(*node)
	startDistance = op.Distance(from, startNode.Point)
	endDistance = op.Distance(to, endNode.Point)
	shortest, _ := path.AStar(startNode, endNode, net, net.costHeuristic)
	nodes, _ := shortest.To(endNode.ID())
	for i := 0; i < len(nodes)-1; i++ {
		e, ok := net.neighbors[nodes[i].ID()][nodes[i+1].ID()]
		if !ok {
			panic("route: missing edge; this shouldn't happen")
		}
		route = append(route, e.LineString)
		distance += e.length
		time += e.time
	}
	return
}

// costHeuristic provides a cost estimate this is guaranteed to be equal
// to or less than the actual cost.
func (net *Network) costHeuristic(x, y graph.Node) float64 {
	distance := op.Distance(x.(*node).Point, y.(*node).Point)
	switch net.minimizeOption {
	// If we're optimizing by time, return use the minimum speed to
	// calculate the time to ensure the heuristic is less than the actual
	// value
	case Time:
		return distance / net.minimumSpeed
	case Distance:
		// If we're optimizing by distance, just return the distance.
		return distance
	default:
		panic(fmt.Errorf("Invalid MinimizeOption %v", net.minimizeOption))
	}
}

// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (net Network) HasEdgeBetween(xid, yid int64) bool {
	if _, ok := net.neighbors[xid][yid]; ok {
		return true
	}
	_, ok := net.neighbors[yid][xid]
	return ok
}
<|endoftext|>


<commit_before>package transport

import "io"

// A Handler responds to an RPC request.
//
// Process is invoked to handle an incoming request. The handler should process
// the request and must update the response message with either the response
// payload or an error.
type Handler interface {
	Process(req ImmutableMessage, res Message)
}

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as RPC handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(req ImmutableMessage, res Message)

// Process calls f(req, res).
func (f HandlerFunc) Process(req ImmutableMessage, res Message) {
	f(req, res)
}

// Provider defines an interface implemented by transports that can be used
// by usrv. The transport layer is responsible for the exchange of encoded
// messages between RPC clients and servers.
type Provider interface {
	// All transports must implement io.Closer to clean up and shutdown.
	io.Closer

	// Dial connects the transport, establishes any declared bindings and
	// starts relaying messages.
	Dial() error

	// Bind listens for messages send to a particular service and
	// endpoint combination and invokes the supplied handler to process them.
	//
	// Transports may implement versioning for bindings in order to support
	// complex deployment flows such as blue-green deployments.
	//
	// Bindings can only be established on a closed transport. Calls to Bind
	// after a call to Dial will result in an error.
	Bind(version, service, endpoint string, handler Handler) error

	// Request performs an RPC and returns back a read-only channel for
	// receiving the result.
	Request(msg Message) <-chan ImmutableMessage
}
<commit_msg>Extend transport Provider interface with an Unbind() method<commit_after>package transport

import "io"

// A Handler responds to an RPC request.
//
// Process is invoked to handle an incoming request. The handler should process
// the request and must update the response message with either the response
// payload or an error.
type Handler interface {
	Process(req ImmutableMessage, res Message)
}

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as RPC handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(req ImmutableMessage, res Message)

// Process calls f(req, res).
func (f HandlerFunc) Process(req ImmutableMessage, res Message) {
	f(req, res)
}

// Provider defines an interface implemented by transports that can be used
// by usrv. The transport layer is responsible for the exchange of encoded
// messages between RPC clients and servers.
type Provider interface {
	// All transports must implement io.Closer to clean up and shutdown.
	io.Closer

	// Dial connects the transport, establishes any declared bindings and
	// starts relaying messages.
	Dial() error

	// Bind listens for messages send to a particular service and
	// endpoint combination and invokes the supplied handler to process them.
	//
	// Transports may implement versioning for bindings in order to support
	// complex deployment flows such as blue-green deployments.
	Bind(version, service, endpoint string, handler Handler) error

	// Unbind removes a message handler previously registered by a call to Bind().
	// Calling Unbind with a (version, service, endpoint) tuple that is not
	// registered has no effect.
	Unbind(version, service, endpoint string)

	// Request performs an RPC and returns back a read-only channel for
	// receiving the result.
	Request(msg Message) <-chan ImmutableMessage
}
<|endoftext|>


<commit_before>package response

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

var debug bool

// Init sets the debug variable to the provided value.
func Init(d bool) {
	debug = d
}

// Response represents an API response
type Response interface {
	Render(w http.ResponseWriter) error
	String() string
}

// Sync response
type syncResponse struct {
	success   bool
	etag      interface{}
	metadata  interface{}
	location  string
	code      int
	headers   map[string]string
	plaintext bool
}

// EmptySyncResponse represents an empty syncResponse.
var EmptySyncResponse = &syncResponse{success: true, metadata: make(map[string]interface{})}

// SyncResponse returns a new syncResponse with the success and metadata fields
// set to the provided values.
func SyncResponse(success bool, metadata interface{}) Response {
	return &syncResponse{success: success, metadata: metadata}
}

// SyncResponseETag returns a new syncResponse with an etag.
func SyncResponseETag(success bool, metadata interface{}, etag interface{}) Response {
	return &syncResponse{success: success, metadata: metadata, etag: etag}
}

// SyncResponseLocation returns a new syncResponse with a location.
func SyncResponseLocation(success bool, metadata interface{}, location string) Response {
	return &syncResponse{success: success, metadata: metadata, location: location}
}

// SyncResponseRedirect returns a new syncResponse with a location, indicating
// a permanent redirect.
func SyncResponseRedirect(address string) Response {
	return &syncResponse{success: true, location: address, code: http.StatusPermanentRedirect}
}

// SyncResponseHeaders returns a new syncResponse with headers.
func SyncResponseHeaders(success bool, metadata interface{}, headers map[string]string) Response {
	return &syncResponse{success: success, metadata: metadata, headers: headers}
}

// SyncResponsePlain return a new syncResponse with plaintext.
func SyncResponsePlain(success bool, metadata string) Response {
	return &syncResponse{success: success, metadata: metadata, plaintext: true}
}

func (r *syncResponse) Render(w http.ResponseWriter) error {
	// Set an appropriate ETag header
	if r.etag != nil {
		etag, err := util.EtagHash(r.etag)
		if err == nil {
			w.Header().Set("ETag", fmt.Sprintf("\"%s\"", etag))
		}
	}

	// Prepare the JSON response
	status := api.Success
	if !r.success {
		status = api.Failure
	}

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

	code := r.code

	if r.location != "" {
		w.Header().Set("Location", r.location)
		if code == 0 {
			code = 201
		}
	}

	// Handle plain text headers.
	if r.plaintext {
		w.Header().Set("Content-Type", "text/plain")
	}

	// Write header and status code.
	if code == 0 {
		code = http.StatusOK
	}

	w.WriteHeader(code)

	// Handle plain text responses.
	if r.plaintext {
		if r.metadata != nil {
			_, err := w.Write([]byte(r.metadata.(string)))
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Handle JSON responses.
	resp := api.ResponseRaw{
		Type:       api.SyncResponse,
		Status:     status.String(),
		StatusCode: int(status),
		Metadata:   r.metadata,
	}

	var debugLogger logger.Logger
	if debug {
		debugLogger = logging.AddContext(logger.Log, log.Ctx{"http_code": code})
	}

	return util.WriteJSON(w, resp, debugLogger)
}

func (r *syncResponse) String() string {
	if r.success {
		return "success"
	}

	return "failure"
}

// Error response
type errorResponse struct {
	code int    // Code to return in both the HTTP header and Code field of the response body.
	msg  string // Message to return in the Error field of the response body.
}

// ErrorResponse returns an error response with the given code and msg.
func ErrorResponse(code int, msg string) Response {
	return &errorResponse{code, msg}
}

// BadRequest returns a bad request response (400) with the given error.
func BadRequest(err error) Response {
	return &errorResponse{http.StatusBadRequest, err.Error()}
}

// Conflict returns a conflict response (409) with the given error.
func Conflict(err error) Response {
	message := "already exists"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusConflict, message}
}

// Forbidden returns a forbidden response (403) with the given error.
func Forbidden(err error) Response {
	message := "not authorized"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusForbidden, message}
}

// InternalError returns an internal error response (500) with the given error.
func InternalError(err error) Response {
	return &errorResponse{http.StatusInternalServerError, err.Error()}
}

// NotFound returns a not found response (404) with the given error.
func NotFound(err error) Response {
	message := "not found"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotFound, message}
}

// NotImplemented returns a not implemented response (501) with the given error.
func NotImplemented(err error) Response {
	message := "not implemented"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotImplemented, message}
}

// PreconditionFailed returns a precondition failed response (412) with the
// given error.
func PreconditionFailed(err error) Response {
	return &errorResponse{http.StatusPreconditionFailed, err.Error()}
}

// Unavailable return an unavailable response (503) with the given error.
func Unavailable(err error) Response {
	message := "unavailable"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusServiceUnavailable, message}
}

func (r *errorResponse) String() string {
	return r.msg
}

func (r *errorResponse) Render(w http.ResponseWriter) error {
	var output io.Writer

	buf := &bytes.Buffer{}
	output = buf
	var captured *bytes.Buffer
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(buf, captured)
	}

	resp := api.ResponseRaw{
		Type:  api.ErrorResponse,
		Error: r.msg,
		Code:  r.code, // Set the error code in the Code field of the response body.
	}

	err := json.NewEncoder(output).Encode(resp)

	if err != nil {
		return err
	}

	if debug {
		debugLogger := logging.AddContext(logger.Log, log.Ctx{"http_code": r.code})
		util.DebugJSON("Error Response", captured, debugLogger)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Content-Type-Options", "nosniff")

	w.WriteHeader(r.code) // Set the error code in the HTTP header response.

	fmt.Fprintln(w, buf.String())

	return nil
}

// FileResponseEntry represents a file response entry.
type FileResponseEntry struct {
	Identifier string
	Path       string
	Filename   string
	Buffer     []byte /* either a path or a buffer must be provided */
}

type fileResponse struct {
	req              *http.Request
	files            []FileResponseEntry
	headers          map[string]string
	removeAfterServe bool
}

// FileResponse returns a new file response.
func FileResponse(r *http.Request, files []FileResponseEntry, headers map[string]string, removeAfterServe bool) Response {
	return &fileResponse{r, files, headers, removeAfterServe}
}

func (r *fileResponse) Render(w http.ResponseWriter) error {
	if r.headers != nil {
		for k, v := range r.headers {
			w.Header().Set(k, v)
		}
	}

	// No file, well, it's easy then
	if len(r.files) == 0 {
		return nil
	}

	// For a single file, return it inline
	if len(r.files) == 1 {
		var rs io.ReadSeeker
		var mt time.Time
		var sz int64

		if r.files[0].Path == "" {
			rs = bytes.NewReader(r.files[0].Buffer)
			mt = time.Now()
			sz = int64(len(r.files[0].Buffer))
		} else {
			f, err := os.Open(r.files[0].Path)
			if err != nil {
				return err
			}
			defer f.Close()

			fi, err := f.Stat()
			if err != nil {
				return err
			}

			mt = fi.ModTime()
			sz = fi.Size()
			rs = f
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
		w.Header().Set("Content-Disposition", fmt.Sprintf("inline;filename=%s", r.files[0].Filename))

		http.ServeContent(w, r.req, r.files[0].Filename, mt, rs)
		if r.files[0].Path != "" && r.removeAfterServe {
			err := os.Remove(r.files[0].Path)
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Now the complex multipart answer.
	mw := multipart.NewWriter(w)
	defer mw.Close()

	w.Header().Set("Content-Type", mw.FormDataContentType())
	w.Header().Set("Transfer-Encoding", "chunked")

	for _, entry := range r.files {
		var rd io.Reader
		if entry.Path != "" {
			fd, err := os.Open(entry.Path)
			if err != nil {
				return err
			}
			defer fd.Close()

			rd = fd
		} else {
			rd = bytes.NewReader(entry.Buffer)
		}

		fw, err := mw.CreateFormFile(entry.Identifier, entry.Filename)
		if err != nil {
			return err
		}

		_, err = io.Copy(fw, rd)
		if err != nil {
			return err
		}
	}

	return nil
}

func (r *fileResponse) String() string {
	return fmt.Sprintf("%d files", len(r.files))
}

type forwardedResponse struct {
	client  lxd.InstanceServer
	request *http.Request
}

// ForwardedResponse takes a request directed to a node and forwards it to
// another node, writing back the response it gegs.
func ForwardedResponse(client lxd.InstanceServer, request *http.Request) Response {
	return &forwardedResponse{
		client:  client,
		request: request,
	}
}

func (r *forwardedResponse) Render(w http.ResponseWriter) error {
	info, err := r.client.GetConnectionInfo()
	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s", info.Addresses[0], r.request.URL.RequestURI())
	forwarded, err := http.NewRequest(r.request.Method, url, r.request.Body)
	if err != nil {
		return err
	}

	for key := range r.request.Header {
		forwarded.Header.Set(key, r.request.Header.Get(key))
	}

	httpClient, err := r.client.GetHTTPClient()
	if err != nil {
		return err
	}

	response, err := httpClient.Do(forwarded)
	if err != nil {
		return err
	}

	for key := range response.Header {
		w.Header().Set(key, response.Header.Get(key))
	}

	w.WriteHeader(response.StatusCode)
	_, err = io.Copy(w, response.Body)
	return err
}

func (r *forwardedResponse) String() string {
	return fmt.Sprintf("request to %s", r.request.URL)
}

type manualResponse struct {
	hook func(w http.ResponseWriter) error
}

// ManualResponse creates a new manual response responder.
func ManualResponse(hook func(w http.ResponseWriter) error) Response {
	return &manualResponse{hook: hook}
}

func (r *manualResponse) Render(w http.ResponseWriter) error {
	return r.hook(w)
}

func (r *manualResponse) String() string {
	return "unknown"
}
<commit_msg>lxd/response: Modernize FileResponse<commit_after>package response

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

var debug bool

// Init sets the debug variable to the provided value.
func Init(d bool) {
	debug = d
}

// Response represents an API response
type Response interface {
	Render(w http.ResponseWriter) error
	String() string
}

// Sync response
type syncResponse struct {
	success   bool
	etag      interface{}
	metadata  interface{}
	location  string
	code      int
	headers   map[string]string
	plaintext bool
}

// EmptySyncResponse represents an empty syncResponse.
var EmptySyncResponse = &syncResponse{success: true, metadata: make(map[string]interface{})}

// SyncResponse returns a new syncResponse with the success and metadata fields
// set to the provided values.
func SyncResponse(success bool, metadata interface{}) Response {
	return &syncResponse{success: success, metadata: metadata}
}

// SyncResponseETag returns a new syncResponse with an etag.
func SyncResponseETag(success bool, metadata interface{}, etag interface{}) Response {
	return &syncResponse{success: success, metadata: metadata, etag: etag}
}

// SyncResponseLocation returns a new syncResponse with a location.
func SyncResponseLocation(success bool, metadata interface{}, location string) Response {
	return &syncResponse{success: success, metadata: metadata, location: location}
}

// SyncResponseRedirect returns a new syncResponse with a location, indicating
// a permanent redirect.
func SyncResponseRedirect(address string) Response {
	return &syncResponse{success: true, location: address, code: http.StatusPermanentRedirect}
}

// SyncResponseHeaders returns a new syncResponse with headers.
func SyncResponseHeaders(success bool, metadata interface{}, headers map[string]string) Response {
	return &syncResponse{success: success, metadata: metadata, headers: headers}
}

// SyncResponsePlain return a new syncResponse with plaintext.
func SyncResponsePlain(success bool, metadata string) Response {
	return &syncResponse{success: success, metadata: metadata, plaintext: true}
}

func (r *syncResponse) Render(w http.ResponseWriter) error {
	// Set an appropriate ETag header
	if r.etag != nil {
		etag, err := util.EtagHash(r.etag)
		if err == nil {
			w.Header().Set("ETag", fmt.Sprintf("\"%s\"", etag))
		}
	}

	// Prepare the JSON response
	status := api.Success
	if !r.success {
		status = api.Failure
	}

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

	code := r.code

	if r.location != "" {
		w.Header().Set("Location", r.location)
		if code == 0 {
			code = 201
		}
	}

	// Handle plain text headers.
	if r.plaintext {
		w.Header().Set("Content-Type", "text/plain")
	}

	// Write header and status code.
	if code == 0 {
		code = http.StatusOK
	}

	w.WriteHeader(code)

	// Handle plain text responses.
	if r.plaintext {
		if r.metadata != nil {
			_, err := w.Write([]byte(r.metadata.(string)))
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Handle JSON responses.
	resp := api.ResponseRaw{
		Type:       api.SyncResponse,
		Status:     status.String(),
		StatusCode: int(status),
		Metadata:   r.metadata,
	}

	var debugLogger logger.Logger
	if debug {
		debugLogger = logging.AddContext(logger.Log, log.Ctx{"http_code": code})
	}

	return util.WriteJSON(w, resp, debugLogger)
}

func (r *syncResponse) String() string {
	if r.success {
		return "success"
	}

	return "failure"
}

// Error response
type errorResponse struct {
	code int    // Code to return in both the HTTP header and Code field of the response body.
	msg  string // Message to return in the Error field of the response body.
}

// ErrorResponse returns an error response with the given code and msg.
func ErrorResponse(code int, msg string) Response {
	return &errorResponse{code, msg}
}

// BadRequest returns a bad request response (400) with the given error.
func BadRequest(err error) Response {
	return &errorResponse{http.StatusBadRequest, err.Error()}
}

// Conflict returns a conflict response (409) with the given error.
func Conflict(err error) Response {
	message := "already exists"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusConflict, message}
}

// Forbidden returns a forbidden response (403) with the given error.
func Forbidden(err error) Response {
	message := "not authorized"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusForbidden, message}
}

// InternalError returns an internal error response (500) with the given error.
func InternalError(err error) Response {
	return &errorResponse{http.StatusInternalServerError, err.Error()}
}

// NotFound returns a not found response (404) with the given error.
func NotFound(err error) Response {
	message := "not found"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotFound, message}
}

// NotImplemented returns a not implemented response (501) with the given error.
func NotImplemented(err error) Response {
	message := "not implemented"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotImplemented, message}
}

// PreconditionFailed returns a precondition failed response (412) with the
// given error.
func PreconditionFailed(err error) Response {
	return &errorResponse{http.StatusPreconditionFailed, err.Error()}
}

// Unavailable return an unavailable response (503) with the given error.
func Unavailable(err error) Response {
	message := "unavailable"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusServiceUnavailable, message}
}

func (r *errorResponse) String() string {
	return r.msg
}

func (r *errorResponse) Render(w http.ResponseWriter) error {
	var output io.Writer

	buf := &bytes.Buffer{}
	output = buf
	var captured *bytes.Buffer
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(buf, captured)
	}

	resp := api.ResponseRaw{
		Type:  api.ErrorResponse,
		Error: r.msg,
		Code:  r.code, // Set the error code in the Code field of the response body.
	}

	err := json.NewEncoder(output).Encode(resp)

	if err != nil {
		return err
	}

	if debug {
		debugLogger := logging.AddContext(logger.Log, log.Ctx{"http_code": r.code})
		util.DebugJSON("Error Response", captured, debugLogger)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Content-Type-Options", "nosniff")

	w.WriteHeader(r.code) // Set the error code in the HTTP header response.

	fmt.Fprintln(w, buf.String())

	return nil
}

// FileResponseEntry represents a file response entry.
type FileResponseEntry struct {
	// Required.
	Identifier string
	Filename   string

	// Read from a filesystem path.
	Path string

	// Read from a file.
	File       io.ReadSeeker
	FileSize   int64
	FileModify time.Time

	// Optional.
	Cleanup func()
}

type fileResponse struct {
	req     *http.Request
	files   []FileResponseEntry
	headers map[string]string
}

// FileResponse returns a new file response.
func FileResponse(r *http.Request, files []FileResponseEntry, headers map[string]string) Response {
	return &fileResponse{r, files, headers}
}

func (r *fileResponse) Render(w http.ResponseWriter) error {
	if r.headers != nil {
		for k, v := range r.headers {
			w.Header().Set(k, v)
		}
	}

	// No file, well, it's easy then
	if len(r.files) == 0 {
		return nil
	}

	// For a single file, return it inline
	if len(r.files) == 1 {
		var rs io.ReadSeeker
		var mt time.Time
		var sz int64

		if r.files[0].File != nil {
			rs = r.files[0].File
			mt = r.files[0].FileModify
			sz = r.files[0].FileSize
		} else {
			f, err := os.Open(r.files[0].Path)
			if err != nil {
				return err
			}
			defer f.Close()

			fi, err := f.Stat()
			if err != nil {
				return err
			}

			mt = fi.ModTime()
			sz = fi.Size()
			rs = f
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
		w.Header().Set("Content-Disposition", fmt.Sprintf("inline;filename=%s", r.files[0].Filename))

		http.ServeContent(w, r.req, r.files[0].Filename, mt, rs)

		if r.files[0].Cleanup != nil {
			r.files[0].Cleanup()
		}

		return nil
	}

	// Now the complex multipart answer.
	mw := multipart.NewWriter(w)
	defer mw.Close()

	w.Header().Set("Content-Type", mw.FormDataContentType())
	w.Header().Set("Transfer-Encoding", "chunked")

	for _, entry := range r.files {
		var rd io.Reader
		if entry.File != nil {
			rd = entry.File
		} else {
			fd, err := os.Open(entry.Path)
			if err != nil {
				return err
			}
			defer fd.Close()

			rd = fd
		}

		fw, err := mw.CreateFormFile(entry.Identifier, entry.Filename)
		if err != nil {
			return err
		}

		_, err = io.Copy(fw, rd)
		if err != nil {
			return err
		}

		if entry.Cleanup != nil {
			entry.Cleanup()
		}

	}

	return nil
}

func (r *fileResponse) String() string {
	return fmt.Sprintf("%d files", len(r.files))
}

type forwardedResponse struct {
	client  lxd.InstanceServer
	request *http.Request
}

// ForwardedResponse takes a request directed to a node and forwards it to
// another node, writing back the response it gegs.
func ForwardedResponse(client lxd.InstanceServer, request *http.Request) Response {
	return &forwardedResponse{
		client:  client,
		request: request,
	}
}

func (r *forwardedResponse) Render(w http.ResponseWriter) error {
	info, err := r.client.GetConnectionInfo()
	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s", info.Addresses[0], r.request.URL.RequestURI())
	forwarded, err := http.NewRequest(r.request.Method, url, r.request.Body)
	if err != nil {
		return err
	}

	for key := range r.request.Header {
		forwarded.Header.Set(key, r.request.Header.Get(key))
	}

	httpClient, err := r.client.GetHTTPClient()
	if err != nil {
		return err
	}

	response, err := httpClient.Do(forwarded)
	if err != nil {
		return err
	}

	for key := range response.Header {
		w.Header().Set(key, response.Header.Get(key))
	}

	w.WriteHeader(response.StatusCode)
	_, err = io.Copy(w, response.Body)
	return err
}

func (r *forwardedResponse) String() string {
	return fmt.Sprintf("request to %s", r.request.URL)
}

type manualResponse struct {
	hook func(w http.ResponseWriter) error
}

// ManualResponse creates a new manual response responder.
func ManualResponse(hook func(w http.ResponseWriter) error) Response {
	return &manualResponse{hook: hook}
}

func (r *manualResponse) Render(w http.ResponseWriter) error {
	return r.hook(w)
}

func (r *manualResponse) String() string {
	return "unknown"
}
<|endoftext|>


<commit_before>package sdm630

import (
	"encoding/binary"
	"fmt"
	"log"
	"math"
	"os"
	"time"

	"github.com/goburrow/modbus"
)

const (
	MaxRetryCount  = 5
	ReadInputReg   = 4
	ReadHoldingReg = 3
)

const (
	ModbusComset2400_8N1  = 1
	ModbusComset9600_8N1  = 2
	ModbusComset19200_8N1 = 3
	ModbusComset2400_8E1  = 4
	ModbusComset9600_8E1  = 5
	ModbusComset19200_8E1 = 6
)

type ModbusEngine struct {
	client  modbus.Client
	handler *modbus.RTUClientHandler
	verbose bool
	status  *Status
}

func NewModbusEngine(
	rtuDevice string,
	comset int,
	verbose bool,
	status *Status,
) *ModbusEngine {
	// Modbus RTU/ASCII
	rtuclient := modbus.NewRTUClientHandler(rtuDevice)
	switch comset {
	case ModbusComset2400_8N1:
		rtuclient.BaudRate = 2400
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset9600_8N1:
		rtuclient.BaudRate = 9600
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset19200_8N1:
		rtuclient.BaudRate = 19200
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset2400_8E1:
		rtuclient.BaudRate = 2400
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	case ModbusComset9600_8E1:
		rtuclient.BaudRate = 9600
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	case ModbusComset19200_8E1:
		rtuclient.BaudRate = 19200
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	default:
		log.Fatal("Invalid communication set specified. See -h for help.")
	}
	rtuclient.Timeout = 300 * time.Millisecond
	if verbose {
		rtuclient.Logger = log.New(os.Stdout, "RTUClientHandler: ", log.LstdFlags)
		log.Printf("Connecting to RTU via %s, %d %d%s%d\r\n", rtuDevice,
			rtuclient.BaudRate, rtuclient.DataBits, rtuclient.Parity,
			rtuclient.StopBits)
	}

	err := rtuclient.Connect()
	if err != nil {
		log.Fatal("Failed to connect: ", err)
	}
	defer rtuclient.Close()

	mbclient := modbus.NewClient(rtuclient)

	return &ModbusEngine{
		client:  mbclient,
		handler: rtuclient,
		verbose: verbose,
		status:  status,
	}
}

func (q *ModbusEngine) query(snip QuerySnip) (retval []byte, err error) {
	q.status.IncreaseModbusRequestCounter()
	// update the slave id in the handler
	q.handler.SlaveId = snip.DeviceId
	switch snip.FuncCode {
	case ReadInputReg:
		retval, err = q.client.ReadInputRegisters(snip.OpCode, snip.ReadLen)
	case ReadHoldingReg:
		retval, err = q.client.ReadHoldingRegisters(snip.OpCode, snip.ReadLen)
	default:
		log.Fatalf("Unknown function code %d - cannot query device.",
			snip.FuncCode)
	}
	if err != nil && q.verbose {
		log.Printf("Failed to retrieve opcode 0x%x, error was: %s\r\n", snip.OpCode, err.Error())
	}
	return retval, err
}

func (q *ModbusEngine) Transform(
	inputStream QuerySnipChannel,
	controlStream ControlSnipChannel,
	outputStream QuerySnipChannel,
) {
	var previousDeviceId uint8
	for {
		snip := <-inputStream
		// The SDM devices need to have a little pause between querying
		// different devices.
		if previousDeviceId != snip.DeviceId {
			time.Sleep(time.Duration(100) * time.Millisecond)
		}
		previousDeviceId = snip.DeviceId

		var err error
		var reading []byte

		tryCnt := 0
		for tryCnt = 0; tryCnt < MaxRetryCount; tryCnt++ {
			reading, err = q.query(snip)
			if err != nil {
				q.status.IncreaseModbusReconnectCounter()
				log.Printf("Device %d failed to respond - retry attempt %d of %d",
					snip.DeviceId, tryCnt+1, MaxRetryCount)
				time.Sleep(time.Duration(100) * time.Millisecond)
			} else {
				break
			}
		}

		if tryCnt == MaxRetryCount {
			errorSnip := ControlSnip{
				Type:     CONTROLSNIP_ERROR,
				Message:  fmt.Sprintf("Device %d did not respond.", snip.DeviceId),
				DeviceId: snip.DeviceId,
			}
			controlStream <- errorSnip
		} else {
			// convert bytes to value
			snip.Value = snip.Transform(reading)
			snip.ReadTimestamp = time.Now()
			outputStream <- snip

			successSnip := ControlSnip{
				Type:     CONTROLSNIP_OK,
				Message:  "OK",
				DeviceId: snip.DeviceId,
			}
			controlStream <- successSnip
		}
	}
}

func (q *ModbusEngine) Scan() {
	type Device struct {
		DeviceId   uint8
		DeviceType MeterType
	}

	devicelist := make([]Device, 0)
	oldtimeout := q.handler.Timeout
	q.handler.Timeout = 50 * time.Millisecond
	log.Printf("Starting bus scan")

	probe := func(meterType MeterType, snip QuerySnip) bool {
		value, err := q.query(snip)
		if err == nil {
			log.Printf("Device %d: %s type device found, %s: %.2f\r\n",
				snip.DeviceId,
				meterType,
				GetIecDescription(snip.IEC61850),
				snip.Transform(value))
			dev := Device{
				DeviceId:   snip.DeviceId,
				DeviceType: meterType,
			}
			devicelist = append(devicelist, dev)
			return true
		}
		return false
	}

	// loop over all valid slave adresses
	var devid uint8
	for devid = 1; devid <= 247; devid++ {
		if probe(METERTYPE_SDM, NewSDMProducer().Probe(devid)) {
			continue
		}
		if probe(METERTYPE_JANITZA, NewJanitzaProducer().Probe(devid)) {
			continue
		}
		if probe(METERTYPE_DZG, NewDZGProducer().Probe(devid)) {
			continue
		}

		log.Printf("Device %d: n/a\r\n", devid)

		// give the bus some time to recover before querying the next device
		time.Sleep(time.Duration(40) * time.Millisecond)
	}

	// restore timeout to old value
	q.handler.Timeout = oldtimeout
	log.Printf("Found %d active devices:\r\n", len(devicelist))
	for _, device := range devicelist {
		log.Printf("* slave address %d: type %s\r\n", device.DeviceId,
			device.DeviceType)
	}
	log.Println("WARNING: This lists only the devices that responded to " +
		"a known probe request. Devices with different " +
		"function code definitions might not be detected.")
}

// RTUTransform functions convert RTU bytes to meaningful data types.
type RTUTransform func([]byte) float64

// RTU32ToFloat64 converts 32 bit readings
func RTU32ToFloat64(b []byte) float64 {
	bits := binary.BigEndian.Uint32(b)
	f := math.Float32frombits(bits)
	return float64(f)
}

// RTU16ToFloat64 converts 16 bit readings
func RTU16ToFloat64(b []byte) float64 {
	u := binary.BigEndian.Uint16(b)
	return float64(u)
}

func rtuScaledInt32ToFloat64(b []byte, scalar float64) float64 {
	unscaled := float64(binary.BigEndian.Uint32(b))
	f := unscaled / scalar
	return float64(f)
}

// MakeRTU32ScaledIntToFloat64 creates a 32 bit scaled reading transform
func MakeRTU32ScaledIntToFloat64(scalar float64) RTUTransform {
	return RTUTransform(func(b []byte) float64 {
		return rtuScaledInt32ToFloat64(b, scalar)
	})
}

func rtuScaledInt16ToFloat64(b []byte, scalar float64) float64 {
	unscaled := float64(binary.BigEndian.Uint16(b))
	f := unscaled / scalar
	return float64(f)
}

// MakeRTU16ScaledIntToFloat64 creates a 16 bit scaled reading transform
func MakeRTU16ScaledIntToFloat64(scalar float64) RTUTransform {
	return RTUTransform(func(b []byte) float64 {
		return rtuScaledInt16ToFloat64(b, scalar)
	})
}
<commit_msg>Split meter implementations from modbus<commit_after>package sdm630

import (
	"encoding/binary"
	"fmt"
	"log"
	"math"
	"os"
	"time"

	"github.com/goburrow/modbus"
)

const (
	MaxRetryCount  = 5
	ReadInputReg   = 4
	ReadHoldingReg = 3
)

const (
	ModbusComset2400_8N1  = 1
	ModbusComset9600_8N1  = 2
	ModbusComset19200_8N1 = 3
	ModbusComset2400_8E1  = 4
	ModbusComset9600_8E1  = 5
	ModbusComset19200_8E1 = 6
)

type ModbusEngine struct {
	client  modbus.Client
	handler *modbus.RTUClientHandler
	verbose bool
	status  *Status
}

func NewModbusEngine(
	rtuDevice string,
	comset int,
	verbose bool,
	status *Status,
) *ModbusEngine {
	// Modbus RTU/ASCII
	rtuclient := modbus.NewRTUClientHandler(rtuDevice)
	switch comset {
	case ModbusComset2400_8N1:
		rtuclient.BaudRate = 2400
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset9600_8N1:
		rtuclient.BaudRate = 9600
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset19200_8N1:
		rtuclient.BaudRate = 19200
		rtuclient.DataBits = 8
		rtuclient.Parity = "N"
		rtuclient.StopBits = 1
	case ModbusComset2400_8E1:
		rtuclient.BaudRate = 2400
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	case ModbusComset9600_8E1:
		rtuclient.BaudRate = 9600
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	case ModbusComset19200_8E1:
		rtuclient.BaudRate = 19200
		rtuclient.DataBits = 8
		rtuclient.Parity = "E"
		rtuclient.StopBits = 1
	default:
		log.Fatal("Invalid communication set specified. See -h for help.")
	}
	rtuclient.Timeout = 300 * time.Millisecond
	if verbose {
		rtuclient.Logger = log.New(os.Stdout, "RTUClientHandler: ", log.LstdFlags)
		log.Printf("Connecting to RTU via %s, %d %d%s%d\r\n", rtuDevice,
			rtuclient.BaudRate, rtuclient.DataBits, rtuclient.Parity,
			rtuclient.StopBits)
	}

	err := rtuclient.Connect()
	if err != nil {
		log.Fatal("Failed to connect: ", err)
	}
	defer rtuclient.Close()

	mbclient := modbus.NewClient(rtuclient)

	return &ModbusEngine{
		client:  mbclient,
		handler: rtuclient,
		verbose: verbose,
		status:  status,
	}
}

func (q *ModbusEngine) query(snip QuerySnip) (retval []byte, err error) {
	q.status.IncreaseModbusRequestCounter()
	// update the slave id in the handler
	q.handler.SlaveId = snip.DeviceId
	switch snip.FuncCode {
	case ReadInputReg:
		retval, err = q.client.ReadInputRegisters(snip.OpCode, snip.ReadLen)
	case ReadHoldingReg:
		retval, err = q.client.ReadHoldingRegisters(snip.OpCode, snip.ReadLen)
	default:
		log.Fatalf("Unknown function code %d - cannot query device.",
			snip.FuncCode)
	}
	if err != nil && q.verbose {
		log.Printf("Failed to retrieve opcode 0x%x, error was: %s\r\n", snip.OpCode, err.Error())
	}
	return retval, err
}

func (q *ModbusEngine) Transform(
	inputStream QuerySnipChannel,
	controlStream ControlSnipChannel,
	outputStream QuerySnipChannel,
) {
	var previousDeviceId uint8
	for {
		snip := <-inputStream
		// The SDM devices need to have a little pause between querying
		// different devices.
		if previousDeviceId != snip.DeviceId {
			time.Sleep(time.Duration(100) * time.Millisecond)
		}
		previousDeviceId = snip.DeviceId

		var err error
		var reading []byte

		tryCnt := 0
		for tryCnt = 0; tryCnt < MaxRetryCount; tryCnt++ {
			reading, err = q.query(snip)
			if err != nil {
				q.status.IncreaseModbusReconnectCounter()
				log.Printf("Device %d failed to respond - retry attempt %d of %d",
					snip.DeviceId, tryCnt+1, MaxRetryCount)
				time.Sleep(time.Duration(100) * time.Millisecond)
			} else {
				break
			}
		}

		if tryCnt == MaxRetryCount {
			errorSnip := ControlSnip{
				Type:     CONTROLSNIP_ERROR,
				Message:  fmt.Sprintf("Device %d did not respond.", snip.DeviceId),
				DeviceId: snip.DeviceId,
			}
			controlStream <- errorSnip
		} else {
			// convert bytes to value
			snip.Value = snip.Transform(reading)
			snip.ReadTimestamp = time.Now()

			outputStream <- snip

			successSnip := ControlSnip{
				Type:     CONTROLSNIP_OK,
				Message:  "OK",
				DeviceId: snip.DeviceId,
			}
			controlStream <- successSnip
		}
	}
}

func (q *ModbusEngine) Scan() {
	type Device struct {
		DeviceId   uint8
		DeviceType MeterType
	}

	devicelist := make([]Device, 0)
	oldtimeout := q.handler.Timeout
	q.handler.Timeout = 50 * time.Millisecond
	log.Printf("Starting bus scan")

	probe := func(meterType MeterType, snip QuerySnip) bool {
		value, err := q.query(snip)
		if err == nil {
			log.Printf("Device %d: %s type device found, %s: %.2f\r\n",
				snip.DeviceId,
				meterType,
				GetIecDescription(snip.IEC61850),
				snip.Transform(value))
			dev := Device{
				DeviceId:   snip.DeviceId,
				DeviceType: meterType,
			}
			devicelist = append(devicelist, dev)
			return true
		}
		return false
	}

	// loop over all valid slave adresses
	var devid uint8
	for devid = 1; devid <= 247; devid++ {
		if probe(METERTYPE_SDM, NewSDMProducer().Probe(devid)) {
			continue
		}
		if probe(METERTYPE_JANITZA, NewJanitzaProducer().Probe(devid)) {
			continue
		}
		if probe(METERTYPE_DZG, NewDZGProducer().Probe(devid)) {
			continue
		}

		log.Printf("Device %d: n/a\r\n", devid)

		// give the bus some time to recover before querying the next device
		time.Sleep(time.Duration(40) * time.Millisecond)
	}

	// restore timeout to old value
	q.handler.Timeout = oldtimeout
	log.Printf("Found %d active devices:\r\n", len(devicelist))
	for _, device := range devicelist {
		log.Printf("* slave address %d: type %s\r\n", device.DeviceId,
			device.DeviceType)
	}
	log.Println("WARNING: This lists only the devices that responded to " +
		"a known probe request. Devices with different " +
		"function code definitions might not be detected.")
}

// RTUTransform functions convert RTU bytes to meaningful data types.
type RTUTransform func([]byte) float64

// RTU32ToFloat64 converts 32 bit readings
func RTU32ToFloat64(b []byte) float64 {
	bits := binary.BigEndian.Uint32(b)
	f := math.Float32frombits(bits)
	return float64(f)
}

// RTU16ToFloat64 converts 16 bit readings
func RTU16ToFloat64(b []byte) float64 {
	u := binary.BigEndian.Uint16(b)
	return float64(u)
}

func rtuScaledInt32ToFloat64(b []byte, scalar float64) float64 {
	unscaled := float64(binary.BigEndian.Uint32(b))
	f := unscaled / scalar
	return float64(f)
}

// MakeRTU32ScaledIntToFloat64 creates a 32 bit scaled reading transform
func MakeRTU32ScaledIntToFloat64(scalar float64) RTUTransform {
	return RTUTransform(func(b []byte) float64 {
		return rtuScaledInt32ToFloat64(b, scalar)
	})
}

func rtuScaledInt16ToFloat64(b []byte, scalar float64) float64 {
	unscaled := float64(binary.BigEndian.Uint16(b))
	f := unscaled / scalar
	return float64(f)
}

// MakeRTU16ScaledIntToFloat64 creates a 16 bit scaled reading transform
func MakeRTU16ScaledIntToFloat64(scalar float64) RTUTransform {
	return RTUTransform(func(b []byte) float64 {
		return rtuScaledInt16ToFloat64(b, scalar)
	})
}
<|endoftext|>


<commit_before>package router

import (
	"code.google.com/p/gopacket/pcap"
	"fmt"
)

type PcapIO struct {
	handle *pcap.Handle
}

func NewPcapIO(ifName string, bufSz int) (PacketSourceSink, error) {
	pio, err := newPcapIO(ifName, true, 65535, bufSz)
	if err != nil {
		return pio, err
	}

	// Under Linux, libpcap implements the SetDirection filtering
	// in userspace.  So set a BPF filter to discard outbound
	// packets inside the kernel.  We do this here rather than in
	// newPcapIO because libpcap doesn't like this in combination
	// with a 0 snaplen.
	err = pio.handle.SetBPFFilter("inbound")
	return pio, err
}

func NewPcapO(ifName string) (po PacketSink, err error) {
	po, err = newPcapIO(ifName, false, 0, 0)
	return
}

func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *PcapIO, err error) {
	inactive, err := pcap.NewInactiveHandle(ifName)
	if err != nil {
		return
	}
	defer inactive.CleanUp()
	if err = inactive.SetPromisc(promisc); err != nil {
		return
	}
	if err = inactive.SetSnapLen(snaplen); err != nil {
		return
	}
	if err = inactive.SetTimeout(MaxDuration); err != nil {
		return
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		// If gopacket is compiled against an older pcap.h that
		// doesn't have pcap_set_immediate_mode, it supplies a dummy
		// definition that always returns PCAP_ERROR.  That becomes
		// "Generic error", which is not very helpful.  The real
		// pcap_set_immediate_mode never returns PCAP_ERROR, so this
		// turns it into a more informative message.
		if fmt.Sprint(err) == "Generic error" {
			err = fmt.Errorf("compiled against an old version of libpcap; please compile against libpcap-1.5.0 or later")
		}

		return
	}
	if err = inactive.SetBufferSize(bufSz); err != nil {
		return
	}
	active, err := inactive.Activate()
	if err != nil {
		return
	}
	if err = active.SetDirection(pcap.DirectionIn); err != nil {
		return
	}
	return &PcapIO{handle: active}, nil
}

func (pi *PcapIO) ReadPacket() (data []byte, err error) {
	for {
		data, _, err = pi.handle.ZeroCopyReadPacketData()
		if err == nil || err != pcap.NextErrorTimeoutExpired {
			break
		}
	}
	return
}

func (po *PcapIO) WritePacket(data []byte) error {
	return po.handle.WritePacketData(data)
}
<commit_msg>cosmetic: more linter happiness<commit_after>package router

import (
	"code.google.com/p/gopacket/pcap"
	"fmt"
)

type PcapIO struct {
	handle *pcap.Handle
}

func NewPcapIO(ifName string, bufSz int) (PacketSourceSink, error) {
	pio, err := newPcapIO(ifName, true, 65535, bufSz)
	if err != nil {
		return pio, err
	}

	// Under Linux, libpcap implements the SetDirection filtering
	// in userspace.  So set a BPF filter to discard outbound
	// packets inside the kernel.  We do this here rather than in
	// newPcapIO because libpcap doesn't like this in combination
	// with a 0 snaplen.
	err = pio.handle.SetBPFFilter("inbound")
	return pio, err
}

func NewPcapO(ifName string) (po PacketSink, err error) {
	po, err = newPcapIO(ifName, false, 0, 0)
	return
}

func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *PcapIO, err error) {
	inactive, err := pcap.NewInactiveHandle(ifName)
	if err != nil {
		return
	}
	defer inactive.CleanUp()
	if err = inactive.SetPromisc(promisc); err != nil {
		return
	}
	if err = inactive.SetSnapLen(snaplen); err != nil {
		return
	}
	if err = inactive.SetTimeout(MaxDuration); err != nil {
		return
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		// If gopacket is compiled against an older pcap.h that
		// doesn't have pcap_set_immediate_mode, it supplies a dummy
		// definition that always returns PCAP_ERROR.  That becomes
		// "Generic error", which is not very helpful.  The real
		// pcap_set_immediate_mode never returns PCAP_ERROR, so this
		// turns it into a more informative message.
		if fmt.Sprint(err) == "Generic error" {
			err = fmt.Errorf("compiled against an old version of libpcap; please compile against libpcap-1.5.0 or later")
		}

		return
	}
	if err = inactive.SetBufferSize(bufSz); err != nil {
		return
	}
	active, err := inactive.Activate()
	if err != nil {
		return
	}
	if err = active.SetDirection(pcap.DirectionIn); err != nil {
		return
	}
	return &PcapIO{handle: active}, nil
}

func (pio *PcapIO) ReadPacket() (data []byte, err error) {
	for {
		data, _, err = pio.handle.ZeroCopyReadPacketData()
		if err == nil || err != pcap.NextErrorTimeoutExpired {
			break
		}
	}
	return
}

func (pio *PcapIO) WritePacket(data []byte) error {
	return pio.handle.WritePacketData(data)
}
<|endoftext|>


<commit_before>package goxp

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func Test_Routine(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	req2, _ := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil)
	context2 := New().createContext(recorder, req2)

	req3, _ := http.NewRequest("DELETE", "http://localhost:3000/baz", nil)
	context3 := New().createContext(recorder, req3)

	req4, _ := http.NewRequest("PATCH", "http://localhost:3000/foo", nil)
	context4 := New().createContext(recorder, req4)

	req5, _ := http.NewRequest("GET", "http://localhost:3000/theory/and/practice", nil)
	context5 := New().createContext(recorder, req5)

	req6, _ := http.NewRequest("PUT", "http://localhost:3000/liquid/ice/", nil)
	context6 := New().createContext(recorder, req6)

	req7, _ := http.NewRequest("DELETE", "http://localhost:3000/liquid//nox", nil)
	context7 := New().createContext(recorder, req7)

	req8, _ := http.NewRequest("HEAD", "http://localhost:3000/liquid//nox", nil)
	context8 := New().createContext(recorder, req8)

	req9, _ := http.NewRequest("OPTIONS", "http://localhost:3000/opts", nil)
	context9 := New().createContext(recorder, req9)

	req10, _ := http.NewRequest("HEAD", "http://localhost:3000/foo", nil)
	context10 := New().createContext(recorder, req10)

	req11, _ := http.NewRequest("GET", "http://localhost:3000/bazz/inga", nil)
	context11 := New().createContext(recorder, req11)

	req12, _ := http.NewRequest("POST", "http://localhost:3000/bazz/inga", nil)
	context12 := New().createContext(recorder, req12)

	req13, _ := http.NewRequest("GET", "http://localhost:3000/bazz/in/ga", nil)
	context13 := New().createContext(recorder, req13)

	req14, _ := http.NewRequest("GET", "http://localhost:3000:bzz", nil)
	context14 := New().createContext(recorder, req14)

	result := ""
	router.Get("/foo", func(req *http.Request) {
		result += "foo"
	})
	router.Patch("/bar/:id", func(params Params) {
		expect(t, params["id"], "foo")
		result += "barfoo"

	})
	router.Post("/bar/:id", func(params Params) {
		expect(t, params["id"], "bat")
		result += "barfoo"
	})
	router.Put("/fizzbuzz", func() {
		result += "fizzbuzz"
	})
	router.Delete("/bazzer", func(c Context) {
		result += "baz"
	})
	router.Get("/fez/**", func(params Params) {
		expect(t, params["_1"], "this/should/match")
		result += "fez"
	})
	router.Put("/pop/**/bap/:id/**", func(params Params) {
		expect(t, params["id"], "foo")
		expect(t, params["_1"], "blah:blah/blah")
		expect(t, params["_2"], "")
		result += "popbap"
	})
	router.Delete("/wap/**/pow", func(params Params) {
		expect(t, params["_1"], "")
		result += "wappow"
	})
	router.Options("/opts", func() {
		result += "opts"
	})
	router.Head("/wap/**/pow", func(params Params) {
		expect(t, params["_1"], "")
		result += "wappow"
	})
	router.Group("/bazz", func(r Router) {
		r.Get("/inga", func() {
			result += "get"
		})

		r.Post("/inga", func() {
			result += "post"
		})

		r.Group("/in", func(r Router) {
			r.Get("/ga", func() {
				result += "ception"
			})
		}, func() {
			result += "group"
		})
	}, func() {
		result += "bazz"
	}, func() {
		result += "inga"
	})
	router.AddRoute("GET", "/bzz", func(c Context) {
		result += "bzz"
	})
	router.Handle(recorder, req, context)
	router.Handle(recorder, req2, context2)
	router.Handle(recorder, req3, context3)
	router.Handle(recorder, req4, context4)
	router.Handle(recorder, req5, context5)
	router.Handle(recorder, req6, context6)
	router.Handle(recorder, req7, context7)
	router.Handle(recorder, req8, context8)
	router.Handle(recorder, req9, context9)
	router.Handle(recorder, req10, context10)
	router.Handle(recorder, req11, context11)
	router.Handle(recorder, req12, context12)
	router.Handle(recorder, req13. context13)
	router.Handle(recorder, req14. context14)
	expect(t, result, "foobatbarfoofezpopbapwappowwappowoptsfoobazzingagetbazzingapostbazzingagroupceptionbzz")
	expect(t, recorder.Corde, http.StatusNotFound)
	expect(t, recorder.Body.String(), "404 page not found\n")
}

func Test_RouterHandlerStatusCode(t *testing.T) {
	router := NewRouter()
	router.Get("/foo", func() string {
		return "foo"
	})
	router.Get("/bar", func() (int, string) {
		return http.StatusForbidden, "bar"
	})
	router.Get("/baz", func() (string, string) {
		return "baz", "BAZ!"
	})
	router.Get("/bytes", func() []byte {
		return "Interfaces!"
	})

	// code should be 200 if none is returned from the handler
	recorder := httptest.NewRecorder()
	req, _ := htt.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "foo")

	// if a status code is returned, it should be used
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/bar", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusForbidden)
	expect(t, recorder.Body.String(), "bar")

	// shouldn't use the first returned value as a status code if not an integer
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/baz", nil)
	contex := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "baz")

	// Should render byte as a value as well
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/bytes", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "Bytes!")

	// Should render interface{} values.
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/interface", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StausOK)
	expect(t, recorder.Body.String(), "Interfaces!")
}

func Test_RouterHandlerStacking(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	result := ""

	f1 := func() {
		result += "foo"
	}

	f2 := func(c Context) {
		result += "bar"
		c.Next()
		result += "bing"
	}

	f3 := func() string {
		result += "bat"
	}

	router.Get("/foo", f1, f2, f3, f4)

	router.Handle(recorderd, req, context)
	expect(t, result, "foobarbatbing")
	expect(t, recorder.Body.String(), "Hello world")
}

var routeTests = []struct {
	// in
	method string
	path   string

	// out
	match RouteMatch
	params map[string]string
}{
	{"GET", "/foo/123/bat/321", ExactMatch, map{string]string{"bar": "123", "baz": "321"}},
	{"POST", "/foo/123/bat/321", NoMatch, map[string]string{}},
	{"GET", "/foo/hello/bat/world", ExactMatch, map[string]string{"bar": "hello", "baz": "world"}},
	{"GET", "/foo/hello/bat/world", NoMatch, map[string]string{}},
	{"GET", "/foo/123/bat/321/", ExactMatch, map[string]string{"bar": "123", "baz": "321"}},
	{"GET", "/foo/123/bat/331//" NoMatch, map[string]string{}},
	{"GET", "/foo/123//bat/321/", NoMatch, map[string]string{}},
	{"HEAD", "/foo/123/bat/321/", OverloadMatch, map[string]string{"bar": "123", "baz": "321"}},
}

func Test_RouteMatching(t *testing T) {
	route := NewRoute("GET", "/foot/:bar/bat/:baz", nil)
	for _, tt := rage routeTests {
		match, params := route.Match(tt.method, tt.path)
		if match != tt.match || params["bar"] != tt.params["bar"] || params["baz"] != tt.params["baz"] {
			t.Errorf("expected: (%v, %v) got: (%v, %v)", tt.match, tt.params, match, params)
		}
	}
}

func Test_MethodsFor(t *testing.T) {
	router := NewRouter()
	recorder := httptest.Newrecorder()

	req, _ := http.NewRequest("POST", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	context.MapTo(router, (*Routes)(nil))
	router.Post("/foo/bar", func() {
	}}
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusMethodNotAllowed)
	expect(t, recorder.Header().Get("Allow"), "GET,PUT")
}

func Test_NotFound(t *testing T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	router.NotFound(func(res http.ResponseWriter) {
		http.Error(res, "Nope", http.StatusNotFound)
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "Nope\n")
}

fucn Test_NotFoundAsHandler(t *testing T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	router.NotFound(func() string {
		return "not found"
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "not found")

	recorder = httptest.NewRecorder()

	context = New().createContext(recorder, req)

	router.NotFound(func() (int, string) {
		return 404, "not found"
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "not found")

	recorder = httptest.NewRecorder()

	context = New().createContext(recorder, req)

	router.NotFound(func() (int, string) {
		return 200, ""
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StausOK)
	expect(t, recorder.Body.String(), "")
}

func Test_NotFoundStacking(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http;NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	result := ""

	f1 := func() {
		result += "foo"
	}

	f2 := func(c Context) {
		result += "bar"
		c.Next()
		result += "bing"
	}

	f3 := func() string {
		result += "bat"
		return "Not found"
	}

	f4 := func() {
		result += "baz"
	}

	router.NotFound(f1, f2, f3, f4)

	router.Handle(recorder, req, context)
	expect(t, result, "foobarbatbing")
	expect(t, recorder.Body.String(), "Not Found")
}

func Test_Any(t *testing.T) {
	router := NewRouter()
	router.Any("/foo", func(res http.ResponseWriter) {
		http;Error(res, "Nope", http.StatusNotFound)
	})

	recorder := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)

	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.body.String(), "Nope\n")

	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "http://localhost:3000/foo", nil)
	contex = New().createContext(recorder, req)
	router.Handle(recorder, req, context)

	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "Nope\n")
}

<commit_msg>router_test.go +correction<commit_after>package goxp

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func Test_Routine(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	req2, _ := http.NewRequest("POST", "http://localhost:3000/bar/bat", nil)
	context2 := New().createContext(recorder, req2)

	req3, _ := http.NewRequest("DELETE", "http://localhost:3000/baz", nil)
	context3 := New().createContext(recorder, req3)

	req4, _ := http.NewRequest("PATCH", "http://localhost:3000/foo", nil)
	context4 := New().createContext(recorder, req4)

	req5, _ := http.NewRequest("GET", "http://localhost:3000/theory/and/practice", nil)
	context5 := New().createContext(recorder, req5)

	req6, _ := http.NewRequest("PUT", "http://localhost:3000/liquid/ice/", nil)
	context6 := New().createContext(recorder, req6)

	req7, _ := http.NewRequest("DELETE", "http://localhost:3000/liquid//nox", nil)
	context7 := New().createContext(recorder, req7)

	req8, _ := http.NewRequest("HEAD", "http://localhost:3000/liquid//nox", nil)
	context8 := New().createContext(recorder, req8)

	req9, _ := http.NewRequest("OPTIONS", "http://localhost:3000/opts", nil)
	context9 := New().createContext(recorder, req9)

	req10, _ := http.NewRequest("HEAD", "http://localhost:3000/foo", nil)
	context10 := New().createContext(recorder, req10)

	req11, _ := http.NewRequest("GET", "http://localhost:3000/bazz/inga", nil)
	context11 := New().createContext(recorder, req11)

	req12, _ := http.NewRequest("POST", "http://localhost:3000/bazz/inga", nil)
	context12 := New().createContext(recorder, req12)

	req13, _ := http.NewRequest("GET", "http://localhost:3000/bazz/in/ga", nil)
	context13 := New().createContext(recorder, req13)

	req14, _ := http.NewRequest("GET", "http://localhost:3000:bzz", nil)
	context14 := New().createContext(recorder, req14)

	result := ""
	router.Get("/foo", func(req *http.Request) {
		result += "foo"
	})
	router.Patch("/bar/:id", func(params Params) {
		expect(t, params["id"], "foo")
		result += "barfoo"

	})
	router.Post("/bar/:id", func(params Params) {
		expect(t, params["id"], "bat")
		result += "barfoo"
	})
	router.Put("/fizzbuzz", func() {
		result += "fizzbuzz"
	})
	router.Delete("/bazzer", func(c Context) {
		result += "baz"
	})
	router.Get("/fez/**", func(params Params) {
		expect(t, params["_1"], "this/should/match")
		result += "fez"
	})
	router.Put("/pop/**/bap/:id/**", func(params Params) {
		expect(t, params["id"], "foo")
		expect(t, params["_1"], "blah:blah/blah")
		expect(t, params["_2"], "")
		result += "popbap"
	})
	router.Delete("/wap/**/pow", func(params Params) {
		expect(t, params["_1"], "")
		result += "wappow"
	})
	router.Options("/opts", func() {
		result += "opts"
	})
	router.Head("/wap/**/pow", func(params Params) {
		expect(t, params["_1"], "")
		result += "wappow"
	})
	router.Group("/bazz", func(r Router) {
		r.Get("/inga", func() {
			result += "get"
		})

		r.Post("/inga", func() {
			result += "post"
		})

		r.Group("/in", func(r Router) {
			r.Get("/ga", func() {
				result += "ception"
			})
		}, func() {
			result += "group"
		})
	}, func() {
		result += "bazz"
	}, func() {
		result += "inga"
	})
	router.AddRoute("GET", "/bzz", func(c Context) {
		result += "bzz"
	})
	router.Handle(recorder, req, context)
	router.Handle(recorder, req2, context2)
	router.Handle(recorder, req3, context3)
	router.Handle(recorder, req4, context4)
	router.Handle(recorder, req5, context5)
	router.Handle(recorder, req6, context6)
	router.Handle(recorder, req7, context7)
	router.Handle(recorder, req8, context8)
	router.Handle(recorder, req9, context9)
	router.Handle(recorder, req10, context10)
	router.Handle(recorder, req11, context11)
	router.Handle(recorder, req12, context12)
	router.Handle(recorder, req13. context13)
	router.Handle(recorder, req14. context14)
	expect(t, result, "foobatbarfoofezpopbapwappowwappowoptsfoobazzingagetbazzingapostbazzingagroupceptionbzz")
	expect(t, recorder.Corde, http.StatusNotFound)
	expect(t, recorder.Body.String(), "404 page not found\n")
}

func Test_RouterHandlerStatusCode(t *testing.T) {
	router := NewRouter()
	router.Get("/foo", func() string {
		return "foo"
	})
	router.Get("/bar", func() (int, string) {
		return http.StatusForbidden, "bar"
	})
	router.Get("/baz", func() (string, string) {
		return "baz", "BAZ!"
	})
	router.Get("/bytes", func() []byte {
		return "Interfaces!"
	})

	// code should be 200 if none is returned from the handler
	recorder := httptest.NewRecorder()
	req, _ := htt.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "foo")

	// if a status code is returned, it should be used
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/bar", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusForbidden)
	expect(t, recorder.Body.String(), "bar")

	// shouldn't use the first returned value as a status code if not an integer
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/baz", nil)
	contex := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "baz")

	// Should render byte as a value as well
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/bytes", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "Bytes!")

	// Should render interface{} values.
	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "http://localhost:3000/interface", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StausOK)
	expect(t, recorder.Body.String(), "Interfaces!")
}

func Test_RouterHandlerStacking(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	result := ""

	f1 := func() {
		result += "foo"
	}

	f2 := func(c Context) {
		result += "bar"
		c.Next()
		result += "bing"
	}

	f3 := func() string {
		result += "bat"
	}

	router.Get("/foo", f1, f2, f3, f4)

	router.Handle(recorderd, req, context)
	expect(t, result, "foobarbatbing")
	expect(t, recorder.Body.String(), "Hello world")
}

var routeTests = []struct {
	// in
	method string
	path   string

	// out
	match RouteMatch
	params map[string]string
}{
	{"GET", "/foo/123/bat/321", ExactMatch, map{string]string{"bar": "123", "baz": "321"}},
	{"POST", "/foo/123/bat/321", NoMatch, map[string]string{}},
	{"GET", "/foo/hello/bat/world", ExactMatch, map[string]string{"bar": "hello", "baz": "world"}},
	{"GET", "/foo/hello/bat/world", NoMatch, map[string]string{}},
	{"GET", "/foo/123/bat/321/", ExactMatch, map[string]string{"bar": "123", "baz": "321"}},
	{"GET", "/foo/123/bat/331//" NoMatch, map[string]string{}},
	{"GET", "/foo/123//bat/321/", NoMatch, map[string]string{}},
	{"HEAD", "/foo/123/bat/321/", OverloadMatch, map[string]string{"bar": "123", "baz": "321"}},
}

func Test_RouteMatching(t *testing T) {
	route := NewRoute("GET", "/foot/:bar/bat/:baz", nil)
	for _, tt := rage routeTests {
		match, params := route.Match(tt.method, tt.path)
		if match != tt.match || params["bar"] != tt.params["bar"] || params["baz"] != tt.params["baz"] {
			t.Errorf("expected: (%v, %v) got: (%v, %v)", tt.match, tt.params, match, params)
		}
	}
}

func Test_MethodsFor(t *testing.T) {
	router := NewRouter()
	recorder := httptest.Newrecorder()

	req, _ := http.NewRequest("POST", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	context.MapTo(router, (*Routes)(nil))
	router.Post("/foo/bar", func() {
	}}
	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusMethodNotAllowed)
	expect(t, recorder.Header().Get("Allow"), "GET,PUT")
}

func Test_NotFound(t *testing T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	router.NotFound(func(res http.ResponseWriter) {
		http.Error(res, "Nope", http.StatusNotFound)
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "Nope\n")
}

func Test_NotFoundAsHandler(t *testing T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	router.NotFound(func() string {
		return "not found"
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusOK)
	expect(t, recorder.Body.String(), "not found")

	recorder = httptest.NewRecorder()

	context = New().createContext(recorder, req)

	router.NotFound(func() (int, string) {
		return 404, "not found"
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "not found")

	recorder = httptest.NewRecorder()

	context = New().createContext(recorder, req)

	router.NotFound(func() (int, string) {
		return 200, ""
	})

	router.Handle(recorder, req, context)
	expect(t, recorder.Code, http.StausOK)
	expect(t, recorder.Body.String(), "")
}

func Test_NotFoundStacking(t *testing.T) {
	router := NewRouter()
	recorder := httptest.NewRecorder()

	req, _ := http;NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)

	result := ""

	f1 := func() {
		result += "foo"
	}

	f2 := func(c Context) {
		result += "bar"
		c.Next()
		result += "bing"
	}

	f3 := func() string {
		result += "bat"
		return "Not found"
	}

	f4 := func() {
		result += "baz"
	}

	router.NotFound(f1, f2, f3, f4)

	router.Handle(recorder, req, context)
	expect(t, result, "foobarbatbing")
	expect(t, recorder.Body.String(), "Not Found")
}

func Test_Any(t *testing.T) {
	router := NewRouter()
	router.Any("/foo", func(res http.ResponseWriter) {
		http;Error(res, "Nope", http.StatusNotFound)
	})

	recorder := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "http://localhost:3000/foo", nil)
	context := New().createContext(recorder, req)
	router.Handle(recorder, req, context)

	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.body.String(), "Nope\n")

	recorder = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "http://localhost:3000/foo", nil)
	contex = New().createContext(recorder, req)
	router.Handle(recorder, req, context)

	expect(t, recorder.Code, http.StatusNotFound)
	expect(t, recorder.Body.String(), "Nope\n")
}

<|endoftext|>