<commit_before>package crawler

import (
	"encoding/json"
	"fmt"
	"github.com/dokterbob/ipfs-search/indexer"
	"github.com/dokterbob/ipfs-search/queue"
	"gopkg.in/ipfs/go-ipfs-api.v1"
	"log"
	"net"
	"net/http"
	"net/url"
	// "path"
	"strings"
	"syscall"
	"time"
)

const (
	// Reconnect time in seconds
	RECONNECT_WAIT    = 2
	TIKA_TIMEOUT      = 120
	METADATA_MAX_SIZE = 50 * 1024 * 1024
)

type CrawlerArgs struct {
	Hash       string
	Name       string
	Size       uint64
	ParentHash string
	ParentName string // This is legacy, should be removed
}

type Crawler struct {
	sh *shell.Shell
	id *indexer.Indexer
	fq *queue.TaskQueue
	hq *queue.TaskQueue
}

func NewCrawler(sh *shell.Shell, id *indexer.Indexer, fq *queue.TaskQueue, hq *queue.TaskQueue) *Crawler {
	return &Crawler{
		sh: sh,
		id: id,
		fq: fq,
		hq: hq,
	}
}

func hashUrl(hash string) string {
	return fmt.Sprintf("/ipfs/%s", hash)
}

// Update references with name, parent_hash and parent_name. Returns true when updated
func update_references(references []indexer.Reference, name string, parent_hash string) ([]indexer.Reference, bool) {
	if references == nil {
		// Initialize empty references when none have been found
		references = []indexer.Reference{}
	}

	if parent_hash == "" {
		// No parent hash, don't bother adding reference
		return references, false
	}

	for i := range references {
		if references[i].ParentHash == parent_hash {
			log.Printf("Reference '%s' for %s exists, not updating", name, parent_hash)
			return references, false
		}
	}

	references = append(references, indexer.Reference{
		Name:       name,
		ParentHash: parent_hash,
	})

	return references, true
}

// Handle IPFS errors graceously, returns try again bool and original error
func (c Crawler) handleError(err error, hash string) (bool, error) {
	if _, ok := err.(*shell.Error); ok && strings.Contains(err.Error(), "proto") {
		// We're not recovering from protocol errors, so panic

		// Attempt to index panic to prevent re-indexing
		metadata := map[string]interface{}{
			"error": err.Error(),
		}

		c.id.IndexItem("invalid", hash, metadata)

		panic(err)
	}

	if uerr, ok := err.(*url.Error); ok {
		// URL errors

		log.Printf("URL error %v", uerr)

		if uerr.Timeout() {
			// Fail on timeouts
			return false, err
		}

		if uerr.Temporary() {
			// Retry on other temp errors
			return true, nil
		}

		// Somehow, the errors below are not temp errors !?
		switch t := uerr.Err.(type) {
		case *net.OpError:
			if t.Op == "dial" {
				log.Printf("Unknown host %v", t)
				return true, nil

			} else if t.Op == "read" {
				log.Printf("Connection refused %v", t)
				return true, nil
			}

		case syscall.Errno:
			if t == syscall.ECONNREFUSED {
				log.Printf("Connection refused %v", t)
				return true, nil
			}
		}
	}

	return false, err
}

func (c Crawler) index_references(hash string, name string, parent_hash string) ([]indexer.Reference, bool, error) {
	var already_indexed bool

	references, item_type, err := c.id.GetReferences(hash)
	if err != nil {
		return nil, false, err
	}

	// TODO: Handle this more explicitly, use and detect NotFound
	if references == nil {
		already_indexed = false
	} else {
		already_indexed = true
	}

	references, references_updated := update_references(references, name, parent_hash)

	if already_indexed {
		if references_updated {
			log.Printf("Found %s, adding reference '%s' from %s", hash, name, parent_hash)

			properties := map[string]interface{}{
				"references": references,
			}

			err := c.id.IndexItem(item_type, hash, properties)
			if err != nil {
				return nil, false, err
			}
		} else {
			log.Printf("Found %s, not updating references.", hash)
		}
	}

	return references, already_indexed, nil
}

// Given a particular hash (file or directory), start crawling
func (c Crawler) CrawlHash(hash string, name string, parent_hash string, parent_name string) error {
	references, already_indexed, err := c.index_references(hash, name, parent_hash)

	if err != nil {
		return err
	}

	if already_indexed {
		return nil
	}

	log.Printf("Crawling hash '%s' (%s)", hash, name)

	url := hashUrl(hash)

	var list *shell.UnixLsObject

	try_again := true
	for try_again {
		list, err = c.sh.FileList(url)

		try_again, err = c.handleError(err, hash)

		if try_again {
			log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
			time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
		}
	}

	if err != nil {
		return err
	}

	switch list.Type {
	case "File":
		// Add to file crawl queue
		args := CrawlerArgs{
			Hash:       hash,
			Name:       name,
			Size:       list.Size,
			ParentHash: parent_hash,
		}

		err = c.fq.AddTask(args)
		if err != nil {
			// failed to send the task
			return err
		}
	case "Directory":
		// Index name and size for directory and directory items
		properties := map[string]interface{}{
			"links":      list.Links,
			"size":       list.Size,
			"references": references,
		}

		err := c.id.IndexItem("directory", hash, properties)
		if err != nil {
			return err
		}

		for _, link := range list.Links {
			args := CrawlerArgs{
				Hash:       link.Hash,
				Name:       link.Name,
				Size:       link.Size,
				ParentHash: hash,
			}

			switch link.Type {
			case "File":
				// Add file to crawl queue
				err = c.fq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}

			case "Directory":
				// Add directory to crawl queue
				c.hq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}
			default:
				log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
			}
		}
	default:
		log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
	}

	log.Printf("Finished hash %s", hash)

	return nil
}

func getMetadata(path string, metadata *map[string]interface{}) error {
	const ipfs_tika_url = "http://localhost:8081"

	client := http.Client{
		Timeout: TIKA_TIMEOUT * time.Duration(time.Second),
	}

	resp, err := client.Get(ipfs_tika_url + path)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("Undesired status '%s' from ipfs-tika.", resp.Status)
	}

	// Parse resulting JSON
	if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
		return err
	}

	return err
}

// Crawl a single object, known to be a file
func (c Crawler) CrawlFile(hash string, name string, parent_hash string, parent_name string, size uint64) error {
	if size == 262144 && parent_hash == "" {
		// Assertion error.
		// REMOVE ME!
		log.Printf("Skipping unreferenced partial content for %s", hash)
		return nil
	}

	references, already_indexed, err := c.index_references(hash, name, parent_hash)

	if err != nil {
		return err
	}

	if already_indexed {
		return nil
	}

	log.Printf("Crawling file %s (%s)\n", hash, name)

	metadata := make(map[string]interface{})

	if size > 0 {
		if size > METADATA_MAX_SIZE {
			// Fail hard for really large files, for now
			return fmt.Errorf("%s (%s) too large, not indexing (for now).", hash, name)
		}

		var path string
		if name != "" && parent_hash != "" {
			path = fmt.Sprintf("/ipfs/%s/%s", parent_hash, name)
		} else {
			path = fmt.Sprintf("/ipfs/%s", hash)
		}

		try_again := true
		for try_again {
			err = getMetadata(path, &metadata)

			try_again, err = c.handleError(err, hash)

			if try_again {
				log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
				time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
			}
		}

		if err != nil {
			return err
		}

		// Check for IPFS links in content
		/*
			for raw_url := range metadata.urls {
				url, err := URL.Parse(raw_url)

				if err != nil {
					return err
				}

				if strings.HasPrefix(url.Path, "/ipfs/") {
					// Found IPFS link!
					args := CrawlerArgs{
						Hash:       link.Hash,
						Name:       link.Name,
						Size:       link.Size,
						ParentHash: hash,
					}

				}
			}
		*/
	}

	metadata["size"] = size
	metadata["references"] = references

	err = c.id.IndexItem("file", hash, metadata)
	if err != nil {
		return err
	}

	log.Printf("Finished file %s", hash)

	return nil
}
<commit_msg>Better logging for references update.<commit_after>package crawler

import (
	"encoding/json"
	"fmt"
	"github.com/dokterbob/ipfs-search/indexer"
	"github.com/dokterbob/ipfs-search/queue"
	"gopkg.in/ipfs/go-ipfs-api.v1"
	"log"
	"net"
	"net/http"
	"net/url"
	// "path"
	"strings"
	"syscall"
	"time"
)

const (
	// Reconnect time in seconds
	RECONNECT_WAIT    = 2
	TIKA_TIMEOUT      = 120
	METADATA_MAX_SIZE = 50 * 1024 * 1024
)

type CrawlerArgs struct {
	Hash       string
	Name       string
	Size       uint64
	ParentHash string
	ParentName string // This is legacy, should be removed
}

type Crawler struct {
	sh *shell.Shell
	id *indexer.Indexer
	fq *queue.TaskQueue
	hq *queue.TaskQueue
}

func NewCrawler(sh *shell.Shell, id *indexer.Indexer, fq *queue.TaskQueue, hq *queue.TaskQueue) *Crawler {
	return &Crawler{
		sh: sh,
		id: id,
		fq: fq,
		hq: hq,
	}
}

func hashUrl(hash string) string {
	return fmt.Sprintf("/ipfs/%s", hash)
}

// Update references with name, parent_hash and parent_name. Returns true when updated
func update_references(references []indexer.Reference, name string, parent_hash string) ([]indexer.Reference, bool) {
	if references == nil {
		// Initialize empty references when none have been found
		references = []indexer.Reference{}
	}

	if parent_hash == "" {
		log.Printf("No parent hash for item, not adding reference")
		return references, false
	}

	for i := range references {
		if references[i].ParentHash == parent_hash {
			log.Printf("Reference '%s' for %s exists, not updating", name, parent_hash)
			return references, false
		}
	}

	references = append(references, indexer.Reference{
		Name:       name,
		ParentHash: parent_hash,
	})

	return references, true
}

// Handle IPFS errors graceously, returns try again bool and original error
func (c Crawler) handleError(err error, hash string) (bool, error) {
	if _, ok := err.(*shell.Error); ok && strings.Contains(err.Error(), "proto") {
		// We're not recovering from protocol errors, so panic

		// Attempt to index panic to prevent re-indexing
		metadata := map[string]interface{}{
			"error": err.Error(),
		}

		c.id.IndexItem("invalid", hash, metadata)

		panic(err)
	}

	if uerr, ok := err.(*url.Error); ok {
		// URL errors

		log.Printf("URL error %v", uerr)

		if uerr.Timeout() {
			// Fail on timeouts
			return false, err
		}

		if uerr.Temporary() {
			// Retry on other temp errors
			return true, nil
		}

		// Somehow, the errors below are not temp errors !?
		switch t := uerr.Err.(type) {
		case *net.OpError:
			if t.Op == "dial" {
				log.Printf("Unknown host %v", t)
				return true, nil

			} else if t.Op == "read" {
				log.Printf("Connection refused %v", t)
				return true, nil
			}

		case syscall.Errno:
			if t == syscall.ECONNREFUSED {
				log.Printf("Connection refused %v", t)
				return true, nil
			}
		}
	}

	return false, err
}

func (c Crawler) index_references(hash string, name string, parent_hash string) ([]indexer.Reference, bool, error) {
	var already_indexed bool

	references, item_type, err := c.id.GetReferences(hash)
	if err != nil {
		return nil, false, err
	}

	// TODO: Handle this more explicitly, use and detect NotFound
	if references == nil {
		already_indexed = false
	} else {
		already_indexed = true
	}

	references, references_updated := update_references(references, name, parent_hash)

	if already_indexed {
		if references_updated {
			log.Printf("Found %s, reference added: '%s' from %s", hash, name, parent_hash)

			properties := map[string]interface{}{
				"references": references,
			}

			err := c.id.IndexItem(item_type, hash, properties)
			if err != nil {
				return nil, false, err
			}
		} else {
			log.Printf("Found %s, references not updated.", hash)
		}
	} else if references_updated {
		log.Printf("Adding %s, reference '%s' from %s", hash, name, parent_hash)
	}

	return references, already_indexed, nil
}

// Given a particular hash (file or directory), start crawling
func (c Crawler) CrawlHash(hash string, name string, parent_hash string, parent_name string) error {
	references, already_indexed, err := c.index_references(hash, name, parent_hash)

	if err != nil {
		return err
	}

	if already_indexed {
		return nil
	}

	log.Printf("Crawling hash '%s' (%s)", hash, name)

	url := hashUrl(hash)

	var list *shell.UnixLsObject

	try_again := true
	for try_again {
		list, err = c.sh.FileList(url)

		try_again, err = c.handleError(err, hash)

		if try_again {
			log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
			time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
		}
	}

	if err != nil {
		return err
	}

	switch list.Type {
	case "File":
		// Add to file crawl queue
		args := CrawlerArgs{
			Hash:       hash,
			Name:       name,
			Size:       list.Size,
			ParentHash: parent_hash,
		}

		err = c.fq.AddTask(args)
		if err != nil {
			// failed to send the task
			return err
		}
	case "Directory":
		// Index name and size for directory and directory items
		properties := map[string]interface{}{
			"links":      list.Links,
			"size":       list.Size,
			"references": references,
		}

		err := c.id.IndexItem("directory", hash, properties)
		if err != nil {
			return err
		}

		for _, link := range list.Links {
			args := CrawlerArgs{
				Hash:       link.Hash,
				Name:       link.Name,
				Size:       link.Size,
				ParentHash: hash,
			}

			switch link.Type {
			case "File":
				// Add file to crawl queue
				err = c.fq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}

			case "Directory":
				// Add directory to crawl queue
				c.hq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}
			default:
				log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
			}
		}
	default:
		log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
	}

	log.Printf("Finished hash %s", hash)

	return nil
}

func getMetadata(path string, metadata *map[string]interface{}) error {
	const ipfs_tika_url = "http://localhost:8081"

	client := http.Client{
		Timeout: TIKA_TIMEOUT * time.Duration(time.Second),
	}

	resp, err := client.Get(ipfs_tika_url + path)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("Undesired status '%s' from ipfs-tika.", resp.Status)
	}

	// Parse resulting JSON
	if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
		return err
	}

	return err
}

// Crawl a single object, known to be a file
func (c Crawler) CrawlFile(hash string, name string, parent_hash string, parent_name string, size uint64) error {
	if size == 262144 && parent_hash == "" {
		// Assertion error.
		// REMOVE ME!
		log.Printf("Skipping unreferenced partial content for %s", hash)
		return nil
	}

	references, already_indexed, err := c.index_references(hash, name, parent_hash)

	if err != nil {
		return err
	}

	if already_indexed {
		return nil
	}

	log.Printf("Crawling file %s (%s)\n", hash, name)

	metadata := make(map[string]interface{})

	if size > 0 {
		if size > METADATA_MAX_SIZE {
			// Fail hard for really large files, for now
			return fmt.Errorf("%s (%s) too large, not indexing (for now).", hash, name)
		}

		var path string
		if name != "" && parent_hash != "" {
			path = fmt.Sprintf("/ipfs/%s/%s", parent_hash, name)
		} else {
			path = fmt.Sprintf("/ipfs/%s", hash)
		}

		try_again := true
		for try_again {
			err = getMetadata(path, &metadata)

			try_again, err = c.handleError(err, hash)

			if try_again {
				log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
				time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
			}
		}

		if err != nil {
			return err
		}

		// Check for IPFS links in content
		/*
			for raw_url := range metadata.urls {
				url, err := URL.Parse(raw_url)

				if err != nil {
					return err
				}

				if strings.HasPrefix(url.Path, "/ipfs/") {
					// Found IPFS link!
					args := CrawlerArgs{
						Hash:       link.Hash,
						Name:       link.Name,
						Size:       link.Size,
						ParentHash: hash,
					}

				}
			}
		*/
	}

	metadata["size"] = size
	metadata["references"] = references

	err = c.id.IndexItem("file", hash, metadata)
	if err != nil {
		return err
	}

	log.Printf("Finished file %s", hash)

	return nil
}
<|endoftext|>


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

package rtreego

import (
	"fmt"
	"math"
	"strings"
)

// DimError represents a failure due to mismatched dimensions.
type DimError struct {
	Expected int
	Actual   int
}

func (err DimError) Error() string {
	return "rtreego: dimension mismatch"
}

// DistError is an improper distance measurement.  It implements the error
// and is generated when a distance-related assertion fails.
type DistError float64

func (err DistError) Error() string {
	return "rtreego: improper distance"
}

// Point represents a point in n-dimensional Euclidean space.
type Point []float64

// Dist computes the Euclidean distance between two points p and q.
func (p Point) dist(q Point) float64 {
	if len(p) != len(q) {
		panic(DimError{len(p), len(q)})
	}
	sum := 0.0
	for i := range p {
		dx := p[i] - q[i]
		sum += dx * dx
	}
	return math.Sqrt(sum)
}

// minDist computes the square of the distance from a point to a rectangle.
// If the point is contained in the rectangle then the distance is zero.
//
// Implemented per Definition 2 of "Nearest Neighbor Queries" by
// N. Roussopoulos, S. Kelley and F. Vincent, ACM SIGMOD, pages 71-79, 1995.
func (p Point) minDist(r *Rect) float64 {
	if len(p) != len(r.p) {
		panic(DimError{len(p), len(r.p)})
	}

	sum := 0.0
	for i, pi := range p {
		if pi < r.p[i] {
			d := pi - r.p[i]
			sum += d * d
		} else if pi > r.q[i] {
			d := pi - r.q[i]
			sum += d * d
		} else {
			sum += 0
		}
	}
	return sum
}

// minMaxDist computes the minimum of the maximum distances from p to points
// on r.  If r is the bounding box of some geometric objects, then there is
// at least one object contained in r within minMaxDist(p, r) of p.
//
// Implemented per Definition 4 of "Nearest Neighbor Queries" by
// N. Roussopoulos, S. Kelley and F. Vincent, ACM SIGMOD, pages 71-79, 1995.
func (p Point) minMaxDist(r *Rect) float64 {
	if len(p) != len(r.p) {
		panic(DimError{len(p), len(r.p)})
	}

	// by definition, MinMaxDist(p, r) =
	// min{1<=k<=n}(|pk - rmk|^2 + sum{1<=i<=n, i != k}(|pi - rMi|^2))
	// where rmk and rMk are defined as follows:

	rm := func(k int) float64 {
		if p[k] <= (r.p[k]+r.q[k])/2 {
			return r.p[k]
		}
		return r.q[k]
	}

	rM := func(k int) float64 {
		if p[k] >= (r.p[k]+r.q[k])/2 {
			return r.p[k]
		}
		return r.q[k]
	}

	// This formula can be computed in linear time by precomputing
	// S = sum{1<=i<=n}(|pi - rMi|^2).

	S := 0.0
	for i := range p {
		d := p[i] - rM(i)
		S += d * d
	}

	// Compute MinMaxDist using the precomputed S.
	min := math.MaxFloat64
	for k := range p {
		d1 := p[k] - rM(k)
		d2 := p[k] - rm(k)
		d := S - d1*d1 + d2*d2
		if d < min {
			min = d
		}
	}

	return min
}

// Rect represents a subset of n-dimensional Euclidean space of the form
// [a1, b1] x [a2, b2] x ... x [an, bn], where ai < bi for all 1 <= i <= n.
type Rect struct {
	p, q Point // Enforced by NewRect: p[i] <= q[i] for all i.
}

// PointCoord returns the coordinate of the point of the rectangle at i
func (r *Rect) PointCoord(i int) float64 {
	return r.p[i]
}

// LengthsCoord returns the coordinate of the lengths of the rectangle at i
func (r *Rect) LengthsCoord(i int) float64 {
	return r.q[i] - r.p[i]
}

// Equal returns true if the two rectangles are equal
func (r *Rect) Equal(other *Rect) bool {
	for i, e := range r.p {
		if e != other.p[i] {
			return false
		}
	}
	for i, e := range r.q {
		if e != other.q[i] {
			return false
		}
	}
	return true
}

func (r *Rect) String() string {
	s := make([]string, len(r.p))
	for i, a := range r.p {
		b := r.q[i]
		s[i] = fmt.Sprintf("[%.2f, %.2f]", a, b)
	}
	return strings.Join(s, "x")
}

// NewRect constructs and returns a pointer to a Rect given a corner point and
// the lengths of each dimension.  The point p should be the most-negative point
// on the rectangle (in every dimension) and every length should be positive.
func NewRect(p Point, lengths []float64) (r *Rect, err error) {
	r = new(Rect)
	r.p = p
	if len(p) != len(lengths) {
		err = &DimError{len(p), len(lengths)}
		return
	}
	r.q = make([]float64, len(p))
	for i := range p {
		if lengths[i] <= 0 {
			err = DistError(lengths[i])
			return
		}
		r.q[i] = p[i] + lengths[i]
	}
	return
}

// NewRectFromPoints constructs and returns a pointer to a Rect given a corner points.
func NewRectFromPoints(minPoint, maxPoint Point) (r *Rect, err error) {
	if len(minPoint) != len(maxPoint) {
		err = &DimError{len(minPoint), len(maxPoint)}
		return
	}

	r = new(Rect)
	r.p = minPoint
	r.q = maxPoint

	return
}

// Size computes the measure of a rectangle (the product of its side lengths).
func (r *Rect) Size() float64 {
	size := 1.0
	for i, a := range r.p {
		b := r.q[i]
		size *= b - a
	}
	return size
}

// margin computes the sum of the edge lengths of a rectangle.
func (r *Rect) margin() float64 {
	// The number of edges in an n-dimensional rectangle is n * 2^(n-1)
	// (http://en.wikipedia.org/wiki/Hypercube_graph).  Thus the number
	// of edges of length (ai - bi), where the rectangle is determined
	// by p = (a1, a2, ..., an) and q = (b1, b2, ..., bn), is 2^(n-1).
	//
	// The margin of the rectangle, then, is given by the formula
	// 2^(n-1) * [(b1 - a1) + (b2 - a2) + ... + (bn - an)].
	dim := len(r.p)
	sum := 0.0
	for i, a := range r.p {
		b := r.q[i]
		sum += b - a
	}
	return math.Pow(2, float64(dim-1)) * sum
}

// containsPoint tests whether p is located inside or on the boundary of r.
func (r *Rect) containsPoint(p Point) bool {
	if len(p) != len(r.p) {
		panic(DimError{len(r.p), len(p)})
	}

	for i, a := range p {
		// p is contained in (or on) r if and only if p <= a <= q for
		// every dimension.
		if a < r.p[i] || a > r.q[i] {
			return false
		}
	}

	return true
}

// containsRect tests whether r2 is is located inside r1.
func (r *Rect) containsRect(r2 *Rect) bool {
	if len(r.p) != len(r2.p) {
		panic(DimError{len(r.p), len(r2.p)})
	}

	for i, a1 := range r.p {
		b1, a2, b2 := r.q[i], r2.p[i], r2.q[i]
		// enforced by constructor: a1 <= b1 and a2 <= b2.
		// so containment holds if and only if a1 <= a2 <= b2 <= b1
		// for every dimension.
		if a1 > a2 || b2 > b1 {
			return false
		}
	}

	return true
}

// intersect computes the intersection of two rectangles.  If no intersection
// exists, the intersection is nil.
func intersect(r1, r2 *Rect) bool {
	dim := len(r1.p)
	if len(r2.p) != dim {
		panic(DimError{dim, len(r2.p)})
	}

	// There are four cases of overlap:
	//
	//     1.  a1------------b1
	//              a2------------b2
	//              p--------q
	//
	//     2.       a1------------b1
	//         a2------------b2
	//              p--------q
	//
	//     3.  a1-----------------b1
	//              a2-------b2
	//              p--------q
	//
	//     4.       a1-------b1
	//         a2-----------------b2
	//              p--------q
	//
	// Thus there are only two cases of non-overlap:
	//
	//     1. a1------b1
	//                    a2------b2
	//
	//     2.             a1------b1
	//        a2------b2
	//
	// Enforced by constructor: a1 <= b1 and a2 <= b2.  So we can just
	// check the endpoints.

	for i := range r1.p {
		a1, b1, a2, b2 := r1.p[i], r1.q[i], r2.p[i], r2.q[i]
		if b2 <= a1 || b1 <= a2 {
			return false
		}
	}
	return true
}

// ToRect constructs a rectangle containing p with side lengths 2*tol.
func (p Point) ToRect(tol float64) *Rect {
	dim := len(p)
	a, b := make([]float64, dim), make([]float64, dim)
	for i := range p {
		a[i] = p[i] - tol
		b[i] = p[i] + tol
	}
	return &Rect{a, b}
}

// boundingBox constructs the smallest rectangle containing both r1 and r2.
func boundingBox(r1, r2 *Rect) (bb *Rect) {
	bb = new(Rect)
	dim := len(r1.p)
	bb.p = make([]float64, dim)
	bb.q = make([]float64, dim)
	if len(r2.p) != dim {
		panic(DimError{dim, len(r2.p)})
	}
	for i := 0; i < dim; i++ {
		if r1.p[i] <= r2.p[i] {
			bb.p[i] = r1.p[i]
		} else {
			bb.p[i] = r2.p[i]
		}
		if r1.q[i] <= r2.q[i] {
			bb.q[i] = r2.q[i]
		} else {
			bb.q[i] = r1.q[i]
		}
	}
	return
}

// boundingBoxN constructs the smallest rectangle containing all of r...
func boundingBoxN(rects ...*Rect) (bb *Rect) {
	if len(rects) == 1 {
		bb = rects[0]
		return
	}
	bb = boundingBox(rects[0], rects[1])
	for _, rect := range rects[2:] {
		bb = boundingBox(bb, rect)
	}
	return
}
<commit_msg>fix code style<commit_after>// Copyright 2012 Daniel Connelly.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rtreego

import (
	"fmt"
	"math"
	"strings"
)

// DimError represents a failure due to mismatched dimensions.
type DimError struct {
	Expected int
	Actual   int
}

func (err DimError) Error() string {
	return "rtreego: dimension mismatch"
}

// DistError is an improper distance measurement.  It implements the error
// and is generated when a distance-related assertion fails.
type DistError float64

func (err DistError) Error() string {
	return "rtreego: improper distance"
}

// Point represents a point in n-dimensional Euclidean space.
type Point []float64

// Dist computes the Euclidean distance between two points p and q.
func (p Point) dist(q Point) float64 {
	if len(p) != len(q) {
		panic(DimError{len(p), len(q)})
	}
	sum := 0.0
	for i := range p {
		dx := p[i] - q[i]
		sum += dx * dx
	}
	return math.Sqrt(sum)
}

// minDist computes the square of the distance from a point to a rectangle.
// If the point is contained in the rectangle then the distance is zero.
//
// Implemented per Definition 2 of "Nearest Neighbor Queries" by
// N. Roussopoulos, S. Kelley and F. Vincent, ACM SIGMOD, pages 71-79, 1995.
func (p Point) minDist(r *Rect) float64 {
	if len(p) != len(r.p) {
		panic(DimError{len(p), len(r.p)})
	}

	sum := 0.0
	for i, pi := range p {
		if pi < r.p[i] {
			d := pi - r.p[i]
			sum += d * d
		} else if pi > r.q[i] {
			d := pi - r.q[i]
			sum += d * d
		} else {
			sum += 0
		}
	}
	return sum
}

// minMaxDist computes the minimum of the maximum distances from p to points
// on r.  If r is the bounding box of some geometric objects, then there is
// at least one object contained in r within minMaxDist(p, r) of p.
//
// Implemented per Definition 4 of "Nearest Neighbor Queries" by
// N. Roussopoulos, S. Kelley and F. Vincent, ACM SIGMOD, pages 71-79, 1995.
func (p Point) minMaxDist(r *Rect) float64 {
	if len(p) != len(r.p) {
		panic(DimError{len(p), len(r.p)})
	}

	// by definition, MinMaxDist(p, r) =
	// min{1<=k<=n}(|pk - rmk|^2 + sum{1<=i<=n, i != k}(|pi - rMi|^2))
	// where rmk and rMk are defined as follows:

	rm := func(k int) float64 {
		if p[k] <= (r.p[k]+r.q[k])/2 {
			return r.p[k]
		}
		return r.q[k]
	}

	rM := func(k int) float64 {
		if p[k] >= (r.p[k]+r.q[k])/2 {
			return r.p[k]
		}
		return r.q[k]
	}

	// This formula can be computed in linear time by precomputing
	// S = sum{1<=i<=n}(|pi - rMi|^2).

	S := 0.0
	for i := range p {
		d := p[i] - rM(i)
		S += d * d
	}

	// Compute MinMaxDist using the precomputed S.
	min := math.MaxFloat64
	for k := range p {
		d1 := p[k] - rM(k)
		d2 := p[k] - rm(k)
		d := S - d1*d1 + d2*d2
		if d < min {
			min = d
		}
	}

	return min
}

// Rect represents a subset of n-dimensional Euclidean space of the form
// [a1, b1] x [a2, b2] x ... x [an, bn], where ai < bi for all 1 <= i <= n.
type Rect struct {
	p, q Point // Enforced by NewRect: p[i] <= q[i] for all i.
}

// PointCoord returns the coordinate of the point of the rectangle at i
func (r *Rect) PointCoord(i int) float64 {
	return r.p[i]
}

// LengthsCoord returns the coordinate of the lengths of the rectangle at i
func (r *Rect) LengthsCoord(i int) float64 {
	return r.q[i] - r.p[i]
}

// Equal returns true if the two rectangles are equal
func (r *Rect) Equal(other *Rect) bool {
	for i, e := range r.p {
		if e != other.p[i] {
			return false
		}
	}
	for i, e := range r.q {
		if e != other.q[i] {
			return false
		}
	}
	return true
}

func (r *Rect) String() string {
	s := make([]string, len(r.p))
	for i, a := range r.p {
		b := r.q[i]
		s[i] = fmt.Sprintf("[%.2f, %.2f]", a, b)
	}
	return strings.Join(s, "x")
}

// NewRect constructs and returns a pointer to a Rect given a corner point and
// the lengths of each dimension.  The point p should be the most-negative point
// on the rectangle (in every dimension) and every length should be positive.
func NewRect(p Point, lengths []float64) (r *Rect, err error) {
	r = new(Rect)
	r.p = p
	if len(p) != len(lengths) {
		err = &DimError{len(p), len(lengths)}
		return
	}
	r.q = make([]float64, len(p))
	for i := range p {
		if lengths[i] <= 0 {
			err = DistError(lengths[i])
			return
		}
		r.q[i] = p[i] + lengths[i]
	}
	return
}

// NewRectFromPoints constructs and returns a pointer to a Rect given a corner points.
func NewRectFromPoints(minPoint, maxPoint Point) (r *Rect, err error) {
	if len(minPoint) != len(maxPoint) {
		err = &DimError{len(minPoint), len(maxPoint)}
		return
	}

	r = &Rect{p: minPoint, q: maxPoint}
	return
}

// Size computes the measure of a rectangle (the product of its side lengths).
func (r *Rect) Size() float64 {
	size := 1.0
	for i, a := range r.p {
		b := r.q[i]
		size *= b - a
	}
	return size
}

// margin computes the sum of the edge lengths of a rectangle.
func (r *Rect) margin() float64 {
	// The number of edges in an n-dimensional rectangle is n * 2^(n-1)
	// (http://en.wikipedia.org/wiki/Hypercube_graph).  Thus the number
	// of edges of length (ai - bi), where the rectangle is determined
	// by p = (a1, a2, ..., an) and q = (b1, b2, ..., bn), is 2^(n-1).
	//
	// The margin of the rectangle, then, is given by the formula
	// 2^(n-1) * [(b1 - a1) + (b2 - a2) + ... + (bn - an)].
	dim := len(r.p)
	sum := 0.0
	for i, a := range r.p {
		b := r.q[i]
		sum += b - a
	}
	return math.Pow(2, float64(dim-1)) * sum
}

// containsPoint tests whether p is located inside or on the boundary of r.
func (r *Rect) containsPoint(p Point) bool {
	if len(p) != len(r.p) {
		panic(DimError{len(r.p), len(p)})
	}

	for i, a := range p {
		// p is contained in (or on) r if and only if p <= a <= q for
		// every dimension.
		if a < r.p[i] || a > r.q[i] {
			return false
		}
	}

	return true
}

// containsRect tests whether r2 is is located inside r1.
func (r *Rect) containsRect(r2 *Rect) bool {
	if len(r.p) != len(r2.p) {
		panic(DimError{len(r.p), len(r2.p)})
	}

	for i, a1 := range r.p {
		b1, a2, b2 := r.q[i], r2.p[i], r2.q[i]
		// enforced by constructor: a1 <= b1 and a2 <= b2.
		// so containment holds if and only if a1 <= a2 <= b2 <= b1
		// for every dimension.
		if a1 > a2 || b2 > b1 {
			return false
		}
	}

	return true
}

// intersect computes the intersection of two rectangles.  If no intersection
// exists, the intersection is nil.
func intersect(r1, r2 *Rect) bool {
	dim := len(r1.p)
	if len(r2.p) != dim {
		panic(DimError{dim, len(r2.p)})
	}

	// There are four cases of overlap:
	//
	//     1.  a1------------b1
	//              a2------------b2
	//              p--------q
	//
	//     2.       a1------------b1
	//         a2------------b2
	//              p--------q
	//
	//     3.  a1-----------------b1
	//              a2-------b2
	//              p--------q
	//
	//     4.       a1-------b1
	//         a2-----------------b2
	//              p--------q
	//
	// Thus there are only two cases of non-overlap:
	//
	//     1. a1------b1
	//                    a2------b2
	//
	//     2.             a1------b1
	//        a2------b2
	//
	// Enforced by constructor: a1 <= b1 and a2 <= b2.  So we can just
	// check the endpoints.

	for i := range r1.p {
		a1, b1, a2, b2 := r1.p[i], r1.q[i], r2.p[i], r2.q[i]
		if b2 <= a1 || b1 <= a2 {
			return false
		}
	}
	return true
}

// ToRect constructs a rectangle containing p with side lengths 2*tol.
func (p Point) ToRect(tol float64) *Rect {
	dim := len(p)
	a, b := make([]float64, dim), make([]float64, dim)
	for i := range p {
		a[i] = p[i] - tol
		b[i] = p[i] + tol
	}
	return &Rect{a, b}
}

// boundingBox constructs the smallest rectangle containing both r1 and r2.
func boundingBox(r1, r2 *Rect) (bb *Rect) {
	bb = new(Rect)
	dim := len(r1.p)
	bb.p = make([]float64, dim)
	bb.q = make([]float64, dim)
	if len(r2.p) != dim {
		panic(DimError{dim, len(r2.p)})
	}
	for i := 0; i < dim; i++ {
		if r1.p[i] <= r2.p[i] {
			bb.p[i] = r1.p[i]
		} else {
			bb.p[i] = r2.p[i]
		}
		if r1.q[i] <= r2.q[i] {
			bb.q[i] = r2.q[i]
		} else {
			bb.q[i] = r1.q[i]
		}
	}
	return
}

// boundingBoxN constructs the smallest rectangle containing all of r...
func boundingBoxN(rects ...*Rect) (bb *Rect) {
	if len(rects) == 1 {
		bb = rects[0]
		return
	}
	bb = boundingBox(rects[0], rects[1])
	for _, rect := range rects[2:] {
		bb = boundingBox(bb, rect)
	}
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package dynamic

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/rest"
)

type dynamicClient struct {
	client *rest.RESTClient
}

var _ Interface = &dynamicClient{}

// ConfigFor returns a copy of the provided config with the
// appropriate dynamic client defaults set.
func ConfigFor(inConfig *rest.Config) *rest.Config {
	config := rest.CopyConfig(inConfig)
	config.AcceptContentTypes = "application/json"
	config.ContentType = "application/json"
	config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
	if config.UserAgent == "" {
		config.UserAgent = rest.DefaultKubernetesUserAgent()
	}
	return config
}

// NewForConfigOrDie creates a new Interface for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) Interface {
	ret, err := NewForConfig(c)
	if err != nil {
		panic(err)
	}
	return ret
}

// NewForConfig creates a new dynamic client or returns an error.
func NewForConfig(inConfig *rest.Config) (Interface, error) {
	config := ConfigFor(inConfig)
	// for serializing the options
	config.GroupVersion = &schema.GroupVersion{}
	config.APIPath = "/if-you-see-this-search-for-the-break"

	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		return nil, err
	}

	return &dynamicClient{client: restClient}, nil
}

type dynamicResourceClient struct {
	client    *dynamicClient
	namespace string
	resource  schema.GroupVersionResource
}

func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
	return &dynamicResourceClient{client: c, resource: resource}
}

func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
	ret := *c
	ret.namespace = ns
	return &ret
}

func (c *dynamicResourceClient) Create(ctx context.Context, obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}
	name := ""
	if len(subresources) > 0 {
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name = accessor.GetName()
		if len(name) == 0 {
			return nil, fmt.Errorf("name is required")
		}
	}

	result := c.client.client.
		Post().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Update(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	name := accessor.GetName()
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.
		Put().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	name := accessor.GetName()
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}

	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.
		Put().
		AbsPath(append(c.makeURLSegments(name), "status")...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error {
	if len(name) == 0 {
		return fmt.Errorf("name is required")
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
	if err != nil {
		return err
	}

	result := c.client.client.
		Delete().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(deleteOptionsByte).
		Do(ctx)
	return result.Error()
}

func (c *dynamicResourceClient) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
	if err != nil {
		return err
	}

	result := c.client.client.
		Delete().
		AbsPath(c.makeURLSegments("")...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(deleteOptionsByte).
		SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).
		Do(ctx)
	return result.Error()
}

func (c *dynamicResourceClient) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
		return list, nil
	}

	list, err := uncastObj.(*unstructured.Unstructured).ToList()
	if err != nil {
		return nil, err
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
	opts.Watch = true
	return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Watch(ctx)
}

func (c *dynamicResourceClient) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	result := c.client.client.
		Patch(pt).
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		Body(data).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) makeURLSegments(name string) []string {
	url := []string{}
	if len(c.resource.Group) == 0 {
		url = append(url, "api")
	} else {
		url = append(url, "apis", c.resource.Group)
	}
	url = append(url, c.resource.Version)

	if len(c.namespace) > 0 {
		url = append(url, "namespaces", c.namespace)
	}
	url = append(url, c.resource.Resource)

	if len(name) > 0 {
		url = append(url, name)
	}

	return url
}
<commit_msg>expose NewForConfigAndClient for the dynamic client<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package dynamic

import (
	"context"
	"fmt"
	"net/http"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/rest"
)

type dynamicClient struct {
	client *rest.RESTClient
}

var _ Interface = &dynamicClient{}

// ConfigFor returns a copy of the provided config with the
// appropriate dynamic client defaults set.
func ConfigFor(inConfig *rest.Config) *rest.Config {
	config := rest.CopyConfig(inConfig)
	config.AcceptContentTypes = "application/json"
	config.ContentType = "application/json"
	config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types
	if config.UserAgent == "" {
		config.UserAgent = rest.DefaultKubernetesUserAgent()
	}
	return config
}

// NewForConfigOrDie creates a new Interface for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) Interface {
	ret, err := NewForConfig(c)
	if err != nil {
		panic(err)
	}
	return ret
}

// NewForConfig creates a new dynamic client or returns an error.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(inConfig *rest.Config) (Interface, error) {
	config := ConfigFor(inConfig)

	httpClient, err := rest.HTTPClientFor(config)
	if err != nil {
		return nil, err
	}
	return NewForConfigAndClient(config, httpClient)
}

// NewForConfigAndClient creates a new dynamic client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(inConfig *rest.Config, h *http.Client) (Interface, error) {
	config := ConfigFor(inConfig)
	// for serializing the options
	config.GroupVersion = &schema.GroupVersion{}
	config.APIPath = "/if-you-see-this-search-for-the-break"

	restClient, err := rest.RESTClientForConfigAndClient(config, h)
	if err != nil {
		return nil, err
	}
	return &dynamicClient{client: restClient}, nil
}

type dynamicResourceClient struct {
	client    *dynamicClient
	namespace string
	resource  schema.GroupVersionResource
}

func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
	return &dynamicResourceClient{client: c, resource: resource}
}

func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
	ret := *c
	ret.namespace = ns
	return &ret
}

func (c *dynamicResourceClient) Create(ctx context.Context, obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}
	name := ""
	if len(subresources) > 0 {
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		name = accessor.GetName()
		if len(name) == 0 {
			return nil, fmt.Errorf("name is required")
		}
	}

	result := c.client.client.
		Post().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Update(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	name := accessor.GetName()
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.
		Put().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	name := accessor.GetName()
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}

	outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
	if err != nil {
		return nil, err
	}

	result := c.client.client.
		Put().
		AbsPath(append(c.makeURLSegments(name), "status")...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(outBytes).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}

	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error {
	if len(name) == 0 {
		return fmt.Errorf("name is required")
	}
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
	if err != nil {
		return err
	}

	result := c.client.client.
		Delete().
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(deleteOptionsByte).
		Do(ctx)
	return result.Error()
}

func (c *dynamicResourceClient) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error {
	deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
	if err != nil {
		return err
	}

	result := c.client.client.
		Delete().
		AbsPath(c.makeURLSegments("")...).
		SetHeader("Content-Type", runtime.ContentTypeJSON).
		Body(deleteOptionsByte).
		SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).
		Do(ctx)
	return result.Error()
}

func (c *dynamicResourceClient) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
	result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	if list, ok := uncastObj.(*unstructured.UnstructuredList); ok {
		return list, nil
	}

	list, err := uncastObj.(*unstructured.Unstructured).ToList()
	if err != nil {
		return nil, err
	}
	return list, nil
}

func (c *dynamicResourceClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
	opts.Watch = true
	return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Watch(ctx)
}

func (c *dynamicResourceClient) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("name is required")
	}
	result := c.client.client.
		Patch(pt).
		AbsPath(append(c.makeURLSegments(name), subresources...)...).
		Body(data).
		SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
		Do(ctx)
	if err := result.Error(); err != nil {
		return nil, err
	}
	retBytes, err := result.Raw()
	if err != nil {
		return nil, err
	}
	uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes)
	if err != nil {
		return nil, err
	}
	return uncastObj.(*unstructured.Unstructured), nil
}

func (c *dynamicResourceClient) makeURLSegments(name string) []string {
	url := []string{}
	if len(c.resource.Group) == 0 {
		url = append(url, "api")
	} else {
		url = append(url, "apis", c.resource.Group)
	}
	url = append(url, c.resource.Version)

	if len(c.namespace) > 0 {
		url = append(url, "namespaces", c.namespace)
	}
	url = append(url, c.resource.Resource)

	if len(name) > 0 {
		url = append(url, name)
	}

	return url
}
<|endoftext|>


<commit_before>package ordpool

import (
	"errors"
	"github.com/bmizerany/assert"
	"testing"
	"time"
)

func TestOneWorkItem(t *testing.T) {
	o := New(10, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	o.GetInputCh() <- "abc"
	roundTrip := <-o.GetOutputCh()
	assert.Equal(t, "abc", roundTrip)
}

func TestFailure(t *testing.T) {
	o := New(10, failWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	o.GetInputCh() <- "abc"
	_, ok := <-o.GetOutputCh()
	assert.T(t, !ok)
	assert.Equal(t, 1, len(o.GetErrs()))
}

func TestMaxThroughput(t *testing.T) {
	const NUM_WORKERS = 2
	o := New(NUM_WORKERS, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	outCh := o.GetOutputCh()

	const NUM_MSGS = 10000
	// Start a background goroutine to read the pool output and check it
	go func() {
		for i := 0; i < NUM_MSGS; i++ {
			msg, ok := <-outCh
			assert.T(t, ok)
			assert.Equal(t, i, msg.(int))
		}
	}()

	inCh := o.GetInputCh()
	for i := 0; i < NUM_MSGS; i++ {
		inCh <- i
	}
	o.Stop()
}

// Test that output order is the same as input order even when work items take different
// amounts of time to compute.
func TestSequential(t *testing.T) {
	o := New(10, func(i interface{}) (interface{}, error) {
		// Sleep for 0 or 1 millisecond
		time.Sleep(time.Duration((i.(int) % 2)) * time.Millisecond)
		return i, nil
	})

	o.Start()
	defer func() {
		o.Stop()
	}()

	inChan := o.GetInputCh()

	const NUM_MSGS = 10000

	go func() {
		for i := 0; i < NUM_MSGS; i++ {
			inChan <- i
		}
		o.Stop()
	}()

	outChan := o.GetOutputCh()
	for i := 0; i < NUM_MSGS; i++ {
		roundTrip := <-outChan
		assert.Equal(t, i, roundTrip)
	}
	o.WaitForShutdown()
}

func TestNoWork(t *testing.T) {
	o := New(10, passthroughWorkFunc)

	o.Start()
	o.Stop()
	o.WaitForShutdown()
}

func passthroughWorkFunc(i interface{}) (interface{}, error) {
	return i, nil
}

func failWorkFunc(i interface{}) (interface{}, error) {
	return nil, errors.New("Intentional failure for testing")
}

// Results 2013-4-26: the pool overhead is on the order of 2us with GOMAXPROCS=1 to 10us
// with GOMAXPROCS=20.
func BenchmarkPassthrough(b *testing.B) {
	const NUM_WORKERS = 5
	o := New(NUM_WORKERS, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	outCh := o.GetOutputCh()

	// Start a background goroutine to read the pool output and discard it
	go func() {
		for i := 0; i < b.N; i++ {
			if _, ok := <-outCh; !ok {
				panic("unexpected output channel close")
			}
		}
	}()

	inCh := o.GetInputCh()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		inCh <- i
	}
	o.Stop()
	b.StopTimer()
}
<commit_msg>Pool shutdown time should be part of benchmark<commit_after>package ordpool

import (
	"errors"
	"github.com/bmizerany/assert"
	"testing"
	"time"
)

func TestOneWorkItem(t *testing.T) {
	o := New(10, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	o.GetInputCh() <- "abc"
	roundTrip := <-o.GetOutputCh()
	assert.Equal(t, "abc", roundTrip)
}

func TestFailure(t *testing.T) {
	o := New(10, failWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	o.GetInputCh() <- "abc"
	_, ok := <-o.GetOutputCh()
	assert.T(t, !ok)
	assert.Equal(t, 1, len(o.GetErrs()))
}

func TestMaxThroughput(t *testing.T) {
	const NUM_WORKERS = 2
	o := New(NUM_WORKERS, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	outCh := o.GetOutputCh()

	const NUM_MSGS = 10000
	// Start a background goroutine to read the pool output and check it
	go func() {
		for i := 0; i < NUM_MSGS; i++ {
			msg, ok := <-outCh
			assert.T(t, ok)
			assert.Equal(t, i, msg.(int))
		}
	}()

	inCh := o.GetInputCh()
	for i := 0; i < NUM_MSGS; i++ {
		inCh <- i
	}
	o.Stop()
}

// Test that output order is the same as input order even when work items take different
// amounts of time to compute.
func TestSequential(t *testing.T) {
	o := New(10, func(i interface{}) (interface{}, error) {
		// Sleep for 0 or 1 millisecond
		time.Sleep(time.Duration((i.(int) % 2)) * time.Millisecond)
		return i, nil
	})

	o.Start()
	defer func() {
		o.Stop()
	}()

	inChan := o.GetInputCh()

	const NUM_MSGS = 10000

	go func() {
		for i := 0; i < NUM_MSGS; i++ {
			inChan <- i
		}
		o.Stop()
	}()

	outChan := o.GetOutputCh()
	for i := 0; i < NUM_MSGS; i++ {
		roundTrip := <-outChan
		assert.Equal(t, i, roundTrip)
	}
	o.WaitForShutdown()
}

func TestNoWork(t *testing.T) {
	o := New(10, passthroughWorkFunc)

	o.Start()
	o.Stop()
	o.WaitForShutdown()
}

func passthroughWorkFunc(i interface{}) (interface{}, error) {
	return i, nil
}

func failWorkFunc(i interface{}) (interface{}, error) {
	return nil, errors.New("Intentional failure for testing")
}

// Results 2013-4-26: the pool overhead is on the order of 2us with GOMAXPROCS=1 to 10us
// with GOMAXPROCS=20.
func BenchmarkPassthrough(b *testing.B) {
	const NUM_WORKERS = 5
	o := New(NUM_WORKERS, passthroughWorkFunc)

	o.Start()
	defer func() {
		o.Stop()
		o.WaitForShutdown()
	}()

	outCh := o.GetOutputCh()

	// Start a background goroutine to read the pool output and discard it
	go func() {
		for i := 0; i < b.N; i++ {
			if _, ok := <-outCh; !ok {
				panic("unexpected output channel close")
			}
		}
	}()

	inCh := o.GetInputCh()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		inCh <- i
	}
	o.Stop()
	o.WaitForShutdown()
	b.StopTimer()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package availabilityset

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/r3labs/terraform/helper/schema"

	aes "github.com/ernestio/crypto/aes"
	"github.com/ernestio/ernestprovider/event"
	"github.com/ernestio/ernestprovider/providers/azure"
)

// Event : This is the Ernest representation of an azure availability setb
type Event struct {
	event.Base
	ID                        string            `json:"id"`
	Name                      string            `json:"name" validate:"required"`
	ResourceGroupName         string            `json:"resource_group_name" validate:"required"`
	Location                  string            `json:"location"`
	PlatformUpdateDomainCount int               `json:"platform_update_domain_count"`
	PlatformFaultDomainCount  int               `json:"platform_fault_domain_count"`
	Managed                   bool              `json:"managed"`
	Tags                      map[string]string `json:"tags"`
	ClientID                  string            `json:"azure_client_id"`
	ClientSecret              string            `json:"azure_client_secret"`
	TenantID                  string            `json:"azure_tenant_id"`
	SubscriptionID            string            `json:"azure_subscription_id"`
	Environment               string            `json:"environment"`
	ErrorMessage              string            `json:"error,omitempty"`
	Components                []json.RawMessage `json:"components"`
	CryptoKey                 string            `json:"-"`
	Validator                 *event.Validator  `json:"-"`
}

// New : Constructor
func New(subject, cryptoKey string, body []byte, val *event.Validator) (event.Event, error) {
	var ev event.Resource
	ev = &Event{CryptoKey: cryptoKey, Validator: val}
	body = []byte(strings.Replace(string(body), `"_component":"availability_sets"`, `"_component":"availability_set"`, 1))
	if err := json.Unmarshal(body, &ev); err != nil {
		err := fmt.Errorf("Error on input message : %s", err)
		return nil, err
	}

	return azure.New(subject, "azurerm_availability_set", body, val, ev)
}

// SetComponents : ....
func (ev *Event) SetComponents(components []event.Event) {
	for _, v := range components {
		ev.Components = append(ev.Components, v.GetBody())
	}
}

// ValidateID : determines if the given id is valid for this resource type
func (ev *Event) ValidateID(id string) bool {
	parts := strings.Split(strings.ToLower(id), "/")
	if len(parts) != 8 {
		return false
	}
	if parts[6] != "microsoft.compute" {
		return false
	}
	if parts[7] != "availabilitysets" {
		return false
	}
	return true
}

// SetID : id setter
func (ev *Event) SetID(id string) {
	ev.ID = id
}

// GetID : id getter
func (ev *Event) GetID() string {
	return ev.ID
}

// SetState : state setter
func (ev *Event) SetState(state string) {
	ev.State = state
}

// ResourceDataToEvent : Translates a ResourceData on a valid Ernest Event
func (ev *Event) ResourceDataToEvent(d *schema.ResourceData) error {
	idParts := strings.Split(d.Id(), "/")
	ev.ID = d.Id()
	ev.Name = idParts[len(idParts)-1]
	ev.ComponentID = "availability_set::" + ev.Name
	ev.ResourceGroupName = d.Get("resource_group_name").(string)
	ev.Location = d.Get("location").(string)
	ev.PlatformUpdateDomainCount = d.Get("platform_update_domain_count").(int)
	ev.PlatformFaultDomainCount = d.Get("platform_fault_domain_count").(int)
	ev.Managed = d.Get("managed").(bool)

	tags := make(map[string]string, 0)
	for k, v := range d.Get("tags").(map[string]interface{}) {
		tags[k] = v.(string)
	}
	ev.Tags = tags
	return nil
}

// EventToResourceData : Translates the current event on a valid ResourceData
func (ev *Event) EventToResourceData(d *schema.ResourceData) error {
	crypto := aes.New()

	encFields := make(map[string]string)
	encFields["subscription_id"] = ev.SubscriptionID
	encFields["client_id"] = ev.ClientID
	encFields["client_secret"] = ev.ClientSecret
	encFields["tenant_id"] = ev.TenantID
	encFields["environment"] = ev.Environment
	for k, v := range encFields {
		dec, err := crypto.Decrypt(v, ev.CryptoKey)
		if err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
		if err := d.Set(k, dec); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	fields := make(map[string]interface{})
	fields["name"] = ev.Name
	fields["resource_group_name"] = ev.ResourceGroupName
	fields["location"] = ev.Location
	fields["platform_update_domain_count"] = ev.PlatformUpdateDomainCount
	fields["platform_fault_domain_count"] = ev.PlatformFaultDomainCount
	fields["managed"] = ev.Managed
	fields["tags"] = ev.Tags
	for k, v := range fields {
		if err := d.Set(k, v); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	return nil
}

// Clone : will mark the event as errored
func (ev *Event) Clone() (event.Event, error) {
	body, _ := json.Marshal(ev)
	return New(ev.Subject, ev.CryptoKey, body, ev.Validator)
}

// Error : will mark the event as errored
func (ev *Event) Error(err error) {
	ev.ErrorMessage = err.Error()
	ev.Body, err = json.Marshal(ev)
}
<commit_msg>removed managed field<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package availabilityset

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/r3labs/terraform/helper/schema"

	aes "github.com/ernestio/crypto/aes"
	"github.com/ernestio/ernestprovider/event"
	"github.com/ernestio/ernestprovider/providers/azure"
)

// Event : This is the Ernest representation of an azure availability setb
type Event struct {
	event.Base
	ID                        string            `json:"id"`
	Name                      string            `json:"name" validate:"required"`
	ResourceGroupName         string            `json:"resource_group_name" validate:"required"`
	Location                  string            `json:"location"`
	PlatformUpdateDomainCount int               `json:"platform_update_domain_count"`
	PlatformFaultDomainCount  int               `json:"platform_fault_domain_count"`
	Managed                   bool              `json:"managed"`
	Tags                      map[string]string `json:"tags"`
	ClientID                  string            `json:"azure_client_id"`
	ClientSecret              string            `json:"azure_client_secret"`
	TenantID                  string            `json:"azure_tenant_id"`
	SubscriptionID            string            `json:"azure_subscription_id"`
	Environment               string            `json:"environment"`
	ErrorMessage              string            `json:"error,omitempty"`
	Components                []json.RawMessage `json:"components"`
	CryptoKey                 string            `json:"-"`
	Validator                 *event.Validator  `json:"-"`
}

// New : Constructor
func New(subject, cryptoKey string, body []byte, val *event.Validator) (event.Event, error) {
	var ev event.Resource
	ev = &Event{CryptoKey: cryptoKey, Validator: val}
	body = []byte(strings.Replace(string(body), `"_component":"availability_sets"`, `"_component":"availability_set"`, 1))
	if err := json.Unmarshal(body, &ev); err != nil {
		err := fmt.Errorf("Error on input message : %s", err)
		return nil, err
	}

	return azure.New(subject, "azurerm_availability_set", body, val, ev)
}

// SetComponents : ....
func (ev *Event) SetComponents(components []event.Event) {
	for _, v := range components {
		ev.Components = append(ev.Components, v.GetBody())
	}
}

// ValidateID : determines if the given id is valid for this resource type
func (ev *Event) ValidateID(id string) bool {
	parts := strings.Split(strings.ToLower(id), "/")
	if len(parts) != 8 {
		return false
	}
	if parts[6] != "microsoft.compute" {
		return false
	}
	if parts[7] != "availabilitysets" {
		return false
	}
	return true
}

// SetID : id setter
func (ev *Event) SetID(id string) {
	ev.ID = id
}

// GetID : id getter
func (ev *Event) GetID() string {
	return ev.ID
}

// SetState : state setter
func (ev *Event) SetState(state string) {
	ev.State = state
}

// ResourceDataToEvent : Translates a ResourceData on a valid Ernest Event
func (ev *Event) ResourceDataToEvent(d *schema.ResourceData) error {
	idParts := strings.Split(d.Id(), "/")
	ev.ID = d.Id()
	ev.Name = idParts[len(idParts)-1]
	ev.ComponentID = "availability_set::" + ev.Name
	ev.ResourceGroupName = d.Get("resource_group_name").(string)
	ev.Location = d.Get("location").(string)
	ev.PlatformUpdateDomainCount = d.Get("platform_update_domain_count").(int)
	ev.PlatformFaultDomainCount = d.Get("platform_fault_domain_count").(int)

	tags := make(map[string]string, 0)
	for k, v := range d.Get("tags").(map[string]interface{}) {
		tags[k] = v.(string)
	}
	ev.Tags = tags
	return nil
}

// EventToResourceData : Translates the current event on a valid ResourceData
func (ev *Event) EventToResourceData(d *schema.ResourceData) error {
	crypto := aes.New()

	encFields := make(map[string]string)
	encFields["subscription_id"] = ev.SubscriptionID
	encFields["client_id"] = ev.ClientID
	encFields["client_secret"] = ev.ClientSecret
	encFields["tenant_id"] = ev.TenantID
	encFields["environment"] = ev.Environment
	for k, v := range encFields {
		dec, err := crypto.Decrypt(v, ev.CryptoKey)
		if err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
		if err := d.Set(k, dec); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	fields := make(map[string]interface{})
	fields["name"] = ev.Name
	fields["resource_group_name"] = ev.ResourceGroupName
	fields["location"] = ev.Location
	fields["platform_update_domain_count"] = ev.PlatformUpdateDomainCount
	fields["platform_fault_domain_count"] = ev.PlatformFaultDomainCount
	fields["tags"] = ev.Tags
	for k, v := range fields {
		if err := d.Set(k, v); err != nil {
			err := fmt.Errorf("Field '%s' not valid : %s", k, err)
			ev.Log("error", err.Error())
			return err
		}
	}

	return nil
}

// Clone : will mark the event as errored
func (ev *Event) Clone() (event.Event, error) {
	body, _ := json.Marshal(ev)
	return New(ev.Subject, ev.CryptoKey, body, ev.Validator)
}

// Error : will mark the event as errored
func (ev *Event) Error(err error) {
	ev.ErrorMessage = err.Error()
	ev.Body, err = json.Marshal(ev)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"strings"
)

const templatePath = "atomic-template.swift"
const destinationPath = "../Source/atomic.swift"

func main() {
	b, err := ioutil.ReadFile(templatePath)
	if err != nil {
		log.Fatal(err.Error())
	}

	boolTypes := []string{"Bool"}
	stringTypes := []string{"String"}
	signedTypes := []string{"Int", "Int64", "Int32", "Int16", "Int8"}
	unsignedTypes := []string{"UInt", "UInt64", "UInt32", "UInt16", "UInt8"}
    floatTypes := []string{"Double", "Float"}
	numberTypes := append(append(signedTypes, unsignedTypes...), floatTypes...)
	allTypes := append(append(numberTypes, boolTypes...), stringTypes...)

	// parse
	templates := make(map[string]string)
	tparts := strings.Split(string(b), "// TEMPLATE:")
	templates["base"] = strings.TrimSpace(tparts[0])
	tparts = tparts[1:]
	for _, tpart := range tparts {
		var idx = strings.Index(tpart, "\n")
		var title = strings.TrimSpace(tpart[:idx])
		templates[title] = strings.TrimSpace(tpart[idx+1:])
	}

	repl := func(key string, op string, t string) string {
		s := templates[key]
		s = strings.Replace(s, "{{O}}", op, -1)
		s = strings.Replace(s, "{{T}}", t, -1)

		if op != t+"A" {
			for {
				idx := strings.Index(s, "Atomic<")
				if idx == -1 {
					break
				}
				idxe := strings.Index(s[idx:], ">") + idx
				s = s[:idx] + s[idx+7:idxe] + "A" + s[idxe+1:]
			}
		}
		return s
	}

	source := templates["base"] + "\n\n"

	// typealias
	for _, t := range allTypes {
		source += repl("typealias", t+"A", t) + "\n"
	}
	source += "\n"

	// initialize
	for _, t := range allTypes {
		source += repl("initialize-head", "", t) + "\n"
		source += "\t" + repl("initialize-body", t, t) + "\n"
		for _, it := range numberTypes {
			if t == it {
				for _, ot := range numberTypes {
					if ot != t {
						source += "\t" + repl("initialize-body", ot, t) + "\n"
					}
				}
				break
			}
		}
		source += repl("initialize-foot", "", t) + "\n"
	}
	source += "\n"

	// arithmetic
	for _, op := range []string{"+", "-", "*", "/", "%"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("arithmetic", op, t) + "\n"
		}
	}
	for _, op := range []string{"<<", ">>", "^", "&", "&+", "&-", "&*"} {
		for _, t := range append(signedTypes, unsignedTypes...) {
			source += repl("arithmetic", op, t) + "\n"
		}
	}
	for _, op := range []string{"+"} {
		for _, t := range stringTypes {
			source += repl("arithmetic", op, t) + "\n"
		}
	}

	// prefix
	for _, op := range []string{"++", "--"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("prefix", op, t) + "\n"
		}
	}
	for _, op := range []string{"+", "-"} {
		for _, t := range append(signedTypes, floatTypes...) {
			source += repl("prefix", op, t) + "\n"
		}
	}
	for _, op := range []string{"~"} {
		for _, t := range signedTypes {
			source += repl("prefix", op, t) + "\n"
		}
	}

	// postfix
	for _, op := range []string{"++", "--"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("postfix", op, t) + "\n"
		}
	}

	// modify
	for _, op := range []string{"+=", "-=", "*=", "/=", "%="} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("modify", op, t) + "\n"
		}
	}
	for _, op := range []string{"+="} {
		for _, t := range stringTypes {
			source += repl("modify", op, t) + "\n"
		}
	}
	for _, op := range []string{"<<=", ">>=", "^=", "&="} {
		for _, t := range append(signedTypes, unsignedTypes...) {
			source += repl("modify", op, t) + "\n"
		}
	}

	match := false
	sourceb := []byte(source)
	destb, err := ioutil.ReadFile(destinationPath)
	if err == nil {
		match = bytes.Compare(destb, sourceb) == 0
	}
	if !match {
		err = ioutil.WriteFile(destinationPath, sourceb, 0666)
		if err != nil {
			log.Fatal(err.Error())
		}
	}

}
<commit_msg>format change<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"strings"
)

const templatePath = "atomic-template.swift"
const destinationPath = "../Source/atomic.swift"

func main() {
	b, err := ioutil.ReadFile(templatePath)
	if err != nil {
		log.Fatal(err.Error())
	}

	boolTypes := []string{"Bool"}
	stringTypes := []string{"String"}
	signedTypes := []string{"Int", "Int64", "Int32", "Int16", "Int8"}
	unsignedTypes := []string{"UInt", "UInt64", "UInt32", "UInt16", "UInt8"}
	floatTypes := []string{"Double", "Float"}
	numberTypes := append(append(signedTypes, unsignedTypes...), floatTypes...)
	allTypes := append(append(numberTypes, boolTypes...), stringTypes...)

	// parse
	templates := make(map[string]string)
	tparts := strings.Split(string(b), "// TEMPLATE:")
	templates["base"] = strings.TrimSpace(tparts[0])
	tparts = tparts[1:]
	for _, tpart := range tparts {
		var idx = strings.Index(tpart, "\n")
		var title = strings.TrimSpace(tpart[:idx])
		templates[title] = strings.TrimSpace(tpart[idx+1:])
	}

	repl := func(key string, op string, t string) string {
		s := templates[key]
		s = strings.Replace(s, "{{O}}", op, -1)
		s = strings.Replace(s, "{{T}}", t, -1)

		if op != t+"A" {
			for {
				idx := strings.Index(s, "Atomic<")
				if idx == -1 {
					break
				}
				idxe := strings.Index(s[idx:], ">") + idx
				s = s[:idx] + s[idx+7:idxe] + "A" + s[idxe+1:]
			}
		}
		return s
	}

	source := templates["base"] + "\n\n"

	// typealias
	for _, t := range allTypes {
		source += repl("typealias", t+"A", t) + "\n"
	}
	source += "\n"

	// initialize
	for _, t := range allTypes {
		source += repl("initialize-head", "", t) + "\n"
		source += "\t" + repl("initialize-body", t, t) + "\n"
		for _, it := range numberTypes {
			if t == it {
				for _, ot := range numberTypes {
					if ot != t {
						source += "\t" + repl("initialize-body", ot, t) + "\n"
					}
				}
				break
			}
		}
		source += repl("initialize-foot", "", t) + "\n"
	}
	source += "\n"

	// arithmetic
	for _, op := range []string{"+", "-", "*", "/", "%"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("arithmetic", op, t) + "\n"
		}
	}
	for _, op := range []string{"<<", ">>", "^", "&", "&+", "&-", "&*"} {
		for _, t := range append(signedTypes, unsignedTypes...) {
			source += repl("arithmetic", op, t) + "\n"
		}
	}
	for _, op := range []string{"+"} {
		for _, t := range stringTypes {
			source += repl("arithmetic", op, t) + "\n"
		}
	}

	// prefix
	for _, op := range []string{"++", "--"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("prefix", op, t) + "\n"
		}
	}
	for _, op := range []string{"+", "-"} {
		for _, t := range append(signedTypes, floatTypes...) {
			source += repl("prefix", op, t) + "\n"
		}
	}
	for _, op := range []string{"~"} {
		for _, t := range signedTypes {
			source += repl("prefix", op, t) + "\n"
		}
	}

	// postfix
	for _, op := range []string{"++", "--"} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("postfix", op, t) + "\n"
		}
	}

	// modify
	for _, op := range []string{"+=", "-=", "*=", "/=", "%="} {
		for _, t := range append(append(signedTypes, unsignedTypes...), floatTypes...) {
			source += repl("modify", op, t) + "\n"
		}
	}
	for _, op := range []string{"+="} {
		for _, t := range stringTypes {
			source += repl("modify", op, t) + "\n"
		}
	}
	for _, op := range []string{"<<=", ">>=", "^=", "&="} {
		for _, t := range append(signedTypes, unsignedTypes...) {
			source += repl("modify", op, t) + "\n"
		}
	}

	match := false
	sourceb := []byte(source)
	destb, err := ioutil.ReadFile(destinationPath)
	if err == nil {
		match = bytes.Compare(destb, sourceb) == 0
	}
	if !match {
		err = ioutil.WriteFile(destinationPath, sourceb, 0666)
		if err != nil {
			log.Fatal(err.Error())
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/k-sone/snmpgo"
)

var hexPrefix *regexp.Regexp = regexp.MustCompile(`^0[xX]`)
var inform bool
var errMessage string

func usage(msg string, code int) {
	errMessage = msg
	flag.Usage()
	os.Exit(code)
}

func parseArgs() (*snmpgo.SNMPArguments, []string) {
	flag.Usage = func() {
		if errMessage != "" {
			fmt.Fprintf(os.Stderr, "%s\n", errMessage)
		}
		fmt.Fprintf(os.Stderr,
			"Usage of %s: [OPTIONS] AGENT UPTIME TRAP-OID [OID TYPE VALUE]..\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "AGENT:\n  hostname:port or ip-address:port\n")
		fmt.Fprintf(os.Stderr, "UPTIME:\n  system uptime\n")
		fmt.Fprintf(os.Stderr, "TYPE:\n")
		fmt.Fprintf(os.Stderr, "  i - INTEGER   u - UNSIGNED   c - COUNTER32 C - COUNTER64\n")
		fmt.Fprintf(os.Stderr, "  t - TIMETICKS a - IPADDRESS  o - OID       n - NULL\n")
		fmt.Fprintf(os.Stderr, "  s - STRING    x - HEX STRING d - DECIMAL STRING\n")
		fmt.Fprintf(os.Stderr, "OPTIONS:\n")
		flag.PrintDefaults()
	}

	protocol := flag.String("p", "udp", "Protocol (udp|udp6|tcp|tcp6)")
	timeout := flag.Uint("t", 5, "Request timeout (number of seconds)")
	retries := flag.Uint("r", 1, "Number of retries")
	version := flag.String("v", "1", "SNMP version to use (1|2c|3)")
	community := flag.String("c", "", "Community")
	username := flag.String("u", "", "Security name")
	seclevel := flag.String("l", "NoAuthNoPriv", "Security level (NoAuthNoPriv|AuthNoPriv|AuthPriv)")
	authproto := flag.String("a", "", "Authentication protocol (MD5|SHA)")
	authpass := flag.String("A", "", "Authentication protocol pass phrase")
	privproto := flag.String("x", "", "Privacy protocol (DES|AES)")
	privpass := flag.String("X", "", "Privacy protocol pass phrase")
	secengine := flag.String("e", "", "Security engine ID")
	contextengine := flag.String("E", "", "Context engine ID")
	contextname := flag.String("n", "", "Context name")
	flag.BoolVar(&inform, "Ci", false, "Send an Inform")

	flag.Parse()

	args := &snmpgo.SNMPArguments{
		Network:          *protocol,
		Address:          flag.Arg(0),
		Timeout:          time.Duration(*timeout) * time.Second,
		Retries:          *retries,
		Community:        *community,
		UserName:         *username,
		AuthPassword:     *authpass,
		AuthProtocol:     snmpgo.AuthProtocol(*authproto),
		PrivPassword:     *privpass,
		PrivProtocol:     snmpgo.PrivProtocol(*privproto),
		SecurityEngineId: *secengine,
		ContextEngineId:  *contextengine,
		ContextName:      *contextname,
	}

	switch *version {
	case "1":
		args.Version = snmpgo.V1
	case "2c":
		args.Version = snmpgo.V2c
	case "3":
		args.Version = snmpgo.V3
	default:
		usage(fmt.Sprintf("Illegal Version, value `%s`", *version), 2)
	}

	switch *seclevel {
	case "NoAuthNoPriv":
		args.SecurityLevel = snmpgo.NoAuthNoPriv
	case "AuthNoPriv":
		args.SecurityLevel = snmpgo.AuthNoPriv
	case "AuthPriv":
		args.SecurityLevel = snmpgo.AuthPriv
	default:
		usage(fmt.Sprintf("Illegal SecurityLevel, value `%s`", *seclevel), 2)
	}

	return args, flag.Args()
}

func getUptime(s string) uint32 {
	if uptime, err := strconv.ParseUint(s, 10, 32); err == nil {
		return uint32(uptime)
	}

	// The syscall.Sysinfo only works on Linux
	//	var info syscall.Sysinfo_t
	//	if err := syscall.Sysinfo(&info); err == nil {
	//		return uint32(info.Uptime * 100)
	//	}

	return 0
}

func buildVariable(kind string, value string) (val snmpgo.Variable, err error) {
	switch kind {
	case "i":
		var num int64
		if num, err = strconv.ParseInt(value, 10, 32); err == nil {
			val = snmpgo.NewInteger(int32(num))
		}
	case "u":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewGauge32(uint32(num))
		}
	case "c":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewCounter32(uint32(num))
		}
	case "C":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 64); err == nil {
			val = snmpgo.NewCounter64(num)
		}
	case "t":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewTimeTicks(uint32(num))
		}
	case "a":
		if ip := net.ParseIP(value); ip != nil && len(ip) == 4 {
			val = snmpgo.NewIpaddress(ip[0], ip[1], ip[2], ip[3])
		} else {
			return nil, fmt.Errorf("%s: no valid IP Address", value)
		}
	case "o":
		val, err = snmpgo.NewOid(value)
	case "n":
		val = snmpgo.NewNull()
	case "s":
		val = snmpgo.NewOctetString([]byte(value))
	case "x":
		var b []byte
		hx := hexPrefix.ReplaceAllString(value, "")
		if b, err = hex.DecodeString(hx); err == nil {
			val = snmpgo.NewOctetString(b)
		} else {
			return nil, fmt.Errorf("%s: no valid Hex String", value)
		}
	case "d":
		s := strings.Split(value, ".")
		b := make([]byte, len(s))
		for i, piece := range s {
			var num int
			if num, err = strconv.Atoi(piece); err != nil || num > 0xff {
				return nil, fmt.Errorf("%s: no valid Decimal String", value)
			}
			b[i] = byte(num)
		}
		val = snmpgo.NewOctetString(b)
	default:
		return nil, fmt.Errorf("%s: unknown TYPE", kind)
	}

	return
}

func buildVarBinds(cmdArgs []string) (snmpgo.VarBinds, error) {
	var varBinds snmpgo.VarBinds

	uptime := snmpgo.NewTimeTicks(getUptime(cmdArgs[1]))
	varBinds = append(varBinds, snmpgo.NewVarBind(snmpgo.OidSysUpTime, uptime))

	oid, err := snmpgo.NewOid(cmdArgs[2])
	if err != nil {
		return nil, err
	}
	varBinds = append(varBinds, snmpgo.NewVarBind(snmpgo.OidSnmpTrap, oid))

	for i := 3; i < len(cmdArgs); i += 3 {
		oid, err := snmpgo.NewOid(cmdArgs[i])
		if err != nil {
			return nil, err
		}

		val, err := buildVariable(cmdArgs[i+1], cmdArgs[i+2])
		if err != nil {
			return nil, err
		}

		varBinds = append(varBinds, snmpgo.NewVarBind(oid, val))
	}

	return varBinds, nil
}

func main() {
	snmpArgs, cmdArgs := parseArgs()
	if l := len(cmdArgs); l < 3 {
		usage("required AGENT and UPTIME and TRAP-OID", 2)
	} else if l%3 != 0 {
		usage(fmt.Sprintf("%s: missing TYPE/VALUE for variable", cmdArgs[l/3*3]), 2)
	}

	varBinds, err := buildVarBinds(cmdArgs)
	if err != nil {
		usage(err.Error(), 2)
	}

	snmp, err := snmpgo.NewSNMP(*snmpArgs)
	if err != nil {
		usage(err.Error(), 2)
	}
	if err = snmp.Open(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer snmp.Close()

	if inform {
		err = snmp.InformRequest(varBinds)
	} else {
		err = snmp.V2Trap(varBinds)
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>fix selectable snmp version<commit_after>package main

import (
	"encoding/hex"
	"flag"
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/k-sone/snmpgo"
)

var hexPrefix *regexp.Regexp = regexp.MustCompile(`^0[xX]`)
var inform bool
var errMessage string

func usage(msg string, code int) {
	errMessage = msg
	flag.Usage()
	os.Exit(code)
}

func parseArgs() (*snmpgo.SNMPArguments, []string) {
	flag.Usage = func() {
		if errMessage != "" {
			fmt.Fprintf(os.Stderr, "%s\n", errMessage)
		}
		fmt.Fprintf(os.Stderr,
			"Usage of %s: [OPTIONS] AGENT UPTIME TRAP-OID [OID TYPE VALUE]..\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "AGENT:\n  hostname:port or ip-address:port\n")
		fmt.Fprintf(os.Stderr, "UPTIME:\n  system uptime\n")
		fmt.Fprintf(os.Stderr, "TYPE:\n")
		fmt.Fprintf(os.Stderr, "  i - INTEGER   u - UNSIGNED   c - COUNTER32 C - COUNTER64\n")
		fmt.Fprintf(os.Stderr, "  t - TIMETICKS a - IPADDRESS  o - OID       n - NULL\n")
		fmt.Fprintf(os.Stderr, "  s - STRING    x - HEX STRING d - DECIMAL STRING\n")
		fmt.Fprintf(os.Stderr, "OPTIONS:\n")
		flag.PrintDefaults()
	}

	protocol := flag.String("p", "udp", "Protocol (udp|udp6|tcp|tcp6)")
	timeout := flag.Uint("t", 5, "Request timeout (number of seconds)")
	retries := flag.Uint("r", 1, "Number of retries")
	version := flag.String("v", "2c", "SNMP version to use (2c|3)")
	community := flag.String("c", "", "Community")
	username := flag.String("u", "", "Security name")
	seclevel := flag.String("l", "NoAuthNoPriv", "Security level (NoAuthNoPriv|AuthNoPriv|AuthPriv)")
	authproto := flag.String("a", "", "Authentication protocol (MD5|SHA)")
	authpass := flag.String("A", "", "Authentication protocol pass phrase")
	privproto := flag.String("x", "", "Privacy protocol (DES|AES)")
	privpass := flag.String("X", "", "Privacy protocol pass phrase")
	secengine := flag.String("e", "", "Security engine ID")
	contextengine := flag.String("E", "", "Context engine ID")
	contextname := flag.String("n", "", "Context name")
	flag.BoolVar(&inform, "Ci", false, "Send an Inform")

	flag.Parse()

	args := &snmpgo.SNMPArguments{
		Network:          *protocol,
		Address:          flag.Arg(0),
		Timeout:          time.Duration(*timeout) * time.Second,
		Retries:          *retries,
		Community:        *community,
		UserName:         *username,
		AuthPassword:     *authpass,
		AuthProtocol:     snmpgo.AuthProtocol(*authproto),
		PrivPassword:     *privpass,
		PrivProtocol:     snmpgo.PrivProtocol(*privproto),
		SecurityEngineId: *secengine,
		ContextEngineId:  *contextengine,
		ContextName:      *contextname,
	}

	switch *version {
	case "2c":
		args.Version = snmpgo.V2c
	case "3":
		args.Version = snmpgo.V3
	default:
		usage(fmt.Sprintf("Illegal Version, value `%s`", *version), 2)
	}

	switch *seclevel {
	case "NoAuthNoPriv":
		args.SecurityLevel = snmpgo.NoAuthNoPriv
	case "AuthNoPriv":
		args.SecurityLevel = snmpgo.AuthNoPriv
	case "AuthPriv":
		args.SecurityLevel = snmpgo.AuthPriv
	default:
		usage(fmt.Sprintf("Illegal SecurityLevel, value `%s`", *seclevel), 2)
	}

	return args, flag.Args()
}

func getUptime(s string) uint32 {
	if uptime, err := strconv.ParseUint(s, 10, 32); err == nil {
		return uint32(uptime)
	}

	// The syscall.Sysinfo only works on Linux
	//	var info syscall.Sysinfo_t
	//	if err := syscall.Sysinfo(&info); err == nil {
	//		return uint32(info.Uptime * 100)
	//	}

	return 0
}

func buildVariable(kind string, value string) (val snmpgo.Variable, err error) {
	switch kind {
	case "i":
		var num int64
		if num, err = strconv.ParseInt(value, 10, 32); err == nil {
			val = snmpgo.NewInteger(int32(num))
		}
	case "u":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewGauge32(uint32(num))
		}
	case "c":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewCounter32(uint32(num))
		}
	case "C":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 64); err == nil {
			val = snmpgo.NewCounter64(num)
		}
	case "t":
		var num uint64
		if num, err = strconv.ParseUint(value, 10, 32); err == nil {
			val = snmpgo.NewTimeTicks(uint32(num))
		}
	case "a":
		if ip := net.ParseIP(value); ip != nil && len(ip) == 4 {
			val = snmpgo.NewIpaddress(ip[0], ip[1], ip[2], ip[3])
		} else {
			return nil, fmt.Errorf("%s: no valid IP Address", value)
		}
	case "o":
		val, err = snmpgo.NewOid(value)
	case "n":
		val = snmpgo.NewNull()
	case "s":
		val = snmpgo.NewOctetString([]byte(value))
	case "x":
		var b []byte
		hx := hexPrefix.ReplaceAllString(value, "")
		if b, err = hex.DecodeString(hx); err == nil {
			val = snmpgo.NewOctetString(b)
		} else {
			return nil, fmt.Errorf("%s: no valid Hex String", value)
		}
	case "d":
		s := strings.Split(value, ".")
		b := make([]byte, len(s))
		for i, piece := range s {
			var num int
			if num, err = strconv.Atoi(piece); err != nil || num > 0xff {
				return nil, fmt.Errorf("%s: no valid Decimal String", value)
			}
			b[i] = byte(num)
		}
		val = snmpgo.NewOctetString(b)
	default:
		return nil, fmt.Errorf("%s: unknown TYPE", kind)
	}

	return
}

func buildVarBinds(cmdArgs []string) (snmpgo.VarBinds, error) {
	var varBinds snmpgo.VarBinds

	uptime := snmpgo.NewTimeTicks(getUptime(cmdArgs[1]))
	varBinds = append(varBinds, snmpgo.NewVarBind(snmpgo.OidSysUpTime, uptime))

	oid, err := snmpgo.NewOid(cmdArgs[2])
	if err != nil {
		return nil, err
	}
	varBinds = append(varBinds, snmpgo.NewVarBind(snmpgo.OidSnmpTrap, oid))

	for i := 3; i < len(cmdArgs); i += 3 {
		oid, err := snmpgo.NewOid(cmdArgs[i])
		if err != nil {
			return nil, err
		}

		val, err := buildVariable(cmdArgs[i+1], cmdArgs[i+2])
		if err != nil {
			return nil, err
		}

		varBinds = append(varBinds, snmpgo.NewVarBind(oid, val))
	}

	return varBinds, nil
}

func main() {
	snmpArgs, cmdArgs := parseArgs()
	if l := len(cmdArgs); l < 3 {
		usage("required AGENT and UPTIME and TRAP-OID", 2)
	} else if l%3 != 0 {
		usage(fmt.Sprintf("%s: missing TYPE/VALUE for variable", cmdArgs[l/3*3]), 2)
	}

	varBinds, err := buildVarBinds(cmdArgs)
	if err != nil {
		usage(err.Error(), 2)
	}

	snmp, err := snmpgo.NewSNMP(*snmpArgs)
	if err != nil {
		usage(err.Error(), 2)
	}
	if err = snmp.Open(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer snmp.Close()

	if inform {
		err = snmp.InformRequest(varBinds)
	} else {
		err = snmp.V2Trap(varBinds)
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cdsclient

import (
	"bufio"
	"bytes"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"strings"
)

const (
	sseEvent = "event"
	sseData  = "data"
)

//SSEvent is a go representation of an http server-sent event
type SSEvent struct {
	URI  string
	Type string
	Data io.Reader
}

// RequestSSEGet takes the uri of an SSE stream and channel, and will send an Event
// down the channel when received, until the stream is closed. It will then
// close the stream. This is blocking, and so you will likely want to call this
// in a new goroutine (via `go c.RequestSSEGet(..)`)
func (c *client) RequestSSEGet(ctx context.Context, path string, evCh chan<- SSEvent, mods ...RequestModifier) error {
	uri := c.config.Host + path
	if strings.HasPrefix(path, "http") {
		uri = path
	}

	req, err := http.NewRequest(http.MethodGet, uri, nil)
	if err != nil {
		return err
	}

	for i := range mods {
		if mods[i] != nil {
			mods[i](req)
		}
	}

	req.Header.Set("Accept", "text/event-stream")
	req.Header.Set("User-Agent", c.config.userAgent)
	req.Header.Set("Connection", "close")
	req.Header.Add(RequestedWithHeader, RequestedWithValue)
	if c.name != "" {
		req.Header.Add(RequestedNameHeader, c.name)
	}
	if c.isProvider {
		req.Header.Add("X-Provider-Name", c.config.User)
		req.Header.Add("X-Provider-Token", c.config.Token)
	}

	if c.config.Hash != "" {
		basedHash := base64.StdEncoding.EncodeToString([]byte(c.config.Hash))
		req.Header.Set(AuthHeader, basedHash)
	}
	if c.config.User != "" && c.config.Token != "" {
		req.Header.Add(SessionTokenHeader, c.config.Token)
		req.SetBasicAuth(c.config.User, c.config.Token)
	}

	resp, err := NoTimeout(c.HTTPClient).Do(req)
	if err != nil {
		return err
	}
	br := bufio.NewReader(resp.Body)
	defer resp.Body.Close() // nolint

	delim := []byte{':', ' '}

	var currEvent *SSEvent
	var EOF bool

	for !EOF {
		if ctx.Err() != nil {
			break
		}

		bs, err := br.ReadBytes('\n')

		if err != nil && err != io.EOF {
			return err
		}

		if len(bs) < 2 {
			continue
		}

		spl := bytes.Split(bs, delim)

		if len(spl) < 2 {
			continue
		}

		currEvent = &SSEvent{URI: uri}
		switch string(spl[0]) {
		case sseEvent:
			currEvent.Type = string(bytes.TrimSpace(spl[1]))
		case sseData:
			currEvent.Data = bytes.NewBuffer(bytes.TrimSpace(spl[1]))
			evCh <- *currEvent
		}
		if err == io.EOF {
			EOF = true
		}
	}

	return nil

}
<commit_msg>fix(sdk): no more ctx.Err() in queue polling (#3425)<commit_after>package cdsclient

import (
	"bufio"
	"bytes"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"strings"
)

const (
	sseEvent = "event"
	sseData  = "data"
)

//SSEvent is a go representation of an http server-sent event
type SSEvent struct {
	URI  string
	Type string
	Data io.Reader
}

// RequestSSEGet takes the uri of an SSE stream and channel, and will send an Event
// down the channel when received, until the stream is closed. It will then
// close the stream. This is blocking, and so you will likely want to call this
// in a new goroutine (via `go c.RequestSSEGet(..)`)
func (c *client) RequestSSEGet(ctx context.Context, path string, evCh chan<- SSEvent, mods ...RequestModifier) error {
	uri := c.config.Host + path
	if strings.HasPrefix(path, "http") {
		uri = path
	}

	req, err := http.NewRequest(http.MethodGet, uri, nil)
	if err != nil {
		return err
	}

	for i := range mods {
		if mods[i] != nil {
			mods[i](req)
		}
	}

	req.Header.Set("Accept", "text/event-stream")
	req.Header.Set("User-Agent", c.config.userAgent)
	req.Header.Set("Connection", "close")
	req.Header.Add(RequestedWithHeader, RequestedWithValue)
	if c.name != "" {
		req.Header.Add(RequestedNameHeader, c.name)
	}
	if c.isProvider {
		req.Header.Add("X-Provider-Name", c.config.User)
		req.Header.Add("X-Provider-Token", c.config.Token)
	}

	if c.config.Hash != "" {
		basedHash := base64.StdEncoding.EncodeToString([]byte(c.config.Hash))
		req.Header.Set(AuthHeader, basedHash)
	}
	if c.config.User != "" && c.config.Token != "" {
		req.Header.Add(SessionTokenHeader, c.config.Token)
		req.SetBasicAuth(c.config.User, c.config.Token)
	}

	resp, err := NoTimeout(c.HTTPClient).Do(req)
	if err != nil {
		return err
	}
	br := bufio.NewReader(resp.Body)
	defer resp.Body.Close() // nolint

	delim := []byte{':', ' '}

	var currEvent *SSEvent
	var EOF bool

	go func(stop *bool) {
		<-ctx.Done()
		*stop = true
	}(&EOF)

	for !EOF {
		bs, err := br.ReadBytes('\n')
		if err != nil && err != io.EOF {
			return err
		}

		if len(bs) < 2 {
			continue
		}

		spl := bytes.Split(bs, delim)

		if len(spl) < 2 {
			continue
		}

		currEvent = &SSEvent{URI: uri}
		switch string(spl[0]) {
		case sseEvent:
			currEvent.Type = string(bytes.TrimSpace(spl[1]))
		case sseData:
			currEvent.Data = bytes.NewBuffer(bytes.TrimSpace(spl[1]))
			evCh <- *currEvent
		}
		if err == io.EOF {
			EOF = true
		}
	}

	return nil

}
<|endoftext|>


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

package processing

import (
	"io"
	"sync"
)

type Decoder interface {
	DecodeNext() (interface{}, error)
}

type Marshaler interface {
	Marshal(interface{}) ([]byte, error)
}

type Worker interface {
	MakeHandler(uint) Handler
	Success() uint
	Failure() uint
	Total() uint
	Done()
	RunCount() uint
}

type Handler func(interface{}) interface{}

func Process(in Decoder, out io.Writer, w Worker, m Marshaler, workers uint) {
	processQueue := make(chan interface{}, workers*4)
	outputQueue := make(chan []byte, workers*4)

	// Create wait groups
	var workerDone sync.WaitGroup
	var outputDone sync.WaitGroup
	workerDone.Add(int(workers))
	outputDone.Add(1)

	// Start the output encoder
	go func() {
		for result := range outputQueue {
			if _, err := out.Write(result); err != nil {
				panic(err.Error())
			}
			if _, err := out.Write([]byte("\n")); err != nil {
				panic(err.Error())
			}
		}
		outputDone.Done()
	}()
	// Start all the workers
	for i := uint(0); i < workers; i++ {
		handler := w.MakeHandler(i)
		runCount := w.RunCount()
		go func(handler Handler) {
			for obj := range processQueue {
				for run := uint(0); run < runCount; run++ {
					result := handler(obj)
					enc, err := m.Marshal(result)
					if err != nil {
						panic(err.Error())
					}
					outputQueue <- enc
				}
			}
			workerDone.Done()
		}(handler)
	}
	// Read the input, send to workers
	for {
		obj, err := in.DecodeNext()
		if err == io.EOF {
			break
		}
		processQueue <- obj
	}
	close(processQueue)
	workerDone.Wait()
	close(outputQueue)
	outputDone.Wait()
	w.Done()
}
<commit_msg>log decoding errors (previously being swallowed)<commit_after>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package processing

import (
	"github.com/zmap/zgrab/ztools/zlog"
	"io"
	"sync"
)

type Decoder interface {
	DecodeNext() (interface{}, error)
}

type Marshaler interface {
	Marshal(interface{}) ([]byte, error)
}

type Worker interface {
	MakeHandler(uint) Handler
	Success() uint
	Failure() uint
	Total() uint
	Done()
	RunCount() uint
}

type Handler func(interface{}) interface{}

func Process(in Decoder, out io.Writer, w Worker, m Marshaler, workers uint) {
	processQueue := make(chan interface{}, workers*4)
	outputQueue := make(chan []byte, workers*4)

	// Create wait groups
	var workerDone sync.WaitGroup
	var outputDone sync.WaitGroup
	workerDone.Add(int(workers))
	outputDone.Add(1)

	// Start the output encoder
	go func() {
		for result := range outputQueue {
			if _, err := out.Write(result); err != nil {
				panic(err.Error())
			}
			if _, err := out.Write([]byte("\n")); err != nil {
				panic(err.Error())
			}
		}
		outputDone.Done()
	}()
	// Start all the workers
	for i := uint(0); i < workers; i++ {
		handler := w.MakeHandler(i)
		runCount := w.RunCount()
		go func(handler Handler) {
			for obj := range processQueue {
				for run := uint(0); run < runCount; run++ {
					result := handler(obj)
					enc, err := m.Marshal(result)
					if err != nil {
						panic(err.Error())
					}
					outputQueue <- enc
				}
			}
			workerDone.Done()
		}(handler)
	}
	// Read the input, send to workers
	for {
		obj, err := in.DecodeNext()
		if err == io.EOF {
			break
		} else if err != nil {
			zlog.Error(err)
		}
		processQueue <- obj
	}
	close(processQueue)
	workerDone.Wait()
	close(outputQueue)
	outputDone.Wait()
	w.Done()
}
<|endoftext|>