<commit_before>package venom

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/spf13/pflag"
)

const (
	SquashFlagsTag = "++"
)

//
// Structures implementing this interface won't be introspected and this function will be called
// instead.
//
type HasFlags interface {
	Flags() *pflag.FlagSet
}

//
// Define new flags based on the provided defaults.
//
// It panics if something goes wrong.
//
func MustDefineFlags(defaults interface{}) *pflag.FlagSet {
	flags, err := DefineFlags(defaults)
	if err != nil {
		panic(err)
	}
	return flags
}

//
// Define new flags based on the provided defaults.
//
func DefineFlags(defaults interface{}) (*pflag.FlagSet, error) {
	a := flagsFactory{
		tags: []string{"flag", "pflag"},
	}
	return a.createFlags(defaults)
}

//
// Parse name for mapstructure tags i.e. fetch banana from:
//
// type Foo struct {
//     foo int `mapstructure:"banana"`
// }
//
func parseMapstructureTag(tag string) (string, bool) {
	parts := strings.SplitN(tag, ",", 2)
	if len(parts) == 0 {
		return "", false
	}
	return parts[0], true
}

type flagInfo struct {
	name      string
	shorthand string
	usage     string
}

//
// Parse flag tag so it later could be used to create cli flag:
//
// type Foo struct {
//     foo int `flag:"foo,f,Do some fooness"`
// }
//
func parseTag(tag string) (flagInfo, error) {
	parts := strings.SplitN(tag, ",", 3)

	// flag: bar, b, Some barness -> flag: bar,b,Some barness
	for i, p := range parts {
		parts[i] = strings.TrimSpace(p)
	}

	var f flagInfo
	switch len(parts) {
	case 1:
		// flag: b
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = ""
			return f, nil
		}
		// flag: bar
		f.name = parts[0]
		f.shorthand = ""
		f.usage = ""
		return f, nil
	case 2:
		// flag: b,Some barness
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = parts[1]
			return f, nil
		}
		// flag: bar,b
		if len(parts[1]) == 1 {
			f.name = parts[0]
			f.shorthand = parts[1]
			f.usage = ""
			return f, nil
		}
		// flag: bar,Some barness
		f.name = parts[0]
		f.shorthand = ""
		f.usage = parts[1]
		return f, nil
	case 3:
		// flag: bar,b,Some barness
		f.name = parts[0]
		f.shorthand = parts[1]
		f.usage = parts[2]
		return f, nil
	default:
		return f, fmt.Errorf("Failed to parse flag tag: %s", tag)
	}
}

type flagsFactory struct {
	tags []string
}

func (a flagsFactory) lookupTag(tag reflect.StructTag) (string, bool) {
	for _, name := range a.tags {
		v, ok := tag.Lookup(name)
		if ok {
			return v, true
		}
	}
	return "", false
}

func (a flagsFactory) createFlags(defaults interface{}) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	//
	// Remove one level of indirection.
	//
	v := reflect.ValueOf(defaults)
	if v.Kind() == reflect.Ptr {
		v = reflect.Indirect(v)
	}

	//
	// Make sure we end up with a struct.
	//
	if v.Kind() != reflect.Struct {
		return nil, errors.New("Struct or pointer to struct expected")
	}

	//
	// For every tagged struct field create a flag.
	//
	for i := 0; i < v.Type().NumField(); i++ {
		structField := v.Type().Field(i)
		fieldType := structField.Type
		fieldValue := v.Field(i)

		tag, ok := a.lookupTag(structField.Tag)
		if !ok {
			continue
		}

		//
		// This means we want to squash all flags from either struct field or inner structure so they appear as is
		// they are defined in the outer structure.
		//
		if tag == SquashFlagsTag {
			//
			// In case we have mapstructure defined it must be ",squash"
			//
			mapTag, ok := structField.Tag.Lookup("mapstructure")
			if ok {
				if mapTag != ",squash" {
					return nil, fmt.Errorf(`Requirement flag:"%s" => mapstructure:",squash" but mapstructure:"%s" found on: %s`, SquashFlagsTag, mapTag, structField.Name)
				}
			}

			if fieldType.Kind() != reflect.Struct {
				return nil, fmt.Errorf(`flag:"%s" is supported only for inner structs but is set on: %s`, SquashFlagsTag, fieldType)
			}

			// Check if the struct implements HasFlags right away
			if hasFlags, ok := fieldValue.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// Check if struct-ptr implements HasFlags
			if fieldValue.CanAddr() {
				fieldValuePtr := fieldValue.Addr()

				if hasFlags, ok := fieldValuePtr.Interface().(HasFlags); ok {
					innerFlags := hasFlags.Flags()
					flags.AddFlagSet(innerFlags)
					continue
				}
			}

			// Check if inner struct implements HasFlags.
			//
			// I can't manage to get a pointer to inner struct here, it is not addressable and etc. Just as a workaround
			// we make a temporary copy and get a pointer to it instead. Suboptimal but meh, config struct are supposed
			// to be cheap to copy. Note that fieldValueCopy is a pointer.
			//
			fieldValueCopy := reflect.New(fieldType)
			fieldValueCopy.Elem().Set(fieldValue)

			if hasFlags, ok := fieldValueCopy.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// No overrides are provided, continue with recursive introspection
			innerFlags, err := a.createFlags(fieldValue.Interface())
			if err != nil {
				return nil, err
			}
			flags.AddFlagSet(innerFlags)
			continue
		}

		//
		// In case we have mapstructure defined it must have exactly the same name as flag has.
		//
		mapTag, ok := structField.Tag.Lookup("mapstructure")
		if ok {
			mapName, ok := parseMapstructureTag(mapTag)
			if ok && !(tag == mapName || strings.HasPrefix(tag, mapName+",")) {
				return nil, fmt.Errorf(`Both "mapstructure" and "flag" tags must have equal names but are different for field: %s`, structField.Name)
				continue
			}
		}

		fi, err := parseTag(tag)
		if err != nil {
			return nil, err
		}
		fs, err := a.createFlag(fi, fieldValue, fieldType)
		if err != nil {
			return nil, err
		}
		flags.AddFlagSet(fs)
	}

	return &flags, nil
}

func cloneSlice(slice interface{}) interface{} {
	t, v := reflect.TypeOf(slice), reflect.ValueOf(slice)

	v2 := reflect.MakeSlice(t, v.Len(), v.Len())
	n := reflect.Copy(v2, v)
	if n != v.Len() {
		panic(fmt.Sprintf("Failed to clone slice: %d != %d", n, v.Len()))
	}

	return v2.Interface()
}

//
// Note that we pass both field value and field type as it is defined in the struct. I'm not 100% sure about this and
// just playing safe here:
//
// Probably it is possible to get the value's type i.e. fieldValue.Type() and will be not equal to the fieldType as
// defined in the struct. I think it is possible in case these types are convertible i.e. fieldValue.Type() is
// convertible to fieldType.
//
func (a flagsFactory) createFlag(fi flagInfo, fieldValue reflect.Value, fieldType reflect.Type) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	name := fi.name
	shorthand := fi.shorthand
	usage := fi.usage

	//
	// Note that switch on type must be *before* the next one that is on kind. This is to prevent kind capturing
	// types that are simply aliases for native types e.g. time.Duration.
	//
	switch fieldType {
	case reflect.TypeOf(time.Time{}):
		val := fieldValue.Interface().(time.Time)
		p := &time.Time{}

		value := newTimeValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	case reflect.TypeOf(time.Duration(0)):
		val := fieldValue.Interface().(time.Duration)

		d := time.Duration(0)
		p := &d

		value := newDurationValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	}

	switch fieldType.Kind() {
	case reflect.Bool:
		value := bool(fieldValue.Bool())
		flags.BoolP(name, shorthand, value, usage)
	case reflect.Int:
		value := int(fieldValue.Int())
		flags.IntP(name, shorthand, value, usage)
	case reflect.Int8:
		value := int8(fieldValue.Int())
		flags.Int8P(name, shorthand, value, usage)
	case reflect.Int16:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage) // Not a typo, pflags doesn't have Int16
	case reflect.Int32:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage)
	case reflect.Int64:
		value := int64(fieldValue.Int())
		flags.Int64P(name, shorthand, value, usage)
	case reflect.Uint:
		value := uint(fieldValue.Uint())
		flags.UintP(name, shorthand, value, usage)
	case reflect.Uint8:
		value := uint8(fieldValue.Uint())
		flags.Uint8P(name, shorthand, value, usage)
	case reflect.Uint16:
		value := uint16(fieldValue.Uint())
		flags.Uint16P(name, shorthand, value, usage)
	case reflect.Uint32:
		value := uint32(fieldValue.Uint())
		flags.Uint32P(name, shorthand, value, usage)
	case reflect.Uint64:
		value := uint64(fieldValue.Uint())
		flags.Uint64P(name, shorthand, value, usage)
	case reflect.Float32:
		value := float32(fieldValue.Float())
		flags.Float32P(name, shorthand, value, usage)
	case reflect.Float64:
		value := float64(fieldValue.Float())
		flags.Float64P(name, shorthand, value, usage)
	case reflect.String:
		value := string(fieldValue.String())
		flags.StringP(name, shorthand, value, usage)
	case reflect.Slice:
		switch fieldType.Elem().Kind() {
		case reflect.Bool:
			value := cloneSlice(fieldValue.Interface()).([]bool)
			flags.BoolSliceP(name, shorthand, value, usage)
		case reflect.Int:
			value := cloneSlice(fieldValue.Interface()).([]int)
			flags.IntSliceP(name, shorthand, value, usage)
		case reflect.Uint:
			value := cloneSlice(fieldValue.Interface()).([]uint)
			flags.UintSliceP(name, shorthand, value, usage)
		case reflect.String:
			value := cloneSlice(fieldValue.Interface()).([]string)
			flags.StringSliceP(name, shorthand, value, usage)
		default:
			return nil, fmt.Errorf("Unsupported slice type for field with flag tag %q: %s", name, fieldType)
		}
	default:
		return nil, fmt.Errorf("Unsupported type for field with flag tag %q: %s", name, fieldType)
	}
	return &flags, nil
}
<commit_msg>Localize mapstructure checks<commit_after>package venom

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/spf13/pflag"
)

const (
	SquashFlagsTag = "++"
)

//
// Structures implementing this interface won't be introspected and this function will be called
// instead.
//
type HasFlags interface {
	Flags() *pflag.FlagSet
}

//
// Define new flags based on the provided defaults.
//
// It panics if something goes wrong.
//
func MustDefineFlags(defaults interface{}) *pflag.FlagSet {
	flags, err := DefineFlags(defaults)
	if err != nil {
		panic(err)
	}
	return flags
}

//
// Define new flags based on the provided defaults.
//
func DefineFlags(defaults interface{}) (*pflag.FlagSet, error) {
	a := flagsFactory{
		tags: []string{"flag", "pflag"},
	}
	return a.createFlags(defaults)
}

//
// Parse name for mapstructure tags i.e. fetch banana from:
//
// type Foo struct {
//     foo int `mapstructure:"banana"`
// }
//
func parseMapstructureTag(tag string) (string, bool) {
	parts := strings.SplitN(tag, ",", 2)
	if len(parts) == 0 {
		return "", false
	}
	return parts[0], true
}

type flagInfo struct {
	name      string
	shorthand string
	usage     string
}

//
// Parse flag tag so it later could be used to create cli flag:
//
// type Foo struct {
//     foo int `flag:"foo,f,Do some fooness"`
// }
//
func parseTag(tag string) (flagInfo, error) {
	parts := strings.SplitN(tag, ",", 3)

	// flag: bar, b, Some barness -> flag: bar,b,Some barness
	for i, p := range parts {
		parts[i] = strings.TrimSpace(p)
	}

	var f flagInfo
	switch len(parts) {
	case 1:
		// flag: b
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = ""
			return f, nil
		}
		// flag: bar
		f.name = parts[0]
		f.shorthand = ""
		f.usage = ""
		return f, nil
	case 2:
		// flag: b,Some barness
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = parts[1]
			return f, nil
		}
		// flag: bar,b
		if len(parts[1]) == 1 {
			f.name = parts[0]
			f.shorthand = parts[1]
			f.usage = ""
			return f, nil
		}
		// flag: bar,Some barness
		f.name = parts[0]
		f.shorthand = ""
		f.usage = parts[1]
		return f, nil
	case 3:
		// flag: bar,b,Some barness
		f.name = parts[0]
		f.shorthand = parts[1]
		f.usage = parts[2]
		return f, nil
	default:
		return f, fmt.Errorf("Failed to parse flag tag: %s", tag)
	}
}

type flagsFactory struct {
	tags []string
}

func (a flagsFactory) lookupTag(tag reflect.StructTag) (string, bool) {
	for _, name := range a.tags {
		v, ok := tag.Lookup(name)
		if ok {
			return v, true
		}
	}
	return "", false
}

func (a flagsFactory) createFlags(defaults interface{}) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	//
	// Remove one level of indirection.
	//
	v := reflect.ValueOf(defaults)
	if v.Kind() == reflect.Ptr {
		v = reflect.Indirect(v)
	}

	//
	// Make sure we end up with a struct.
	//
	if v.Kind() != reflect.Struct {
		return nil, errors.New("Struct or pointer to struct expected")
	}

	//
	// For every tagged struct field create a flag.
	//
	for i := 0; i < v.Type().NumField(); i++ {
		structField := v.Type().Field(i)
		fieldType := structField.Type
		fieldValue := v.Field(i)

		tag, ok := a.lookupTag(structField.Tag)
		if !ok {
			continue
		}

		//
		// Make sure mapstructure tag is in sync with flag tag. This is not a hard requirement but
		// is almost certainly what you want to check every time.
		//
		mapTag, ok := structField.Tag.Lookup("mapstructure")
		if ok {
			switch tag {
			case SquashFlagsTag:
				//
				// In case we have mapstructure defined it must be ",squash"
				//
				if mapTag != ",squash" {
					return nil, fmt.Errorf(`Requirement flag:"%s" => mapstructure:",squash" but mapstructure:"%s" found on: %s`, SquashFlagsTag, mapTag, structField.Name)
				}
			default:
				//
				// In case we have mapstructure defined it must have exactly the same name as flag has.
				//
				mapName, ok := parseMapstructureTag(mapTag)
				if ok && !(tag == mapName || strings.HasPrefix(tag, mapName+",")) {
					return nil, fmt.Errorf(`Both "mapstructure" and "flag" tags must have equal names but are different for field: %s`, structField.Name)
				}
			}
		}

		//
		// This means we want to squash all flags from either struct field or inner structure so they appear as is
		// they are defined in the outer structure.
		//
		if tag == SquashFlagsTag {
			if fieldType.Kind() != reflect.Struct {
				return nil, fmt.Errorf(`flag:"%s" is supported only for inner structs but is set on: %s`, SquashFlagsTag, fieldType)
			}

			// Check if the struct implements HasFlags right away
			if hasFlags, ok := fieldValue.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// Check if struct-ptr implements HasFlags
			if fieldValue.CanAddr() {
				fieldValuePtr := fieldValue.Addr()

				if hasFlags, ok := fieldValuePtr.Interface().(HasFlags); ok {
					innerFlags := hasFlags.Flags()
					flags.AddFlagSet(innerFlags)
					continue
				}
			}

			// Check if inner struct implements HasFlags.
			//
			// I can't manage to get a pointer to inner struct here, it is not addressable and etc. Just as a workaround
			// we make a temporary copy and get a pointer to it instead. Suboptimal but meh, config struct are supposed
			// to be cheap to copy. Note that fieldValueCopy is a pointer.
			//
			fieldValueCopy := reflect.New(fieldType)
			fieldValueCopy.Elem().Set(fieldValue)

			if hasFlags, ok := fieldValueCopy.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// No overrides are provided, continue with recursive introspection
			innerFlags, err := a.createFlags(fieldValue.Interface())
			if err != nil {
				return nil, err
			}
			flags.AddFlagSet(innerFlags)
			continue
		}

		fi, err := parseTag(tag)
		if err != nil {
			return nil, err
		}
		fs, err := a.createFlag(fi, fieldValue, fieldType)
		if err != nil {
			return nil, err
		}
		flags.AddFlagSet(fs)
	}

	return &flags, nil
}

func cloneSlice(slice interface{}) interface{} {
	t, v := reflect.TypeOf(slice), reflect.ValueOf(slice)

	v2 := reflect.MakeSlice(t, v.Len(), v.Len())
	n := reflect.Copy(v2, v)
	if n != v.Len() {
		panic(fmt.Sprintf("Failed to clone slice: %d != %d", n, v.Len()))
	}

	return v2.Interface()
}

//
// Note that we pass both field value and field type as it is defined in the struct. I'm not 100% sure about this and
// just playing safe here:
//
// Probably it is possible to get the value's type i.e. fieldValue.Type() and will be not equal to the fieldType as
// defined in the struct. I think it is possible in case these types are convertible i.e. fieldValue.Type() is
// convertible to fieldType.
//
func (a flagsFactory) createFlag(fi flagInfo, fieldValue reflect.Value, fieldType reflect.Type) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	name := fi.name
	shorthand := fi.shorthand
	usage := fi.usage

	//
	// Note that switch on type must be *before* the next one that is on kind. This is to prevent kind capturing
	// types that are simply aliases for native types e.g. time.Duration.
	//
	switch fieldType {
	case reflect.TypeOf(time.Time{}):
		val := fieldValue.Interface().(time.Time)
		p := &time.Time{}

		value := newTimeValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	case reflect.TypeOf(time.Duration(0)):
		val := fieldValue.Interface().(time.Duration)

		d := time.Duration(0)
		p := &d

		value := newDurationValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	}

	switch fieldType.Kind() {
	case reflect.Bool:
		value := bool(fieldValue.Bool())
		flags.BoolP(name, shorthand, value, usage)
	case reflect.Int:
		value := int(fieldValue.Int())
		flags.IntP(name, shorthand, value, usage)
	case reflect.Int8:
		value := int8(fieldValue.Int())
		flags.Int8P(name, shorthand, value, usage)
	case reflect.Int16:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage) // Not a typo, pflags doesn't have Int16
	case reflect.Int32:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage)
	case reflect.Int64:
		value := int64(fieldValue.Int())
		flags.Int64P(name, shorthand, value, usage)
	case reflect.Uint:
		value := uint(fieldValue.Uint())
		flags.UintP(name, shorthand, value, usage)
	case reflect.Uint8:
		value := uint8(fieldValue.Uint())
		flags.Uint8P(name, shorthand, value, usage)
	case reflect.Uint16:
		value := uint16(fieldValue.Uint())
		flags.Uint16P(name, shorthand, value, usage)
	case reflect.Uint32:
		value := uint32(fieldValue.Uint())
		flags.Uint32P(name, shorthand, value, usage)
	case reflect.Uint64:
		value := uint64(fieldValue.Uint())
		flags.Uint64P(name, shorthand, value, usage)
	case reflect.Float32:
		value := float32(fieldValue.Float())
		flags.Float32P(name, shorthand, value, usage)
	case reflect.Float64:
		value := float64(fieldValue.Float())
		flags.Float64P(name, shorthand, value, usage)
	case reflect.String:
		value := string(fieldValue.String())
		flags.StringP(name, shorthand, value, usage)
	case reflect.Slice:
		switch fieldType.Elem().Kind() {
		case reflect.Bool:
			value := cloneSlice(fieldValue.Interface()).([]bool)
			flags.BoolSliceP(name, shorthand, value, usage)
		case reflect.Int:
			value := cloneSlice(fieldValue.Interface()).([]int)
			flags.IntSliceP(name, shorthand, value, usage)
		case reflect.Uint:
			value := cloneSlice(fieldValue.Interface()).([]uint)
			flags.UintSliceP(name, shorthand, value, usage)
		case reflect.String:
			value := cloneSlice(fieldValue.Interface()).([]string)
			flags.StringSliceP(name, shorthand, value, usage)
		default:
			return nil, fmt.Errorf("Unsupported slice type for field with flag tag %q: %s", name, fieldType)
		}
	default:
		return nil, fmt.Errorf("Unsupported type for field with flag tag %q: %s", name, fieldType)
	}
	return &flags, nil
}
<|endoftext|>


<commit_before>// Simple tool to show battery status from SysFS as GTK icon.
package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/mattn/go-gtk/gtk"
	"power"
)

var levels = []string{
	"empty",
	"caution",
	"low",
	"good",
	"full",
}

var states = []string{
	"charged",
	"charging",
}

type Icon struct {
	Battery    power.Battery
	StatusIcon *gtk.StatusIcon
}

func getIcons() []Icon {
	bat, err := power.Get()
	if err != nil {
		log.Fatalf("failed to get battery info: %v\n", err)
	}
	result := make([]Icon, len(bat))
	for i, b := range bat {
		icon := Icon{
			Battery: b,
		}
		in := icon.getName()
		icon.StatusIcon = gtk.NewStatusIconFromIconName(in)
		log.Printf("Created status icon %v with icon name %s\n", icon, in)
		result[i] = icon
	}
	return result
}

// getName builds the GTK icon name.
func (i Icon) getName() string {
	state := strings.ToLower(i.Battery.State.String())
	var level string
	if i.Battery.Current < 0.1 { // TODO: Map, or something.
		level = "empty"
	} else if i.Battery.Current < 0.4 {
		level = "caution"
	} else if i.Battery.Current < 0.9 {
		level = "good"
	} else {
		level = "full"
	}
	if state == "discharging" || state == "full" {
		return fmt.Sprintf("battery-%s", level)
	} else {
		return fmt.Sprintf("battery-%s-%s", level, state)
	}
}

// update updates the icon with new battery info.
func (i *Icon) update(battery power.Battery) {
	// TODO: also set / update tooltip.
	oldName := i.getName()
	i.Battery = battery
	newName := i.getName()
	if newName != oldName {
		log.Printf("Changing icon to %q from %q..\n", newName, oldName)
		i.StatusIcon.SetFromIconName(newName)
	}
}

// poll reads battery info and sleeps for specified duration.
func poll(d time.Duration, icon []Icon) {
	for {
		bat, err := power.Get()
		if err != nil {
			log.Fatalf("failed to get battery info: %v\n", err)
		}
		for i, b := range bat {
			log.Printf("[Battery %d]: %+v\n", i, b)
			icon[i].update(b)
		}
		time.Sleep(d)
	}
}

func main() {
	gtk.Init(&os.Args)
	icons := getIcons()
	d, err := time.ParseDuration("20s")
	if err != nil {
		log.Fatalf("bad duration: %v\n", err)
	}
	go poll(d, icons)
	log.Printf("Calling gtk.Main()..")
	gtk.Main()
}
<commit_msg>tweaks icon-picking logic, adds tooltip, TODOs<commit_after>// Simple tool to show battery status from SysFS as GTK icon.
package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/mattn/go-gtk/gtk"
	"power"
)

var levels = []string{
	"empty",
	"caution",
	"low",
	"good",
	"full",
}

var states = []string{
	"charged",
	"charging",
}

type Icon struct {
	Battery    power.Battery
	StatusIcon *gtk.StatusIcon
}

func getIcons() []Icon {
	bat, err := power.Get()
	if err != nil {
		log.Fatalf("failed to get battery info: %v\n", err)
	}
	result := make([]Icon, len(bat))
	for i, b := range bat {
		icon := Icon{
			Battery: b,
		}
		in := icon.getName()
		icon.StatusIcon = gtk.NewStatusIconFromIconName(in)
		log.Printf("Created status icon %v with icon name %s\n", icon, in)
		result[i] = icon
	}
	return result
}

// getName builds the GTK icon name.
func (i Icon) getName() string {
	state := strings.ToLower(i.Battery.State.String())
	var level string
	if i.Battery.Current < 0.1 { // TODO: Map, or something.
		level = "empty"
	} else if i.Battery.Current < 0.4 {
		level = "caution"
	} else if i.Battery.Current < 0.9 {
		level = "good"
	} else {
		level = "full"
	}
	if state == "unknown" {
		if level == "full" {
			// Full batteries sometimes are reported as "unknown", for some reason.
			state = "full"
		} else {
			state = "missing"
		}
	}
	if state == "missing" {
		return "battery-missing"
	} else if state == "discharging" || state == "full" {
		return fmt.Sprintf("battery-%s", level)
	} else {
		return fmt.Sprintf("battery-%s-%s", level, state)
	}
}

// update updates the icon with new battery info.
func (i *Icon) update(battery power.Battery) {
	oldName := i.getName()
	i.Battery = battery
	newName := i.getName()
	if newName != oldName {
		log.Printf("Changing icon to %q from %q..\n", newName, oldName)
		// TODO: this should check if the icon name to set actually exists, somehow.
		i.StatusIcon.SetFromIconName(newName)
	}
	i.StatusIcon.SetTooltipText(battery.String())
}

// poll reads battery info and sleeps for specified duration.
func poll(d time.Duration, icons []Icon) {
	for {
		// TODO: when a battery disappears (e.g. is disconnected), the
		// icon persists (but the goroutine seems to block, maybe on SysFS
		// read). Repro and address - icon should go away.
		bat, err := power.Get()
		if err != nil {
			log.Fatalf("failed to get battery info: %v\n", err)
		}
		for i, b := range bat {
			log.Printf("[Battery %d]: %+v\n", i, b)
			icons[i].update(b)
		}
		time.Sleep(d)
	}
}

func main() {
	gtk.Init(&os.Args)
	icons := getIcons()
	d, err := time.ParseDuration("20s")
	if err != nil {
		log.Fatalf("bad duration: %v\n", err)
	}
	go poll(d, icons)
	log.Printf("Calling gtk.Main()..")
	gtk.Main()
}
<|endoftext|>


<commit_before>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"encoding/json"
	"fmt"
)

// GraphDefinitionRequestStyle represents the graph style attributes
type GraphDefinitionRequestStyle struct {
	Palette *string `json:"palette,omitempty"`
	Width   *string `json:"width,omitempty"`
	Type    *string `json:"type,omitempty"`
}

// GraphDefinitionRequest represents the requests passed into each graph.
type GraphDefinitionRequest struct {
	Query              *string                      `json:"q,omitempty"`
	Stacked            *bool                        `json:"stacked,omitempty"`
	Aggregator         *string                      `json:"aggregator,omitempty"`
	ConditionalFormats []DashboardConditionalFormat `json:"conditional_formats,omitempty"`
	Type               *string                      `json:"type,omitempty"`
	Style              *GraphDefinitionRequestStyle `json:"style,omitempty"`

	// For change type graphs
	ChangeType     *string `json:"change_type,omitempty"`
	OrderDirection *string `json:"order_dir,omitempty"`
	CompareTo      *string `json:"compare_to,omitempty"`
	IncreaseGood   *bool   `json:"increase_good,omitempty"`
	OrderBy        *string `json:"order_by,omitempty"`
	ExtraCol       *string `json:"extra_col,omitempty"`
}

type GraphDefinitionMarker struct {
	Type  *string      `json:"type,omitempty"`
	Value *string      `json:"value,omitempty"`
	Label *string      `json:"label,omitempty"`
	Val   *json.Number `json:"val,omitempty"`
	Min   *json.Number `json:"min,omitempty"`
	Max   *json.Number `json:"max,omitempty"`
}

// Graph represents a graph that might exist on a dashboard.
type Graph struct {
	Title      *string `json:"title,omitempty"`
	Definition struct {
		Viz      *string                  `json:"viz,omitempty"`
		Requests []GraphDefinitionRequest `json:"requests,omitempty"`
		Events   []struct {
			Query *string `json:"q,omitempty"`
		} `json:"events,omitempty"`
		Markers []GraphDefinitionMarker `json:"markers,omitempty"`

		// For timeseries type graphs
		Yaxis struct {
			Min   *float64 `json:"min,omitempty"`
			Max   *float64 `json:"max,omitempty"`
			Scale *string  `json:"scale,omitempty"`
		} `json:"yaxis,omitempty"`

		// For query value type graphs
		Autoscale  *bool   `json:"austoscale,omitempty"`
		TextAlign  *string `json:"text_align,omitempty"`
		Precision  *string `json:"precision,omitempty"`
		CustomUnit *string `json:"custom_unit,omitempty"`

		// For hostname type graphs
		Style *struct {
			Palette     *string `json:"palette,omitempty"`
			PaletteFlip *bool   `json:"paletteFlip,omitempty"`
		}
		Groups                []string `json:"group,omitempty"`
		IncludeNoMetricHosts  *bool    `json:"noMetricHosts,omitempty"`
		Scopes                []string `json:"scope,omitempty"`
		IncludeUngroupedHosts *bool    `json:"noGroupHosts,omitempty"`
	} `json:"definition"`
}

// Template variable represents a template variable that might exist on a dashboard
type TemplateVariable struct {
	Name    *string `json:"name,omitempty"`
	Prefix  *string `json:"prefix,omitempty"`
	Default *string `json:"default,omitempty"`
}

// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
	Id                *int               `json:"id,omitempty"`
	Description       *string            `json:"description,omitempty"`
	Title             *string            `json:"title,omitempty"`
	Graphs            []Graph            `json:"graphs,omitempty"`
	TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
	ReadOnly          *bool              `json:"read_only,omitempty"`
}

// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
	Id          *int    `json:"id,string,omitempty"` // TODO: Remove ',string'.
	Resource    *string `json:"resource,omitempty"`
	Description *string `json:"description,omitempty"`
	Title       *string `json:"title,omitempty"`
}

// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
	Dashboards []DashboardLite `json:"dashes,omitempty"`
}

// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
	Resource  *string    `json:"resource,omitempty"`
	Url       *string    `json:"url,omitempty"`
	Dashboard *Dashboard `json:"dash,omitempty"`
}

type DashboardConditionalFormat struct {
	Palette       *string      `json:"palette,omitempty"`
	Comparator    *string      `json:"comparator,omitempty"`
	CustomBgColor *string      `json:"custom_bg_color,omitempty"`
	Value         *json.Number `json:"value,omitempty"`
	Inverted      *bool        `json:"invert,omitempty"`
	CustomFgColor *string      `json:"custom_fg_color,omitempty"`
}

// GetDashboard returns a single dashboard created on this account.
func (client *Client) GetDashboard(id int) (*Dashboard, error) {
	var out reqGetDashboard
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out); err != nil {
		return nil, err
	}
	return out.Dashboard, nil
}

// GetDashboards returns a list of all dashboards created on this account.
func (client *Client) GetDashboards() ([]DashboardLite, error) {
	var out reqGetDashboards
	if err := client.doJsonRequest("GET", "/v1/dash", nil, &out); err != nil {
		return nil, err
	}
	return out.Dashboards, nil
}

// DeleteDashboard deletes a dashboard by the identifier.
func (client *Client) DeleteDashboard(id int) error {
	return client.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}

// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (client *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
	var out reqGetDashboard
	if err := client.doJsonRequest("POST", "/v1/dash", dash, &out); err != nil {
		return nil, err
	}
	return out.Dashboard, nil
}

// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (client *Client) UpdateDashboard(dash *Dashboard) error {
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/dash/%d", *dash.Id),
		dash, nil)
}
<commit_msg>Breaking down Graph struct will allow generation of accessors and will make it a little easier to use.<commit_after>/*
 * Datadog API for Go
 *
 * Please see the included LICENSE file for licensing information.
 *
 * Copyright 2013 by authors and contributors.
 */

package datadog

import (
	"encoding/json"
	"fmt"
)

// GraphDefinitionRequestStyle represents the graph style attributes
type GraphDefinitionRequestStyle struct {
	Palette *string `json:"palette,omitempty"`
	Width   *string `json:"width,omitempty"`
	Type    *string `json:"type,omitempty"`
}

// GraphDefinitionRequest represents the requests passed into each graph.
type GraphDefinitionRequest struct {
	Query              *string                      `json:"q,omitempty"`
	Stacked            *bool                        `json:"stacked,omitempty"`
	Aggregator         *string                      `json:"aggregator,omitempty"`
	ConditionalFormats []DashboardConditionalFormat `json:"conditional_formats,omitempty"`
	Type               *string                      `json:"type,omitempty"`
	Style              *GraphDefinitionRequestStyle `json:"style,omitempty"`

	// For change type graphs
	ChangeType     *string `json:"change_type,omitempty"`
	OrderDirection *string `json:"order_dir,omitempty"`
	CompareTo      *string `json:"compare_to,omitempty"`
	IncreaseGood   *bool   `json:"increase_good,omitempty"`
	OrderBy        *string `json:"order_by,omitempty"`
	ExtraCol       *string `json:"extra_col,omitempty"`
}

type GraphDefinitionMarker struct {
	Type  *string      `json:"type,omitempty"`
	Value *string      `json:"value,omitempty"`
	Label *string      `json:"label,omitempty"`
	Val   *json.Number `json:"val,omitempty"`
	Min   *json.Number `json:"min,omitempty"`
	Max   *json.Number `json:"max,omitempty"`
}

type GraphEvent struct {
	Query *string `json:"q,omitempty"`
}

type Yaxis struct {
	Min   *float64 `json:"min,omitempty"`
	Max   *float64 `json:"max,omitempty"`
	Scale *string  `json:"scale,omitempty"`
}

type Style struct {
	Palette     *string `json:"palette,omitempty"`
	PaletteFlip *bool   `json:"paletteFlip,omitempty"`
}

// Graph represents a graph that might exist on a dashboard.
type Graph struct {
	Title      *string `json:"title,omitempty"`
	Definition struct {
		Viz      *string                  `json:"viz,omitempty"`
		Requests []GraphDefinitionRequest `json:"requests,omitempty"`
		Events   []GraphEvent             `json:"events,omitempty"`
		Markers  []GraphDefinitionMarker  `json:"markers,omitempty"`

		// For timeseries type graphs
		Yaxis Yaxis `json:"yaxis,omitempty"`

		// For query value type graphs
		Autoscale  *bool   `json:"austoscale,omitempty"`
		TextAlign  *string `json:"text_align,omitempty"`
		Precision  *string `json:"precision,omitempty"`
		CustomUnit *string `json:"custom_unit,omitempty"`

		// For hostname type graphs
		Style *Style `json:"Style,omitempty"`

		Groups                []string `json:"group,omitempty"`
		IncludeNoMetricHosts  *bool    `json:"noMetricHosts,omitempty"`
		Scopes                []string `json:"scope,omitempty"`
		IncludeUngroupedHosts *bool    `json:"noGroupHosts,omitempty"`
	} `json:"definition"`
}

// Template variable represents a template variable that might exist on a dashboard
type TemplateVariable struct {
	Name    *string `json:"name,omitempty"`
	Prefix  *string `json:"prefix,omitempty"`
	Default *string `json:"default,omitempty"`
}

// Dashboard represents a user created dashboard. This is the full dashboard
// struct when we load a dashboard in detail.
type Dashboard struct {
	Id                *int               `json:"id,omitempty"`
	Description       *string            `json:"description,omitempty"`
	Title             *string            `json:"title,omitempty"`
	Graphs            []Graph            `json:"graphs,omitempty"`
	TemplateVariables []TemplateVariable `json:"template_variables,omitempty"`
	ReadOnly          *bool              `json:"read_only,omitempty"`
}

// DashboardLite represents a user created dashboard. This is the mini
// struct when we load the summaries.
type DashboardLite struct {
	Id          *int    `json:"id,string,omitempty"` // TODO: Remove ',string'.
	Resource    *string `json:"resource,omitempty"`
	Description *string `json:"description,omitempty"`
	Title       *string `json:"title,omitempty"`
}

// reqGetDashboards from /api/v1/dash
type reqGetDashboards struct {
	Dashboards []DashboardLite `json:"dashes,omitempty"`
}

// reqGetDashboard from /api/v1/dash/:dashboard_id
type reqGetDashboard struct {
	Resource  *string    `json:"resource,omitempty"`
	Url       *string    `json:"url,omitempty"`
	Dashboard *Dashboard `json:"dash,omitempty"`
}

type DashboardConditionalFormat struct {
	Palette       *string      `json:"palette,omitempty"`
	Comparator    *string      `json:"comparator,omitempty"`
	CustomBgColor *string      `json:"custom_bg_color,omitempty"`
	Value         *json.Number `json:"value,omitempty"`
	Inverted      *bool        `json:"invert,omitempty"`
	CustomFgColor *string      `json:"custom_fg_color,omitempty"`
}

// GetDashboard returns a single dashboard created on this account.
func (client *Client) GetDashboard(id int) (*Dashboard, error) {
	var out reqGetDashboard
	if err := client.doJsonRequest("GET", fmt.Sprintf("/v1/dash/%d", id), nil, &out); err != nil {
		return nil, err
	}
	return out.Dashboard, nil
}

// GetDashboards returns a list of all dashboards created on this account.
func (client *Client) GetDashboards() ([]DashboardLite, error) {
	var out reqGetDashboards
	if err := client.doJsonRequest("GET", "/v1/dash", nil, &out); err != nil {
		return nil, err
	}
	return out.Dashboards, nil
}

// DeleteDashboard deletes a dashboard by the identifier.
func (client *Client) DeleteDashboard(id int) error {
	return client.doJsonRequest("DELETE", fmt.Sprintf("/v1/dash/%d", id), nil, nil)
}

// CreateDashboard creates a new dashboard when given a Dashboard struct. Note
// that the Id, Resource, Url and similar elements are not used in creation.
func (client *Client) CreateDashboard(dash *Dashboard) (*Dashboard, error) {
	var out reqGetDashboard
	if err := client.doJsonRequest("POST", "/v1/dash", dash, &out); err != nil {
		return nil, err
	}
	return out.Dashboard, nil
}

// UpdateDashboard in essence takes a Dashboard struct and persists it back to
// the server. Use this if you've updated your local and need to push it back.
func (client *Client) UpdateDashboard(dash *Dashboard) error {
	return client.doJsonRequest("PUT", fmt.Sprintf("/v1/dash/%d", *dash.Id),
		dash, nil)
}
<|endoftext|>


<commit_before>package torrent

import (
	"math"
)

// Stats contains statistics about Torrent.
type Stats struct {
	// Status of the torrent.
	Status Status

	// Contains the error if torrent is stopped unexpectedly.
	Error error

	Pieces struct {
		Have    uint32
		Missing uint32
		Total   uint32
	}

	Bytes struct {
		// Bytes that are downloaded and passed hash check.
		Complete int64

		// The number of bytes that is needed to complete all missing pieces.
		Incomplete int64

		// The number of total bytes of files in torrent.
		//
		// Total = Complete + Incomplete
		Total int64

		// Downloaded is the number of bytes downloaded from swarm.
		// Because some pieces may be downloaded more than once, this number may be greater than BytesCompleted returns.
		// TODO put into resume
		Downloaded int64

		// Protocol messages are not included, only piece data is counted.
		Uploaded int64

		Wasted int64

		// BytesUploaded is the number of bytes uploaded to the swarm.
		// TODO BytesUploaded   int64
	}

	Peers struct {
		Connected struct {
			// Number of peers that are connected, handshaked and ready to send and receive messages.
			// ConnectedPeers = IncomingPeers + OutgoingPeers
			Total int

			// Number of peers that have connected to us.
			Incoming int

			// Number of peers that we have connected to.
			Outgoing int
		}

		Handshake struct {
			// Number of peers that are not handshaked yet.
			Total int

			// Number of incoming peers in handshake state.
			Incoming int

			// Number of outgoing peers in handshake state.
			Outgoing int
		}

		// Number of peer addresses that are ready to be connected.
		Ready int
	}

	Downloads struct {
		Piece struct {
			// Number of active piece downloads.
			Total int

			// Number of pieces that are being downloaded normally.
			Running int

			// Number of pieces that are being downloaded too slow.
			Snubbed int

			// Number of piece downloads in choked state.
			Choked int
		}

		Metadata struct {
			// Number of active metadata downloads.
			Total int

			// Number of peers that uploading too slow.
			Snubbed int

			// Number of peers that are being downloaded normally.
			Running int
		}
	}

	Torrent struct {
		Name        string
		Private     bool
		PieceLength uint32
	}
}

func (t *Torrent) stats() Stats {
	var stats Stats
	stats.Status = t.status()
	stats.Error = t.lastError
	stats.Peers.Ready = t.addrList.Len()
	stats.Peers.Handshake.Incoming = len(t.incomingHandshakers)
	stats.Peers.Handshake.Outgoing = len(t.outgoingHandshakers)
	stats.Peers.Handshake.Total = len(t.incomingHandshakers) + len(t.outgoingHandshakers)
	stats.Peers.Connected.Total = len(t.peers)
	stats.Peers.Connected.Incoming = len(t.incomingPeers)
	stats.Peers.Connected.Outgoing = len(t.outgoingPeers)
	stats.Downloads.Metadata.Total = len(t.infoDownloaders)
	stats.Downloads.Metadata.Snubbed = len(t.infoDownloadersSnubbed)
	stats.Downloads.Metadata.Running = len(t.infoDownloaders) - len(t.infoDownloadersSnubbed)
	stats.Downloads.Piece.Total = len(t.pieceDownloaders)
	stats.Downloads.Piece.Snubbed = len(t.pieceDownloadersSnubbed)
	stats.Downloads.Piece.Choked = len(t.pieceDownloadersChoked)
	stats.Downloads.Piece.Running = len(t.pieceDownloaders) - len(t.pieceDownloadersChoked) - len(t.pieceDownloadersSnubbed)

	if t.info != nil {
		stats.Bytes.Total = t.info.TotalLength
		stats.Bytes.Complete = t.bytesComplete()
		stats.Bytes.Incomplete = stats.Bytes.Total - stats.Bytes.Complete

		stats.Torrent.Name = t.info.Name
		stats.Torrent.Private = (t.info.Private == 1)
		stats.Torrent.PieceLength = t.info.PieceLength
	} else {
		// Some trackers don't send any peer address if don't tell we have missing bytes.
		stats.Bytes.Incomplete = math.MaxUint32

		stats.Torrent.Name = t.name
	}
	if t.bitfield != nil {
		stats.Pieces.Total = t.bitfield.Len()
		stats.Pieces.Have = t.bitfield.Count()
		stats.Pieces.Missing = stats.Pieces.Total - stats.Pieces.Have
	}
	stats.Bytes.Downloaded = t.bytesDownloaded
	stats.Bytes.Uploaded = t.bytesUploaded
	stats.Bytes.Wasted = t.bytesWasted
	return stats
}

func (t *Torrent) bytesComplete() int64 {
	if t.bitfield == nil {
		return 0
	}
	n := int64(t.info.PieceLength) * int64(t.bitfield.Count())
	if t.bitfield.Test(t.bitfield.Len() - 1) {
		n -= int64(t.info.PieceLength)
		n += int64(t.pieces[t.bitfield.Len()-1].Length)
	}
	return n
}
<commit_msg>show available piece count<commit_after>package torrent

import (
	"math"
)

// Stats contains statistics about Torrent.
type Stats struct {
	// Status of the torrent.
	Status Status

	// Contains the error if torrent is stopped unexpectedly.
	Error error

	Pieces struct {
		Have      uint32
		Missing   uint32
		Available uint32
		Total     uint32
	}

	Bytes struct {
		// Bytes that are downloaded and passed hash check.
		Complete int64

		// The number of bytes that is needed to complete all missing pieces.
		Incomplete int64

		// The number of total bytes of files in torrent.
		//
		// Total = Complete + Incomplete
		Total int64

		// Downloaded is the number of bytes downloaded from swarm.
		// Because some pieces may be downloaded more than once, this number may be greater than BytesCompleted returns.
		// TODO put into resume
		Downloaded int64

		// Protocol messages are not included, only piece data is counted.
		Uploaded int64

		Wasted int64

		// BytesUploaded is the number of bytes uploaded to the swarm.
		// TODO BytesUploaded   int64
	}

	Peers struct {
		Connected struct {
			// Number of peers that are connected, handshaked and ready to send and receive messages.
			// ConnectedPeers = IncomingPeers + OutgoingPeers
			Total int

			// Number of peers that have connected to us.
			Incoming int

			// Number of peers that we have connected to.
			Outgoing int
		}

		Handshake struct {
			// Number of peers that are not handshaked yet.
			Total int

			// Number of incoming peers in handshake state.
			Incoming int

			// Number of outgoing peers in handshake state.
			Outgoing int
		}

		// Number of peer addresses that are ready to be connected.
		Ready int
	}

	Downloads struct {
		Piece struct {
			// Number of active piece downloads.
			Total int

			// Number of pieces that are being downloaded normally.
			Running int

			// Number of pieces that are being downloaded too slow.
			Snubbed int

			// Number of piece downloads in choked state.
			Choked int
		}

		Metadata struct {
			// Number of active metadata downloads.
			Total int

			// Number of peers that uploading too slow.
			Snubbed int

			// Number of peers that are being downloaded normally.
			Running int
		}
	}

	Torrent struct {
		Name        string
		Private     bool
		PieceLength uint32
	}
}

func (t *Torrent) stats() Stats {
	var stats Stats
	stats.Status = t.status()
	stats.Error = t.lastError
	stats.Peers.Ready = t.addrList.Len()
	stats.Peers.Handshake.Incoming = len(t.incomingHandshakers)
	stats.Peers.Handshake.Outgoing = len(t.outgoingHandshakers)
	stats.Peers.Handshake.Total = len(t.incomingHandshakers) + len(t.outgoingHandshakers)
	stats.Peers.Connected.Total = len(t.peers)
	stats.Peers.Connected.Incoming = len(t.incomingPeers)
	stats.Peers.Connected.Outgoing = len(t.outgoingPeers)
	stats.Downloads.Metadata.Total = len(t.infoDownloaders)
	stats.Downloads.Metadata.Snubbed = len(t.infoDownloadersSnubbed)
	stats.Downloads.Metadata.Running = len(t.infoDownloaders) - len(t.infoDownloadersSnubbed)
	stats.Downloads.Piece.Total = len(t.pieceDownloaders)
	stats.Downloads.Piece.Snubbed = len(t.pieceDownloadersSnubbed)
	stats.Downloads.Piece.Choked = len(t.pieceDownloadersChoked)
	stats.Downloads.Piece.Running = len(t.pieceDownloaders) - len(t.pieceDownloadersChoked) - len(t.pieceDownloadersSnubbed)

	if t.info != nil {
		stats.Bytes.Total = t.info.TotalLength
		stats.Bytes.Complete = t.bytesComplete()
		stats.Bytes.Incomplete = stats.Bytes.Total - stats.Bytes.Complete

		stats.Torrent.Name = t.info.Name
		stats.Torrent.Private = (t.info.Private == 1)
		stats.Torrent.PieceLength = t.info.PieceLength
	} else {
		// Some trackers don't send any peer address if don't tell we have missing bytes.
		stats.Bytes.Incomplete = math.MaxUint32

		stats.Torrent.Name = t.name
	}
	if t.bitfield != nil {
		stats.Pieces.Total = t.bitfield.Len()
		stats.Pieces.Have = t.bitfield.Count()
		stats.Pieces.Missing = stats.Pieces.Total - stats.Pieces.Have
	}
	stats.Pieces.Available = t.avaliablePieceCount()
	stats.Bytes.Downloaded = t.bytesDownloaded
	stats.Bytes.Uploaded = t.bytesUploaded
	stats.Bytes.Wasted = t.bytesWasted
	return stats
}

func (t *Torrent) avaliablePieceCount() uint32 {
	var n uint32
	for _, pi := range t.pieces {
		if len(pi.HavingPeers) > 0 {
			n++
		}
	}
	return n
}

func (t *Torrent) bytesComplete() int64 {
	if t.bitfield == nil {
		return 0
	}
	n := int64(t.info.PieceLength) * int64(t.bitfield.Count())
	if t.bitfield.Test(t.bitfield.Len() - 1) {
		n -= int64(t.info.PieceLength)
		n += int64(t.pieces[t.bitfield.Len()-1].Length)
	}
	return n
}
<|endoftext|>


<commit_before>package app_runner

import (
	"fmt"

	"github.com/cloudfoundry-incubator/receptor"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
)

const (
	spyDownloadUrl string = "http://file_server.service.dc1.consul:8080/v1/static/docker-circus/docker-circus.tgz"
)

type DiegoAppRunner struct {
	receptorClient receptor.Client
	domain         string
}

func NewDiegoAppRunner(receptorClient receptor.Client, domain string) *DiegoAppRunner {
	return &DiegoAppRunner{receptorClient, domain}
}

func (appRunner *DiegoAppRunner) StartDockerApp(name, dockerImagePath, startCommand string, appArgs []string, memoryMB, diskMB, port int) error {
	if existingLrpCount, err := appRunner.existingLrpsCount(name); err != nil {
		return err
	} else if existingLrpCount != 0 {
		return newExistingAppError(name)
	}
	return appRunner.desireLrp(name, startCommand, dockerImagePath, appArgs, memoryMB, diskMB, port)
}

func (appRunner *DiegoAppRunner) ScaleDockerApp(name string, instances int) error {
	if existingLrpCount, err := appRunner.existingLrpsCount(name); err != nil {
		return err
	} else if existingLrpCount == 0 {
		return newAppNotStartedError(name)
	}

	return appRunner.updateLrp(name, instances)
}

func (appRunner *DiegoAppRunner) StopDockerApp(name string) error {
	if existingLrpCount, err := appRunner.existingLrpsCount(name); err != nil {
		return err
	} else if existingLrpCount == 0 {
		return newAppNotStartedError(name)
	}

	return appRunner.receptorClient.DeleteDesiredLRP(name)
}

func (appRunner *DiegoAppRunner) IsDockerAppUp(processGuid string) (bool, error) {
	actualLrps, err := appRunner.receptorClient.ActualLRPsByProcessGuid(processGuid)
	status := len(actualLrps) > 0 && actualLrps[0].State == receptor.ActualLRPStateRunning

	return status, err
}

func (appRunner *DiegoAppRunner) existingLrpsCount(name string) (int, error) {
	desiredLRPs, err := appRunner.receptorClient.DesiredLRPs()
	if err != nil {
		return 0, err
	}

	for _, desiredLRP := range desiredLRPs {
		if desiredLRP.ProcessGuid == name {
			return desiredLRP.Instances, nil
		}
	}

	return 0, nil
}

func (appRunner *DiegoAppRunner) desireLrp(name, startCommand, dockerImagePath string, appArgs []string, memoryMB, diskMB, port int) error {
	err := appRunner.receptorClient.CreateDesiredLRP(receptor.DesiredLRPCreateRequest{
		ProcessGuid: name,
		Domain:      "diego-edge",
		RootFSPath:  dockerImagePath,
		Instances:   1,
		Stack:       "lucid64",
		Routes:      []string{fmt.Sprintf("%s.%s", name, appRunner.domain)},
		MemoryMB:    memoryMB,
		DiskMB:      diskMB,
		Ports:       []uint32{uint32(port)},
		LogGuid:     name,
		LogSource:   "APP",
		Setup: &models.DownloadAction{
			From: spyDownloadUrl,
			To:   "/tmp",
		},
		Action: &models.RunAction{
			Path: startCommand,
			Args: appArgs,
		},
		Monitor: &models.RunAction{
			Path: "/tmp/spy",
			Args: []string{"-addr", fmt.Sprintf(":%d", port)},
		},
	})

	return err
}

func (appRunner *DiegoAppRunner) updateLrp(name string, instances int) error {
	err := appRunner.receptorClient.UpdateDesiredLRP(
		name,
		receptor.DesiredLRPUpdateRequest{
			Instances: &instances,
		},
	)

	return err
}
<commit_msg>refactor existingLrps to desiredLRPs<commit_after>package app_runner

import (
	"fmt"

	"github.com/cloudfoundry-incubator/receptor"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
)

const (
	spyDownloadUrl string = "http://file_server.service.dc1.consul:8080/v1/static/docker-circus/docker-circus.tgz"
)

type DiegoAppRunner struct {
	receptorClient receptor.Client
	domain         string
}

func NewDiegoAppRunner(receptorClient receptor.Client, domain string) *DiegoAppRunner {
	return &DiegoAppRunner{receptorClient, domain}
}

func (appRunner *DiegoAppRunner) StartDockerApp(name, dockerImagePath, startCommand string, appArgs []string, memoryMB, diskMB, port int) error {
	if desiredLRPsCount, err := appRunner.desiredLRPsCount(name); err != nil {
		return err
	} else if desiredLRPsCount != 0 {
		return newExistingAppError(name)
	}
	return appRunner.desireLrp(name, startCommand, dockerImagePath, appArgs, memoryMB, diskMB, port)
}

func (appRunner *DiegoAppRunner) ScaleDockerApp(name string, instances int) error {
	if desiredLRPsCount, err := appRunner.desiredLRPsCount(name); err != nil {
		return err
	} else if desiredLRPsCount == 0 {
		return newAppNotStartedError(name)
	}

	return appRunner.updateLrp(name, instances)
}

func (appRunner *DiegoAppRunner) StopDockerApp(name string) error {
	if desiredLRPsCount, err := appRunner.desiredLRPsCount(name); err != nil {
		return err
	} else if desiredLRPsCount == 0 {
		return newAppNotStartedError(name)
	}

	return appRunner.receptorClient.DeleteDesiredLRP(name)
}

func (appRunner *DiegoAppRunner) IsDockerAppUp(processGuid string) (bool, error) {
	actualLrps, err := appRunner.receptorClient.ActualLRPsByProcessGuid(processGuid)
	status := len(actualLrps) > 0 && actualLrps[0].State == receptor.ActualLRPStateRunning

	return status, err
}

func (appRunner *DiegoAppRunner) desiredLRPsCount(name string) (int, error) {
	desiredLRPs, err := appRunner.receptorClient.DesiredLRPs()
	if err != nil {
		return 0, err
	}

	for _, desiredLRP := range desiredLRPs {
		if desiredLRP.ProcessGuid == name {
			return desiredLRP.Instances, nil
		}
	}

	return 0, nil
}

func (appRunner *DiegoAppRunner) desireLrp(name, startCommand, dockerImagePath string, appArgs []string, memoryMB, diskMB, port int) error {
	err := appRunner.receptorClient.CreateDesiredLRP(receptor.DesiredLRPCreateRequest{
		ProcessGuid: name,
		Domain:      "diego-edge",
		RootFSPath:  dockerImagePath,
		Instances:   1,
		Stack:       "lucid64",
		Routes:      []string{fmt.Sprintf("%s.%s", name, appRunner.domain)},
		MemoryMB:    memoryMB,
		DiskMB:      diskMB,
		Ports:       []uint32{uint32(port)},
		LogGuid:     name,
		LogSource:   "APP",
		Setup: &models.DownloadAction{
			From: spyDownloadUrl,
			To:   "/tmp",
		},
		Action: &models.RunAction{
			Path: startCommand,
			Args: appArgs,
		},
		Monitor: &models.RunAction{
			Path: "/tmp/spy",
			Args: []string{"-addr", fmt.Sprintf(":%d", port)},
		},
	})

	return err
}

func (appRunner *DiegoAppRunner) updateLrp(name string, instances int) error {
	err := appRunner.receptorClient.UpdateDesiredLRP(
		name,
		receptor.DesiredLRPUpdateRequest{
			Instances: &instances,
		},
	)

	return err
}
<|endoftext|>


<commit_before>package itunes

import (
	"errors"
	"log"
	"sync"

	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

type track struct {
	handle    *ole.IDispatch
	artworks  *ole.IDispatch
	wg        *sync.WaitGroup
	parent    *sync.WaitGroup
	closeChan chan bool

	Name   string
	Artist string
}

func createTrack(handle *ole.IDispatch, parent *sync.WaitGroup) (*track, error) {
	if handle == nil {
		return nil, errors.New("handle is nil")
	}
	parent.Add(1)
	properties := [...]string{
		"Name", "Artist",
	}
	values := make([]string, len(properties))

	for i, property := range properties {
		v, err := oleutil.GetProperty(handle, property)
		if err != nil {
			return nil, err
		}

		values[i] = v.ToString()
	}

	track := &track{
		handle:    handle,
		Name:      values[0],
		Artist:    values[1],
		closeChan: make(chan bool),
		parent:    parent,
		wg:        new(sync.WaitGroup),
	}

	return track, nil
}

func (t *track) Close() {
	close(t.closeChan)
	t.wg.Wait()

	t.handle.Release()
	if t.artworks != nil {
		t.artworks.Release()
	}

	t.parent.Done()
}

func (t *track) Play() error {
	_, err := t.handle.CallMethod("Play")
	return err
}

func (t *track) GetArtworks() (chan *artwork, error) {
	t.wg.Add(1)
	defer t.wg.Done()

	if t.artworks == nil {
		v, err := t.handle.GetProperty("Artwork")
		if err != nil {
			return nil, err
		}
		t.artworks = v.ToIDispatch()
	}

	v, err := t.artworks.GetProperty("Count")
	if err != nil {
		return nil, err
	}

	count := int(v.Val)

	output := make(chan *artwork)
	go func() {
		t.wg.Add(1)
		defer t.wg.Done()
		defer close(output)

		for i := 1; i <= count; i++ {
			v, err = t.artworks.GetProperty("Item", i)
			if err != nil {
				log.Println(err)
				return
			}
			artwork, err := createArtwork(v.ToIDispatch(), t.parent)
			if err != nil {
				log.Println(err)
				return
			}

			select {
			case <-t.closeChan:
				artwork.Close()
				return
			case output <- artwork:
			}
		}
	}()

	return output, nil
}
<commit_msg>fix close handle when calling play function<commit_after>package itunes

import (
	"errors"
	"log"
	"sync"

	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

type track struct {
	handle    *ole.IDispatch
	artworks  *ole.IDispatch
	wg        *sync.WaitGroup
	parent    *sync.WaitGroup
	closeChan chan bool

	Name   string
	Artist string
}

func createTrack(handle *ole.IDispatch, parent *sync.WaitGroup) (*track, error) {
	if handle == nil {
		return nil, errors.New("handle is nil")
	}
	parent.Add(1)
	properties := [...]string{
		"Name", "Artist",
	}
	values := make([]string, len(properties))

	for i, property := range properties {
		v, err := oleutil.GetProperty(handle, property)
		if err != nil {
			return nil, err
		}

		values[i] = v.ToString()
	}

	track := &track{
		handle:    handle,
		Name:      values[0],
		Artist:    values[1],
		closeChan: make(chan bool),
		parent:    parent,
		wg:        new(sync.WaitGroup),
	}

	return track, nil
}

func (t *track) Close() {
	close(t.closeChan)
	t.wg.Wait()

	t.handle.Release()
	if t.artworks != nil {
		t.artworks.Release()
	}

	t.parent.Done()
}

func (t *track) Play() error {
	t.wg.Add(1)
	defer t.wg.Done()
	_, err := t.handle.CallMethod("Play")
	return err
}

func (t *track) GetArtworks() (chan *artwork, error) {
	t.wg.Add(1)
	defer t.wg.Done()

	if t.artworks == nil {
		v, err := t.handle.GetProperty("Artwork")
		if err != nil {
			return nil, err
		}
		t.artworks = v.ToIDispatch()
	}

	v, err := t.artworks.GetProperty("Count")
	if err != nil {
		return nil, err
	}

	count := int(v.Val)

	output := make(chan *artwork)
	go func() {
		t.wg.Add(1)
		defer t.wg.Done()
		defer close(output)

		for i := 1; i <= count; i++ {
			v, err = t.artworks.GetProperty("Item", i)
			if err != nil {
				log.Println(err)
				return
			}
			artwork, err := createArtwork(v.ToIDispatch(), t.parent)
			if err != nil {
				log.Println(err)
				return
			}

			select {
			case <-t.closeChan:
				artwork.Close()
				return
			case output <- artwork:
			}
		}
	}()

	return output, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	// "html"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

import "github.com/strickyak/canvas"

var PORT = flag.Int("p", 8080, "port to listen on")
var WIDTH = flag.Int("w", 640, "Width of PNG in pixels")
var HEIGHT = flag.Int("h", 360, "Height of PNG in pixels")

var notnum = regexp.MustCompile("[^0-9]+")

/*
var colors = []canvas.Color{
	canvas.RGB(0, 0, 0),
	canvas.RGB(255, 255, 255),
	canvas.RGB(255, 0, 0),
	canvas.RGB(0, 255, 0),
	canvas.RGB(0, 0, 255),
}
*/

type H complex128

func (h H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
	strs := notnum.Split(r.URL.Path, -1)
	var nums []float64
	for _, s := range strs {
		if s == "" {
			continue
		}
		f, err := strconv.ParseFloat(s, 64)
		if err != nil {
			panic(err)
		}
		nums = append(nums, f)
	}

	can := canvas.NewCanvas(*WIDTH, *HEIGHT)
	for i := 0; i < len(nums)-8; i += 9 {
		x1 := int(nums[i+0] / 100.0 * float64(*WIDTH))
		y1 := int(nums[i+1] / 100.0 * float64(*HEIGHT))
		x2 := int(nums[i+2] / 100.0 * float64(*WIDTH))
		y2 := int(nums[i+3] / 100.0 * float64(*HEIGHT))
		x3 := int(nums[i+4] / 100.0 * float64(*WIDTH))
		y3 := int(nums[i+5] / 100.0 * float64(*HEIGHT))

		red := byte(nums[i+6])
		green := byte(nums[i+7])
		blue := byte(nums[i+8])

		can.PaintTriangle(x1, y1, x2, y2, x3, y3, canvas.RGB(red, green, blue))
	}

	w.Header().Set("Content-Type", "image/png")
	can.WritePng(w)
}

func main() {
	var myHandler H

	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", *PORT),
		Handler:        myHandler,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(s.ListenAndServe())
}
<commit_msg>Remark<commit_after>/*
	HTTP Server produces a PNG given a URL with 9-tuples in the path:

		x1,y1,x2,y2,x3,y3,r,g,b

	(x1, y2), (x2, y2), (x3, y3) are corners of triangle.
	Visible screen is real 0..100 on both x and y.
	r, g, & b are in 0..255.
	Background is black.
*/
package main

import (
	"flag"
	"fmt"
	// "html"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

import "github.com/strickyak/canvas"

var PORT = flag.Int("p", 8080, "port to listen on")
var WIDTH = flag.Int("w", 640, "Width of PNG in pixels")
var HEIGHT = flag.Int("h", 360, "Height of PNG in pixels")

var notnum = regexp.MustCompile("[^0-9]+")

/*
var colors = []canvas.Color{
	canvas.RGB(0, 0, 0),
	canvas.RGB(255, 255, 255),
	canvas.RGB(255, 0, 0),
	canvas.RGB(0, 255, 0),
	canvas.RGB(0, 0, 255),
}
*/

type H complex128

func (h H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
	strs := notnum.Split(r.URL.Path, -1)
	var nums []float64
	for _, s := range strs {
		if s == "" {
			continue
		}
		f, err := strconv.ParseFloat(s, 64)
		if err != nil {
			panic(err)
		}
		nums = append(nums, f)
	}

	can := canvas.NewCanvas(*WIDTH, *HEIGHT)
	for i := 0; i < len(nums)-8; i += 9 {
		x1 := int(nums[i+0] / 100.0 * float64(*WIDTH))
		y1 := int(nums[i+1] / 100.0 * float64(*HEIGHT))
		x2 := int(nums[i+2] / 100.0 * float64(*WIDTH))
		y2 := int(nums[i+3] / 100.0 * float64(*HEIGHT))
		x3 := int(nums[i+4] / 100.0 * float64(*WIDTH))
		y3 := int(nums[i+5] / 100.0 * float64(*HEIGHT))

		red := byte(nums[i+6])
		green := byte(nums[i+7])
		blue := byte(nums[i+8])

		can.PaintTriangle(x1, y1, x2, y2, x3, y3, canvas.RGB(red, green, blue))
	}

	w.Header().Set("Content-Type", "image/png")
	can.WritePng(w)
}

func main() {
	var myHandler H

	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", *PORT),
		Handler:        myHandler,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(s.ListenAndServe())
}
<|endoftext|>


<commit_before>package uchiwa

import "github.com/palourde/logger"

// BuildEvents constructs events objects for frontend consumption
func BuildEvents() {
	for _, e := range tmpResults.Events {
		m := e.(map[string]interface{})

		// build backward compatible event object for Sensu < 0.13.0
		if m["id"] == nil {

			// build client object
			c := m["client"]
			delete(m, "client")
			m["client"] = map[string]interface{}{"name": c}

			// build check object
			c = m["check"]
			delete(m, "check")
			m["check"] = map[string]interface{}{"name": c, "issued": m["issued"], "output": m["output"], "status": m["status"], "occurrences": m["occurrences"]}

			// is flapping?
			if m["action"] == false {
				m["action"] = "create"
			} else {
				m["action"] = "flapping"
			}

			// remove old entries
			delete(m, "issued")
			delete(m, "output")
			delete(m, "status")
		}

		c, ok := m["client"].(map[string]interface{})
		if !ok {
			logger.Warningf("Could not assert event's client interface: %+v", c)
			continue
		}

		k := m["check"].(map[string]interface{})
		if !ok {
			logger.Warningf("Could not assert event's check interface: %+v", k)
			continue
		}

		m["acknowledged"] = isAcknowledged(c["name"].(string), k["name"].(string), m["dc"].(string))
	}
}

// ResolveEvent send a POST request to the /resolve endpoint in order to resolve an event
func ResolveEvent(data interface{}) error {

	api, m, err := findDcFromInterface(data)

	_, err = api.ResolveEvent(m["payload"])
	if err != nil {
		logger.Warning(err)
		return err
	}

	return nil
}
<commit_msg>Remove unnecessary addition of occurrence parameter<commit_after>package uchiwa

import "github.com/palourde/logger"

// BuildEvents constructs events objects for frontend consumption
func BuildEvents() {
	for _, e := range tmpResults.Events {
		m := e.(map[string]interface{})

		// build backward compatible event object for Sensu < 0.13.0
		if m["id"] == nil {

			// build client object
			c := m["client"]
			delete(m, "client")
			m["client"] = map[string]interface{}{"name": c}

			// build check object
			c = m["check"]
			delete(m, "check")
			m["check"] = map[string]interface{}{"name": c, "issued": m["issued"], "output": m["output"], "status": m["status"]}

			// is flapping?
			if m["action"] == false {
				m["action"] = "create"
			} else {
				m["action"] = "flapping"
			}

			// remove old entries
			delete(m, "issued")
			delete(m, "output")
			delete(m, "status")
		}

		c, ok := m["client"].(map[string]interface{})
		if !ok {
			logger.Warningf("Could not assert event's client interface: %+v", c)
			continue
		}

		k := m["check"].(map[string]interface{})
		if !ok {
			logger.Warningf("Could not assert event's check interface: %+v", k)
			continue
		}

		m["acknowledged"] = isAcknowledged(c["name"].(string), k["name"].(string), m["dc"].(string))
	}
}

// ResolveEvent send a POST request to the /resolve endpoint in order to resolve an event
func ResolveEvent(data interface{}) error {

	api, m, err := findDcFromInterface(data)

	_, err = api.ResolveEvent(m["payload"])
	if err != nil {
		logger.Warning(err)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package crypto

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"io"

	"github.com/adrienkohlbecker/errors"
)

func gcm(key []byte) (cipher.AEAD, errors.Error) {

	c, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.WrapPrefix(err, "Unable to initialize AES cipher", 0)
	}

	aead, err := cipher.NewGCM(c)
	if err != nil {
		return nil, errors.WrapPrefix(err, "Unable to initialize GCM cipher", 0)
	}

	return aead, nil

}

func nonce(size int) ([]byte, errors.Error) {

	nonce := make([]byte, size)

	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to generate nonce", 0)
	}

	return nonce, nil

}

func encryptBytes(key []byte, plaintext []byte) ([]byte, errors.Error) {

	aead, err := gcm(key)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to initialize GCM cipher", 0)
	}

	nonce, err := nonce(aead.NonceSize())
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to generate nonce", 0)
	}

	ciphertext := aead.Seal([]byte{}, nonce, plaintext, []byte{})

	return append(nonce, ciphertext...), nil

}

func decryptBytes(key []byte, bytes []byte) ([]byte, errors.Error) {

	aead, err := gcm(key)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to initialize GCM cipher", 0)
	}

	nonceSize := aead.NonceSize()

	nonce := bytes[:nonceSize]
	ciphertext := bytes[nonceSize:]

	plaintext, goErr := aead.Open([]byte{}, nonce, ciphertext, []byte{})
	if goErr != nil {
		return []byte{}, errors.WrapPrefix(goErr, "Unable to decrypt ciphertext", 0)
	}

	return plaintext, nil

}
<commit_msg>Clarify we use AES-GCM<commit_after>package crypto

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"io"

	"github.com/adrienkohlbecker/errors"
)

func aesgcm(key []byte) (cipher.AEAD, errors.Error) {

	c, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.WrapPrefix(err, "Unable to initialize AES cipher", 0)
	}

	aead, err := cipher.NewGCM(c)
	if err != nil {
		return nil, errors.WrapPrefix(err, "Unable to initialize GCM cipher", 0)
	}

	return aead, nil

}

func nonce(size int) ([]byte, errors.Error) {

	nonce := make([]byte, size)

	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to generate nonce", 0)
	}

	return nonce, nil

}

func encryptBytes(key []byte, plaintext []byte) ([]byte, errors.Error) {

	aead, err := aesgcm(key)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to initialize AES-GCM cipher", 0)
	}

	nonce, err := nonce(aead.NonceSize())
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to generate nonce", 0)
	}

	ciphertext := aead.Seal([]byte{}, nonce, plaintext, []byte{})

	return append(nonce, ciphertext...), nil

}

func decryptBytes(key []byte, bytes []byte) ([]byte, errors.Error) {

	aead, err := aesgcm(key)
	if err != nil {
		return []byte{}, errors.WrapPrefix(err, "Unable to initialize AES-GCM cipher", 0)
	}

	nonceSize := aead.NonceSize()

	nonce := bytes[:nonceSize]
	ciphertext := bytes[nonceSize:]

	plaintext, goErr := aead.Open([]byte{}, nonce, ciphertext, []byte{})
	if goErr != nil {
		return []byte{}, errors.WrapPrefix(goErr, "Unable to decrypt ciphertext", 0)
	}

	return plaintext, nil

}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

// This chaincode is a test for chaincode invoking another chaincode - invokes chaincode_example02

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) GetChaincodeToCall() string {
	//This is the hashcode for github.com/hyperledger/fabric/core/example/chaincode/chaincode_example02
	//if the example is modifed this hashcode will change!!
	chainCodeToCall := "5c86473475a109e4c50e57016cae64937151dd0f17a05fb918665fd205ab86fa5796153a6d8f1c064af8a4e4a7484121011f0db9022bc6cb2d3cc29f0aaf2648"
	return chainCodeToCall
}

// Init takes two arguements, a string and int. These are stored in the key/value pair in the state
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Indicates whether event has happened. Initially 0
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	// Initialize the chaincode
	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for event status")
	}
	fmt.Printf("eventVal = %d\n", eventVal)

	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Invoke invokes another chaincode - chaincode_example02, upon receipt of an event and changes event state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Event entity
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expected integer value for event state change")
	}

	if eventVal != 1 {
		fmt.Printf("Unexpected event. Doing nothing\n")
		return nil, nil
	}

	// Get the chaincode to call from the ledger
	chainCodeToCall := t.GetChaincodeToCall()

	f := "invoke"
	invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10")
	response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs)
	if err != nil {
		errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error())
		fmt.Printf(errStr)
		return nil, errors.New(errStr)
	}

	fmt.Printf("Invoke chaincode successful. Got response %s", string(response))

	// Write the event state back to the ledger
	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var event string // Event entity
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting entity to query")
	}

	event = args[0]

	// Get the state from the ledger
	eventValbytes, err := stub.GetState(event)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	if eventValbytes == nil {
		jsonResp := "{\"Error\":\"Nil value for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + event + "\",\"Amount\":\"" + string(eventValbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return []byte(jsonResp), nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<commit_msg>Reverting the change in 1759<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

// This chaincode is a test for chaincode invoking another chaincode - invokes chaincode_example02

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) GetChaincodeToCall() string {
	//This is the hashcode for github.com/hyperledger/fabric/core/example/chaincode/chaincode_example02
	//if the example is modifed this hashcode will change!!
	chainCodeToCall := "ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"
	return chainCodeToCall
}

// Init takes two arguements, a string and int. These are stored in the key/value pair in the state
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Indicates whether event has happened. Initially 0
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	// Initialize the chaincode
	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for event status")
	}
	fmt.Printf("eventVal = %d\n", eventVal)

	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Invoke invokes another chaincode - chaincode_example02, upon receipt of an event and changes event state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Event entity
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expected integer value for event state change")
	}

	if eventVal != 1 {
		fmt.Printf("Unexpected event. Doing nothing\n")
		return nil, nil
	}

	// Get the chaincode to call from the ledger
	chainCodeToCall := t.GetChaincodeToCall()

	f := "invoke"
	invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10")
	response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs)
	if err != nil {
		errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error())
		fmt.Printf(errStr)
		return nil, errors.New(errStr)
	}

	fmt.Printf("Invoke chaincode successful. Got response %s", string(response))

	// Write the event state back to the ledger
	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var event string // Event entity
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting entity to query")
	}

	event = args[0]

	// Get the state from the ledger
	eventValbytes, err := stub.GetState(event)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	if eventValbytes == nil {
		jsonResp := "{\"Error\":\"Nil value for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + event + "\",\"Amount\":\"" + string(eventValbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return []byte(jsonResp), nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

// This chaincode is a test for chaincode invoking another chaincode - invokes chaincode_example02

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) GetChaincodeToCall() string {
	//This is the hashcode for github.com/hyperledger/fabric/core/example/chaincode/chaincode_example02
	//if the example is modifed this hashcode will change!!
	chainCodeToCall := "ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"
	return chainCodeToCall
}

// Init takes two arguements, a string and int. These are stored in the key/value pair in the state
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Indicates whether event has happened. Initially 0
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	// Initialize the chaincode
	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for event status")
	}
	fmt.Printf("eventVal = %d\n", eventVal)

	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Invoke invokes another chaincode - chaincode_example02, upon receipt of an event and changes event state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Event entity
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expected integer value for event state change")
	}

	if eventVal != 1 {
		fmt.Printf("Unexpected event. Doing nothing\n")
		return nil, nil
	}

	// Get the chaincode to call from the ledger
	chainCodeToCall := t.GetChaincodeToCall()

	f := "invoke"
	invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10")
	response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs)
	if err != nil {
		errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error())
		fmt.Printf(errStr)
		return nil, errors.New(errStr)
	}

	fmt.Printf("Invoke chaincode successful. Got response %s", string(response))

	// Write the event state back to the ledger
	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var event string // Event entity
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting entity to query")
	}

	event = args[0]

	// Get the state from the ledger
	eventValbytes, err := stub.GetState(event)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	if eventValbytes == nil {
		jsonResp := "{\"Error\":\"Nil value for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + event + "\",\"Amount\":\"" + string(eventValbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return []byte(jsonResp), nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<commit_msg>Fixing a unit test error in cc2cc<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

// This chaincode is a test for chaincode invoking another chaincode - invokes chaincode_example02

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) GetChaincodeToCall() string {
	//This is the hashcode for github.com/hyperledger/fabric/core/example/chaincode/chaincode_example02
	//if the example is modifed this hashcode will change!!
	chainCodeToCall := "5c86473475a109e4c50e57016cae64937151dd0f17a05fb918665fd205ab86fa5796153a6d8f1c064af8a4e4a7484121011f0db9022bc6cb2d3cc29f0aaf2648"
	return chainCodeToCall
}

// Init takes two arguements, a string and int. These are stored in the key/value pair in the state
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Indicates whether event has happened. Initially 0
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	// Initialize the chaincode
	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for event status")
	}
	fmt.Printf("eventVal = %d\n", eventVal)

	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Invoke invokes another chaincode - chaincode_example02, upon receipt of an event and changes event state
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	var event string // Event entity
	var eventVal int // State of event
	var err error

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	event = args[0]
	eventVal, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expected integer value for event state change")
	}

	if eventVal != 1 {
		fmt.Printf("Unexpected event. Doing nothing\n")
		return nil, nil
	}

	// Get the chaincode to call from the ledger
	chainCodeToCall := t.GetChaincodeToCall()

	f := "invoke"
	invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10")
	response, err := stub.InvokeChaincode(chainCodeToCall, invokeArgs)
	if err != nil {
		errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error())
		fmt.Printf(errStr)
		return nil, errors.New(errStr)
	}

	fmt.Printf("Invoke chaincode successful. Got response %s", string(response))

	// Write the event state back to the ledger
	err = stub.PutState(event, []byte(strconv.Itoa(eventVal)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var event string // Event entity
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting entity to query")
	}

	event = args[0]

	// Get the state from the ledger
	eventValbytes, err := stub.GetState(event)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	if eventValbytes == nil {
		jsonResp := "{\"Error\":\"Nil value for " + event + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + event + "\",\"Amount\":\"" + string(eventValbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return []byte(jsonResp), nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>package sched

import (
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/tsaf/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/conf"
	"github.com/StackExchange/tsaf/expr"
)

type context struct {
	*State
	Alert *conf.Alert

	schedule *Schedule
}

func (s *Schedule) data(st *State, a *conf.Alert) *context {
	return &context{
		State:    st,
		Alert:    a,
		schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *context) Ack() string {
	u := c.schedule.URL()
	u.Path = fmt.Sprintf("/api/acknowledge/%s/%s", c.Alert.Name, c.State.Group.String())
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *context) HostView(host string) string {
	u := c.schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *context) EGraph(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.schedule.Conf.HttpListen,
		Path:     "/egraph",
		RawQuery: q,
	}
	if strings.HasPrefix(c.schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.data(st, a))
}

// E executes the given expression and returns a value with corresponding tags
// to the context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, nil is returned. The precision
// of numbers is truncated for convienent display. Array expressions are not
// supported.
func (c *context) E(v string) (s string) {
	e, err := expr.New(v)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return
	}
	res, _, err := e.Execute(c.schedule.cache, nil)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return
	}
	for _, r := range res {
		if r.Group.Equal(c.State.Group) {
			s = truncate(r.Value)
		}
	}
	for _, r := range res {
		if r.Group == nil {
			s = truncate(r.Value)
		}
	}
	return
}

// truncate displays needed decimals for a Number.
func truncate(v expr.Value) string {
	switch t := v.(type) {
	case expr.Number:
		if t < 1 {
			return fmt.Sprintf("%.4f", t)
		} else if t < 100 {
			return fmt.Sprintf("%.1f", t)
		} else {
			return fmt.Sprintf("%.0f", t)
		}
	default:
		return ""
	}
}
<commit_msg>Export the context and some of it's fields<commit_after>package sched

import (
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/StackExchange/tsaf/_third_party/github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/conf"
	"github.com/StackExchange/tsaf/expr"
)

type Context struct {
	*State
	Alert *conf.Alert

	Schedule *Schedule
}

func (s *Schedule) data(st *State, a *conf.Alert) *Context {
	return &Context{
		State:    st,
		Alert:    a,
		Schedule: s,
	}
}

type unknownContext struct {
	Time  time.Time
	Name  string
	Group AlertKeys

	schedule *Schedule
}

func (s *Schedule) unknownData(t time.Time, name string, group AlertKeys) *unknownContext {
	return &unknownContext{
		Time:     t,
		Group:    group,
		Name:     name,
		schedule: s,
	}
}

// URL returns a prepopulated URL for external access, with path and query empty.
func (s *Schedule) URL() *url.URL {
	u := url.URL{
		Scheme: "http",
		Host:   s.Conf.HttpListen,
	}
	if strings.HasPrefix(s.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			u.Host = "localhost" + u.Host
		} else {
			u.Host = h + u.Host
		}
	}
	return &u
}

// Ack returns the URL to acknowledge an alert.
func (c *Context) Ack() string {
	u := c.Schedule.URL()
	u.Path = fmt.Sprintf("/api/acknowledge/%s/%s", c.Alert.Name, c.State.Group.String())
	return u.String()
}

// HostView returns the URL to the host view page.
func (c *Context) HostView(host string) string {
	u := c.Schedule.URL()
	u.Path = "/host"
	u.RawQuery = fmt.Sprintf("time=1d-ago&host=%s", host)
	return u.String()
}

func (c *Context) EGraph(v string) string {
	q := url.QueryEscape("q=" + opentsdb.ReplaceTags(v, c.Group))
	u := url.URL{
		Scheme:   "http",
		Host:     c.Schedule.Conf.HttpListen,
		Path:     "/egraph",
		RawQuery: q,
	}
	if strings.HasPrefix(c.Schedule.Conf.HttpListen, ":") {
		h, err := os.Hostname()
		if err != nil {
			return ""
		}
		u.Host = h + u.Host
	}
	return u.String()
}

func (s *Schedule) ExecuteBody(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Body == nil {
		return nil
	}
	return t.Body.Execute(w, s.data(st, a))
}

func (s *Schedule) ExecuteSubject(w io.Writer, a *conf.Alert, st *State) error {
	t := a.Template
	if t == nil || t.Subject == nil {
		return nil
	}
	return t.Subject.Execute(w, s.data(st, a))
}

// E executes the given expression and returns a value with corresponding tags
// to the Context's tags. If no such result is found, the first result with nil
// tags is returned. If no such result is found, nil is returned. The precision
// of numbers is truncated for convienent display. Array expressions are not
// supported.
func (c *Context) E(v string) (s string) {
	e, err := expr.New(v)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return
	}
	res, _, err := e.Execute(c.Schedule.cache, nil)
	if err != nil {
		log.Printf("%s: %v", v, err)
		return
	}
	for _, r := range res {
		if r.Group.Equal(c.State.Group) {
			s = truncate(r.Value)
		}
	}
	for _, r := range res {
		if r.Group == nil {
			s = truncate(r.Value)
		}
	}
	return
}

// truncate displays needed decimals for a Number.
func truncate(v expr.Value) string {
	switch t := v.(type) {
	case expr.Number:
		if t < 1 {
			return fmt.Sprintf("%.4f", t)
		} else if t < 100 {
			return fmt.Sprintf("%.1f", t)
		} else {
			return fmt.Sprintf("%.0f", t)
		}
	default:
		return ""
	}
}
<|endoftext|>