<commit_before>package water

import (
	"encoding/hex"
	"html/template"
	"net/http"
	"strconv"
)

func (ctx *Context) Cookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}

	return cookie.Value
}

func (ctx *Context) CookieEscape(name string) string {
	return template.HTMLEscapeString(ctx.Cookie(name))
}

func (ctx *Context) CookieBool(name string) bool {
	v, _ := strconv.ParseBool(ctx.Cookie(name))
	return v
}

func (ctx *Context) CookieInt(name string) int {
	v, _ := strconv.Atoi(ctx.Cookie(name))
	return v
}

func (ctx *Context) CookieInt64(name string) int64 {
	v, _ := strconv.ParseInt(ctx.Cookie(name), 10, 64)
	return v
}

func (ctx *Context) CookieUint(name string) uint {
	v, _ := strconv.ParseUint(ctx.Cookie(name), 10, 64)
	return uint(v)
}

func (ctx *Context) CookieUint64(name string) uint64 {
	v, _ := strconv.ParseUint(ctx.Cookie(name), 10, 64)
	return v
}

func (ctx *Context) CookieFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.Cookie(name), 64)
	return v
}

func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = value

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int32:
			cookie.MaxAge = int(v)
		case int64:
			cookie.MaxAge = int(v)
		}
	}

	cookie.Path = "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	}

	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	ctx.ResponseWriter.Header().Add("Set-Cookie", cookie.String())
}

func (ctx *Context) SecureCookie(secret, key string) (string, bool) {
	val := ctx.Cookie(key)
	if val == "" {
		return "", false
	}

	data, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}

	text, err := AESDecrypt([]byte(secret), data)
	return string(text), err == nil
}

// http2 is Recommended
// 推荐使用http2
func (ctx *Context) SetSecureCookie(secret, name, value string, others ...interface{}) {
	text, err := AESEncrypt([]byte(secret), []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}
	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}
<commit_msg>+ cookie expires for ie<commit_after>package water

import (
	"encoding/hex"
	"html/template"
	"net/http"
	"strconv"
	"time"
)

func (ctx *Context) Cookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}

	return cookie.Value
}

func (ctx *Context) CookieEscape(name string) string {
	return template.HTMLEscapeString(ctx.Cookie(name))
}

func (ctx *Context) CookieBool(name string) bool {
	v, _ := strconv.ParseBool(ctx.Cookie(name))
	return v
}

func (ctx *Context) CookieInt(name string) int {
	v, _ := strconv.Atoi(ctx.Cookie(name))
	return v
}

func (ctx *Context) CookieInt64(name string) int64 {
	v, _ := strconv.ParseInt(ctx.Cookie(name), 10, 64)
	return v
}

func (ctx *Context) CookieUint(name string) uint {
	v, _ := strconv.ParseUint(ctx.Cookie(name), 10, 64)
	return uint(v)
}

func (ctx *Context) CookieUint64(name string) uint64 {
	v, _ := strconv.ParseUint(ctx.Cookie(name), 10, 64)
	return v
}

func (ctx *Context) CookieFloat64(name string) float64 {
	v, _ := strconv.ParseFloat(ctx.Cookie(name), 64)
	return v
}

func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = value

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int32:
			cookie.MaxAge = int(v)
		case int64:
			cookie.MaxAge = int(v)
		}

		// for ie
		if cookie.MaxAge > 0 {
			cookie.Expires = time.Now().Add(time.Duration(cookie.MaxAge) * time.Second)
		}
	}

	cookie.Path = "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	}

	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	ctx.ResponseWriter.Header().Add("Set-Cookie", cookie.String())
}

func (ctx *Context) SecureCookie(secret, key string) (string, bool) {
	val := ctx.Cookie(key)
	if val == "" {
		return "", false
	}

	data, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}

	text, err := AESDecrypt([]byte(secret), data)
	return string(text), err == nil
}

// http2 is Recommended
// 推荐使用http2
func (ctx *Context) SetSecureCookie(secret, name, value string, others ...interface{}) {
	text, err := AESEncrypt([]byte(secret), []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}
	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}
<|endoftext|>


<commit_before>// BSD licensed

package interfacetools

import (
	"errors"
	"reflect"
	"bytes"
	"fmt"
)

// Copier is the interface implemented by objects
// that can decode input interfaces themselves.
// The Copier must copy the input data if it wishes
// to retain the data after returning. Unhandled
// input must return an error.
type Copier interface {
	CopyIn(interface{}) error
}

// Performs a deep-copy of source object to the passed in interface.
//
// If the object is a struct, then the copy is attempted based on the tag
// of the json tag of the field; the same rules apply per encoding/json.
// If a field is not available, then a copier skips it.
func CopyOut(src interface{}, out interface{}) (err error) {
	return CopyOutTagged(src, out, "json")
}

func CopyOutTagged(src interface{}, out interface{}, tag string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	v := reflect.ValueOf(out)
	if v.Kind() != reflect.Ptr {
		return errors.New("output interface must be a pointer")
	}

	dec := newDecoder(tag)
	iv := reflect.ValueOf(src)
	ov := reflect.ValueOf(out)
	return dec.decode(iv, ov)
}

type decoder struct {
	tag  string
	path []string
}

func newDecoder(tag string) *decoder {
	return &decoder{tag, make([]string, 0, 12)}
}

func (d *decoder) pathString() string {
	if len(d.path) == 0 {
		return ""
	}

	var buf bytes.Buffer
	for i := range d.path {
		if i > 0 {
			buf.WriteString(".")
		}
		buf.WriteString(d.path[i])
	}
	buf.WriteString(" ")
	return buf.String()
}

func (d *decoder) pushPath(s string) {
	if d.path != nil {
		d.path = append(d.path, s)
	}
}

func (d *decoder) popPath() string {
	if len(d.path) > 0 {
		s := d.path[len(d.path)-1]
		d.path = d.path[:len(d.path)-1]
		return s
	}
	return ""
}

func (d *decoder) tryCopyIn(sv reflect.Value, v reflect.Value) bool {
	// If v is a named type and is addressable,
	// start with its address, so that if the type has pointer methods,
	// we find them.
	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
		v = v.Addr()
	}
	for {
		// Load value from interface, but only if the result will be
		// usefully addressable.
		if v.Kind() == reflect.Interface && !v.IsNil() {
			e := v.Elem()
			if e.Kind() == reflect.Ptr && !e.IsNil() && e.Elem().Kind() == reflect.Ptr {
				v = e
				continue
			}
		}
		if v.Kind() != reflect.Ptr {
			break
		}
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		if v.Type().NumMethod() > 0 {
			if u, ok := v.Interface().(Copier); ok {
				// Can now attempt CopyIn
				if u.CopyIn(sv.Interface()) == nil {
					return true
				}
			}
		}
		v = v.Elem()
	}

	return false
}

func (d *decoder) decode(sv reflect.Value, v reflect.Value) error {
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}

	if sv.Kind() == reflect.Ptr {
		sv = sv.Elem()
	}

	if sv.Kind() == reflect.Interface {
		if sv.IsNil() {
			return nil
		}
		sv = sv.Elem()
	}

	if !v.CanSet() {
		return errors.New("cannot set field " + v.String())
	}

	var e reflect.Type
	if v.Kind() == reflect.Ptr {
		e = v.Type().Elem()
	} else {
		e = v.Type()
	}

	switch e.Kind() {
	case reflect.Map:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		if sv.Kind() != reflect.Map {
			return errors.New("src not map")
		}
		t := v.Type()
		if t.Key().Kind() != reflect.String {
			return errors.New("dest<map> does not use string key")
		}
		if v.IsNil() {
			v.Set(reflect.MakeMap(t))
		}

		return d.mapCopy(sv, v)

	case reflect.Struct:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		// Decode map[string] interface{} into struct
		if sv.Kind() != reflect.Map {
			return errors.New("src not map")
		}
		if v.Kind() == reflect.Ptr && v.IsNil() {
			v.Set(reflect.New(e))
		}

		if v.Kind() == reflect.Ptr {
			return d.mapToStruct(sv, v.Elem())
		} else {
			return d.mapToStruct(sv, v)
		}

	case reflect.Slice, reflect.Array:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		if sv.Kind() != reflect.Slice {
			return errors.New("src not slice")
		}

		if v.Kind() == reflect.Slice && v.IsNil() {
			v.Set(reflect.MakeSlice(v.Type(), sv.Len(), sv.Len()))
		}

		return d.sliceCopy(sv, v)
	}

	if v.Kind() == reflect.Ptr {
		nv := reflect.New(e)

		if d.tryCopyIn(sv, nv) {
			return nil
		}

		err := d.decodeScalar(sv, nv)
		if err == nil {
			v.Set(nv)
		}
		return err
	}

	if d.tryCopyIn(sv, v) {
		return nil
	}

	return d.decodeScalar(sv, v)
}

func (d *decoder) mapCopy(src reflect.Value, dst reflect.Value) error {
	sv := src.MapKeys()
	dt := dst.Type().Elem()

	for i := range sv {
		ot := reflect.New(dt)

		if dt.Kind() == reflect.Ptr {
			ot = reflect.New(ot.Type().Elem())
		}

		d.pushPath(sv[i].String())
		err := d.decode(src.MapIndex(sv[i]), ot)
		if err != nil {
			err = errors.New(d.pathString() + err.Error())
			d.path = nil
			return err
		}
		d.popPath()

		dst.SetMapIndex(sv[i], ot.Elem())
	}
	return nil
}

func (d *decoder) mapToStruct(src reflect.Value, dst reflect.Value) error {
	fieldIdx := make(map[string] int)
	for i := 0; i < dst.Type().NumField(); i++ {
		sf := dst.Type().Field(i)
		tag := sf.Tag.Get(d.tag)
		if tag == "" {
			// do by name (only if exported field)
			if sf.Name[0] >= 'A' && sf.Name[0] <= 'Z' {
				fieldIdx[sf.Name] = i
			}
		} else if tag == "-" {
			// skip this field
		} else {
			fieldIdx[tag] = i
		}
	}

	sv := src.MapKeys()
	for i, k := range sv {
		if it, ok := fieldIdx[k.String()]; ok {
			d.pushPath(sv[i].String())
			err := d.decode(src.MapIndex(sv[i]), dst.Field(it))
			if err != nil {
				err = errors.New(d.pathString() + err.Error())
				d.path = nil
				return err
			}
			d.popPath()
		}
	}
	return nil
}

func (d *decoder) sliceCopy(src reflect.Value, dst reflect.Value) error {
	for i := 0; i < src.Len(); i++ {
		if i < dst.Len() {
			d.pushPath(fmt.Sprintf("[%d]", i))
			err := d.decode(src.Index(i), dst.Index(i))
			if err != nil {
				err = errors.New(d.pathString() + err.Error())
				d.path = nil
				return err
			}
			d.popPath()
		}
	}
	return nil
}

func (d *decoder) decodeScalar(src reflect.Value, dst reflect.Value) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	switch dst.Kind() {
	case reflect.Bool:
		dst.SetBool(src.Bool())

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		dst.SetInt(int64(src.Float()))

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		dst.SetUint(uint64(src.Float()))

	case reflect.Float32, reflect.Float64:
		dst.SetFloat(src.Float())

	case reflect.Interface:
		dst.Set(src)

	case reflect.String:
		if src.Kind() != reflect.String {
			return errors.New("not string kind: " + src.Kind().String())
		}
		dst.SetString(src.String())
	}

	return nil
}
<commit_msg>Allow cross-type conversions for numbers.<commit_after>// BSD licensed

package interfacetools

import (
	"errors"
	"reflect"
	"bytes"
	"fmt"
	"strconv"
)

// Copier is the interface implemented by objects
// that can decode input interfaces themselves.
// The Copier must copy the input data if it wishes
// to retain the data after returning. Unhandled
// input must return an error.
type Copier interface {
	CopyIn(interface{}) error
}

// Performs a deep-copy of source object to the passed in interface.
//
// If the object is a struct, then the copy is attempted based on the tag
// of the json tag of the field; the same rules apply per encoding/json.
// If a field is not available, then a copier skips it.
func CopyOut(src interface{}, out interface{}) (err error) {
	return CopyOutTagged(src, out, "json")
}

func CopyOutTagged(src interface{}, out interface{}, tag string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	v := reflect.ValueOf(out)
	if v.Kind() != reflect.Ptr {
		return errors.New("output interface must be a pointer")
	}

	dec := newDecoder(tag)
	iv := reflect.ValueOf(src)
	ov := reflect.ValueOf(out)
	return dec.decode(iv, ov)
}

type decoder struct {
	tag  string
	path []string
}

func newDecoder(tag string) *decoder {
	return &decoder{tag, make([]string, 0, 12)}
}

func (d *decoder) pathString() string {
	if len(d.path) == 0 {
		return ""
	}

	var buf bytes.Buffer
	for i := range d.path {
		if i > 0 {
			buf.WriteString(".")
		}
		buf.WriteString(d.path[i])
	}
	buf.WriteString(" ")
	return buf.String()
}

func (d *decoder) pushPath(s string) {
	if d.path != nil {
		d.path = append(d.path, s)
	}
}

func (d *decoder) popPath() string {
	if len(d.path) > 0 {
		s := d.path[len(d.path)-1]
		d.path = d.path[:len(d.path)-1]
		return s
	}
	return ""
}

func (d *decoder) tryCopyIn(sv reflect.Value, v reflect.Value) bool {
	// If v is a named type and is addressable,
	// start with its address, so that if the type has pointer methods,
	// we find them.
	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
		v = v.Addr()
	}
	for {
		// Load value from interface, but only if the result will be
		// usefully addressable.
		if v.Kind() == reflect.Interface && !v.IsNil() {
			e := v.Elem()
			if e.Kind() == reflect.Ptr && !e.IsNil() && e.Elem().Kind() == reflect.Ptr {
				v = e
				continue
			}
		}
		if v.Kind() != reflect.Ptr {
			break
		}
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		if v.Type().NumMethod() > 0 {
			if u, ok := v.Interface().(Copier); ok {
				// Can now attempt CopyIn
				if u.CopyIn(sv.Interface()) == nil {
					return true
				}
			}
		}
		v = v.Elem()
	}

	return false
}

func (d *decoder) decode(sv reflect.Value, v reflect.Value) error {
	if v.Kind() == reflect.Ptr && !v.IsNil() {
		v = v.Elem()
	}

	if sv.Kind() == reflect.Ptr {
		sv = sv.Elem()
	}

	if sv.Kind() == reflect.Interface {
		if sv.IsNil() {
			return nil
		}
		sv = sv.Elem()
	}

	if !v.CanSet() {
		return errors.New("cannot set field " + v.String())
	}

	var e reflect.Type
	if v.Kind() == reflect.Ptr {
		e = v.Type().Elem()
	} else {
		e = v.Type()
	}

	switch e.Kind() {
	case reflect.Map:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		if sv.Kind() != reflect.Map {
			return errors.New("src not map")
		}
		t := v.Type()
		if t.Key().Kind() != reflect.String {
			return errors.New("dest<map> does not use string key")
		}
		if v.IsNil() {
			v.Set(reflect.MakeMap(t))
		}

		return d.mapCopy(sv, v)

	case reflect.Struct:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		// Decode map[string] interface{} into struct
		if sv.Kind() != reflect.Map {
			return errors.New("src not map")
		}
		if v.Kind() == reflect.Ptr && v.IsNil() {
			v.Set(reflect.New(e))
		}

		if v.Kind() == reflect.Ptr {
			return d.mapToStruct(sv, v.Elem())
		} else {
			return d.mapToStruct(sv, v)
		}

	case reflect.Slice, reflect.Array:
		if d.tryCopyIn(sv, v) {
			return nil
		}

		if sv.Kind() != reflect.Slice {
			return errors.New("src not slice")
		}

		if v.Kind() == reflect.Slice && v.IsNil() {
			v.Set(reflect.MakeSlice(v.Type(), sv.Len(), sv.Len()))
		}

		return d.sliceCopy(sv, v)
	}

	if v.Kind() == reflect.Ptr {
		nv := reflect.New(e)

		if d.tryCopyIn(sv, nv) {
			return nil
		}

		err := d.decodeScalar(sv, nv)
		if err == nil {
			v.Set(nv)
		}
		return err
	}

	if d.tryCopyIn(sv, v) {
		return nil
	}

	return d.decodeScalar(sv, v)
}

func (d *decoder) mapCopy(src reflect.Value, dst reflect.Value) error {
	sv := src.MapKeys()
	dt := dst.Type().Elem()

	for i := range sv {
		ot := reflect.New(dt)

		if dt.Kind() == reflect.Ptr {
			ot = reflect.New(ot.Type().Elem())
		}

		d.pushPath(sv[i].String())
		err := d.decode(src.MapIndex(sv[i]), ot)
		if err != nil {
			err = errors.New(d.pathString() + err.Error())
			d.path = nil
			return err
		}
		d.popPath()

		dst.SetMapIndex(sv[i], ot.Elem())
	}
	return nil
}

func (d *decoder) mapToStruct(src reflect.Value, dst reflect.Value) error {
	fieldIdx := make(map[string] int)
	for i := 0; i < dst.Type().NumField(); i++ {
		sf := dst.Type().Field(i)
		tag := sf.Tag.Get(d.tag)
		if tag == "" {
			// do by name (only if exported field)
			if sf.Name[0] >= 'A' && sf.Name[0] <= 'Z' {
				fieldIdx[sf.Name] = i
			}
		} else if tag == "-" {
			// skip this field
		} else {
			fieldIdx[tag] = i
		}
	}

	sv := src.MapKeys()
	for i, k := range sv {
		if it, ok := fieldIdx[k.String()]; ok {
			d.pushPath(sv[i].String())
			err := d.decode(src.MapIndex(sv[i]), dst.Field(it))
			if err != nil {
				err = errors.New(d.pathString() + err.Error())
				d.path = nil
				return err
			}
			d.popPath()
		}
	}
	return nil
}

func (d *decoder) sliceCopy(src reflect.Value, dst reflect.Value) error {
	for i := 0; i < src.Len(); i++ {
		if i < dst.Len() {
			d.pushPath(fmt.Sprintf("[%d]", i))
			err := d.decode(src.Index(i), dst.Index(i))
			if err != nil {
				err = errors.New(d.pathString() + err.Error())
				d.path = nil
				return err
			}
			d.popPath()
		}
	}
	return nil
}

func (d *decoder) decodeScalar(src reflect.Value, dst reflect.Value) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	switch dst.Kind() {
	case reflect.Bool:
		dst.SetBool(src.Bool())

	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		switch src.Kind() {
		case reflect.String:
			n, err := strconv.ParseInt(src.String(), 10, 64)
			if err != nil {
				return err
			}
			dst.SetInt(n)

		case reflect.Float32, reflect.Float64:
			dst.SetInt(int64(src.Float()))

		case reflect.Int, reflect.Int8, reflect.Int16,
		     reflect.Int32, reflect.Int64:
			dst.SetInt(src.Int())

		case reflect.Uint, reflect.Uint8, reflect.Uint16,
		     reflect.Uint32, reflect.Uint64:
			dst.SetInt(int64(src.Uint()))

		default:
			return errors.New(fmt.Sprintf("Cannot convert source kind %v to destination kind %v", src.Kind(), dst.Kind()))
		}

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		switch src.Kind() {
		case reflect.String:
			n, err := strconv.ParseUint(src.String(), 10, 64)
			if err != nil {
				return err
			}
			dst.SetUint(n)

		case reflect.Float32, reflect.Float64:
			dst.SetUint(uint64(src.Float()))

		case reflect.Int, reflect.Int8, reflect.Int16,
		     reflect.Int32, reflect.Int64:
			dst.SetUint(uint64(src.Int()))

		case reflect.Uint, reflect.Uint8, reflect.Uint16,
		     reflect.Uint32, reflect.Uint64:
			dst.SetUint(src.Uint())

		default:
			return errors.New(fmt.Sprintf("Cannot convert source kind %v to dest kind %v", src.Kind(), dst.Kind()))
		}

	case reflect.Float32, reflect.Float64:
		dst.SetFloat(src.Float())
		switch src.Kind() {
		case reflect.String:
			n, err := strconv.ParseFloat(src.String(), 64)
			if err != nil {
				return err
			}
			dst.SetFloat(n)

		case reflect.Float32, reflect.Float64:
			dst.SetFloat(src.Float())

		case reflect.Int, reflect.Int8, reflect.Int16,
		     reflect.Int32, reflect.Int64:
			dst.SetFloat(float64(src.Int()))

		case reflect.Uint, reflect.Uint8, reflect.Uint16,
		     reflect.Uint32, reflect.Uint64:
			dst.SetFloat(float64(src.Uint()))

		default:
			return errors.New(fmt.Sprintf("Cannot convert source kind %v to dest kind %v", src.Kind(), dst.Kind()))
		}

	case reflect.Interface:
		dst.Set(src)

	case reflect.String:
		if src.Kind() != reflect.String {
			return errors.New("not string kind: " + src.Kind().String())
		}
		dst.SetString(src.String())
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Fix Response.String() 🐛<commit_after><|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"encoding/base64"
	"math/big"
	"reflect"
	"strings"

	"code.google.com/p/go.crypto/ssh"
)

// returns a base64 encoded ciphertext. The salt is generated internally
func CredulousEncode(plaintext string, pubkey ssh.PublicKey) (cipher string, salt string, err error) {
	salt = "pepper"
	s := reflect.ValueOf(pubkey).Elem()
	rsaKey := rsa.PublicKey{
		N: s.Field(0).Interface().(*big.Int),
		E: s.Field(1).Interface().(int),
	}
	out, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, &rsaKey, []byte(salt+plaintext), []byte("Credulous"))
	panic_the_err(err)
	cipher = base64.StdEncoding.EncodeToString(out)
	return cipher, salt, nil
}

func CredulousDecode(ciphertext string, salt string, privkey *rsa.PrivateKey) (plaintext string, err error) {
	in, err := base64.StdEncoding.DecodeString(ciphertext)
	out, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privkey, in, []byte("Credulous"))
	panic_the_err(err)
	plaintext = strings.Replace(string(out), salt, "", 1)
	return plaintext, nil
}
<commit_msg>Generate the salt randomly each time<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"encoding/base64"
	"math/big"
	"reflect"
	"strings"

	"code.google.com/p/go.crypto/ssh"
)

func generateSalt() (salt string, err error) {
	const SALT_LENGTH = 8
	b := make([]byte, SALT_LENGTH)
	n, err := rand.Read(b)
	encoder := base64.StdEncoding
	encoded := make([]byte, encoder.EncodedLen(len(b)))
	encoder.Encode(encoded, b)
	if err != nil {
		return encoded, nil
	}
}

// returns a base64 encoded ciphertext. The salt is generated internally
func CredulousEncode(plaintext string, pubkey ssh.PublicKey) (cipher string, salt string, err error) {
	salt, err = generateSalt()
	if err != nil {
		return "", "", err
	}
	s := reflect.ValueOf(pubkey).Elem()
	rsaKey := rsa.PublicKey{
		N: s.Field(0).Interface().(*big.Int),
		E: s.Field(1).Interface().(int),
	}
	out, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, &rsaKey, []byte(salt+plaintext), []byte("Credulous"))
	panic_the_err(err)
	cipher = base64.StdEncoding.EncodeToString(out)
	return cipher, salt, nil
}

func CredulousDecode(ciphertext string, salt string, privkey *rsa.PrivateKey) (plaintext string, err error) {
	in, err := base64.StdEncoding.DecodeString(ciphertext)
	out, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privkey, in, []byte("Credulous"))
	panic_the_err(err)
	plaintext = strings.Replace(string(out), salt, "", 1)
	return plaintext, nil
}
<|endoftext|>


<commit_before>package main

// To run this package...
// go run gen.go -- --sdk 3.14.16

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	do "gopkg.in/godo.v2"
)

type service struct {
	Name      string
	Fullname  string
	Namespace string
	TaskName  string
	Tag       string
	Input     string
	Output    string
}

const (
	testsSubDir = "tests"
)

type mapping struct {
	PlaneInput  string
	PlaneOutput string
	Services    []service
}

var (
	gopath          = os.Getenv("GOPATH")
	sdkVersion      string
	autorestDir     string
	swaggersDir     string
	testGen         bool
	deps            do.S
	services        = []*service{}
	servicesMapping = []mapping{
		{
			PlaneOutput: "arm",
			PlaneInput:  "resource-manager",
			Services: []service{
				{Name: "advisor"},
				{Name: "analysisservices"},
				// {
				// Autorest Bug
				// Name: "apimanagement",
				// },
				{Name: "appinsights"},
				{Name: "authorization"},
				{Name: "automation"},
				{Name: "batch"},
				{Name: "billing"},
				{Name: "cdn"},
				// {
				// bug in AutoRest (duplicated files)
				// Name: "cognitiveservices",
				// },
				{Name: "commerce"},
				{Name: "compute"},
				{
					Name:  "containerservice",
					Input: "compute",
					Tag:   "package-container-service-2017-01",
				},
				{Name: "consumption"},
				{Name: "containerinstance"},
				{Name: "containerregistry"},
				{Name: "cosmos-db"},
				{Name: "customer-insights"},
				{
					Name:   "account",
					Input:  "datalake-analytics",
					Output: "datalake-analytics/account",
				},
				{
					Name:   "account",
					Input:  "datalake-store",
					Output: "datalake-store/account",
				},
				{Name: "devtestlabs"},
				{Name: "dns"},
				{Name: "eventgrid"},
				{Name: "eventhub"},
				{Name: "hdinsight"},
				{Name: "intune"},
				{Name: "iothub"},
				{Name: "keyvault"},
				{Name: "logic"},
				{
					Name:   "commitmentplans",
					Input:  "machinelearning",
					Output: "machinelearning/commitmentPlans",
					Tag:    "package-commitmentPlans-2016-05-preview",
				},
				{
					Name:   "webservices",
					Input:  "machinelearning",
					Output: "machinelearning/webservices",
					Tag:    "package-webservices-2017-01",
				},
				{Name: "mediaservices"},
				{Name: "mobileengagement"},
				{Name: "monitor"},
				{Name: "mysql"},
				{Name: "network"},
				{Name: "notificationhubs"},
				// {
				// bug in the Go generator https://github.com/Azure/autorest/issues/2219
				// Name: "operationalinsights",
				// },
				{Name: "postgresql"},
				{Name: "powerbiembedded"},
				{Name: "recoveryservices"},
				{Name: "recoveryservicesbackup"},
				{Name: "recoveryservicessiterecovery"},
				{Name: "redis"},
				{Name: "relay"},
				{Name: "resourcehealth"},
				{
					Name:   "features",
					Input:  "resources",
					Output: "resources/features",
					Tag:    "package-features-2015-12",
				},
				{
					Name:   "links",
					Input:  "resources",
					Output: "resources/links",
					Tag:    "package-links-2016-09",
				},
				{
					Name:   "locks",
					Input:  "resources",
					Output: "resources/locks",
					Tag:    "package-locks-2016-09",
				},
				{
					Name:   "managedapplications",
					Input:  "resources",
					Output: "resources/managedapplications",
					Tag:    "package-managedapplications-2016-09",
				},
				{
					Name:   "policy",
					Input:  "resources",
					Output: "resources/policy",
					Tag:    "package-policy-2016-12",
				},
				{
					Name:   "resources",
					Input:  "resources",
					Output: "resources/resources",
					Tag:    "package-resources-2017-05",
				},
				{
					Name:   "subscriptions",
					Input:  "resources",
					Output: "resources/subscriptions",
					Tag:    "package-subscriptions-2016-06",
				},
				{Name: "scheduler"},
				{Name: "search"},
				{Name: "servermanagement"},
				{Name: "service-map"},
				{Name: "servicebus"},
				{Name: "servicefabric"},
				{Name: "sql"},
				{Name: "storage"},
				{Name: "storageimportexport"},
				{Name: "storsimple8000series"},
				{Name: "streamanalytics"},
				// {
				// error in the modeler
				// 	Name:    "timeseriesinsights",
				// },
				{Name: "trafficmanager"},
				{Name: "visualstudio"},
				{Name: "web"},
			},
		},
		{
			PlaneOutput: "dataplane",
			PlaneInput:  "data-plane",
			Services: []service{
				{
					Name: "keyvault",
				},
			},
		},
		{
			PlaneInput: "data-plane",
			Services: []service{
				{
					Name:   "filesystem",
					Input:  "datalake-store",
					Output: "datalake-store/filesystem",
				},
			},
		},
		{
			PlaneOutput: "arm",
			PlaneInput:  "data-plane",
			Services: []service{
				{
					Name: "graphrbac",
				},
			},
		},
	}
)

func main() {
	for _, swaggerGroup := range servicesMapping {
		swg := swaggerGroup
		for _, service := range swg.Services {
			s := service
			initAndAddService(&s, swg.PlaneInput, swg.PlaneOutput)
		}
	}
	do.Godo(tasks)
}

func initAndAddService(service *service, planeInput, planeOutput string) {
	if service.Input == "" {
		service.Input = service.Name
	}
	service.Input = filepath.Join(service.Input, planeInput, "readme.md")
	if service.Output == "" {
		service.Output = service.Name
	}
	service.TaskName = fmt.Sprintf("%s>%s", planeOutput, strings.Join(strings.Split(service.Output, "/"), ">"))
	service.Fullname = filepath.Join(planeOutput, service.Output)
	service.Namespace = filepath.Join("github.com", "Azure", "azure-sdk-for-go", service.Fullname)
	service.Output = filepath.Join(gopath, "src", service.Namespace)

	services = append(services, service)
	deps = append(deps, service.TaskName)
}

func tasks(p *do.Project) {
	p.Task("default", do.S{"setvars", "generate:all", "management"}, nil)
	p.Task("setvars", nil, setVars)
	p.Use("generate", generateTasks)
	p.Use("gofmt", formatTasks)
	p.Use("gobuild", buildTasks)
	p.Use("golint", lintTasks)
	p.Use("govet", vetTasks)
	p.Task("management", do.S{"setvars"}, managementVersion)
	p.Task("addVersion", nil, addVersion)
}

func setVars(c *do.Context) {
	if gopath == "" {
		panic("Gopath not set\n")
	}

	sdkVersion = c.Args.MustString("s", "sdk", "version")
	autorestDir = c.Args.MayString("", "a", "ar", "autorest")
	swaggersDir = c.Args.MayString("", "w", "sw", "swagger")
	testGen = c.Args.MayBool(false, "t", "testgen")
}

func generateTasks(p *do.Project) {
	addTasks(generate, p)
}

func generate(service *service) {
	codegen := "--go"
	if testGen {
		codegen = "--go.testgen"
		service.Fullname = strings.Join([]string{service.Fullname, testsSubDir}, string(os.PathSeparator))
		service.Output = filepath.Join(service.Output, testsSubDir)
	}

	fmt.Printf("Generating %s...\n\n", service.Fullname)

	fullInput := ""
	if swaggersDir == "" {
		fullInput = fmt.Sprintf("https://raw.githubusercontent.com/Azure/azure-rest-api-specs/current/specification/%s", service.Input)
	} else {
		fullInput = filepath.Join(swaggersDir, "azure-rest-api-specs", "specification", service.Input)
	}

	execCommand := "autorest"
	commandArgs := []string{
		fullInput,
		codegen,
		"--license-header=MICROSOFT_APACHE",
		fmt.Sprintf("--namespace=%s", service.Name),
		fmt.Sprintf("--output-folder=%s", service.Output),
		fmt.Sprintf("--package-version=%s", sdkVersion),
		"--clear-output-folder",
		"--can-clear-output-folder",
	}
	if service.Tag != "" {
		commandArgs = append(commandArgs, fmt.Sprintf("--tag=%s", service.Tag))
	}
	if testGen {
		commandArgs = append([]string{"-LEGACY"}, commandArgs...)
	}

	if autorestDir != "" {
		// if an AutoRest directory was specified then assume
		// the caller wants to use a locally-built version.
		commandArgs = append(commandArgs, fmt.Sprintf("--use=%s", autorestDir))
	}

	autorest := exec.Command(execCommand, commandArgs...)

	fmt.Println(commandArgs)

	if _, err := runner(autorest); err != nil {
		panic(fmt.Errorf("Autorest error: %s", err))
	}

	format(service)
	build(service)
	lint(service)
	vet(service)
}

func formatTasks(p *do.Project) {
	addTasks(format, p)
}

func format(service *service) {
	fmt.Printf("Formatting %s...\n\n", service.Fullname)
	gofmt := exec.Command("gofmt", "-w", service.Output)
	_, err := runner(gofmt)
	if err != nil {
		panic(fmt.Errorf("gofmt error: %s", err))
	}
}

func buildTasks(p *do.Project) {
	addTasks(build, p)
}

func build(service *service) {
	fmt.Printf("Building %s...\n\n", service.Fullname)
	gobuild := exec.Command("go", "build", service.Namespace)
	_, err := runner(gobuild)
	if err != nil {
		panic(fmt.Errorf("go build error: %s", err))
	}
}

func lintTasks(p *do.Project) {
	addTasks(lint, p)
}

func lint(service *service) {
	fmt.Printf("Linting %s...\n\n", service.Fullname)
	golint := exec.Command(filepath.Join(gopath, "bin", "golint"), service.Namespace)
	_, err := runner(golint)
	if err != nil {
		panic(fmt.Errorf("golint error: %s", err))
	}
}

func vetTasks(p *do.Project) {
	addTasks(vet, p)
}

func vet(service *service) {
	fmt.Printf("Vetting %s...\n\n", service.Fullname)
	govet := exec.Command("go", "vet", service.Namespace)
	_, err := runner(govet)
	if err != nil {
		panic(fmt.Errorf("go vet error: %s", err))
	}
}

func addVersion(c *do.Context) {
	gitStatus := exec.Command("git", "status", "-s")
	out, err := runner(gitStatus)
	if err != nil {
		panic(fmt.Errorf("Git error: %s", err))
	}
	files := strings.Split(out, "\n")

	for _, f := range files {
		if strings.HasPrefix(f, " M ") && strings.HasSuffix(f, "version.go") {
			gitAdd := exec.Command("git", "add", f[3:])
			_, err := runner(gitAdd)
			if err != nil {
				panic(fmt.Errorf("Git error: %s", err))
			}
		}
	}
}

func managementVersion(c *do.Context) {
	version("management")
}

func version(packageName string) {
	versionFile := filepath.Join(packageName, "version.go")
	os.Remove(versionFile)
	template := `// +build go1.7

package %s

var (
	sdkVersion = "%s"
)
`
	data := []byte(fmt.Sprintf(template, packageName, sdkVersion))
	ioutil.WriteFile(versionFile, data, 0644)
}

func addTasks(fn func(*service), p *do.Project) {
	for _, service := range services {
		s := service
		p.Task(s.TaskName, nil, func(c *do.Context) {
			fn(s)
		})
	}
	p.Task("all", deps, nil)
}

func runner(cmd *exec.Cmd) (string, error) {
	var stdout, stderr bytes.Buffer
	cmd.Stdout, cmd.Stderr = &stdout, &stderr
	err := cmd.Run()
	if stdout.Len() > 0 {
		fmt.Println(stdout.String())
	}
	if stderr.Len() > 0 {
		fmt.Println(stderr.String())
	}
	return stdout.String(), err
}
<commit_msg>generates SDK is parallel, also reports failures at the end (#766)<commit_after>package main

// To run this package...
// go run gen.go -- --sdk 3.14.16

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"time"

	do "gopkg.in/godo.v2"
)

type service struct {
	Name      string
	Fullname  string
	Namespace string
	TaskName  string
	Tag       string
	Input     string
	Output    string
}

const (
	testsSubDir = "tests"
)

type mapping struct {
	PlaneInput  string
	PlaneOutput string
	Services    []service
}

type failList []string

type failLocker struct {
	sync.Mutex
	failList
}

var (
	start           time.Time
	gopath          = os.Getenv("GOPATH")
	sdkVersion      string
	autorestDir     string
	swaggersDir     string
	testGen         bool
	deps            do.P
	services        = []*service{}
	servicesMapping = []mapping{
		{
			PlaneOutput: "arm",
			PlaneInput:  "resource-manager",
			Services: []service{
				{Name: "advisor"},
				{Name: "analysisservices"},
				// {
				// Autorest Bug, duplicate files
				// 	Name: "apimanagement",
				// },
				{Name: "appinsights"},
				{Name: "authorization"},
				{Name: "automation"},
				{
					Name:   "commerce",
					Input:  "azsadmin/resource-manager/commerce",
					Output: "azsadmin/commerce",
				},
				{
					Name:   "fabric",
					Input:  "azsadmin/resource-manager/fabric",
					Output: "azsadmin/fabric",
				},
				{
					Name:   "infrastructureinsights",
					Input:  "azsadmin/resource-manager/InfrastructureInsights",
					Output: "azsadmin/infrastructureinsights",
				},
				{Name: "batch"},
				{Name: "billing"},
				{Name: "cdn"},
				// {
				// bug in AutoRest (duplicated files)
				// 	Name: "cognitiveservices",
				// },
				{Name: "commerce"},
				{Name: "compute"},
				{
					Name:  "containerservice",
					Input: "compute/resource-manager",
					Tag:   "package-container-service-2017-01",
				},
				{Name: "consumption"},
				{Name: "containerinstance"},
				{Name: "containerregistry"},
				{Name: "cosmos-db"},
				{Name: "customer-insights"},
				{
					Name:   "account",
					Input:  "datalake-analytics/resource-manager",
					Output: "datalake-analytics/account",
				},
				{
					Name:   "account",
					Input:  "datalake-store/resource-manager",
					Output: "datalake-store/account",
				},
				{Name: "devtestlabs"},
				{Name: "dns"},
				{Name: "eventgrid"},
				{Name: "eventhub"},
				{Name: "hdinsight"},
				{Name: "intune"},
				{Name: "iothub"},
				{Name: "keyvault"},
				{Name: "logic"},
				{
					Name:   "commitmentplans",
					Input:  "machinelearning/resource-manager",
					Output: "machinelearning/commitmentPlans",
					Tag:    "package-commitmentPlans-2016-05-preview",
				},
				{
					Name:   "webservices",
					Input:  "machinelearning/resource-manager",
					Output: "machinelearning/webservices",
					Tag:    "package-webservices-2017-01",
				},
				{Name: "mediaservices"},
				{Name: "mobileengagement"},
				{Name: "monitor"},
				{Name: "mysql"},
				{Name: "network"},
				{Name: "notificationhubs"},
				// {
				// bug in the Go generator https://github.com/Azure/autorest/issues/2219
				// 	Name: "operationalinsights",
				// },
				{Name: "operationsmanagement"},
				{Name: "postgresql"},
				{Name: "powerbiembedded"},
				{Name: "recoveryservices"},
				{Name: "recoveryservicesbackup"},
				{Name: "recoveryservicessiterecovery"},
				{Name: "redis"},
				{Name: "relay"},
				{Name: "resourcehealth"},
				{
					Name:   "features",
					Input:  "resources/resource-manager",
					Output: "resources/features",
					Tag:    "package-features-2015-12",
				},
				{
					Name:   "links",
					Input:  "resources/resource-manager",
					Output: "resources/links",
					Tag:    "package-links-2016-09",
				},
				{
					Name:   "locks",
					Input:  "resources/resource-manager",
					Output: "resources/locks",
					Tag:    "package-locks-2016-09",
				},
				{
					Name:   "managedapplications",
					Input:  "resources/resource-manager",
					Output: "resources/managedapplications",
					Tag:    "package-managedapplications-2016-09",
				},
				{
					Name:   "policy",
					Input:  "resources/resource-manager",
					Output: "resources/policy",
					Tag:    "package-policy-2016-12",
				},
				{
					Name:   "resources",
					Input:  "resources/resource-manager",
					Output: "resources/resources",
					Tag:    "package-resources-2017-05",
				},
				{
					Name:   "subscriptions",
					Input:  "resources/resource-manager",
					Output: "resources/subscriptions",
					Tag:    "package-subscriptions-2016-06",
				},
				{Name: "scheduler"},
				{Name: "search"},
				{Name: "servermanagement"},
				{Name: "service-map"},
				{Name: "servicebus"},
				{Name: "servicefabric"},
				{Name: "sql"},
				{Name: "storage"},
				{Name: "storageimportexport"},
				{Name: "storsimple8000series"},
				{Name: "streamanalytics"},
				// {
				// error in the modeler
				// https://github.com/Azure/autorest/issues/2579
				// Name: "timeseriesinsights",
				// },
				{Name: "trafficmanager"},
				{Name: "visualstudio"},
				// {
				// bug on methods
				// Name: "web",
				// },
			},
		},
		{
			PlaneOutput: "dataplane",
			PlaneInput:  "data-plane",
			Services: []service{
				{
					Name: "keyvault",
				},
			},
		},
		{
			PlaneInput: "data-plane",
			Services: []service{
				{
					Name:   "filesystem",
					Input:  "datalake-store/data-plane",
					Output: "datalake-store/filesystem",
				},
			},
		},
		{
			PlaneOutput: "arm",
			PlaneInput:  "data-plane",
			Services: []service{
				{
					Name: "graphrbac",
				},
			},
		},
	}
	fails = failLocker{}
)

func init() {
	start = time.Now()
	for _, swaggerGroup := range servicesMapping {
		swg := swaggerGroup
		for _, service := range swg.Services {
			s := service
			initAndAddService(&s, swg.PlaneInput, swg.PlaneOutput)
		}
	}
}

func main() {
	do.Godo(tasks)
}

func initAndAddService(service *service, planeInput, planeOutput string) {
	if service.Input == "" {
		service.Input = service.Name
	}
	path := []string{service.Input}
	if service.Input == service.Name {
		path = append(path, planeInput)
	}
	path = append(path, "readme.md")
	service.Input = filepath.Join(path...)

	if service.Output == "" {
		service.Output = service.Name
	}
	service.TaskName = fmt.Sprintf("%s>%s", planeOutput, strings.Join(strings.Split(service.Output, "/"), ">"))
	service.Fullname = filepath.Join(planeOutput, service.Output)
	service.Namespace = filepath.Join("github.com", "Azure", "azure-sdk-for-go", service.Fullname)
	service.Output = filepath.Join(gopath, "src", service.Namespace)

	services = append(services, service)
	deps = append(deps, service.TaskName)
}

func tasks(p *do.Project) {
	p.Task("default", do.S{"setvars", "generate:all", "management", "report"}, nil)
	p.Task("setvars", nil, setVars)
	p.Use("generate", generateTasks)
	p.Use("gofmt", formatTasks)
	p.Use("gobuild", buildTasks)
	p.Use("golint", lintTasks)
	p.Use("govet", vetTasks)
	p.Task("management", do.S{"setvars"}, managementVersion)
	p.Task("addVersion", nil, addVersion)
	p.Task("report", nil, report)
}

func setVars(c *do.Context) {
	if gopath == "" {
		panic("Gopath not set\n")
	}

	sdkVersion = c.Args.MustString("s", "sdk", "version")
	autorestDir = c.Args.MayString("", "a", "ar", "autorest")
	swaggersDir = c.Args.MayString("", "w", "sw", "swagger")
	testGen = c.Args.MayBool(false, "t", "testgen")
}

func generateTasks(p *do.Project) {
	addTasks(generate, p)
}

func generate(service *service) {
	codegen := "--go"
	if testGen {
		codegen = "--go.testgen"
		service.Fullname = strings.Join([]string{service.Fullname, testsSubDir}, string(os.PathSeparator))
		service.Output = filepath.Join(service.Output, testsSubDir)
	}

	fmt.Printf("Generating %s...\n\n", service.Fullname)

	fullInput := ""
	if swaggersDir == "" {
		fullInput = fmt.Sprintf("https://raw.githubusercontent.com/Azure/azure-rest-api-specs/current/specification/%s", service.Input)
	} else {
		fullInput = filepath.Join(swaggersDir, "azure-rest-api-specs", "specification", service.Input)
	}

	execCommand := "autorest"
	commandArgs := []string{
		fullInput,
		codegen,
		"--license-header=MICROSOFT_APACHE",
		fmt.Sprintf("--namespace=%s", service.Name),
		fmt.Sprintf("--output-folder=%s", service.Output),
		fmt.Sprintf("--package-version=%s", sdkVersion),
		"--clear-output-folder",
		"--can-clear-output-folder",
	}
	if service.Tag != "" {
		commandArgs = append(commandArgs, fmt.Sprintf("--tag=%s", service.Tag))
	}
	if testGen {
		commandArgs = append([]string{"-LEGACY"}, commandArgs...)
	}

	if autorestDir != "" {
		// if an AutoRest directory was specified then assume
		// the caller wants to use a locally-built version.
		commandArgs = append(commandArgs, fmt.Sprintf("--use=%s", autorestDir))
	}

	autorest := exec.Command(execCommand, commandArgs...)

	fmt.Println(commandArgs)

	if _, stderr, err := runner(autorest); err != nil {
		fails.Add(fmt.Sprintf("%s: autorest error: %s: %s", service.Fullname, err, stderr))
	}

	format(service)
	build(service)
	lint(service)
	vet(service)
}

func formatTasks(p *do.Project) {
	addTasks(format, p)
}

func format(service *service) {
	fmt.Printf("Formatting %s...\n\n", service.Fullname)
	gofmt := exec.Command("gofmt", "-w", service.Output)
	_, stderr, err := runner(gofmt)
	if err != nil {
		fails.Add(fmt.Sprintf("%s: gofmt error:%s: %s", service.Fullname, err, stderr))
	}
}

func buildTasks(p *do.Project) {
	addTasks(build, p)
}

func build(service *service) {
	fmt.Printf("Building %s...\n\n", service.Fullname)
	gobuild := exec.Command("go", "build", service.Namespace)
	_, stderr, err := runner(gobuild)
	if err != nil {
		fails.Add(fmt.Sprintf("%s: build error: %s: %s", service.Fullname, err, stderr))
	}
}

func lintTasks(p *do.Project) {
	addTasks(lint, p)
}

func lint(service *service) {
	fmt.Printf("Linting %s...\n\n", service.Fullname)
	golint := exec.Command(filepath.Join(gopath, "bin", "golint"), service.Namespace)
	_, stderr, err := runner(golint)
	if err != nil {
		fails.Add(fmt.Sprintf("%s: golint error: %s: %s", service.Fullname, err, stderr))
	}
}

func vetTasks(p *do.Project) {
	addTasks(vet, p)
}

func vet(service *service) {
	fmt.Printf("Vetting %s...\n\n", service.Fullname)
	govet := exec.Command("go", "vet", service.Namespace)
	_, stderr, err := runner(govet)
	if err != nil {
		fails.Add(fmt.Sprintf("%s: go vet error: %s: %s", service.Fullname, err, stderr))
	}
}

func addVersion(c *do.Context) {
	gitStatus := exec.Command("git", "status", "-s")
	out, _, err := runner(gitStatus)
	if err != nil {
		panic(fmt.Errorf("Git error: %s", err))
	}
	files := strings.Split(out, "\n")

	for _, f := range files {
		if strings.HasPrefix(f, " M ") && strings.HasSuffix(f, "version.go") {
			gitAdd := exec.Command("git", "add", f[3:])
			_, _, err := runner(gitAdd)
			if err != nil {
				panic(fmt.Errorf("Git error: %s", err))
			}
		}
	}
}

func managementVersion(c *do.Context) {
	version("management")
}

func version(packageName string) {
	versionFile := filepath.Join(packageName, "version.go")
	os.Remove(versionFile)
	template := `// +build go1.7

package %s

var (
	sdkVersion = "%s"
)
`
	data := []byte(fmt.Sprintf(template, packageName, sdkVersion))
	ioutil.WriteFile(versionFile, data, 0644)
}

func addTasks(fn func(*service), p *do.Project) {
	for _, service := range services {
		s := service
		p.Task(s.TaskName, nil, func(c *do.Context) {
			fn(s)
		})
	}
	p.Task("all", deps, nil)
}

func runner(cmd *exec.Cmd) (string, string, error) {
	var stdout, stderr bytes.Buffer
	cmd.Stdout, cmd.Stderr = &stdout, &stderr
	err := cmd.Run()
	if stdout.Len() > 0 {
		fmt.Println(stdout.String())
	}
	if stderr.Len() > 0 {
		fmt.Println(stderr.String())
	}
	return stdout.String(), stderr.String(), err
}

func (fl *failLocker) Add(fail string) {
	fl.Lock()
	defer fl.Unlock()
	fl.failList = append(fl.failList, fail)
}

func report(c *do.Context) {
	fmt.Printf("Script ran for %s\n", time.Since(start))
	for _, f := range fails.failList {
		fmt.Println(f)
		fmt.Println("==========")
	}
}
<|endoftext|>


<commit_before>package immortal

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	count       uint32
	count_defer uint32
	process     *os.Process
}

func (self *Daemon) String() string {
	return fmt.Sprintf("%d", self.process.Pid)
}

func (self *Daemon) WritePid(file string, pid int) error {
	if err := ioutil.WriteFile(file, []byte(fmt.Sprintf("%d", pid)), 0644); err != nil {
		return err
	}
	return nil
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.count, uint32(1)) != 0 {
		log.Printf("PID: %d running", self.process.Pid)
		return
	}

	// Command to execute
	cmd := exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
		}

		// https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		cmd.Stdout = w
		cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		cmd.Stdin = nil
		cmd.Stdout = nil
		cmd.Stderr = nil
	}

	go func() {
		// count_defer defaults to 0, 1 to run only once/down (don't restart)
		defer func() {
			atomic.StoreUint32(&self.count, self.count_defer)
		}()

		if self.Logger.IsLogging() {
			defer w.Close()
		}

		if err := cmd.Start(); err != nil {
			self.Control.state <- err
			return
		}

		self.process = cmd.Process

		// write parent pid
		if self.Pid.Parent != "" {
			if err := self.WritePid(self.Pid.Parent, os.Getpid()); err != nil {
				log.Print(err)
			}
		}

		// write child pid
		if self.Pid.Child != "" {
			if err := self.WritePid(self.Pid.Child, self.process.Pid); err != nil {
				log.Print(err)
			}
		}

		self.Control.state <- cmd.Wait()
	}()
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// create fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}

		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// read fifo
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<commit_msg>	modified:   daemon.go<commit_after>package immortal

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"sync/atomic"
	"syscall"
	"time"
)

type Daemon struct {
	*Config
	*Control
	Forker
	Logger
	count       uint32
	count_defer uint32
	process     *os.Process
}

func (self *Daemon) String() string {
	return fmt.Sprintf("%d", self.process.Pid)
}

func (self *Daemon) WritePid(file string, pid int) error {
	if err := ioutil.WriteFile(file, []byte(fmt.Sprintf("%d", pid)), 0644); err != nil {
		return err
	}
	return nil
}

func (self *Daemon) Run() {
	if atomic.SwapUint32(&self.count, uint32(1)) != 0 {
		log.Printf("PID: %d running", self.process.Pid)
		return
	}

	if self.Wait > 0 {
		time.Sleep(self.Wait * time.Second)
	}

	// Command to execute
	cmd := exec.Command(self.command[0], self.command[1:]...)

	// change working directory
	if self.Cwd != "" {
		cmd.Dir = self.Cwd
	}

	// set environment vars
	if self.Env != nil {
		env := os.Environ()
		for k, v := range self.Env {
			env = append(env, fmt.Sprintf("%s=%s", k, v))
		}
		cmd.Env = env
	}

	sysProcAttr := new(syscall.SysProcAttr)

	// set owner
	if self.user != nil {
		uid, err := strconv.Atoi(self.user.Uid)
		if err != nil {
			self.Control.state <- err
		}

		gid, err := strconv.Atoi(self.user.Gid)
		if err != nil {
			self.Control.state <- err
		}

		// https://golang.org/pkg/syscall/#SysProcAttr
		sysProcAttr.Credential = &syscall.Credential{
			Uid: uint32(uid),
			Gid: uint32(gid),
		}
	}

	// Set process group ID to Pgid, or, if Pgid == 0, to new pid
	sysProcAttr.Setpgid = true
	sysProcAttr.Pgid = 0

	cmd.SysProcAttr = sysProcAttr

	// log only if are available loggers
	var (
		r *io.PipeReader
		w *io.PipeWriter
	)
	if self.Logger.IsLogging() {
		r, w = io.Pipe()
		cmd.Stdout = w
		cmd.Stderr = w
		go self.Logger.StdHandler(r)
	} else {
		cmd.Stdin = nil
		cmd.Stdout = nil
		cmd.Stderr = nil
	}

	go func() {
		// count_defer defaults to 0, 1 to run only once/down (don't restart)
		defer func() {
			atomic.StoreUint32(&self.count, self.count_defer)
		}()

		if self.Logger.IsLogging() {
			defer w.Close()
		}

		if err := cmd.Start(); err != nil {
			self.Control.state <- err
			return
		}

		self.process = cmd.Process

		// write parent pid
		if self.Pid.Parent != "" {
			if err := self.WritePid(self.Pid.Parent, os.Getpid()); err != nil {
				log.Print(err)
			}
		}

		// write child pid
		if self.Pid.Child != "" {
			if err := self.WritePid(self.Pid.Child, self.process.Pid); err != nil {
				log.Print(err)
			}
		}

		self.Control.state <- cmd.Wait()
	}()
}

func New(cfg *Config) (*Daemon, error) {
	var (
		supDir string
		err    error
	)

	if cfg.Cwd != "" {
		supDir = filepath.Join(cfg.Cwd, "supervise")
	} else {
		d, err := os.Getwd()
		if err != nil {
			return nil, err
		}
		supDir = filepath.Join(d, "supervise")
	}

	control := &Control{
		fifo:  make(chan Return),
		quit:  make(chan struct{}),
		state: make(chan error),
	}

	// if ctrl create supervise dir
	if cfg.ctrl {
		// create fifo
		var ctrl = []string{"control", "ok"}
		for _, v := range ctrl {
			if err := MakeFifo(filepath.Join(supDir, v)); err != nil {
				return nil, err
			}
		}

		// lock
		if lock, err := os.Create(filepath.Join(supDir, "lock")); err != nil {
			return nil, err
		} else if err = syscall.Flock(int(lock.Fd()), syscall.LOCK_EX+syscall.LOCK_NB); err != nil {
			return nil, err
		}

		// read fifo
		if control.fifo_control, err = OpenFifo(filepath.Join(supDir, "control")); err != nil {
			return nil, err
		}
		if control.fifo_ok, err = OpenFifo(filepath.Join(supDir, "ok")); err != nil {
			return nil, err
		}
	}

	return &Daemon{
		Config:  cfg,
		Control: control,
		Forker:  &Fork{},
		Logger: &LogWriter{
			logger: NewLogger(cfg),
		},
	}, nil
}
<|endoftext|>


<commit_before>// +build linux,amd64

package seccomp

// Using BPF filters
//
// ref: http://www.gsp.com/cgi-bin/man.cgi?topic=bpf
import "syscall"

func jumpGreaterThan(f *filter, v uint, jt sockFilter) {
	lo := uint32(uint64(v) % 0x100000000)
	hi := uint32(uint64(v) / 0x100000000)
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JGT+syscall.BPF_K, (hi), 4, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, (hi), 0, 5))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JGE+syscall.BPF_K, (lo), 0, 2))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
	*f = append(*f, jt)
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
}

func jumpEqualTo(f *filter, v uint, jt sockFilter) {
	lo := uint32(uint64(v) % 0x100000000)
	hi := uint32(uint64(v) / 0x100000000)
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, (hi), 0, 5))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, (lo), 0, 2))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
	*f = append(*f, jt)
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
}

func jumpLessThan(f *filter, v uint, jt sockFilter) {
	lo := uint32(uint64(v) % 0x100000000)
	hi := uint32(uint64(v) / 0x100000000)
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JGT+syscall.BPF_K, (hi), 6, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, (hi), 0, 3))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JGT+syscall.BPF_K, (lo), 2, 0))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
	*f = append(*f, jt)
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
}

func jumpNotEqualTo(f *filter, v uint, jt sockFilter) {
	lo := uint32(uint64(v) % 0x100000000)
	hi := uint32(uint64(v) / 0x100000000)
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, hi, 5, 0))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 0))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, lo, 2, 0))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
	*f = append(*f, jt)
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
}

// this checks for a value inside a mask. The evalusation is equal to doing
// CLONE_NEWUSER & syscallMask == CLONE_NEWUSER
func jumpMaskEqualTo(f *filter, v uint, jt sockFilter) {
	lo := uint32(uint64(v) % 0x100000000)
	hi := uint32(uint64(v) / 0x100000000)
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, hi, 0, 6))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 0))
	*f = append(*f, scmpBpfStmt(syscall.BPF_ALU+syscall.BPF_AND, uint32(v)))
	*f = append(*f, scmpBpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, lo, 0, 2))
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
	*f = append(*f, jt)
	*f = append(*f, scmpBpfStmt(syscall.BPF_LD+syscall.BPF_MEM, 1))
}
<commit_msg>Delete jump_amd64.go<commit_after><|endoftext|>


<commit_before>package coordinator

import (
	"bytes"
	log "code.google.com/p/log4go"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"protocol"
	"sync"
	"sync/atomic"
	"time"
)

type ProtobufClient struct {
	connLock          sync.Mutex
	conn              net.Conn
	hostAndPort       string
	requestBufferLock sync.RWMutex
	requestBuffer     map[uint32]*runningRequest
	reconnectWait     sync.WaitGroup
	connectCalled     bool
	lastRequestId     uint32
	writeTimeout      time.Duration
}

type runningRequest struct {
	timeMade     time.Time
	responseChan chan *protocol.Response
}

const (
	REQUEST_RETRY_ATTEMPTS = 2
	MAX_RESPONSE_SIZE      = MAX_REQUEST_SIZE
	MAX_REQUEST_TIME       = time.Second * 1200
	RECONNECT_RETRY_WAIT   = time.Millisecond * 100
)

func NewProtobufClient(hostAndPort string, writeTimeout time.Duration) *ProtobufClient {
	fmt.Println("NewProtobufClient")
	return &ProtobufClient{
		hostAndPort:   hostAndPort,
		requestBuffer: make(map[uint32]*runningRequest),
		writeTimeout:  writeTimeout,
	}
}

func (self *ProtobufClient) Connect() {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	if self.connectCalled {
		return
	}
	self.connectCalled = true
	go func() {
		self.reconnect()
		self.readResponses()
	}()
	go self.peridicallySweepTimedOutRequests()
}

func (self *ProtobufClient) Close() {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	if self.conn != nil {
		self.conn.Close()
		self.conn = nil
	}
}

func (self *ProtobufClient) getConnection() net.Conn {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	return self.conn
}

// Makes a request to the server. If the responseStream chan is not nil it will expect a response from the server
// with a matching request.Id. The REQUEST_RETRY_ATTEMPTS constant of 3 and the RECONNECT_RETRY_WAIT of 100ms means
// that an attempt to make a request to a downed server will take 300ms to time out.
func (self *ProtobufClient) MakeRequest(request *protocol.Request, responseStream chan *protocol.Response) error {
	if request.Id == nil {
		id := atomic.AddUint32(&self.lastRequestId, uint32(1))
		request.Id = &id
	}
	if responseStream != nil {
		self.requestBufferLock.Lock()

		// this should actually never happen. The sweeper should clear out dead requests
		// before the uint32 ids roll over.
		if oldReq, alreadyHasRequestById := self.requestBuffer[*request.Id]; alreadyHasRequestById {
			message := "already has a request with this id, must have timed out"
			log.Error(message)
			oldReq.responseChan <- &protocol.Response{Type: &endStreamResponse, ErrorMessage: &message}
		}
		self.requestBuffer[*request.Id] = &runningRequest{time.Now(), responseStream}
		self.requestBufferLock.Unlock()
	}

	data, err := request.Encode()
	if err != nil {
		return err
	}

	conn := self.getConnection()
	if conn == nil {
		conn = self.reconnect()
		if conn == nil {
			return fmt.Errorf("Failed to connect to server %s", self.hostAndPort)
		}
	}

	conn.SetWriteDeadline(time.Now().Add(self.writeTimeout))
	buff := bytes.NewBuffer(make([]byte, 0, len(data)+8))
	binary.Write(buff, binary.LittleEndian, uint32(len(data)))
	_, err = conn.Write(append(buff.Bytes(), data...))

	if err == nil {
		return nil
	}

	// if we got here it errored out, clear out the request
	self.requestBufferLock.Lock()
	delete(self.requestBuffer, *request.Id)
	self.requestBufferLock.Unlock()
	return err
}

func (self *ProtobufClient) readResponses() {
	message := make([]byte, 0, MAX_RESPONSE_SIZE)
	buff := bytes.NewBuffer(message)
	for {
		buff.Reset()
		conn := self.getConnection()
		if conn == nil {
			continue
		}
		var messageSizeU uint32
		var err error
		err = binary.Read(conn, binary.LittleEndian, &messageSizeU)
		if err != nil {
			continue
		}
		messageSize := int64(messageSizeU)
		messageReader := io.LimitReader(conn, messageSize)
		_, err = io.Copy(buff, messageReader)
		if err != nil {
			continue
		}
		response, err := protocol.DecodeResponse(buff)
		if err != nil {
			log.Error("error unmarshaling response: %s", err)
		} else {
			self.sendResponse(response)
		}
	}
}

func (self *ProtobufClient) sendResponse(response *protocol.Response) {
	self.requestBufferLock.RLock()
	req, ok := self.requestBuffer[*response.RequestId]
	self.requestBufferLock.RUnlock()
	if ok {
		if *response.Type == protocol.Response_END_STREAM || *response.Type == protocol.Response_WRITE_OK {
			self.requestBufferLock.Lock()
			delete(self.requestBuffer, *response.RequestId)
			self.requestBufferLock.Unlock()
		}
		select {
		case req.responseChan <- response:
		default:
			log.Error("ProtobufClient: Response buffer full! ", self.hostAndPort, response)
			// if it's an end stream response, we have to send it so start it in a goroutine so we can make sure it gets through without blocking the reading of responses.
			if *response.Type == protocol.Response_END_STREAM || *response.Type == protocol.Response_WRITE_OK || *response.Type == protocol.Response_ACCESS_DENIED {
				go func() {
					req.responseChan <- response
				}()
			}
		}
	}
}

func (self *ProtobufClient) reconnect() net.Conn {
	self.connLock.Lock()
	defer self.connLock.Unlock()

	if self.conn != nil {
		self.conn.Close()
	}
	conn, err := net.DialTimeout("tcp", self.hostAndPort, self.writeTimeout)
	if err == nil {
		self.conn = conn
		log.Info("connected to %s", self.hostAndPort)
		return self.conn
	}
	log.Error("failed to connect to %s", self.hostAndPort)
	return nil
}

func (self *ProtobufClient) peridicallySweepTimedOutRequests() {
	for {
		time.Sleep(time.Minute)
		self.requestBufferLock.Lock()
		maxAge := time.Now().Add(-MAX_REQUEST_TIME)
		for k, req := range self.requestBuffer {
			if req.timeMade.Before(maxAge) {
				delete(self.requestBuffer, k)
				log.Warn("Request timed out.")
			}
		}
		self.requestBufferLock.Unlock()
	}
}
<commit_msg>Make protobuf client reconnect on error.<commit_after>package coordinator

import (
	"bytes"
	log "code.google.com/p/log4go"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"protocol"
	"sync"
	"sync/atomic"
	"time"
)

type ProtobufClient struct {
	connLock          sync.Mutex
	conn              net.Conn
	hostAndPort       string
	requestBufferLock sync.RWMutex
	requestBuffer     map[uint32]*runningRequest
	reconnectWait     sync.WaitGroup
	connectCalled     bool
	lastRequestId     uint32
	writeTimeout      time.Duration
}

type runningRequest struct {
	timeMade     time.Time
	responseChan chan *protocol.Response
}

const (
	REQUEST_RETRY_ATTEMPTS = 2
	MAX_RESPONSE_SIZE      = MAX_REQUEST_SIZE
	MAX_REQUEST_TIME       = time.Second * 1200
	RECONNECT_RETRY_WAIT   = time.Millisecond * 100
)

func NewProtobufClient(hostAndPort string, writeTimeout time.Duration) *ProtobufClient {
	fmt.Println("NewProtobufClient")
	return &ProtobufClient{
		hostAndPort:   hostAndPort,
		requestBuffer: make(map[uint32]*runningRequest),
		writeTimeout:  writeTimeout,
	}
}

func (self *ProtobufClient) Connect() {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	if self.connectCalled {
		return
	}
	self.connectCalled = true
	go func() {
		self.reconnect()
		self.readResponses()
	}()
	go self.peridicallySweepTimedOutRequests()
}

func (self *ProtobufClient) Close() {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	if self.conn != nil {
		self.conn.Close()
		self.conn = nil
	}
}

func (self *ProtobufClient) getConnection() net.Conn {
	self.connLock.Lock()
	defer self.connLock.Unlock()
	return self.conn
}

// Makes a request to the server. If the responseStream chan is not nil it will expect a response from the server
// with a matching request.Id. The REQUEST_RETRY_ATTEMPTS constant of 3 and the RECONNECT_RETRY_WAIT of 100ms means
// that an attempt to make a request to a downed server will take 300ms to time out.
func (self *ProtobufClient) MakeRequest(request *protocol.Request, responseStream chan *protocol.Response) error {
	if request.Id == nil {
		id := atomic.AddUint32(&self.lastRequestId, uint32(1))
		request.Id = &id
	}
	if responseStream != nil {
		self.requestBufferLock.Lock()

		// this should actually never happen. The sweeper should clear out dead requests
		// before the uint32 ids roll over.
		if oldReq, alreadyHasRequestById := self.requestBuffer[*request.Id]; alreadyHasRequestById {
			message := "already has a request with this id, must have timed out"
			log.Error(message)
			oldReq.responseChan <- &protocol.Response{Type: &endStreamResponse, ErrorMessage: &message}
		}
		self.requestBuffer[*request.Id] = &runningRequest{time.Now(), responseStream}
		self.requestBufferLock.Unlock()
	}

	data, err := request.Encode()
	if err != nil {
		return err
	}

	conn := self.getConnection()
	if conn == nil {
		conn = self.reconnect()
		if conn == nil {
			return fmt.Errorf("Failed to connect to server %s", self.hostAndPort)
		}
	}

	conn.SetWriteDeadline(time.Now().Add(self.writeTimeout))
	buff := bytes.NewBuffer(make([]byte, 0, len(data)+8))
	binary.Write(buff, binary.LittleEndian, uint32(len(data)))
	_, err = conn.Write(append(buff.Bytes(), data...))

	if err == nil {
		return nil
	}

	// if we got here it errored out, clear out the request
	self.requestBufferLock.Lock()
	delete(self.requestBuffer, *request.Id)
	self.requestBufferLock.Unlock()
	self.reconnect()
	return err
}

func (self *ProtobufClient) readResponses() {
	message := make([]byte, 0, MAX_RESPONSE_SIZE)
	buff := bytes.NewBuffer(message)
	for {
		buff.Reset()
		conn := self.getConnection()
		if conn == nil {
			continue
		}
		var messageSizeU uint32
		var err error
		err = binary.Read(conn, binary.LittleEndian, &messageSizeU)
		if err != nil {
			continue
		}
		messageSize := int64(messageSizeU)
		messageReader := io.LimitReader(conn, messageSize)
		_, err = io.Copy(buff, messageReader)
		if err != nil {
			continue
		}
		response, err := protocol.DecodeResponse(buff)
		if err != nil {
			log.Error("error unmarshaling response: %s", err)
		} else {
			self.sendResponse(response)
		}
	}
}

func (self *ProtobufClient) sendResponse(response *protocol.Response) {
	self.requestBufferLock.RLock()
	req, ok := self.requestBuffer[*response.RequestId]
	self.requestBufferLock.RUnlock()
	if ok {
		if *response.Type == protocol.Response_END_STREAM || *response.Type == protocol.Response_WRITE_OK {
			self.requestBufferLock.Lock()
			delete(self.requestBuffer, *response.RequestId)
			self.requestBufferLock.Unlock()
		}
		select {
		case req.responseChan <- response:
		default:
			log.Error("ProtobufClient: Response buffer full! ", self.hostAndPort, response)
			// if it's an end stream response, we have to send it so start it in a goroutine so we can make sure it gets through without blocking the reading of responses.
			if *response.Type == protocol.Response_END_STREAM || *response.Type == protocol.Response_WRITE_OK || *response.Type == protocol.Response_ACCESS_DENIED {
				go func() {
					req.responseChan <- response
				}()
			}
		}
	}
}

func (self *ProtobufClient) reconnect() net.Conn {
	self.connLock.Lock()
	defer self.connLock.Unlock()

	if self.conn != nil {
		self.conn.Close()
	}
	conn, err := net.DialTimeout("tcp", self.hostAndPort, self.writeTimeout)
	if err == nil {
		self.conn = conn
		log.Info("connected to %s", self.hostAndPort)
		return self.conn
	}
	log.Error("failed to connect to %s", self.hostAndPort)
	return nil
}

func (self *ProtobufClient) peridicallySweepTimedOutRequests() {
	for {
		time.Sleep(time.Minute)
		self.requestBufferLock.Lock()
		maxAge := time.Now().Add(-MAX_REQUEST_TIME)
		for k, req := range self.requestBuffer {
			if req.timeMade.Before(maxAge) {
				delete(self.requestBuffer, k)
				log.Warn("Request timed out.")
			}
		}
		self.requestBufferLock.Unlock()
	}
}
<|endoftext|>


<commit_before>package hoverfly

import (
	"os"
	"strconv"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// Configuration - initial structure of configuration
type Configuration struct {
	AdminPort          string
	ProxyPort          string
	Mode               string
	Destination        string
	Middleware         string
	DatabaseName       string
	Verbose            bool
	Development        bool
	SecretKey          []byte
	JWTExpirationDelta int
	AuthEnabled        bool
	ProxyControlChan   chan bool

	mu sync.Mutex
}

// SetMode - provides safe way to set new mode
func (c *Configuration) SetMode(mode string) {
	c.mu.Lock()
	c.Mode = mode
	c.mu.Unlock()
}

// GetMode - provides safe way to get current mode
func (c *Configuration) GetMode() (mode string) {
	c.mu.Lock()
	mode = c.Mode
	c.mu.Unlock()
	return
}

// DefaultPort - default proxy port
const DefaultPort = "8500"

// DefaultAdminPort - default admin interface port
const DefaultAdminPort = "8888"

// DefaultDatabaseName - default database name that will be created
// or used by Hoverfly
const DefaultDatabaseName = "requests.db"

// DefaultJWTExpirationDelta - default token expiration if environment variable is no provided
const DefaultJWTExpirationDelta = 72

// Environment variables
const (
	HoverflyAuthEnabledEV     = "HoverflyAuthEnabled"
	HoverflySecretEV          = "HoverflySecret"
	HoverflyTokenExpirationEV = "HoverflyTokenExpiration"

	HoverflyAdminPortEV = "AdminPort"
	HoverflyProxyPortEV = "ProxyPort"

	HoverflyDBEV         = "HoverflyDB"
	HoverflyMiddlewareEV = "HoverflyMiddleware"
)

// InitSettings gets and returns initial configuration from env
// variables or sets defaults
func InitSettings() *Configuration {

	var appConfig Configuration
	// getting default admin interface port
	if os.Getenv(HoverflyAdminPortEV) != "" {
		appConfig.AdminPort = os.Getenv(HoverflyAdminPortEV)
	} else {
		appConfig.AdminPort = DefaultAdminPort
	}

	// getting proxy port
	if os.Getenv(HoverflyProxyPortEV) != "" {
		appConfig.ProxyPort = os.Getenv(HoverflyProxyPortEV)
	} else {
		appConfig.ProxyPort = DefaultPort
	}

	databaseName := os.Getenv(HoverflyDBEV)
	if databaseName == "" {
		databaseName = DefaultDatabaseName
	}
	appConfig.DatabaseName = databaseName

	if os.Getenv(HoverflySecretEV) != "" {
		appConfig.SecretKey = []byte(os.Getenv(HoverflySecretEV))
	} else {
		appConfig.SecretKey = GetRandomName(10)
	}

	if os.Getenv(HoverflyTokenExpirationEV) != "" {

		exp, err := strconv.Atoi(os.Getenv(HoverflyTokenExpirationEV))
		if err != nil {
			log.WithFields(log.Fields{
				"error":                   err.Error(),
				"HoverflyTokenExpiration": os.Getenv(HoverflyTokenExpirationEV),
			}).Error("failed to get token exipration delta, using default value")
			exp = DefaultJWTExpirationDelta
		}
		appConfig.JWTExpirationDelta = exp

	} else {
		appConfig.JWTExpirationDelta = DefaultJWTExpirationDelta
	}

	if os.Getenv(HoverflyAuthEnabledEV) == "true" {
		appConfig.AuthEnabled = true
	} else {
		appConfig.AuthEnabled = false
	}

	// middleware configuration
	appConfig.Middleware = os.Getenv(HoverflyMiddlewareEV)

	appConfig.ProxyControlChan = make(chan bool)

	return &appConfig
}
<commit_msg>updated settings configuration<commit_after>package hoverfly

import (
	"os"
	"strconv"
	"sync"

	log "github.com/Sirupsen/logrus"
)

// Configuration - initial structure of configuration
type Configuration struct {
	AdminPort    string
	ProxyPort    string
	Mode         string
	Destination  string
	Middleware   string
	DatabaseName string

	Verbose     bool
	Development bool

	SecretKey          []byte
	JWTExpirationDelta int
	AuthEnabled        bool

	ProxyControlChan chan bool
	ProxyControlWG   sync.WaitGroup

	mu sync.Mutex
}

// SetMode - provides safe way to set new mode
func (c *Configuration) SetMode(mode string) {
	c.mu.Lock()
	c.Mode = mode
	c.mu.Unlock()
}

// GetMode - provides safe way to get current mode
func (c *Configuration) GetMode() (mode string) {
	c.mu.Lock()
	mode = c.Mode
	c.mu.Unlock()
	return
}

// DefaultPort - default proxy port
const DefaultPort = "8500"

// DefaultAdminPort - default admin interface port
const DefaultAdminPort = "8888"

// DefaultDatabaseName - default database name that will be created
// or used by Hoverfly
const DefaultDatabaseName = "requests.db"

// DefaultJWTExpirationDelta - default token expiration if environment variable is no provided
const DefaultJWTExpirationDelta = 72

// Environment variables
const (
	HoverflyAuthEnabledEV     = "HoverflyAuthEnabled"
	HoverflySecretEV          = "HoverflySecret"
	HoverflyTokenExpirationEV = "HoverflyTokenExpiration"

	HoverflyAdminPortEV = "AdminPort"
	HoverflyProxyPortEV = "ProxyPort"

	HoverflyDBEV         = "HoverflyDB"
	HoverflyMiddlewareEV = "HoverflyMiddleware"
)

// InitSettings gets and returns initial configuration from env
// variables or sets defaults
func InitSettings() *Configuration {

	var appConfig Configuration
	// getting default admin interface port
	if os.Getenv(HoverflyAdminPortEV) != "" {
		appConfig.AdminPort = os.Getenv(HoverflyAdminPortEV)
	} else {
		appConfig.AdminPort = DefaultAdminPort
	}

	// getting proxy port
	if os.Getenv(HoverflyProxyPortEV) != "" {
		appConfig.ProxyPort = os.Getenv(HoverflyProxyPortEV)
	} else {
		appConfig.ProxyPort = DefaultPort
	}

	databaseName := os.Getenv(HoverflyDBEV)
	if databaseName == "" {
		databaseName = DefaultDatabaseName
	}
	appConfig.DatabaseName = databaseName

	if os.Getenv(HoverflySecretEV) != "" {
		appConfig.SecretKey = []byte(os.Getenv(HoverflySecretEV))
	} else {
		appConfig.SecretKey = GetRandomName(10)
	}

	if os.Getenv(HoverflyTokenExpirationEV) != "" {

		exp, err := strconv.Atoi(os.Getenv(HoverflyTokenExpirationEV))
		if err != nil {
			log.WithFields(log.Fields{
				"error":                   err.Error(),
				"HoverflyTokenExpiration": os.Getenv(HoverflyTokenExpirationEV),
			}).Error("failed to get token exipration delta, using default value")
			exp = DefaultJWTExpirationDelta
		}
		appConfig.JWTExpirationDelta = exp

	} else {
		appConfig.JWTExpirationDelta = DefaultJWTExpirationDelta
	}

	if os.Getenv(HoverflyAuthEnabledEV) == "true" {
		appConfig.AuthEnabled = true
	} else {
		appConfig.AuthEnabled = false
	}

	// middleware configuration
	appConfig.Middleware = os.Getenv(HoverflyMiddlewareEV)

	appConfig.ProxyControlChan = make(chan bool)

	return &appConfig
}
<|endoftext|>


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

package carrier

import (
	dispatch "github.com/projectriff/riff/function-sidecar/pkg/dispatcher"
	"github.com/projectriff/riff/message-transport/pkg/transport"
	"log"
)

func Run(consumer transport.Consumer, producer transport.Producer, dispatcher dispatch.Dispatcher, replyTopic string) {

	go func() {
		for {
			// Incoming message
			msg, open := <-consumer.Messages()
			if open {
				dispatcher.Input() <- msg
			} else {
				// Transport closed
				log.Print("Exiting transport Consumer loop")
				return
			}
		}
	}()

	go func() {
		for {
			// Result message
			resultMsg, open := <-dispatcher.Output() // Make sure to drain channel even if output==""
			if open {
				if replyTopic != "" {
					log.Printf("<<< %s\n", resultMsg)
					err := producer.Send(replyTopic, resultMsg)
					if err != nil {
						log.Printf("Error sending reply message: %v", err)
						continue
					}
				} else {
					log.Printf("=== Not sending function return value as reply topic was not provided. Raw result = %s\n", resultMsg)
				}
			} else {
				log.Print("Exiting transport Producer loop")
				return
			}
		}
	}()

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

package carrier

import (
	dispatch "github.com/projectriff/riff/function-sidecar/pkg/dispatcher"
	"github.com/projectriff/riff/message-transport/pkg/transport"
	"log"
)

func Run(consumer transport.Consumer, producer transport.Producer, dispatcher dispatch.Dispatcher, replyTopic string) {

	go func() {
		for {
			// Incoming message
			msg, open := <-consumer.Messages()
			log.Printf(">>> %s\n", msg)
			if open {
				dispatcher.Input() <- msg
			} else {
				// Transport closed
				log.Print("Exiting transport Consumer loop")
				return
			}
		}
	}()

	go func() {
		for {
			// Result message
			resultMsg, open := <-dispatcher.Output() // Make sure to drain channel even if output==""
			if open {
				if replyTopic != "" {
					log.Printf("<<< %s\n", resultMsg)
					err := producer.Send(replyTopic, resultMsg)
					if err != nil {
						log.Printf("Error sending reply message: %v", err)
						continue
					}
				} else {
					log.Printf("=== Not sending function return value as reply topic was not provided. Raw result = %s\n", resultMsg)
				}
			} else {
				log.Print("Exiting transport Producer loop")
				return
			}
		}
	}()

}
<|endoftext|>


<commit_before>package aws

import (
	"errors"
	"fmt"
	"io"
	"net/url"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"github.com/yuuki1/droot/log"
)

const uploadPartSize = 64 * 1024 * 1024 // 64MB part size
const downloadPartSize = uploadPartSize

type S3Client struct {
	svc s3iface.S3API
}

func NewS3Client() *S3Client {
	var svc s3iface.S3API
	if log.IsDebug {
		svc = s3.New(session.New(), aws.NewConfig().WithLogLevel(aws.LogDebug))
	} else {
		svc = s3.New(session.New())
	}
	return &S3Client{svc: svc}
}

func (clt *S3Client) ExistsBucket(bucket string) (bool, error) {
	_, err := clt.svc.ListObjects(&s3.ListObjectsInput{
		Bucket: &bucket,
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

func (clt *S3Client) Upload(s3Url *url.URL, reader io.Reader) (string, error) {
	bucket, object := s3Url.Host, s3Url.Path

	ok, err := clt.ExistsBucket(bucket)
	if err != nil {
		return "", err
	}
	if !ok {
		return "", errors.New(fmt.Sprintf("No such bucket: %s", bucket))
	}

	uploader := s3manager.NewUploaderWithClient(clt.svc)
	upOutput, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: &bucket,
		Key:    &object,
		Body:   reader,
	}, func(u *s3manager.Uploader) {
		u.PartSize = uploadPartSize
	})
	if err != nil {
		return "", err
	}

	return upOutput.Location, nil
}

func (clt *S3Client) Download(s3Url *url.URL, file io.WriterAt) (int64, error) {
	bucket, object := s3Url.Host, s3Url.Path

	ok, err := clt.ExistsBucket(bucket)
	if err != nil {
		return -1, err
	}
	if !ok {
		return -1, errors.New(fmt.Sprintf("No such bucket: %s", bucket))
	}

	downloader := s3manager.NewDownloaderWithClient(clt.svc)
	nBytes, err := downloader.Download(file, &s3.GetObjectInput{
		Bucket: &bucket,
		Key:    &object,
	}, func(d *s3manager.Downloader) {
		d.PartSize = downloadPartSize
	})
	if err != nil {
		return -1, err
	}

	return nBytes, nil
}
<commit_msg>Fix variable name<commit_after>package aws

import (
	"errors"
	"fmt"
	"io"
	"net/url"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"github.com/yuuki1/droot/log"
)

const uploadPartSize = 64 * 1024 * 1024 // 64MB part size
const downloadPartSize = uploadPartSize

type S3Client struct {
	svc s3iface.S3API
}

func NewS3Client() *S3Client {
	var svc s3iface.S3API
	if log.IsDebug {
		svc = s3.New(session.New(), aws.NewConfig().WithLogLevel(aws.LogDebug))
	} else {
		svc = s3.New(session.New())
	}
	return &S3Client{svc: svc}
}

func (clt *S3Client) ExistsBucket(bucket string) (bool, error) {
	_, err := clt.svc.ListObjects(&s3.ListObjectsInput{
		Bucket: &bucket,
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

func (clt *S3Client) Upload(s3Url *url.URL, reader io.Reader) (string, error) {
	bucket, object := s3Url.Host, s3Url.Path

	ok, err := clt.ExistsBucket(bucket)
	if err != nil {
		return "", err
	}
	if !ok {
		return "", errors.New(fmt.Sprintf("No such bucket: %s", bucket))
	}

	uploader := s3manager.NewUploaderWithClient(clt.svc)
	upOutput, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: &bucket,
		Key:    &object,
		Body:   reader,
	}, func(u *s3manager.Uploader) {
		u.PartSize = uploadPartSize
	})
	if err != nil {
		return "", err
	}

	return upOutput.Location, nil
}

func (clt *S3Client) Download(s3Url *url.URL, writer io.WriterAt) (int64, error) {
	bucket, object := s3Url.Host, s3Url.Path

	ok, err := clt.ExistsBucket(bucket)
	if err != nil {
		return -1, err
	}
	if !ok {
		return -1, errors.New(fmt.Sprintf("No such bucket: %s", bucket))
	}

	downloader := s3manager.NewDownloaderWithClient(clt.svc)
	nBytes, err := downloader.Download(writer, &s3.GetObjectInput{
		Bucket: &bucket,
		Key:    &object,
	}, func(d *s3manager.Downloader) {
		d.PartSize = downloadPartSize
	})
	if err != nil {
		return -1, err
	}

	return nBytes, nil
}
<|endoftext|>


<commit_before>// Package sidekick implements some Go test helper flags and functions.
package sidekick

import (
	"flag"
	"fmt"
	"strings"
)

type stringSlice []string

func (ss stringSlice) String() string      { return strings.Join(ss, ",") }
func (ss *stringSlice) Set(s string) error { *ss = append(*ss, s); return nil }

var (
	// Debug is similar to testing.Verbose. Set to true when using flag
	// -debug.
	Debug bool

	skips stringSlice
	cases stringSlice
)

func init() {
	flag.Var(&skips, "skip", "skip test case")
	flag.Var(&cases, "case", "run test case")
	flag.BoolVar(&Debug, "debug", false, "enter debug mode")
}

// SkipCase checks if a test case should be run based on flags -skip or -case.
// SkipCase compares values in string form, you can pass in value has
// fmt.Stringer or any other interfaces that package fmt has supported.
func SkipCase(c interface{}) bool {
	for _, item := range skips {
		if item == fmt.Sprint(c) {
			return true
		}
	}

	for _, item := range cases {
		if item == fmt.Sprint(c) {
			return false
		}
	}

	if len(cases) > 0 {
		return true
	}

	return false
}

// TODO
// type Skiper interface{}
// type Caser interface{}
<commit_msg>Add log flag setting<commit_after>// Package sidekick implements some Go test helper flags and functions.
package sidekick

import (
	"flag"
	"fmt"
	"log"
	"strings"
)

type stringSlice []string

func (ss stringSlice) String() string      { return strings.Join(ss, ",") }
func (ss *stringSlice) Set(s string) error { *ss = append(*ss, s); return nil }

var (
	// Debug is similar to testing.Verbose. Set to true when using flag
	// -debug.
	Debug bool

	skips stringSlice
	cases stringSlice
)

func init() {
	flag.Var(&skips, "skip", "skip test case")
	flag.Var(&cases, "case", "run test case")
	flag.BoolVar(&Debug, "debug", false, "enter debug mode")

	log.SetFlags(log.Lshortfile | log.LstdFlags)
}

// SkipCase checks if a test case should be run based on flags -skip or -case.
// SkipCase compares values in string form, you can pass in value has
// fmt.Stringer or any other interfaces that package fmt has supported.
func SkipCase(c interface{}) bool {
	for _, item := range skips {
		if item == fmt.Sprint(c) {
			return true
		}
	}

	for _, item := range cases {
		if item == fmt.Sprint(c) {
			return false
		}
	}

	if len(cases) > 0 {
		return true
	}

	return false
}

// TODO
// type Skiper interface{}
// type Caser interface{}
<|endoftext|>


<commit_before>// Copyright 2014 Paul Hammond.
// This software is licensed under the MIT license, see LICENSE.txt for details.
package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"strings"

	"github.com/ogier/pflag"
)

type Config struct {
	WebhookUrl string `json:"webhook_url"`
	Channel    string `json:"channel"`
}

func ReadConfig() (*Config, error) {
	homeDir := ""
	usr, err := user.Current()
	if err == nil {
		homeDir = usr.HomeDir
	}

	for _, path := range []string{"/etc/slackcat.conf", homeDir + "/.slackcat.conf", "./slackcat.conf"} {
		file, err := os.Open(path)
		if os.IsNotExist(err) {
			continue
		}
		if err != nil {
			return nil, err
		}

		json.NewDecoder(file)
		conf := Config{}
		err = json.NewDecoder(file).Decode(&conf)
		if err != nil {
			return nil, err
		}
		return &conf, nil
	}
	return &Config{}, nil
}

type SlackMsg struct {
	Channel  string `json:"channel"`
	Username string `json:"username"`
	Text     string `json:"text"`
	Parse    string `json:"parse"`
}

func (m SlackMsg) Encode() (string, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func (m SlackMsg) Post(WebhookURL string) error {
	encoded, err := m.Encode()
	if err != nil {
		return err
	}

	resp, err := http.PostForm(WebhookURL, url.Values{"payload": {encoded}})
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return errors.New("Not OK")
	}
	return nil
}

func username() string {
	username := "<unknown>"
	usr, err := user.Current()
	if err == nil {
		username = usr.Username
	}

	hostname := "<unknown>"
	host, err := os.Hostname()
	if err == nil {
		hostname = host
	}
	return fmt.Sprintf("%s@%s", username, hostname)
}

func main() {

	cfg, err := ReadConfig()
	if err != nil {
		log.Fatalf("Could not read config: %v", err)
	}

	pflag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: slackcat [-c #channel] [-n name] [message]")
	}

	channel := pflag.StringP("channel", "c", cfg.Channel, "channel")
	name := pflag.StringP("name", "n", username(), "name")
	pflag.Parse()

	// was there a message on the command line? If so use it.
	args := pflag.Args()
	if len(args) > 0 {
		msg := SlackMsg{
			Channel:  *channel,
			Username: *name,
			Parse:    "full",
			Text:     strings.Join(args, " "),
		}

		err = msg.Post(cfg.WebhookUrl)
		if err != nil {
			log.Fatalf("Post failed: %v", err)
		}
		os.Exit(0)
	}

	// ...Otherwise scan stdin
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		msg := SlackMsg{
			Channel:  *channel,
			Username: *name,
			Parse:    "full",
			Text:     scanner.Text(),
		}

		err = msg.Post(cfg.WebhookUrl)
		if err != nil {
			log.Fatalf("Post failed: %v", err)
		}
	}
	if err := scanner.Err(); err != nil {
		log.Fatalf("Error reading: %v", err)
	}
}
<commit_msg>return not os.Exit<commit_after>// Copyright 2014 Paul Hammond.
// This software is licensed under the MIT license, see LICENSE.txt for details.
package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"strings"

	"github.com/ogier/pflag"
)

type Config struct {
	WebhookUrl string `json:"webhook_url"`
	Channel    string `json:"channel"`
}

func ReadConfig() (*Config, error) {
	homeDir := ""
	usr, err := user.Current()
	if err == nil {
		homeDir = usr.HomeDir
	}

	for _, path := range []string{"/etc/slackcat.conf", homeDir + "/.slackcat.conf", "./slackcat.conf"} {
		file, err := os.Open(path)
		if os.IsNotExist(err) {
			continue
		}
		if err != nil {
			return nil, err
		}

		json.NewDecoder(file)
		conf := Config{}
		err = json.NewDecoder(file).Decode(&conf)
		if err != nil {
			return nil, err
		}
		return &conf, nil
	}
	return &Config{}, nil
}

type SlackMsg struct {
	Channel  string `json:"channel"`
	Username string `json:"username"`
	Text     string `json:"text"`
	Parse    string `json:"parse"`
}

func (m SlackMsg) Encode() (string, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func (m SlackMsg) Post(WebhookURL string) error {
	encoded, err := m.Encode()
	if err != nil {
		return err
	}

	resp, err := http.PostForm(WebhookURL, url.Values{"payload": {encoded}})
	if err != nil {
		return err
	}

	if resp.StatusCode != http.StatusOK {
		return errors.New("Not OK")
	}
	return nil
}

func username() string {
	username := "<unknown>"
	usr, err := user.Current()
	if err == nil {
		username = usr.Username
	}

	hostname := "<unknown>"
	host, err := os.Hostname()
	if err == nil {
		hostname = host
	}
	return fmt.Sprintf("%s@%s", username, hostname)
}

func main() {

	cfg, err := ReadConfig()
	if err != nil {
		log.Fatalf("Could not read config: %v", err)
	}

	pflag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: slackcat [-c #channel] [-n name] [message]")
	}

	channel := pflag.StringP("channel", "c", cfg.Channel, "channel")
	name := pflag.StringP("name", "n", username(), "name")
	pflag.Parse()

	// was there a message on the command line? If so use it.
	args := pflag.Args()
	if len(args) > 0 {
		msg := SlackMsg{
			Channel:  *channel,
			Username: *name,
			Parse:    "full",
			Text:     strings.Join(args, " "),
		}

		err = msg.Post(cfg.WebhookUrl)
		if err != nil {
			log.Fatalf("Post failed: %v", err)
		}
		return
	}

	// ...Otherwise scan stdin
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		msg := SlackMsg{
			Channel:  *channel,
			Username: *name,
			Parse:    "full",
			Text:     scanner.Text(),
		}

		err = msg.Post(cfg.WebhookUrl)
		if err != nil {
			log.Fatalf("Post failed: %v", err)
		}
	}
	if err := scanner.Err(); err != nil {
		log.Fatalf("Error reading: %v", err)
	}
}
<|endoftext|>