<commit_before>package postgres

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/lib/pq"

	"github.com/archsh/go.xql"
)

type Elemented interface {
	Elem2Strings() []string
	Strings2Elem(...string) error
}

type StringArray []string

func (h StringArray) Declare(props xql.PropertySet) string {
	size, _ := props.GetInt("size", 32)
	return fmt.Sprintf("varchar(%d)[]", size)
}

//
//func (a StringArray) Elem2Strings() []string {
//	var ss []string
//	for _, x := range a {
//		ss = append(ss,
//			strings.Replace(
//				strings.Replace(x, `'`, `\'`, -1), `"`, `\"`, -1))
//	}
//	return ss
//}
//
//func (a *StringArray) Strings2Elem(ss ...string) error {
//	(*a) = ss
//	return nil
//}

func (p StringArray) Scan(src interface{}) error {
	var ps []string
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = StringArray(ps)
		return nil
	}
	//return pq.Array(p).Scan(src)
	//return Array_Scan(src, p)
}

func (p StringArray) Value() (driver.Value, error) {
	return pq.Array([]string(p)).Value()
	//return Array_Value(&p)
}

type IntegerArray []int

func (h IntegerArray) Declare(props xql.PropertySet) string {
	return "integer[]"
}

//func (a IntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *IntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 32)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, int(n))
//		}
//	}
//	return nil
//}

func (p IntegerArray) Scan(src interface{}) error {
	var ps []int
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = IntegerArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p IntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int(p)).Value()
	//return Array_Value(&p)
}

type SmallIntegerArray []int16

func (h SmallIntegerArray) Declare(props xql.PropertySet) string {
	return "smallint[]"
}

//func (a SmallIntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *SmallIntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 16)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, int16(n))
//		}
//	}
//	return nil
//}

func (p SmallIntegerArray) Scan(src interface{}) error {
	var ps []int16
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = SmallIntegerArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p SmallIntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int16(p)).Value()
	//return Array_Value(&p)
}

type BigIntegerArray []int64

func (h BigIntegerArray) Declare(props xql.PropertySet) string {
	return "bigint[]"
}

//func (a BigIntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *BigIntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 64)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, n)
//		}
//	}
//	return nil
//}

func (p BigIntegerArray) Scan(src interface{}) error {
	var ps []int64
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = BigIntegerArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p BigIntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int64(p)).Value()
	//return Array_Value(&p)
}

type RealArray []float32

func (h RealArray) Declare(props xql.PropertySet) string {
	return "real[]"
}

//func (a RealArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%f", x))
//	}
//	return ss
//}
//
//func (a *RealArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseFloat(s, 32)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, float32(n))
//		}
//	}
//	return nil
//}

func (p RealArray) Scan(src interface{}) error {
	var ps []float32
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = RealArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p RealArray) Value() (driver.Value, error) {
	return pq.Array([]float32(p)).Value()
	//return Array_Value(&p)
}

type DoubleArray []float64

func (h DoubleArray) Declare(props xql.PropertySet) string {
	return "double[]"
}

//func (a DoubleArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%f", x))
//	}
//	return ss
//}
//
//func (a *DoubleArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseFloat(s, 64)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, n)
//		}
//	}
//	return nil
//}

func (p DoubleArray) Scan(src interface{}) error {
	var ps []float64
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = DoubleArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p DoubleArray) Value() (driver.Value, error) {
	return pq.Array([]float64(p)).Value()
	//return Array_Value(&p)
}

type BoolArray []bool

func (h BoolArray) Declare(props xql.PropertySet) string {
	return "bool[]"
}

//func (a BoolArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%s", x))
//	}
//	return ss
//}
//
//func (a *BoolArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		switch strings.ToLower(s) {
//		case "y", "yes", "t", "true", "ok":
//			(*a) = append(*a, true)
//		default:
//			(*a) = append(*a, false)
//		}
//	}
//	return nil
//}

func (p BoolArray) Scan(src interface{}) error {
	var ps []bool
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		p = BoolArray(ps)
		return nil
	}
	//return Array_Scan(src, p)
}

func (p BoolArray) Value() (driver.Value, error) {
	return pq.Array([]bool(p)).Value()
	//return Array_Value(&p)
}

// PARSING ARRAYS
// SEE http://www.postgresql.org/docs/9.1/static/arrays.html#ARRAYS-IO
// Arrays are output within {} and a delimiter, which is a comma for most
// postgres types (; for box)
//
// Individual values are surrounded by quotes:
// The array output routine will put double quotes around element values if
// they are empty strings, contain curly braces, delimiter characters,
// double quotes, backslashes, or white space, or match the word NULL.
// Double quotes and backslashes embedded in element values will be
// backslash-escaped. For numeric data types it is safe to assume that double
// quotes will never appear, but for textual data types one should be prepared
// to cope with either the presence or absence of quotes.

// construct a regexp to extract values:
var (
	// unquoted array values must not contain: (" , \ { } whitespace NULL)
	// and must be at least one char
	unquotedChar  = `[^",\\{}\s(NULL)]`
	unquotedValue = fmt.Sprintf("(%s)+", unquotedChar)

	// quoted array values are surrounded by double quotes, can be any
	// character except " or \, which must be backslash escaped:
	quotedChar  = `[^"\\]|\\"|\\\\`
	quotedValue = fmt.Sprintf("\"(%s)*\"", quotedChar)

	// an array value may be either quoted or unquoted:
	arrayValue = fmt.Sprintf("(?P<value>(%s|%s))", unquotedValue, quotedValue)

	// Array values are separated with a comma IF there is more than one value:
	arrayExp = regexp.MustCompile(fmt.Sprintf("((%s)(,)?)", arrayValue))

	valueIndex int
)

// Find the index of the 'value' named expression
func init() {
	for i, subexp := range arrayExp.SubexpNames() {
		if subexp == "value" {
			valueIndex = i
			break
		}
	}
}

// Parse the output string from the array type.
// Regex used: (((?P<value>(([^",\\{}\s(NULL)])+|"([^"\\]|\\"|\\\\)*")))(,)?)
func parseArray(array string) []string {
	results := make([]string, 0)
	matches := arrayExp.FindAllStringSubmatch(array, -1)
	for _, match := range matches {
		s := match[valueIndex]
		// the string _might_ be wrapped in quotes, so trim them:
		s = strings.Trim(s, "\"")
		results = append(results, s)
	}
	return results
}

//func (p *StringArray) Scan(src interface{}) error {
//    asBytes, ok := src.([]byte)
//    if !ok {
//        return error(errors.New("Scan source was not []bytes."))
//    }
//
//    asString := string(asBytes)
//    parsed := parseArray(asString)
//    (*p) = StringArray(parsed)
//
//    return nil
//}
//
//func (p StringArray) Value() (driver.Value, error) {
//    var ss []string
//    for _, s := range p {
//        ss = append(ss, fmt.Sprintf(`"%s"`, s))
//    }
//    return strings.Join([]string{"{", strings.Join(ss, ","), "}"}, ""), nil
//}

func Array_Scan(src interface{}, dest interface{}) error {
	if nil == src || dest == nil {
		return nil
	}
	asBytes, ok := src.([]byte)
	if !ok {
		return error(errors.New("Scan source was not []bytes."))
	}

	asString := string(asBytes)
	parsed := parseArray(asString)
	if vv, ok := dest.(Elemented); ok {
		return vv.Strings2Elem(parsed...)
	}
	return errors.New("Elemented should be implemented.")
}

func Array_Value(v interface{}) (driver.Value, error) {
	if nil == v {
		return nil, nil
	}
	if vv, ok := v.(Elemented); ok {
		return strings.Join([]string{"{", strings.Join(vv.Elem2Strings(), ","), "}"}, ""), nil
	}
	return nil, errors.New("Elemented should be implemented.")
}
<commit_msg>Updated.<commit_after>package postgres

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/lib/pq"

	"github.com/archsh/go.xql"
)

type Elemented interface {
	Elem2Strings() []string
	Strings2Elem(...string) error
}

type StringArray []string

func (h StringArray) Declare(props xql.PropertySet) string {
	size, _ := props.GetInt("size", 32)
	return fmt.Sprintf("varchar(%d)[]", size)
}

//
//func (a StringArray) Elem2Strings() []string {
//	var ss []string
//	for _, x := range a {
//		ss = append(ss,
//			strings.Replace(
//				strings.Replace(x, `'`, `\'`, -1), `"`, `\"`, -1))
//	}
//	return ss
//}
//
//func (a *StringArray) Strings2Elem(ss ...string) error {
//	(*a) = ss
//	return nil
//}

func (p *StringArray) Scan(src interface{}) error {
	var ps []string
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		pp := StringArray(ps)
		p = &pp
		return nil
	}
	//return pq.Array(p).Scan(src)
	//return Array_Scan(src, p)
}

func (p StringArray) Value() (driver.Value, error) {
	return pq.Array([]string(p)).Value()
	//return Array_Value(&p)
}

type IntegerArray []int

func (h IntegerArray) Declare(props xql.PropertySet) string {
	return "integer[]"
}

//func (a IntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *IntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 32)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, int(n))
//		}
//	}
//	return nil
//}

func (p *IntegerArray) Scan(src interface{}) error {
	var ps []int
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = IntegerArray(ps)
		pp := IntegerArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p IntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int(p)).Value()
	//return Array_Value(&p)
}

type SmallIntegerArray []int16

func (h SmallIntegerArray) Declare(props xql.PropertySet) string {
	return "smallint[]"
}

//func (a SmallIntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *SmallIntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 16)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, int16(n))
//		}
//	}
//	return nil
//}

func (p *SmallIntegerArray) Scan(src interface{}) error {
	var ps []int16
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = SmallIntegerArray(ps)
		pp := SmallIntegerArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p SmallIntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int16(p)).Value()
	//return Array_Value(&p)
}

type BigIntegerArray []int64

func (h BigIntegerArray) Declare(props xql.PropertySet) string {
	return "bigint[]"
}

//func (a BigIntegerArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%d", x))
//	}
//	return ss
//}
//
//func (a *BigIntegerArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseInt(s, 10, 64)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, n)
//		}
//	}
//	return nil
//}

func (p *BigIntegerArray) Scan(src interface{}) error {
	var ps []int64
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = BigIntegerArray(ps)
		pp := BigIntegerArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p BigIntegerArray) Value() (driver.Value, error) {
	return pq.Array([]int64(p)).Value()
	//return Array_Value(&p)
}

type RealArray []float32

func (h RealArray) Declare(props xql.PropertySet) string {
	return "real[]"
}

//func (a RealArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%f", x))
//	}
//	return ss
//}
//
//func (a *RealArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseFloat(s, 32)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, float32(n))
//		}
//	}
//	return nil
//}

func (p *RealArray) Scan(src interface{}) error {
	var ps []float32
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = RealArray(ps)
		pp := RealArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p RealArray) Value() (driver.Value, error) {
	return pq.Array([]float32(p)).Value()
	//return Array_Value(&p)
}

type DoubleArray []float64

func (h DoubleArray) Declare(props xql.PropertySet) string {
	return "double[]"
}

//func (a DoubleArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%f", x))
//	}
//	return ss
//}
//
//func (a *DoubleArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		n, e := strconv.ParseFloat(s, 64)
//		if nil != e {
//			return e
//		} else {
//			(*a) = append(*a, n)
//		}
//	}
//	return nil
//}

func (p *DoubleArray) Scan(src interface{}) error {
	var ps []float64
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = DoubleArray(ps)
		pp := DoubleArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p DoubleArray) Value() (driver.Value, error) {
	return pq.Array([]float64(p)).Value()
	//return Array_Value(&p)
}

type BoolArray []bool

func (h BoolArray) Declare(props xql.PropertySet) string {
	return "bool[]"
}

//func (a BoolArray) Elem2Strings() []string {
//	ss := []string{}
//	for _, x := range a {
//		ss = append(ss, fmt.Sprintf("%s", x))
//	}
//	return ss
//}
//
//func (a *BoolArray) Strings2Elem(ss ...string) error {
//	for _, s := range ss {
//		switch strings.ToLower(s) {
//		case "y", "yes", "t", "true", "ok":
//			(*a) = append(*a, true)
//		default:
//			(*a) = append(*a, false)
//		}
//	}
//	return nil
//}

func (p *BoolArray) Scan(src interface{}) error {
	var ps []bool
	if e := pq.Array(ps).Scan(src); nil != e {
		return e
	} else {
		//p = BoolArray(ps)
		pp := BoolArray(ps)
		p = &pp
		return nil
	}
	//return Array_Scan(src, p)
}

func (p BoolArray) Value() (driver.Value, error) {
	return pq.Array([]bool(p)).Value()
	//return Array_Value(&p)
}

// PARSING ARRAYS
// SEE http://www.postgresql.org/docs/9.1/static/arrays.html#ARRAYS-IO
// Arrays are output within {} and a delimiter, which is a comma for most
// postgres types (; for box)
//
// Individual values are surrounded by quotes:
// The array output routine will put double quotes around element values if
// they are empty strings, contain curly braces, delimiter characters,
// double quotes, backslashes, or white space, or match the word NULL.
// Double quotes and backslashes embedded in element values will be
// backslash-escaped. For numeric data types it is safe to assume that double
// quotes will never appear, but for textual data types one should be prepared
// to cope with either the presence or absence of quotes.

// construct a regexp to extract values:
var (
	// unquoted array values must not contain: (" , \ { } whitespace NULL)
	// and must be at least one char
	unquotedChar  = `[^",\\{}\s(NULL)]`
	unquotedValue = fmt.Sprintf("(%s)+", unquotedChar)

	// quoted array values are surrounded by double quotes, can be any
	// character except " or \, which must be backslash escaped:
	quotedChar  = `[^"\\]|\\"|\\\\`
	quotedValue = fmt.Sprintf("\"(%s)*\"", quotedChar)

	// an array value may be either quoted or unquoted:
	arrayValue = fmt.Sprintf("(?P<value>(%s|%s))", unquotedValue, quotedValue)

	// Array values are separated with a comma IF there is more than one value:
	arrayExp = regexp.MustCompile(fmt.Sprintf("((%s)(,)?)", arrayValue))

	valueIndex int
)

// Find the index of the 'value' named expression
func init() {
	for i, subexp := range arrayExp.SubexpNames() {
		if subexp == "value" {
			valueIndex = i
			break
		}
	}
}

// Parse the output string from the array type.
// Regex used: (((?P<value>(([^",\\{}\s(NULL)])+|"([^"\\]|\\"|\\\\)*")))(,)?)
func parseArray(array string) []string {
	results := make([]string, 0)
	matches := arrayExp.FindAllStringSubmatch(array, -1)
	for _, match := range matches {
		s := match[valueIndex]
		// the string _might_ be wrapped in quotes, so trim them:
		s = strings.Trim(s, "\"")
		results = append(results, s)
	}
	return results
}

//func (p *StringArray) Scan(src interface{}) error {
//    asBytes, ok := src.([]byte)
//    if !ok {
//        return error(errors.New("Scan source was not []bytes."))
//    }
//
//    asString := string(asBytes)
//    parsed := parseArray(asString)
//    (*p) = StringArray(parsed)
//
//    return nil
//}
//
//func (p StringArray) Value() (driver.Value, error) {
//    var ss []string
//    for _, s := range p {
//        ss = append(ss, fmt.Sprintf(`"%s"`, s))
//    }
//    return strings.Join([]string{"{", strings.Join(ss, ","), "}"}, ""), nil
//}

func Array_Scan(src interface{}, dest interface{}) error {
	if nil == src || dest == nil {
		return nil
	}
	asBytes, ok := src.([]byte)
	if !ok {
		return error(errors.New("Scan source was not []bytes."))
	}

	asString := string(asBytes)
	parsed := parseArray(asString)
	if vv, ok := dest.(Elemented); ok {
		return vv.Strings2Elem(parsed...)
	}
	return errors.New("Elemented should be implemented.")
}

func Array_Value(v interface{}) (driver.Value, error) {
	if nil == v {
		return nil, nil
	}
	if vv, ok := v.(Elemented); ok {
		return strings.Join([]string{"{", strings.Join(vv.Elem2Strings(), ","), "}"}, ""), nil
	}
	return nil, errors.New("Elemented should be implemented.")
}
<|endoftext|>


<commit_before>package digests

import (
	"fmt"

	"github.com/ion-channel/ionic/scanner"
	"github.com/ion-channel/ionic/scans"
)

func vulnerabilityDigests(status *scanner.ScanStatus, eval *scans.Evaluation) ([]Digest, error) {
	digests := make([]Digest, 0)

	var vulnCount, uniqVulnCount int
	var highs int
	var crits int
	if eval != nil {
		b, ok := eval.TranslatedResults.Data.(scans.VulnerabilityResults)
		if !ok {
			return nil, fmt.Errorf("error coercing evaluation translated results into vuln")
		}

		vulnCount = b.Meta.VulnerabilityCount

		ids := make(map[int]bool, 0)

		for i := range b.Vulnerabilities {
			for j := range b.Vulnerabilities[i].Vulnerabilities {
				v := b.Vulnerabilities[i].Vulnerabilities[j]
				ids[v.ID] = true

				switch v.ScoreVersion {
				case "3.0":
					if v.ScoreDetails.CVSSv3 != nil && v.ScoreDetails.CVSSv3.BaseScore >= 9.0 {
						crits++
					} else if v.ScoreDetails.CVSSv3 != nil && v.ScoreDetails.CVSSv3.BaseScore >= 7.0 {
						highs++
					}
				case "2.0":
					if v.ScoreDetails.CVSSv2 != nil && v.ScoreDetails.CVSSv2.BaseScore >= 7.0 {
						highs++
					}
				default:
				}
			}
		}

		uniqVulnCount = len(ids)
	}

	// total vulns
	d := NewDigest(status, totalVulnerabilitiesIndex, "total vulnerability", "total vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", vulnCount)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to total vulnerabilities digest: %v", err.Error())
		}

		if vulnCount > 0 {
			d.Warning = true
			d.WarningMessage = "vulnerabilities found"

			if vulnCount == 1 {
				d.WarningMessage = "vulnerability found"
			}
		}
	}

	digests = append(digests, *d)

	// unique vulns
	d = NewDigest(status, uniqueVulnerabilitiesIndex, "unique vulnerability", "unique vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", uniqVulnCount)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}
	}

	digests = append(digests, *d)

	// high vulns
	d = NewDigest(status, highVulnerabilitiesIndex, "high vulnerability", "high vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", highs)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}
	}

	digests = append(digests, *d)

	// critical vulns
	d = NewDigest(status, criticalVulnerabilitiesIndex, "critical vulnerability", "critical vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", crits)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}
	}

	digests = append(digests, *d)

	return digests, nil
}
<commit_msg>forcibly detach total and uniq digests from evals<commit_after>package digests

import (
	"fmt"

	"github.com/ion-channel/ionic/scanner"
	"github.com/ion-channel/ionic/scans"
)

func vulnerabilityDigests(status *scanner.ScanStatus, eval *scans.Evaluation) ([]Digest, error) {
	digests := make([]Digest, 0)

	var vulnCount, uniqVulnCount int
	var highs int
	var crits int
	if eval != nil {
		b, ok := eval.TranslatedResults.Data.(scans.VulnerabilityResults)
		if !ok {
			return nil, fmt.Errorf("error coercing evaluation translated results into vuln")
		}

		vulnCount = b.Meta.VulnerabilityCount

		ids := make(map[int]bool, 0)

		for i := range b.Vulnerabilities {
			for j := range b.Vulnerabilities[i].Vulnerabilities {
				v := b.Vulnerabilities[i].Vulnerabilities[j]
				ids[v.ID] = true

				switch v.ScoreVersion {
				case "3.0":
					if v.ScoreDetails.CVSSv3 != nil && v.ScoreDetails.CVSSv3.BaseScore >= 9.0 {
						crits++
					} else if v.ScoreDetails.CVSSv3 != nil && v.ScoreDetails.CVSSv3.BaseScore >= 7.0 {
						highs++
					}
				case "2.0":
					if v.ScoreDetails.CVSSv2 != nil && v.ScoreDetails.CVSSv2.BaseScore >= 7.0 {
						highs++
					}
				default:
				}
			}
		}

		uniqVulnCount = len(ids)
	}

	// total vulns
	d := NewDigest(status, totalVulnerabilitiesIndex, "total vulnerability", "total vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", vulnCount)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to total vulnerabilities digest: %v", err.Error())
		}

		if vulnCount > 0 {
			d.Warning = true
			d.WarningMessage = "vulnerabilities found"

			if vulnCount == 1 {
				d.WarningMessage = "vulnerability found"
			}
		}

		d.Evaluated = false // As of now there's no rule to evaluate this against so it's set to not evaluated.
	}

	digests = append(digests, *d)

	// unique vulns
	d = NewDigest(status, uniqueVulnerabilitiesIndex, "unique vulnerability", "unique vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", uniqVulnCount)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}

		d.Evaluated = false // As of now there's no rule to evaluate this against so it's set to not evaluated.
	}

	digests = append(digests, *d)

	// high vulns
	d = NewDigest(status, highVulnerabilitiesIndex, "high vulnerability", "high vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", highs)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}
	}

	digests = append(digests, *d)

	// critical vulns
	d = NewDigest(status, criticalVulnerabilitiesIndex, "critical vulnerability", "critical vulnerabilities")

	if eval != nil {
		err := d.AppendEval(eval, "count", crits)
		if err != nil {
			return nil, fmt.Errorf("failed to add evaluation data to unique vulnerabilities digest: %v", err.Error())
		}
	}

	digests = append(digests, *d)

	return digests, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"sort"
	"sync"
	"sync/atomic"
	"time"

	"github.com/hamaxx/gracevisor/common/report"
)

var (
	ErrNoActiveInstances  = errors.New("No active instances")
	ErrInstanceNotRunning = errors.New("Instance is not running")
)

type InstanceStatusSort []*Instance

func (v InstanceStatusSort) Len() int {
	return len(v)
}
func (v InstanceStatusSort) Swap(i, j int) {
	v[i], v[j] = v[j], v[i]
}
func (v InstanceStatusSort) Less(i, j int) bool {
	// only bring serving, starting and stopping apps to display
	// leave order of others unchanged
	if v[i].status <= InstanceStatusStopping || v[j].status <= InstanceStatusStopping {
		return v[i].status > v[j].status
	}
	return false
}

type App struct {
	config *AppConfig

	instances          []*Instance
	activeInstance     *Instance
	activeInstanceLock sync.RWMutex

	rp       *ReverseProxy
	portPool *PortPool

	externalHostPort string

	instanceId uint32

	appLogger *AppLogger
}

func NewApp(config *AppConfig, portPool *PortPool) *App {
	app := &App{
		config:           config,
		instances:        make([]*Instance, 0, 10),
		portPool:         portPool,
		externalHostPort: fmt.Sprintf("%s:%d", config.ExternalHost, config.ExternalPort),
	}

	app.appLogger = NewAppLogger(app)
	app.rp = &ReverseProxy{App: app}

	app.startInstanceUpdater()

	return app
}

func (a *App) startInstanceUpdater() {
	ticker := time.NewTicker(time.Second)

	restartCount := 0

	go func() {
		// TODO refactor this. Instances should trigger status changes.
		for {
			lastStatus := -1

			for _, instance := range a.instances {
				status := instance.UpdateStatus()
				lastStatus = status

				if instance == a.activeInstance {
					if status != InstanceStatusServing {
						a.activeInstance = nil
					}
				} else {
					if status == InstanceStatusServing {
						restartCount = 0
						a.activeInstanceLock.Lock()
						currentActive := a.activeInstance
						a.activeInstance = instance
						a.activeInstanceLock.Unlock()

						if currentActive != nil {
							currentActive.Stop()
						}
					}
				}
			}

			if lastStatus == InstanceStatusExited || lastStatus == InstanceStatusFailed || lastStatus == InstanceStatusTimedOut {
				if restartCount < a.config.MaxRetries {
					restartCount++
					err := a.StartNewInstance()
					if err != nil {
						log.Print(err)
					}
				}
			}

			<-ticker.C
		}
	}()
}

// reserveInstance reserves active instance for an active http request
func (a *App) reserveInstance() (*Instance, error) {
	a.activeInstanceLock.RLock()
	instance := a.activeInstance

	if instance == nil {
		a.activeInstanceLock.RUnlock()
		return nil, ErrNoActiveInstances
	}

	instance.Serve()
	a.activeInstanceLock.RUnlock()

	return instance, nil
}

func (a *App) StartNewInstance() error {
	newInstance, err := NewInstance(a, atomic.AddUint32(&a.instanceId, 1))
	if err != nil {
		return err
	}

	a.instances = append(a.instances, newInstance)
	return nil
}

func (a *App) StopInstances(instanceId int, kill bool) error {
	stopped := false
	for _, instance := range a.instances {
		if instanceId > 0 && int(instance.id) != instanceId {
			continue
		}
		if instance.status == InstanceStatusServing || instance.status == InstanceStatusStarting {
			stopped = true
			if kill {
				instance.Kill()
			} else {
				instance.Stop()
			}
		}
	}
	if !stopped {
		return ErrInstanceNotRunning
	}
	return nil
}

func (a *App) ListenAndServe() error {
	if err := a.StartNewInstance(); err != nil {
		return err
	}

	if a.config.Proxy == ProxyTypeTCP {
		return NewTcpProxy(a).ServeTcp()
	}
	return http.ListenAndServe(a.externalHostPort, a.rp)
}

// Report returns report for rpc status commands
func (a *App) Report(displayN int) *report.App {
	appReport := &report.App{
		Name: a.config.Name,
		Host: a.config.ExternalHost,
		Port: a.config.ExternalPort,
	}

	from := 0
	if len(a.instances) > displayN {
		from = len(a.instances) - displayN
	}

	sort.Stable(InstanceStatusSort(a.instances))

	for _, instance := range a.instances[from:len(a.instances)] {
		instanceReport := instance.Report()
		appReport.Instances = append(appReport.Instances, instanceReport)
	}

	return appReport
}
<commit_msg>Log message<commit_after>package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"sort"
	"sync"
	"sync/atomic"
	"time"

	"github.com/hamaxx/gracevisor/common/report"
)

var (
	ErrNoActiveInstances  = errors.New("No active instances")
	ErrInstanceNotRunning = errors.New("Instance is not running")
)

type InstanceStatusSort []*Instance

func (v InstanceStatusSort) Len() int {
	return len(v)
}
func (v InstanceStatusSort) Swap(i, j int) {
	v[i], v[j] = v[j], v[i]
}
func (v InstanceStatusSort) Less(i, j int) bool {
	// only bring serving, starting and stopping apps to display
	// leave order of others unchanged
	if v[i].status <= InstanceStatusStopping || v[j].status <= InstanceStatusStopping {
		return v[i].status > v[j].status
	}
	return false
}

type App struct {
	config *AppConfig

	instances          []*Instance
	activeInstance     *Instance
	activeInstanceLock sync.RWMutex

	rp       *ReverseProxy
	portPool *PortPool

	externalHostPort string

	instanceId uint32

	appLogger *AppLogger
}

func NewApp(config *AppConfig, portPool *PortPool) *App {
	app := &App{
		config:           config,
		instances:        make([]*Instance, 0, 10),
		portPool:         portPool,
		externalHostPort: fmt.Sprintf("%s:%d", config.ExternalHost, config.ExternalPort),
	}

	app.appLogger = NewAppLogger(app)
	app.rp = &ReverseProxy{App: app}

	app.startInstanceUpdater()

	return app
}

func (a *App) startInstanceUpdater() {
	ticker := time.NewTicker(time.Second)

	restartCount := 0

	go func() {
		// TODO refactor this. Instances should trigger status changes.
		for {
			lastStatus := -1

			for _, instance := range a.instances {
				status := instance.UpdateStatus()
				lastStatus = status

				if instance == a.activeInstance {
					if status != InstanceStatusServing {
						a.activeInstance = nil
					}
				} else {
					if status == InstanceStatusServing {
						restartCount = 0
						a.activeInstanceLock.Lock()
						currentActive := a.activeInstance
						a.activeInstance = instance
						a.activeInstanceLock.Unlock()

						if currentActive != nil {
							currentActive.Stop()
						}
					}
				}
			}

			if lastStatus == InstanceStatusExited || lastStatus == InstanceStatusFailed || lastStatus == InstanceStatusTimedOut {
				if restartCount < a.config.MaxRetries {
					restartCount++
					err := a.StartNewInstance()
					if err != nil {
						log.Print(err)
					}
				}
			}

			<-ticker.C
		}
	}()
}

// reserveInstance reserves active instance for an active http request
func (a *App) reserveInstance() (*Instance, error) {
	a.activeInstanceLock.RLock()
	instance := a.activeInstance

	if instance == nil {
		a.activeInstanceLock.RUnlock()
		return nil, ErrNoActiveInstances
	}

	instance.Serve()
	a.activeInstanceLock.RUnlock()

	return instance, nil
}

func (a *App) StartNewInstance() error {
	newInstance, err := NewInstance(a, atomic.AddUint32(&a.instanceId, 1))
	if err != nil {
		return err
	}

	a.instances = append(a.instances, newInstance)
	return nil
}

func (a *App) StopInstances(instanceId int, kill bool) error {
	stopped := false
	for _, instance := range a.instances {
		if instanceId > 0 && int(instance.id) != instanceId {
			continue
		}
		if instance.status == InstanceStatusServing || instance.status == InstanceStatusStarting {
			stopped = true
			if kill {
				instance.Kill()
			} else {
				instance.Stop()
			}
		}
	}
	if !stopped {
		return ErrInstanceNotRunning
	}
	return nil
}

func (a *App) ListenAndServe() error {
	if err := a.StartNewInstance(); err != nil {
		return err
	}

	if a.config.Proxy == ProxyTypeTCP {
		log.Print("Starting tcp proxy")
		return NewTcpProxy(a).ServeTcp()
	}
	log.Print("Starting http proxy")
	return http.ListenAndServe(a.externalHostPort, a.rp)
}

// Report returns report for rpc status commands
func (a *App) Report(displayN int) *report.App {
	appReport := &report.App{
		Name: a.config.Name,
		Host: a.config.ExternalHost,
		Port: a.config.ExternalPort,
	}

	from := 0
	if len(a.instances) > displayN {
		from = len(a.instances) - displayN
	}

	sort.Stable(InstanceStatusSort(a.instances))

	for _, instance := range a.instances[from:len(a.instances)] {
		instanceReport := instance.Report()
		appReport.Instances = append(appReport.Instances, instanceReport)
	}

	return appReport
}
<|endoftext|>


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

package rcmd

import (
	"fmt"
	"io"
	"log"
	"os"
	stdpath "path"
	"reflect"
	"sort"
	"strings"

	"github.com/google/go-cmp/cmp"
	"go-hep.org/x/hep/groot/riofs"
	"go-hep.org/x/hep/groot/root"
	"go-hep.org/x/hep/groot/rtree"
)

// Diff compares the values of the list of keys between the two provided ROOT files.
// Diff writes the differing data (if any) to w.
//
// if w is nil, os.Stdout is used.
// if the slice of keys is nil, all keys are considered.
func Diff(w io.Writer, ref, chk *riofs.File, keys []string) error {
	cmd, err := newDiffCmd(w, ref, chk, keys)
	if err != nil {
		return fmt.Errorf("could not compute keys to compare: %w", err)
	}

	return cmd.diffFiles()
}

type diffCmd struct {
	w    io.Writer
	fref *riofs.File
	fchk *riofs.File
	keys []string
}

func newDiffCmd(w io.Writer, fref, fchk *riofs.File, keys []string) (*diffCmd, error) {
	var (
		err   error
		ukeys []string
		cmd   = &diffCmd{fref: fref, fchk: fchk, w: w}
	)

	if w == nil {
		cmd.w = os.Stdout
	}

	if len(keys) != 0 {
		for _, k := range keys {
			k = strings.TrimSpace(k)
			if k == "" {
				continue
			}
			ukeys = append(ukeys, k)
		}

		if len(ukeys) == 0 {
			return nil, fmt.Errorf("empty key set")
		}
	} else {
		for _, k := range cmd.fref.Keys() {
			ukeys = append(ukeys, k.Name())
		}
	}

	allgood := true
	for _, k := range ukeys {
		_, err = cmd.fref.Get(k)
		if err != nil {
			allgood = false
			fmt.Fprintf(cmd.w, "key[%s] -- missing from ref-file\n", k)
			log.Printf("key %q is missing from ref-file=%q", k, cmd.fref.Name())
		}

		_, err = cmd.fchk.Get(k)
		if err != nil {
			allgood = false
			fmt.Fprintf(cmd.w, "key[%s] -- missing from chk-file\n", k)
			log.Printf("key %q is missing from chk-file=%q", k, cmd.fchk.Name())
		}

		cmd.keys = append(cmd.keys, k)
	}

	if len(cmd.keys) == 0 {
		return nil, fmt.Errorf("empty key set")
	}

	if !allgood {
		return nil, fmt.Errorf("key set differ")
	}

	sort.Strings(cmd.keys)
	return cmd, nil
}

func (cmd *diffCmd) diffFiles() error {
	for _, key := range cmd.keys {
		ref, err := cmd.fref.Get(key)
		if err != nil {
			return err
		}

		chk, err := cmd.fchk.Get(key)
		if err != nil {
			return err
		}

		err = cmd.diffObject(key, ref, chk)
		if err != nil {
			return err
		}
	}

	return nil
}

func (cmd *diffCmd) diffObject(key string, ref, chk root.Object) error {
	refType := reflect.TypeOf(ref)
	chkType := reflect.TypeOf(chk)

	if !reflect.DeepEqual(refType, chkType) {
		return fmt.Errorf("%s: type of keys differ: ref=%v chk=%v", key, refType, chkType)
	}

	switch ref := ref.(type) {
	case rtree.Tree:
		return cmd.diffTree(key, ref, chk.(rtree.Tree))
	case riofs.Directory:
		return cmd.diffDir(key, ref, chk.(riofs.Directory))

	case root.Object:
		ok := reflect.DeepEqual(ref, chk)
		if !ok {
			fmt.Fprintf(cmd.w, "key[%s] (%T) -- (-ref +chk)\n-%v\n+%v\n", key, ref, ref, chk)
			return fmt.Errorf("%s: keys differ", key)
		}
		return nil
	default:
		return fmt.Errorf("unhandled type %T (key=%v)", ref, key)
	}
}

func (cmd *diffCmd) diffDir(key string, ref, chk riofs.Directory) error {
	kref := ref.Keys()
	kchk := chk.Keys()
	if len(kref) != len(kchk) {
		return fmt.Errorf("%s: number of keys in directory differ: ref=%d, chk=%d", key, len(kref), len(kchk))
	}

	krefset := make(map[string]struct{})
	kchkset := make(map[string]struct{})
	for _, k := range kref {
		krefset[k.Name()] = struct{}{}
	}
	for _, k := range kchk {
		kchkset[k.Name()] = struct{}{}
	}
	refnames := make([]string, 0, len(krefset))
	for k := range krefset {
		refnames = append(refnames, k)
	}
	chknames := make([]string, 0, len(kchkset))
	for k := range kchkset {
		chknames = append(chknames, k)
	}
	sort.Strings(refnames)
	sort.Strings(chknames)
	if len(krefset) != len(kchkset) {
		return fmt.Errorf("%s: keys in directory differ: ref=%s, chk=%s", key, refnames, chknames)
	}

	for _, k := range refnames {
		oref, err := ref.Get(k)
		if err != nil {
			return fmt.Errorf("%s: could not retrieve %s from ref-directory", key, k)
		}
		ochk, err := chk.Get(k)
		if err != nil {
			return fmt.Errorf("%s: could not retrieve %s from chk-directory", key, k)
		}

		err = cmd.diffObject(stdpath.Join(key, k), oref, ochk)
		if err != nil {
			return fmt.Errorf("%s: values for %s in directory differ: %w", key, k, err)
		}
	}

	return nil
}

func (cmd *diffCmd) diffTree(key string, ref, chk rtree.Tree) error {
	if eref, echk := ref.Entries(), chk.Entries(); eref != echk {
		return fmt.Errorf("%s: number of entries differ: ref=%v chk=%v", key, eref, echk)
	}

	refVars := rtree.NewReadVars(ref)
	chkVars := rtree.NewReadVars(chk)

	quit := make(chan struct{})
	defer close(quit)

	refc := make(chan treeEntry)
	chkc := make(chan treeEntry)

	go cmd.treeDump(quit, refc, ref, refVars)
	go cmd.treeDump(quit, chkc, chk, chkVars)

	allgood := true
	n := chk.Entries()
	for i := int64(0); i < n; i++ {
		ref := <-refc
		chk := <-chkc
		if ref.err != nil {
			return fmt.Errorf("%s: error reading ref-tree: %w", key, ref.err)
		}
		if chk.err != nil {
			return fmt.Errorf("%s: error reading chk-tree: %w", key, chk.err)
		}
		if chk.n != ref.n {
			return fmt.Errorf("%s: tree out of sync (ref=%d, chk=%d)", key, ref.n, chk.n)
		}

		for ii := range refVars {
			var (
				ref  = reflect.Indirect(reflect.ValueOf(refVars[ii].Value)).Interface()
				chk  = reflect.Indirect(reflect.ValueOf(chkVars[ii].Value)).Interface()
				diff = cmp.Diff(ref, chk)
			)
			if diff != "" {
				fmt.Fprintf(cmd.w, "key[%s][%04d].%s -- (-ref +chk)\n%s", key, i, refVars[ii].Name, diff)
				allgood = false
			}
		}
		ref.ok <- 1
		chk.ok <- 1
	}

	if !allgood {
		return fmt.Errorf("%s: trees differ", key)
	}

	return nil
}

type treeEntry struct {
	n   int64
	err error
	ok  chan int
}

func (cmd *diffCmd) treeDump(quit chan struct{}, out chan treeEntry, t rtree.Tree, vars []rtree.ReadVar) {
	sc, err := rtree.NewScannerVars(t, vars...)
	if err != nil {
		out <- treeEntry{err: err}
		return
	}
	defer sc.Close()

	defer close(out)

	next := make(chan int)
	for sc.Next() {
		err = sc.Scan()
		select {
		case <-quit:
			return
		case out <- treeEntry{err: err, n: sc.Entry(), ok: next}:
			<-next
			continue
		}
	}
}
<commit_msg>groot/rcmd: use rtree.Reader in lieu of rtree.Scanner<commit_after>// Copyright ©2020 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rcmd

import (
	"fmt"
	"io"
	"log"
	"os"
	stdpath "path"
	"reflect"
	"sort"
	"strings"

	"github.com/google/go-cmp/cmp"
	"go-hep.org/x/hep/groot/riofs"
	"go-hep.org/x/hep/groot/root"
	"go-hep.org/x/hep/groot/rtree"
)

// Diff compares the values of the list of keys between the two provided ROOT files.
// Diff writes the differing data (if any) to w.
//
// if w is nil, os.Stdout is used.
// if the slice of keys is nil, all keys are considered.
func Diff(w io.Writer, ref, chk *riofs.File, keys []string) error {
	cmd, err := newDiffCmd(w, ref, chk, keys)
	if err != nil {
		return fmt.Errorf("could not compute keys to compare: %w", err)
	}

	return cmd.diffFiles()
}

type diffCmd struct {
	w    io.Writer
	fref *riofs.File
	fchk *riofs.File
	keys []string
}

func newDiffCmd(w io.Writer, fref, fchk *riofs.File, keys []string) (*diffCmd, error) {
	var (
		err   error
		ukeys []string
		cmd   = &diffCmd{fref: fref, fchk: fchk, w: w}
	)

	if w == nil {
		cmd.w = os.Stdout
	}

	if len(keys) != 0 {
		for _, k := range keys {
			k = strings.TrimSpace(k)
			if k == "" {
				continue
			}
			ukeys = append(ukeys, k)
		}

		if len(ukeys) == 0 {
			return nil, fmt.Errorf("empty key set")
		}
	} else {
		for _, k := range cmd.fref.Keys() {
			ukeys = append(ukeys, k.Name())
		}
	}

	allgood := true
	for _, k := range ukeys {
		_, err = cmd.fref.Get(k)
		if err != nil {
			allgood = false
			fmt.Fprintf(cmd.w, "key[%s] -- missing from ref-file\n", k)
			log.Printf("key %q is missing from ref-file=%q", k, cmd.fref.Name())
		}

		_, err = cmd.fchk.Get(k)
		if err != nil {
			allgood = false
			fmt.Fprintf(cmd.w, "key[%s] -- missing from chk-file\n", k)
			log.Printf("key %q is missing from chk-file=%q", k, cmd.fchk.Name())
		}

		cmd.keys = append(cmd.keys, k)
	}

	if len(cmd.keys) == 0 {
		return nil, fmt.Errorf("empty key set")
	}

	if !allgood {
		return nil, fmt.Errorf("key set differ")
	}

	sort.Strings(cmd.keys)
	return cmd, nil
}

func (cmd *diffCmd) diffFiles() error {
	for _, key := range cmd.keys {
		ref, err := cmd.fref.Get(key)
		if err != nil {
			return err
		}

		chk, err := cmd.fchk.Get(key)
		if err != nil {
			return err
		}

		err = cmd.diffObject(key, ref, chk)
		if err != nil {
			return err
		}
	}

	return nil
}

func (cmd *diffCmd) diffObject(key string, ref, chk root.Object) error {
	refType := reflect.TypeOf(ref)
	chkType := reflect.TypeOf(chk)

	if !reflect.DeepEqual(refType, chkType) {
		return fmt.Errorf("%s: type of keys differ: ref=%v chk=%v", key, refType, chkType)
	}

	switch ref := ref.(type) {
	case rtree.Tree:
		return cmd.diffTree(key, ref, chk.(rtree.Tree))
	case riofs.Directory:
		return cmd.diffDir(key, ref, chk.(riofs.Directory))

	case root.Object:
		ok := reflect.DeepEqual(ref, chk)
		if !ok {
			fmt.Fprintf(cmd.w, "key[%s] (%T) -- (-ref +chk)\n-%v\n+%v\n", key, ref, ref, chk)
			return fmt.Errorf("%s: keys differ", key)
		}
		return nil
	default:
		return fmt.Errorf("unhandled type %T (key=%v)", ref, key)
	}
}

func (cmd *diffCmd) diffDir(key string, ref, chk riofs.Directory) error {
	kref := ref.Keys()
	kchk := chk.Keys()
	if len(kref) != len(kchk) {
		return fmt.Errorf("%s: number of keys in directory differ: ref=%d, chk=%d", key, len(kref), len(kchk))
	}

	krefset := make(map[string]struct{})
	kchkset := make(map[string]struct{})
	for _, k := range kref {
		krefset[k.Name()] = struct{}{}
	}
	for _, k := range kchk {
		kchkset[k.Name()] = struct{}{}
	}
	refnames := make([]string, 0, len(krefset))
	for k := range krefset {
		refnames = append(refnames, k)
	}
	chknames := make([]string, 0, len(kchkset))
	for k := range kchkset {
		chknames = append(chknames, k)
	}
	sort.Strings(refnames)
	sort.Strings(chknames)
	if len(krefset) != len(kchkset) {
		return fmt.Errorf("%s: keys in directory differ: ref=%s, chk=%s", key, refnames, chknames)
	}

	for _, k := range refnames {
		oref, err := ref.Get(k)
		if err != nil {
			return fmt.Errorf("%s: could not retrieve %s from ref-directory", key, k)
		}
		ochk, err := chk.Get(k)
		if err != nil {
			return fmt.Errorf("%s: could not retrieve %s from chk-directory", key, k)
		}

		err = cmd.diffObject(stdpath.Join(key, k), oref, ochk)
		if err != nil {
			return fmt.Errorf("%s: values for %s in directory differ: %w", key, k, err)
		}
	}

	return nil
}

func (cmd *diffCmd) diffTree(key string, ref, chk rtree.Tree) error {
	if eref, echk := ref.Entries(), chk.Entries(); eref != echk {
		return fmt.Errorf("%s: number of entries differ: ref=%v chk=%v", key, eref, echk)
	}

	refVars := rtree.NewReadVars(ref)
	chkVars := rtree.NewReadVars(chk)

	quit := make(chan struct{})
	defer close(quit)

	refc := make(chan treeEntry)
	chkc := make(chan treeEntry)

	go cmd.treeDump(quit, refc, ref, refVars)
	go cmd.treeDump(quit, chkc, chk, chkVars)

	allgood := true
	n := chk.Entries()
	for i := int64(0); i < n; i++ {
		ref := <-refc
		chk := <-chkc
		if ref.err != nil {
			return fmt.Errorf("%s: error reading ref-tree: %w", key, ref.err)
		}
		if chk.err != nil {
			return fmt.Errorf("%s: error reading chk-tree: %w", key, chk.err)
		}
		if chk.n != ref.n {
			return fmt.Errorf("%s: tree out of sync (ref=%d, chk=%d)", key, ref.n, chk.n)
		}

		for ii := range refVars {
			var (
				ref  = reflect.Indirect(reflect.ValueOf(refVars[ii].Value)).Interface()
				chk  = reflect.Indirect(reflect.ValueOf(chkVars[ii].Value)).Interface()
				diff = cmp.Diff(ref, chk)
			)
			if diff != "" {
				fmt.Fprintf(cmd.w, "key[%s][%04d].%s -- (-ref +chk)\n%s", key, i, refVars[ii].Name, diff)
				allgood = false
			}
		}
		ref.ok <- 1
		chk.ok <- 1
	}

	if !allgood {
		return fmt.Errorf("%s: trees differ", key)
	}

	return nil
}

type treeEntry struct {
	n   int64
	err error
	ok  chan int
}

func (cmd *diffCmd) treeDump(quit chan struct{}, out chan treeEntry, t rtree.Tree, vars []rtree.ReadVar) {
	r, err := rtree.NewReader(t, vars)
	if err != nil {
		out <- treeEntry{err: err}
		return
	}
	defer r.Close()

	defer close(out)

	next := make(chan int)
	err = r.Read(func(ctx rtree.RCtx) error {
		select {
		case <-quit:
			return io.EOF
		case out <- treeEntry{err: nil, n: ctx.Entry, ok: next}:
			<-next
			return nil
		}
	})
	if err != nil {
		out <- treeEntry{err: err}
	}
}
<|endoftext|>


<commit_before>package grpcweb

import (
	"context"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket/websocketjs"

	"github.com/johanbrandhorst/protobuf/grpcweb/status"
	"github.com/johanbrandhorst/protobuf/internal"
)

// closeEvent allows a CloseEvent to be used as an error.
type closeEvent struct {
	*js.Object
	Code     int    `js:"code"`
	Reason   string `js:"reason"`
	WasClean bool   `js:"wasClean"`
}

func (e closeEvent) isWebsocketEvent() {}

func (e *closeEvent) Error() string {
	var cleanStmt string
	if e.WasClean {
		cleanStmt = "clean"
	} else {
		cleanStmt = "unclean"
	}
	return fmt.Sprintf("CloseEvent: (%s) (%d) %s", cleanStmt, e.Code, e.Reason)
}

func beginHandlerOpen(ch chan error, removeHandlers func()) func(ev *js.Object) {
	return func(ev *js.Object) {
		removeHandlers()
		close(ch)
	}
}

func beginHandlerClose(ch chan error, removeHandlers func()) func(ev *js.Object) {
	return func(ev *js.Object) {
		removeHandlers()
		go func() {
			ch <- &closeEvent{Object: ev}
			close(ch)
		}()
	}
}

// ClientStream is the interface exposed by the websocket proxy
type ClientStream interface {
	RecvMsg() ([]byte, error)
	SendMsg([]byte) error
	CloseSend() error
	CloseAndRecv() ([]byte, error)
	Context() context.Context
}

// NewClientStream opens a new WebSocket connection for performing client-side
// and bi-directional streaming. It will block until the connection is
// established or fails to connect.
func (c *Client) NewClientStream(ctx context.Context, method string) (ClientStream, error) {
	ws, err := websocketjs.New(strings.Replace(c.host, "https", "wss", 1) + "/" + c.service + "/" + method)
	if err != nil {
		return nil, err
	}
	conn := &conn{
		WebSocket: ws,
		ch:        make(chan wsEvent, 1),
		ctx:       ctx,
	}

	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	conn.BinaryType = "arraybuffer"

	conn.AddEventListener("message", false, conn.onMessage)
	conn.AddEventListener("close", false, conn.onClose)

	openCh := make(chan error, 1)

	var (
		openHandler  func(ev *js.Object)
		closeHandler func(ev *js.Object)
	)

	// Handlers need to be removed to prevent a panic when the WebSocket closes
	// immediately and fires both open and close before they can be removed.
	// This way, handlers are removed before the channel is closed.
	removeHandlers := func() {
		ws.RemoveEventListener("open", false, openHandler)
		ws.RemoveEventListener("close", false, closeHandler)
	}

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler = beginHandlerOpen(openCh, removeHandlers)
	closeHandler = beginHandlerClose(openCh, removeHandlers)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh
	if ok && err != nil {
		return nil, err
	}

	return conn, nil
}

// wsEvent encapsulates both message and close events
type wsEvent interface {
	isWebsocketEvent()
}

type conn struct {
	*websocketjs.WebSocket

	ch  chan wsEvent
	ctx context.Context
}

type messageEvent struct {
	*js.Object
	Data *js.Object `js:"data"`
}

func (m messageEvent) isWebsocketEvent() {}

func (c *conn) onMessage(ev *js.Object) {
	go func() {
		c.ch <- &messageEvent{Object: ev}
	}()
}

func (c *conn) onClose(ev *js.Object) {
	go func() {
		// We queue the error to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- &closeEvent{Object: ev}
	}()
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *conn) receiveFrame(ctx context.Context) (*messageEvent, error) {
	select {
	case event, ok := <-c.ch:
		if !ok { // The channel has been closed
			return nil, io.EOF
		}

		switch m := event.(type) {
		case *messageEvent:
			return m, nil
		case *closeEvent:
			close(c.ch)
			if m.Code == 4000 { // codes.OK
				return nil, io.EOF
			}
			// Otherwise, propagate close error
			return nil, m
		default:
			return nil, errors.New("unexpected message type")
		}
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

// RecvMsg reads a message from the stream.
// It blocks until a message or error has been received.
func (c *conn) RecvMsg() ([]byte, error) {
	ev, err := c.receiveFrame(c.ctx)
	if err != nil {
		if cerr, ok := err.(*closeEvent); ok && internal.IsgRPCErrorCode(cerr.Code) {
			return nil, &status.Status{
				Code:    internal.ParseErrorCode(cerr.Code),
				Message: cerr.Reason,
			}
		}
		return nil, err
	}

	// Check if it's an array buffer. If so, convert it to a Go byte slice.
	if constructor := ev.Data.Get("constructor"); constructor == js.Global.Get("ArrayBuffer") {
		uint8Array := js.Global.Get("Uint8Array").New(ev.Data)
		return uint8Array.Interface().([]byte), nil
	}
	return []byte(ev.Data.String()), nil
}

// SendMsg sends a message on the stream.
func (c *conn) SendMsg(msg []byte) error {
	return c.Send(msg)
}

// CloseSend closes the stream.
func (c *conn) CloseSend() error {
	// CloseSend does not itself read the close event,
	// it will be done by the next Recv
	return c.SendMsg(internal.FormatCloseMessage())
}

// CloseAndRecv closes the stream and returns the last message.
func (c *conn) CloseAndRecv() ([]byte, error) {
	err := c.CloseSend()
	if err != nil {
		return nil, err
	}

	// Read last message
	msg, err := c.RecvMsg()
	if err != nil {
		return nil, err
	}

	// Read close event
	_, err = c.RecvMsg()
	if err != io.EOF {
		return nil, err
	}

	return msg, nil
}

// Context returns the streams context.
func (c *conn) Context() context.Context {
	return c.ctx
}
<commit_msg>Close websocket when context expires<commit_after>package grpcweb

import (
	"context"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket/websocketjs"

	"github.com/johanbrandhorst/protobuf/grpcweb/status"
	"github.com/johanbrandhorst/protobuf/internal"
)

// closeEvent allows a CloseEvent to be used as an error.
type closeEvent struct {
	*js.Object
	Code     int    `js:"code"`
	Reason   string `js:"reason"`
	WasClean bool   `js:"wasClean"`
}

func (e closeEvent) isWebsocketEvent() {}

func (e *closeEvent) Error() string {
	var cleanStmt string
	if e.WasClean {
		cleanStmt = "clean"
	} else {
		cleanStmt = "unclean"
	}
	return fmt.Sprintf("CloseEvent: (%s) (%d) %s", cleanStmt, e.Code, e.Reason)
}

func beginHandlerOpen(ch chan error, removeHandlers func()) func(ev *js.Object) {
	return func(ev *js.Object) {
		removeHandlers()
		close(ch)
	}
}

func beginHandlerClose(ch chan error, removeHandlers func()) func(ev *js.Object) {
	return func(ev *js.Object) {
		removeHandlers()
		go func() {
			ch <- &closeEvent{Object: ev}
			close(ch)
		}()
	}
}

// ClientStream is the interface exposed by the websocket proxy
type ClientStream interface {
	RecvMsg() ([]byte, error)
	SendMsg([]byte) error
	CloseSend() error
	CloseAndRecv() ([]byte, error)
	Context() context.Context
}

// NewClientStream opens a new WebSocket connection for performing client-side
// and bi-directional streaming. It will block until the connection is
// established or fails to connect.
func (c *Client) NewClientStream(ctx context.Context, method string) (ClientStream, error) {
	ws, err := websocketjs.New(strings.Replace(c.host, "https", "wss", 1) + "/" + c.service + "/" + method)
	if err != nil {
		return nil, err
	}
	conn := &conn{
		WebSocket: ws,
		ch:        make(chan wsEvent, 1),
		ctx:       ctx,
	}

	// We need this so that received binary data is in ArrayBufferView format so
	// that it can easily be read.
	conn.BinaryType = "arraybuffer"

	conn.AddEventListener("message", false, conn.onMessage)
	conn.AddEventListener("close", false, conn.onClose)

	openCh := make(chan error, 1)

	var (
		openHandler  func(ev *js.Object)
		closeHandler func(ev *js.Object)
	)

	// Handlers need to be removed to prevent a panic when the WebSocket closes
	// immediately and fires both open and close before they can be removed.
	// This way, handlers are removed before the channel is closed.
	removeHandlers := func() {
		ws.RemoveEventListener("open", false, openHandler)
		ws.RemoveEventListener("close", false, closeHandler)
	}

	// We have to use variables for the functions so that we can remove the
	// event handlers afterwards.
	openHandler = beginHandlerOpen(openCh, removeHandlers)
	closeHandler = beginHandlerClose(openCh, removeHandlers)

	ws.AddEventListener("open", false, openHandler)
	ws.AddEventListener("close", false, closeHandler)

	err, ok := <-openCh
	if ok && err != nil {
		return nil, err
	}

	return conn, nil
}

// wsEvent encapsulates both message and close events
type wsEvent interface {
	isWebsocketEvent()
}

type conn struct {
	*websocketjs.WebSocket

	ch  chan wsEvent
	ctx context.Context
}

type messageEvent struct {
	*js.Object
	Data *js.Object `js:"data"`
}

func (m messageEvent) isWebsocketEvent() {}

func (c *conn) onMessage(ev *js.Object) {
	go func() {
		c.ch <- &messageEvent{Object: ev}
	}()
}

func (c *conn) onClose(ev *js.Object) {
	go func() {
		// We queue the error to the end so that any messages received prior to
		// closing get handled first.
		c.ch <- &closeEvent{Object: ev}
	}()
}

// receiveFrame receives one full frame from the WebSocket. It blocks until the
// frame is received.
func (c *conn) receiveFrame(ctx context.Context) (*messageEvent, error) {
	select {
	case event, ok := <-c.ch:
		if !ok { // The channel has been closed
			return nil, io.EOF
		}

		switch m := event.(type) {
		case *messageEvent:
			return m, nil
		case *closeEvent:
			close(c.ch)
			if m.Code == 4000 { // codes.OK
				return nil, io.EOF
			}
			// Otherwise, propagate close error
			return nil, m
		default:
			return nil, errors.New("unexpected message type")
		}
	case <-ctx.Done():
		_ = c.Close()
		return nil, ctx.Err()
	}
}

// RecvMsg reads a message from the stream.
// It blocks until a message or error has been received.
func (c *conn) RecvMsg() ([]byte, error) {
	ev, err := c.receiveFrame(c.ctx)
	if err != nil {
		if cerr, ok := err.(*closeEvent); ok && internal.IsgRPCErrorCode(cerr.Code) {
			return nil, &status.Status{
				Code:    internal.ParseErrorCode(cerr.Code),
				Message: cerr.Reason,
			}
		}
		return nil, err
	}

	// Check if it's an array buffer. If so, convert it to a Go byte slice.
	if constructor := ev.Data.Get("constructor"); constructor == js.Global.Get("ArrayBuffer") {
		uint8Array := js.Global.Get("Uint8Array").New(ev.Data)
		return uint8Array.Interface().([]byte), nil
	}
	return []byte(ev.Data.String()), nil
}

// SendMsg sends a message on the stream.
func (c *conn) SendMsg(msg []byte) error {
	return c.Send(msg)
}

// CloseSend closes the stream.
func (c *conn) CloseSend() error {
	// CloseSend does not itself read the close event,
	// it will be done by the next Recv
	return c.SendMsg(internal.FormatCloseMessage())
}

// CloseAndRecv closes the stream and returns the last message.
func (c *conn) CloseAndRecv() ([]byte, error) {
	err := c.CloseSend()
	if err != nil {
		return nil, err
	}

	// Read last message
	msg, err := c.RecvMsg()
	if err != nil {
		return nil, err
	}

	// Read close event
	_, err = c.RecvMsg()
	if err != io.EOF {
		return nil, err
	}

	return msg, nil
}

// Context returns the streams context.
func (c *conn) Context() context.Context {
	return c.ctx
}
<|endoftext|>


<commit_before>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package plugins implements plugin management for the policy engine.
package plugins

import (
	"context"
	"encoding/json"

	"github.com/open-policy-agent/opa/plugins/rest"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/util"
)

// Plugin defines the interface for OPA plugins.
type Plugin interface {
	Start(ctx context.Context) error
	Stop(ctx context.Context)
}

// Manager implements lifecycle management of plugins and gives plugins access
// to engine-wide components like storage.
type Manager struct {
	Labels   map[string]string
	Store    storage.Store
	services map[string]rest.Client
	plugins  []Plugin
}

// New creates a new Manager using config.
func New(config []byte, id string, store storage.Store) (*Manager, error) {

	var parsedConfig struct {
		Services []json.RawMessage
		Labels   map[string]string
	}

	if err := util.Unmarshal(config, &parsedConfig); err != nil {
		return nil, err
	}

	if parsedConfig.Labels == nil {
		parsedConfig.Labels = map[string]string{}
	}

	services := map[string]rest.Client{}

	for _, s := range parsedConfig.Services {
		client, err := rest.New(s)
		if err != nil {
			return nil, err
		}
		services[client.Service()] = client
	}

	parsedConfig.Labels["id"] = id

	m := &Manager{
		Labels:   parsedConfig.Labels,
		Store:    store,
		services: services,
	}

	return m, nil
}

// Register adds a plugin to the manager. When the manager is started, all of
// the plugins will be started.
func (m *Manager) Register(plugin Plugin) {
	m.plugins = append(m.plugins, plugin)
}

// Start starts the manager.
func (m *Manager) Start(ctx context.Context) error {
	if m == nil {
		return nil
	}
	for _, p := range m.plugins {
		if err := p.Start(ctx); err != nil {
			return err
		}
	}
	return nil
}

// Client returns a client for communicating with a remote service.
func (m *Manager) Client(name string) rest.Client {
	return m.services[name]
}

// Services returns a list of services that m can provide clients for.
func (m *Manager) Services() []string {
	s := make([]string, 0, len(m.services))
	for name := range m.services {
		s = append(s, name)
	}
	return s
}
<commit_msg>Added compiler instance to the plugin manager<commit_after>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package plugins implements plugin management for the policy engine.
package plugins

import (
	"context"
	"encoding/json"
	"sync"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/plugins/rest"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/util"
)

// Plugin defines the interface for OPA plugins.
type Plugin interface {
	Start(ctx context.Context) error
	Stop(ctx context.Context)
}

// Manager implements lifecycle management of plugins and gives plugins access
// to engine-wide components like storage.
type Manager struct {
	Labels   map[string]string
	Store    storage.Store
	Compiler *ast.Compiler
	services map[string]rest.Client
	plugins  []Plugin
	mtx      sync.RWMutex
}

// New creates a new Manager using config.
func New(config []byte, id string, store storage.Store) (*Manager, error) {

	var parsedConfig struct {
		Services []json.RawMessage
		Labels   map[string]string
	}

	if err := util.Unmarshal(config, &parsedConfig); err != nil {
		return nil, err
	}

	if parsedConfig.Labels == nil {
		parsedConfig.Labels = map[string]string{}
	}

	services := map[string]rest.Client{}

	for _, s := range parsedConfig.Services {
		client, err := rest.New(s)
		if err != nil {
			return nil, err
		}
		services[client.Service()] = client
	}

	parsedConfig.Labels["id"] = id

	m := &Manager{
		Labels:   parsedConfig.Labels,
		Store:    store,
		services: services,
	}

	return m, nil
}

// Register adds a plugin to the manager. When the manager is started, all of
// the plugins will be started.
func (m *Manager) Register(plugin Plugin) {
	m.plugins = append(m.plugins, plugin)
}

// GetCompiler returns the compiler instance
func (m *Manager) GetCompiler() *ast.Compiler {
	m.mtx.RLock()
	defer m.mtx.RUnlock()
	return m.Compiler
}

func (m *Manager) setCompiler(compiler *ast.Compiler) {
	m.mtx.Lock()
	defer m.mtx.Unlock()
	m.Compiler = compiler
}

// Start starts the manager.
func (m *Manager) Start(ctx context.Context) error {
	if m == nil {
		return nil
	}

	err := storage.Txn(ctx, m.Store, storage.TransactionParams{}, func(txn storage.Transaction) error {
		// load policies from storage
		compiler, err := loadCompilerFromStore(ctx, m.Store, txn)
		if err != nil {
			return err
		}
		// set compiler on manager
		m.setCompiler(compiler)
		return nil
	})

	if err != nil {
		return err
	}

	// start plugins
	for _, p := range m.plugins {
		if err := p.Start(ctx); err != nil {
			return err
		}
	}

	return storage.Txn(ctx, m.Store, storage.WriteParams, func(txn storage.Transaction) error {
		_, err := m.Store.Register(ctx, txn, storage.TriggerConfig{OnCommit: func(ctx context.Context, txn storage.Transaction, event storage.TriggerEvent) {
			if event.PolicyChanged() {
				compiler, _ := loadCompilerFromStore(ctx, m.Store, txn)
				m.setCompiler(compiler)
			}
		}})
		return err
	})
}

func loadCompilerFromStore(ctx context.Context, store storage.Store, txn storage.Transaction) (*ast.Compiler, error) {
	policies, err := store.ListPolicies(ctx, txn)
	if err != nil {
		return nil, err
	}
	modules := map[string]*ast.Module{}

	for _, policy := range policies {
		bs, err := store.GetPolicy(ctx, txn, policy)
		if err != nil {
			return nil, err
		}
		module, err := ast.ParseModule(policy, string(bs))
		if err != nil {
			return nil, err
		}
		modules[policy] = module
	}

	compiler := ast.NewCompiler()
	compiler.Compile(modules)
	return compiler, nil
}

// Client returns a client for communicating with a remote service.
func (m *Manager) Client(name string) rest.Client {
	return m.services[name]
}

// Services returns a list of services that m can provide clients for.
func (m *Manager) Services() []string {
	s := make([]string, 0, len(m.services))
	for name := range m.services {
		s = append(s, name)
	}
	return s
}
<|endoftext|>


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

package time

func init() {
	// force US/Pacific for time zone tests
	ForceUSPacificForTesting()
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

var OrigZoneSources = zoneSources

func forceZipFileForTesting(zipOnly bool) {
	zoneSources = make([]string, len(OrigZoneSources))
	copy(zoneSources, OrigZoneSources)
	if zipOnly {
		zoneSources = zoneSources[len(zoneSources)-1:]
	}
}

var Interrupt = interrupt
var DaysIn = daysIn

func empty(arg interface{}, seq uintptr) {}

// Test that a runtimeTimer with a duration so large it overflows
// does not cause other timers to hang.
//
// This test has to be in internal_test.go since it fiddles with
// unexported data structures.
func CheckRuntimeTimerOverflow() {
	// We manually create a runtimeTimer to bypass the overflow
	// detection logic in NewTimer: we're testing the underlying
	// runtime.addtimer function.
	r := &runtimeTimer{
		when: runtimeNano() + (1<<63 - 1),
		f:    empty,
		arg:  nil,
	}
	startTimer(r)

	// Start a goroutine that should send on t.C right away.
	t := NewTimer(1)

	defer func() {
		// Subsequent tests won't work correctly if we don't stop the
		// overflow timer and kick the timer proc back into service.
		//
		// The timer proc is now sleeping and can only be awoken by
		// adding a timer to the *beginning* of the heap. We can't
		// wake it up by calling NewTimer since other tests may have
		// left timers running that should have expired before ours.
		// Instead we zero the overflow timer duration and start it
		// once more.
		stopTimer(r)
		t.Stop()
		resetTimer(r, 0)
	}()

	// If the test fails, we will hang here until the timeout in the testing package
	// fires, which is 10 minutes. It would be nice to catch the problem sooner,
	// but there is no reliable way to guarantee that timerproc schedules without
	// doing something involving timerproc itself. Previous failed attempts have
	// tried calling runtime.Gosched and runtime.GC, but neither is reliable.
	// So we fall back to hope: We hope we don't hang here.
	<-t.C
}

var (
	MinMonoTime = Time{wall: 1 << 63, ext: -1 << 63, loc: UTC}
	MaxMonoTime = Time{wall: 1 << 63, ext: 1<<63 - 1, loc: UTC}
)
<commit_msg>time: stop referring to timerproc in comment<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time

func init() {
	// force US/Pacific for time zone tests
	ForceUSPacificForTesting()
}

func initTestingZone() {
	z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
	if err != nil {
		panic("cannot load America/Los_Angeles for testing: " + err.Error())
	}
	z.name = "Local"
	localLoc = *z
}

var OrigZoneSources = zoneSources

func forceZipFileForTesting(zipOnly bool) {
	zoneSources = make([]string, len(OrigZoneSources))
	copy(zoneSources, OrigZoneSources)
	if zipOnly {
		zoneSources = zoneSources[len(zoneSources)-1:]
	}
}

var Interrupt = interrupt
var DaysIn = daysIn

func empty(arg interface{}, seq uintptr) {}

// Test that a runtimeTimer with a duration so large it overflows
// does not cause other timers to hang.
//
// This test has to be in internal_test.go since it fiddles with
// unexported data structures.
func CheckRuntimeTimerOverflow() {
	// We manually create a runtimeTimer to bypass the overflow
	// detection logic in NewTimer: we're testing the underlying
	// runtime.addtimer function.
	r := &runtimeTimer{
		when: runtimeNano() + (1<<63 - 1),
		f:    empty,
		arg:  nil,
	}
	startTimer(r)

	// Start a goroutine that should send on t.C right away.
	t := NewTimer(1)

	defer func() {
		// Subsequent tests won't work correctly if we don't stop the
		// overflow timer and kick the timer proc back into service.
		//
		// The timer proc is now sleeping and can only be awoken by
		// adding a timer to the *beginning* of the heap. We can't
		// wake it up by calling NewTimer since other tests may have
		// left timers running that should have expired before ours.
		// Instead we zero the overflow timer duration and start it
		// once more.
		stopTimer(r)
		t.Stop()
		resetTimer(r, 0)
	}()

	// If the test fails, we will hang here until the timeout in the
	// testing package fires, which is 10 minutes. It would be nice to
	// catch the problem sooner, but there is no reliable way to guarantee
	// that timers are run without doing something involving the scheduler.
	// Previous failed attempts have tried calling runtime.Gosched and
	// runtime.GC, but neither is reliable. So we fall back to hope:
	// We hope we don't hang here.
	<-t.C
}

var (
	MinMonoTime = Time{wall: 1 << 63, ext: -1 << 63, loc: UTC}
	MaxMonoTime = Time{wall: 1 << 63, ext: 1<<63 - 1, loc: UTC}
)
<|endoftext|>


<commit_before><commit_msg>implement missing Pos, End and exprNode methods<commit_after><|endoftext|>


<commit_before>// package network implements micro network node
package network

import (
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/network"
	"github.com/micro/go-micro/network/resolver"
	"github.com/micro/go-micro/network/resolver/dns"
	"github.com/micro/go-micro/network/resolver/http"
	"github.com/micro/go-micro/network/resolver/registry"
	"github.com/micro/go-micro/router"
	"github.com/micro/go-micro/tunnel"
	"github.com/micro/go-micro/util/log"
)

var (
	// Name of the network service
	Name = "go.micro.network"
	// Address is the tunnel address
	Address = ":8084"
	// Tunnel is the name of the tunnel
	Tunnel = "tun:0"
	// Resolver is network resolver
	Resolver = "dns"
)

// run runs the micro server
func run(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("tunnel_id")) > 0 {
		Tunnel = ctx.String("tunnel_id")
		// We need host:port for the Endpoint value in the proxy
		parts := strings.Split(Tunnel, ":")
		if len(parts) == 1 {
			Tunnel = Tunnel + ":0"
		}
	}
	var nodes []string
	if len(ctx.String("server")) > 0 {
		nodes = strings.Split(ctx.String("server"), ",")
	}

	if len(ctx.String("resolver")) > 0 {
		Resolver = ctx.String("resolver")
	}
	var res resolver.Resolver
	switch Resolver {
	case "dns":
		res = &dns.Resolver{}
	case "http":
		res = &http.Resolver{}
	case "registry":
		res = &registry.Resolver{}
	}

	// create a tunnel
	tun := tunnel.NewTunnel(
		tunnel.Address(Address),
		tunnel.Nodes(nodes...),
	)

	// local tunnel router
	rtr := router.NewRouter(
		router.Network(Name),
	)

	// creaate new network
	net := network.NewNetwork(
		network.Name(Name),
		network.Address(Address),
		network.Tunnel(tun),
		network.Router(rtr),
		network.Resolver(res),
	)

	// Initialise service
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(time.Duration(ctx.GlobalInt("register_ttl"))*time.Second),
		micro.RegisterInterval(time.Duration(ctx.GlobalInt("register_interval"))*time.Second),
		micro.Server(net.Server()),
	)

	// initialize router
	rtr.Init(
		router.Id(service.Server().Options().Id),
		router.Registry(service.Client().Options().Registry),
	)

	if err := service.Run(); err != nil {
		log.Log("Network %s failed: %v", Name, err)
	}
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "network",
		Usage: "Run the micro network node",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the micro network address :8084",
				EnvVar: "MICRO_NETWORK_ADDRESS",
			},
			cli.StringFlag{
				Name:   "tunnel_id",
				Usage:  "Id of the tunnel used as the internal dial/listen address.",
				EnvVar: "MICRO_TUNNEL_ID",
			},
			cli.StringFlag{
				Name:   "server",
				Usage:  "Set the micro network server address. This can be a comma separated list.",
				EnvVar: "MICRO_NETWORK_SERVER",
			},
			cli.StringFlag{
				Name:   "resolver",
				Usage:  "Set the micro network resolver. This can be a comma separated list.",
				EnvVar: "MICRO_NETWORK_RESOLVER",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<commit_msg>Connect network before starting it<commit_after>// package network implements micro network node
package network

import (
	"os"
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/network"
	"github.com/micro/go-micro/network/resolver"
	"github.com/micro/go-micro/network/resolver/dns"
	"github.com/micro/go-micro/network/resolver/http"
	"github.com/micro/go-micro/network/resolver/registry"
	"github.com/micro/go-micro/router"
	"github.com/micro/go-micro/tunnel"
	"github.com/micro/go-micro/util/log"
)

var (
	// Name of the network service
	Name = "go.micro.network"
	// Address is the tunnel address
	Address = ":8084"
	// Tunnel is the name of the tunnel
	Tunnel = "tun:0"
	// Resolver is network resolver
	Resolver = "dns"
)

// run runs the micro server
func run(ctx *cli.Context, srvOpts ...micro.Option) {
	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("tunnel_id")) > 0 {
		Tunnel = ctx.String("tunnel_id")
		// We need host:port for the Endpoint value in the proxy
		parts := strings.Split(Tunnel, ":")
		if len(parts) == 1 {
			Tunnel = Tunnel + ":0"
		}
	}
	var nodes []string
	if len(ctx.String("server")) > 0 {
		nodes = strings.Split(ctx.String("server"), ",")
	}

	if len(ctx.String("resolver")) > 0 {
		Resolver = ctx.String("resolver")
	}
	var res resolver.Resolver
	switch Resolver {
	case "dns":
		res = &dns.Resolver{}
	case "http":
		res = &http.Resolver{}
	case "registry":
		res = &registry.Resolver{}
	}

	// create a tunnel
	tun := tunnel.NewTunnel(
		tunnel.Address(Address),
		tunnel.Nodes(nodes...),
	)

	// local tunnel router
	rtr := router.NewRouter(
		router.Network(Name),
	)

	// creaate new network
	net := network.NewNetwork(
		network.Name(Name),
		network.Address(Address),
		network.Tunnel(tun),
		network.Router(rtr),
		network.Resolver(res),
	)

	if err := net.Connect(); err != nil {
		log.Logf("Network failed to connect: %v", err)
		os.Exit(1)
	}

	// Initialise service
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(time.Duration(ctx.GlobalInt("register_ttl"))*time.Second),
		micro.RegisterInterval(time.Duration(ctx.GlobalInt("register_interval"))*time.Second),
		micro.Server(net.Server()),
	)

	// initialize router
	rtr.Init(
		router.Id(service.Server().Options().Id),
		router.Registry(service.Client().Options().Registry),
	)

	if err := service.Run(); err != nil {
		log.Log("Network %s failed: %v", Name, err)
	}
}

func Commands(options ...micro.Option) []cli.Command {
	command := cli.Command{
		Name:  "network",
		Usage: "Run the micro network node",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the micro network address :8084",
				EnvVar: "MICRO_NETWORK_ADDRESS",
			},
			cli.StringFlag{
				Name:   "tunnel_id",
				Usage:  "Id of the tunnel used as the internal dial/listen address.",
				EnvVar: "MICRO_TUNNEL_ID",
			},
			cli.StringFlag{
				Name:   "server",
				Usage:  "Set the micro network server address. This can be a comma separated list.",
				EnvVar: "MICRO_NETWORK_SERVER",
			},
			cli.StringFlag{
				Name:   "resolver",
				Usage:  "Set the micro network resolver. This can be a comma separated list.",
				EnvVar: "MICRO_NETWORK_RESOLVER",
			},
		},
		Action: func(ctx *cli.Context) {
			run(ctx, options...)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<|endoftext|>


<commit_before>package proto

import (
	"errors"
	"os"
	"path/filepath"
	"sync"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/writeaheadlog"
)

// A ContractSet provides safe concurrent access to a set of contracts. Its
// purpose is to serialize modifications to individual contracts, as well as
// to provide operations on the set as a whole.
type ContractSet struct {
	contracts map[types.FileContractID]*SafeContract
	wal       *writeaheadlog.WAL
	dir       string
	mu        sync.Mutex
}

// Acquire looks up the contract with the specified FileContractID and locks
// it before returning it. If the contract is not present in the set, Acquire
// returns false and a zero-valued RenterContract.
func (cs *ContractSet) Acquire(id types.FileContractID) (*SafeContract, bool) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[id]
	cs.mu.Unlock()
	if !ok {
		return nil, false
	}
	safeContract.mu.Lock()
	// We need to check if the contract is still in the map or if it has been
	// deleted in the meantime.
	cs.mu.Lock()
	_, ok = cs.contracts[id]
	cs.mu.Unlock()
	if !ok {
		safeContract.mu.Unlock()
		return nil, false
	}
	return safeContract, true
}

// Delete removes a contract from the set. The contract must have been
// previously acquired by Acquire. If the contract is not present in the set,
// Delete is a no-op.
func (cs *ContractSet) Delete(c *SafeContract) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[c.header.ID()]
	if !ok {
		cs.mu.Unlock()
		return
	}
	delete(cs.contracts, c.header.ID())
	cs.mu.Unlock()
	safeContract.mu.Unlock()
	// delete contract file
	os.Remove(filepath.Join(cs.dir, c.header.ID().String()+contractExtension))
}

// IDs returns the FileContractID of each contract in the set. The contracts
// are not locked.
func (cs *ContractSet) IDs() []types.FileContractID {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	ids := make([]types.FileContractID, 0, len(cs.contracts))
	for id := range cs.contracts {
		ids = append(ids, id)
	}
	return ids
}

// Len returns the number of contracts in the set.
func (cs *ContractSet) Len() int {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	return len(cs.contracts)
}

// Return returns a locked contract to the set and unlocks it. The contract
// must have been previously acquired by Acquire. If the contract is not
// present in the set, Return panics.
func (cs *ContractSet) Return(c *SafeContract) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[c.header.ID()]
	if !ok {
		cs.mu.Unlock()
		build.Critical("no contract with that id")
	}
	cs.mu.Unlock()
	safeContract.mu.Unlock()
}

// View returns a copy of the contract with the specified ID. The contracts is
// not locked. Certain fields, including the MerkleRoots, are set to nil for
// safety reasons. If the contract is not present in the set, View
// returns false and a zero-valued RenterContract.
func (cs *ContractSet) View(id types.FileContractID) (modules.RenterContract, bool) {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	safeContract, ok := cs.contracts[id]
	if !ok {
		return modules.RenterContract{}, false
	}
	return safeContract.Metadata(), true
}

// ViewAll returns the metadata of each contract in the set. The contracts are
// not locked.
func (cs *ContractSet) ViewAll() []modules.RenterContract {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	contracts := make([]modules.RenterContract, 0, len(cs.contracts))
	for _, safeContract := range cs.contracts {
		contracts = append(contracts, safeContract.Metadata())
	}
	return contracts
}

// Close closes all contracts in a contract set, this means rendering it unusable for I/O
func (cs *ContractSet) Close() error {
	for _, c := range cs.contracts {
		c.f.Close()
	}
	_, err := cs.wal.CloseIncomplete()
	return err
}

// NewContractSet returns a ContractSet storing its contracts in the specified
// dir.
func NewContractSet(dir string) (*ContractSet, error) {
	if err := os.MkdirAll(dir, 0700); err != nil {
		return nil, err
	}
	d, err := os.Open(dir)
	if err != nil {
		return nil, err
	} else if stat, err := d.Stat(); err != nil {
		return nil, err
	} else if !stat.IsDir() {
		return nil, errors.New("not a directory")
	}
	defer d.Close()

	// Load the WAL. Any recovered updates will be applied after loading
	// contracts.
	// COMPATv1.3.1RC2 Rename old wals to have the 'wal' extension if new file
	// doesn't exist.
	if err := v131RC2RenameWAL(dir); err != nil {
		return nil, err
	}
	walTxns, wal, err := writeaheadlog.New(filepath.Join(dir, "contractset.wal"))
	if err != nil {
		return nil, err
	}

	cs := &ContractSet{
		contracts: make(map[types.FileContractID]*SafeContract),
		wal:       wal,
		dir:       dir,
	}

	// Load the contract files.
	dirNames, err := d.Readdirnames(-1)
	if err != nil {
		return nil, err
	}

	for _, filename := range dirNames {
		if filepath.Ext(filename) != contractExtension {
			continue
		}
		path := filepath.Join(dir, filename)
		if err := cs.loadSafeContract(path, walTxns); err != nil {
			return nil, err
		}
	}

	return cs, nil
}

// v131RC2RenameWAL renames an existing old wal file from contractset.log to
// contractset.wal
func v131RC2RenameWAL(dir string) error {
	oldPath := filepath.Join(dir, "contractset.log")
	newPath := filepath.Join(dir, "contractset.wal")
	_, errOld := os.Stat(oldPath)
	_, errNew := os.Stat(newPath)
	if !os.IsNotExist(errOld) && os.IsNotExist(errNew) {
		return build.ExtendErr("failed to rename contractset.log to contractset.wal",
			os.Rename(oldPath, newPath))
	}
	return nil
}
<commit_msg>build.Critical message if Delete is called twice on a contract<commit_after>package proto

import (
	"errors"
	"os"
	"path/filepath"
	"sync"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/writeaheadlog"
)

// A ContractSet provides safe concurrent access to a set of contracts. Its
// purpose is to serialize modifications to individual contracts, as well as
// to provide operations on the set as a whole.
type ContractSet struct {
	contracts map[types.FileContractID]*SafeContract
	wal       *writeaheadlog.WAL
	dir       string
	mu        sync.Mutex
}

// Acquire looks up the contract with the specified FileContractID and locks
// it before returning it. If the contract is not present in the set, Acquire
// returns false and a zero-valued RenterContract.
func (cs *ContractSet) Acquire(id types.FileContractID) (*SafeContract, bool) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[id]
	cs.mu.Unlock()
	if !ok {
		return nil, false
	}
	safeContract.mu.Lock()
	// We need to check if the contract is still in the map or if it has been
	// deleted in the meantime.
	cs.mu.Lock()
	_, ok = cs.contracts[id]
	cs.mu.Unlock()
	if !ok {
		safeContract.mu.Unlock()
		return nil, false
	}
	return safeContract, true
}

// Delete removes a contract from the set. The contract must have been
// previously acquired by Acquire. If the contract is not present in the set,
// Delete is a no-op.
func (cs *ContractSet) Delete(c *SafeContract) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[c.header.ID()]
	if !ok {
		cs.mu.Unlock()
		build.Critical("Delete called on already deleted contract")
		return
	}
	delete(cs.contracts, c.header.ID())
	cs.mu.Unlock()
	safeContract.mu.Unlock()
	// delete contract file
	os.Remove(filepath.Join(cs.dir, c.header.ID().String()+contractExtension))
}

// IDs returns the FileContractID of each contract in the set. The contracts
// are not locked.
func (cs *ContractSet) IDs() []types.FileContractID {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	ids := make([]types.FileContractID, 0, len(cs.contracts))
	for id := range cs.contracts {
		ids = append(ids, id)
	}
	return ids
}

// Len returns the number of contracts in the set.
func (cs *ContractSet) Len() int {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	return len(cs.contracts)
}

// Return returns a locked contract to the set and unlocks it. The contract
// must have been previously acquired by Acquire. If the contract is not
// present in the set, Return panics.
func (cs *ContractSet) Return(c *SafeContract) {
	cs.mu.Lock()
	safeContract, ok := cs.contracts[c.header.ID()]
	if !ok {
		cs.mu.Unlock()
		build.Critical("no contract with that id")
	}
	cs.mu.Unlock()
	safeContract.mu.Unlock()
}

// View returns a copy of the contract with the specified ID. The contracts is
// not locked. Certain fields, including the MerkleRoots, are set to nil for
// safety reasons. If the contract is not present in the set, View
// returns false and a zero-valued RenterContract.
func (cs *ContractSet) View(id types.FileContractID) (modules.RenterContract, bool) {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	safeContract, ok := cs.contracts[id]
	if !ok {
		return modules.RenterContract{}, false
	}
	return safeContract.Metadata(), true
}

// ViewAll returns the metadata of each contract in the set. The contracts are
// not locked.
func (cs *ContractSet) ViewAll() []modules.RenterContract {
	cs.mu.Lock()
	defer cs.mu.Unlock()
	contracts := make([]modules.RenterContract, 0, len(cs.contracts))
	for _, safeContract := range cs.contracts {
		contracts = append(contracts, safeContract.Metadata())
	}
	return contracts
}

// Close closes all contracts in a contract set, this means rendering it unusable for I/O
func (cs *ContractSet) Close() error {
	for _, c := range cs.contracts {
		c.f.Close()
	}
	_, err := cs.wal.CloseIncomplete()
	return err
}

// NewContractSet returns a ContractSet storing its contracts in the specified
// dir.
func NewContractSet(dir string) (*ContractSet, error) {
	if err := os.MkdirAll(dir, 0700); err != nil {
		return nil, err
	}
	d, err := os.Open(dir)
	if err != nil {
		return nil, err
	} else if stat, err := d.Stat(); err != nil {
		return nil, err
	} else if !stat.IsDir() {
		return nil, errors.New("not a directory")
	}
	defer d.Close()

	// Load the WAL. Any recovered updates will be applied after loading
	// contracts.
	// COMPATv1.3.1RC2 Rename old wals to have the 'wal' extension if new file
	// doesn't exist.
	if err := v131RC2RenameWAL(dir); err != nil {
		return nil, err
	}
	walTxns, wal, err := writeaheadlog.New(filepath.Join(dir, "contractset.wal"))
	if err != nil {
		return nil, err
	}

	cs := &ContractSet{
		contracts: make(map[types.FileContractID]*SafeContract),
		wal:       wal,
		dir:       dir,
	}

	// Load the contract files.
	dirNames, err := d.Readdirnames(-1)
	if err != nil {
		return nil, err
	}

	for _, filename := range dirNames {
		if filepath.Ext(filename) != contractExtension {
			continue
		}
		path := filepath.Join(dir, filename)
		if err := cs.loadSafeContract(path, walTxns); err != nil {
			return nil, err
		}
	}

	return cs, nil
}

// v131RC2RenameWAL renames an existing old wal file from contractset.log to
// contractset.wal
func v131RC2RenameWAL(dir string) error {
	oldPath := filepath.Join(dir, "contractset.log")
	newPath := filepath.Join(dir, "contractset.wal")
	_, errOld := os.Stat(oldPath)
	_, errNew := os.Stat(newPath)
	if !os.IsNotExist(errOld) && os.IsNotExist(errNew) {
		return build.ExtendErr("failed to rename contractset.log to contractset.wal",
			os.Rename(oldPath, newPath))
	}
	return nil
}
<|endoftext|>


<commit_before>package gapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/url"
)

// Annotation represents a Grafana API Annotation
type Annotation struct {
	ID          int64    `json:"id,omitempty"`
	AlertID     int64    `json:"alertId,omitempty"`
	DashboardID int64    `json:"dashboardId"`
	PanelID     int64    `json:"panelId"`
	UserID      int64    `json:"userId,omitempty"`
	UserName    string   `json:"userName,omitempty"`
	NewState    string   `json:"newState,omitempty"`
	PrevState   string   `json:"prevState,omitempty"`
	Time        int64    `json:"time"`
	TimeEnd     int64    `json:"timeEnd,omitempty"`
	Text        string   `json:"text"`
	Metric      string   `json:"metric,omitempty"`
	RegionID    int64    `json:"regionId,omitempty"`
	Type        string   `json:"type,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	IsRegion    bool     `json:"isRegion,omitempty"`
}

// GraphiteAnnotation represents a Grafana API annotation in Graphite format
type GraphiteAnnotation struct {
	What string   `json:"what"`
	When int64    `json:"when"`
	Data string   `json:"data"`
	Tags []string `json:"tags,omitempty"`
}

// Annotations fetches the annotations queried with the params it's passed
func (c *Client) Annotations(params url.Values) ([]Annotation, error) {
	req, err := c.newRequest("GET", "/api/annotation", params, nil)
	if err != nil {
		return nil, err
	}

	resp, err := c.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(resp.Status)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	result := []Annotation{}
	err = json.Unmarshal(data, &result)
	return result, err
}

// NewAnnotation creates a new annotation with the Annotation it is passed
func (c *Client) NewAnnotation(a *Annotation) (int64, error) {
	data, err := json.Marshal(a)
	if err != nil {
		return 0, err
	}
	req, err := c.newRequest("POST", "/api/annotations", nil, bytes.NewBuffer(data))
	if err != nil {
		return 0, err
	}

	resp, err := c.Do(req)
	if err != nil {
		return 0, err
	}
	if resp.StatusCode != 200 {
		return 0, errors.New(resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	result := struct {
		ID int64 `json:"id"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.ID, err
}

// NewGraphiteAnnotation creates a new annotation with the GraphiteAnnotation it is passed
func (c *Client) NewGraphiteAnnotation(gfa *GraphiteAnnotation) (int64, error) {
	data, err := json.Marshal(gfa)
	if err != nil {
		return 0, err
	}
	req, err := c.newRequest("POST", "/api/annotations/graphite", nil, bytes.NewBuffer(data))
	if err != nil {
		return 0, err
	}

	resp, err := c.Do(req)
	if err != nil {
		return 0, err
	}
	if resp.StatusCode != 200 {
		return 0, errors.New(resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	result := struct {
		ID int64 `json:"id"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.ID, err
}

// UpdateAnnotation updates all properties an existing annotation with the Annotation it is passed.
func (c *Client) UpdateAnnotation(id int64, a *Annotation) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	data, err := json.Marshal(a)
	if err != nil {
		return "", err
	}
	req, err := c.newRequest("PUT", path, nil, bytes.NewBuffer(data))
	if err != nil {
		return "", err
	}

	resp, err := c.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", errors.New(resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// PatchAnnotation updates one or more properties of an existing annotation that matches the specified ID.
func (c *Client) PatchAnnotation(id int64, a *Annotation) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	data, err := json.Marshal(a)
	if err != nil {
		return "", err
	}
	req, err := c.newRequest("PATCH", path, nil, bytes.NewBuffer(data))
	if err != nil {
		return "", err
	}

	resp, err := c.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", errors.New(resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// DeleteAnnotation deletes the annotation of the ID it is passed
func (c *Client) DeleteAnnotation(id int64) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	req, err := c.newRequest("DELETE", path, nil, bytes.NewBuffer(nil))
	if err != nil {
		return "", err
	}

	resp, err := c.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", errors.New(resp.Status)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// DeleteAnnotationByRegionID deletes the annotation corresponding to the region ID it is passed
func (c *Client) DeleteAnnotationByRegionID(id int64) (string, error) {
	path := fmt.Sprintf("/api/annotations/region/%d", id)
	req, err := c.newRequest("DELETE", path, nil, bytes.NewBuffer(nil))
	if err != nil {
		return "", err
	}

	resp, err := c.Do(req)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != 200 {
		return "", errors.New(resp.Status)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}
<commit_msg>annotations methods use common request method<commit_after>package gapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
)

// Annotation represents a Grafana API Annotation
type Annotation struct {
	ID          int64    `json:"id,omitempty"`
	AlertID     int64    `json:"alertId,omitempty"`
	DashboardID int64    `json:"dashboardId"`
	PanelID     int64    `json:"panelId"`
	UserID      int64    `json:"userId,omitempty"`
	UserName    string   `json:"userName,omitempty"`
	NewState    string   `json:"newState,omitempty"`
	PrevState   string   `json:"prevState,omitempty"`
	Time        int64    `json:"time"`
	TimeEnd     int64    `json:"timeEnd,omitempty"`
	Text        string   `json:"text"`
	Metric      string   `json:"metric,omitempty"`
	RegionID    int64    `json:"regionId,omitempty"`
	Type        string   `json:"type,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	IsRegion    bool     `json:"isRegion,omitempty"`
}

// GraphiteAnnotation represents a Grafana API annotation in Graphite format
type GraphiteAnnotation struct {
	What string   `json:"what"`
	When int64    `json:"when"`
	Data string   `json:"data"`
	Tags []string `json:"tags,omitempty"`
}

// Annotations fetches the annotations queried with the params it's passed
func (c *Client) Annotations(params url.Values) ([]Annotation, error) {
	resp, err := c.request("GET", "/api/annotation", params, nil)
	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	result := []Annotation{}
	err = json.Unmarshal(data, &result)
	return result, err
}

// NewAnnotation creates a new annotation with the Annotation it is passed
func (c *Client) NewAnnotation(a *Annotation) (int64, error) {
	data, err := json.Marshal(a)
	if err != nil {
		return 0, err
	}
	resp, err := c.request("POST", "/api/annotations", nil, bytes.NewBuffer(data))
	if err != nil {
		return 0, err
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	result := struct {
		ID int64 `json:"id"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.ID, err
}

// NewGraphiteAnnotation creates a new annotation with the GraphiteAnnotation it is passed
func (c *Client) NewGraphiteAnnotation(gfa *GraphiteAnnotation) (int64, error) {
	data, err := json.Marshal(gfa)
	if err != nil {
		return 0, err
	}
	resp, err := c.request("POST", "/api/annotations/graphite", nil, bytes.NewBuffer(data))
	if err != nil {
		return 0, err
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	result := struct {
		ID int64 `json:"id"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.ID, err
}

// UpdateAnnotation updates all properties an existing annotation with the Annotation it is passed.
func (c *Client) UpdateAnnotation(id int64, a *Annotation) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	data, err := json.Marshal(a)
	if err != nil {
		return "", err
	}
	resp, err := c.request("PUT", path, nil, bytes.NewBuffer(data))
	if err != nil {
		return "", err
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// PatchAnnotation updates one or more properties of an existing annotation that matches the specified ID.
func (c *Client) PatchAnnotation(id int64, a *Annotation) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	data, err := json.Marshal(a)
	if err != nil {
		return "", err
	}
	resp, err := c.request("PATCH", path, nil, bytes.NewBuffer(data))
	if err != nil {
		return "", err
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// DeleteAnnotation deletes the annotation of the ID it is passed
func (c *Client) DeleteAnnotation(id int64) (string, error) {
	path := fmt.Sprintf("/api/annotations/%d", id)
	resp, err := c.request("DELETE", path, nil, bytes.NewBuffer(nil))
	if err != nil {
		return "", err
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}

// DeleteAnnotationByRegionID deletes the annotation corresponding to the region ID it is passed
func (c *Client) DeleteAnnotationByRegionID(id int64) (string, error) {
	path := fmt.Sprintf("/api/annotations/region/%d", id)
	resp, err := c.request("DELETE", path, nil, bytes.NewBuffer(nil))
	if err != nil {
		return "", err
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	result := struct {
		Message string `json:"message"`
	}{}
	err = json.Unmarshal(data, &result)
	return result.Message, err
}
<|endoftext|>