<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"path"
	"unicode"

	"github.com/DeedleFake/signage"
)

type marshalFunc func(string, []signage.Bill) (io.Reader, error)

func marshalRSS(t string, bills []signage.Bill) (io.Reader, error) {
	var buf bytes.Buffer
	err := tmpl.ExecuteTemplate(&buf, "rss", map[string]interface{}{
		"Type":  t,
		"Bills": bills,
	})
	return &buf, err
}

func marshalJSON(t string, bills []signage.Bill) (io.Reader, error) {
	buf, err := json.Marshal(map[string]interface{}{
		"type":  t,
		"bills": bills,
	})
	return bytes.NewReader(buf), err
}

type getFunc func() ([]signage.Bill, error)

func getBills(rw http.ResponseWriter, req *http.Request, mode string, get getFunc, marshal marshalFunc) {
	bills, err := get()
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	buf, err := marshal(mode, bills)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	_, err = io.Copy(rw, buf)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}
}

var (
	marshallers = map[string]marshalFunc{
		"": marshalRSS,

		".rss":  marshalRSS,
		".json": marshalJSON,
	}

	modes = map[string]getFunc{
		"signed":  signage.GetSigned,
		"vetoed":  signage.GetVetoed,
		"pending": signage.GetPending,
	}
)

func handleList(rw http.ResponseWriter, req *http.Request) {
	var buf bytes.Buffer
	err := tmpl.ExecuteTemplate(&buf, "list", map[string]interface{}{
		"Marshallers": marshallers,
		"Modes":       modes,
	})
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	_, err = io.Copy(rw, &buf)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}
}

func mux(rw http.ResponseWriter, req *http.Request) {
	name := path.Base(req.URL.Path)
	ext := path.Ext(name)

	mode := name[:len(name)-len(ext)]
	get, ok := modes[mode]
	if !ok {
		handleList(rw, req)
		return
	}

	marshal, ok := marshallers[ext]
	if !ok {
		http.Error(rw, fmt.Sprintf("Unknown format: %q", ext), http.StatusBadRequest)
		return
	}

	mode = string(unicode.ToUpper(rune(mode[0]))) + mode[1:]
	getBills(rw, req, mode, get, marshal)
}

func main() {
	log.Fatalln(http.ListenAndServe(":8080", http.HandlerFunc(mux)))
}
<commit_msg>cmd/signage: Better logging and error messages.<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"path"
	"unicode"

	"github.com/DeedleFake/signage"
)

type marshalFunc func(string, []signage.Bill) (io.Reader, error)

func marshalRSS(t string, bills []signage.Bill) (io.Reader, error) {
	var buf bytes.Buffer
	err := tmpl.ExecuteTemplate(&buf, "rss", map[string]interface{}{
		"Type":  t,
		"Bills": bills,
	})
	return &buf, err
}

func marshalJSON(t string, bills []signage.Bill) (io.Reader, error) {
	buf, err := json.Marshal(map[string]interface{}{
		"type":  t,
		"bills": bills,
	})
	return bytes.NewReader(buf), err
}

type getFunc func() ([]signage.Bill, error)

func getBills(rw http.ResponseWriter, req *http.Request, mode string, get getFunc, marshal marshalFunc) {
	bills, err := get()
	if err != nil {
		log.Printf("Failed to get bills: %v", err)
		http.Error(rw, "Error: Failed to get bills.", http.StatusInternalServerError)
		return
	}

	buf, err := marshal(mode, bills)
	if err != nil {
		log.Printf("Failed to marshal bills: %v", err)
		http.Error(rw, "Error: Failed to marshal bills.", http.StatusInternalServerError)
		return
	}

	_, err = io.Copy(rw, buf)
	if err != nil {
		log.Printf("Failed to write to client: %v", err)
		http.Error(rw, "Error: Failed to write to cl... Wait, how can you see this?", http.StatusInternalServerError)
		return
	}
}

var (
	marshallers = map[string]marshalFunc{
		"": marshalRSS,

		".rss":  marshalRSS,
		".json": marshalJSON,
	}

	modes = map[string]getFunc{
		"signed":  signage.GetSigned,
		"vetoed":  signage.GetVetoed,
		"pending": signage.GetPending,
	}
)

func handleList(rw http.ResponseWriter, req *http.Request) {
	var buf bytes.Buffer
	err := tmpl.ExecuteTemplate(&buf, "list", map[string]interface{}{
		"Marshallers": marshallers,
		"Modes":       modes,
	})
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	_, err = io.Copy(rw, &buf)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}
}

func mux(rw http.ResponseWriter, req *http.Request) {
	log.Printf("%q request for %q from %v", req.Method, req.URL, req.RemoteAddr)

	name := path.Base(req.URL.Path)
	ext := path.Ext(name)

	mode := name[:len(name)-len(ext)]
	get, ok := modes[mode]
	if !ok {
		handleList(rw, req)
		return
	}

	marshal, ok := marshallers[ext]
	if !ok {
		http.Error(rw, fmt.Sprintf("Unknown format: %q", ext), http.StatusBadRequest)
		return
	}

	mode = string(unicode.ToUpper(rune(mode[0]))) + mode[1:]
	getBills(rw, req, mode, get, marshal)
}

func main() {
	log.Fatalln(http.ListenAndServe(":8080", http.HandlerFunc(mux)))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	//	pickle "github.com/hydrogen18/stalecucumber"
	"github.com/pkg/errors"
	"go/build"
	"go/format"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
)

// value is one of these
//    int64
//    float64
//    bool
//    []byte
//    string
//    time.Time
//    nil - for NULL values

/*

)

func (t *{{ .Type }}) Scan(value interface{}) error {
	s, ok := value.({{ .Primative }})
	if !ok {
		return fmt.Errorf("Can't convert %v to {{ .Primative }}", value)
	}

	*t = {{ .Type }}(s)
	return nil
}

func (t {{ .Type }}) Value() (driver.Value, error) {
	return {{ .Primative }}(t), nil
}
*/

const StringTemplate = ``

const ScannerTemplate = `
// DO NOT EDIT - Auto generated by sqltype for {{ .Type }}

package {{ .Package }}

import (
	"fmt"
	"reflect"
	"database/sql/driver"
	{{if or (eq .Primative "int") (eq .Primative "bool") }}
	"strconv"
	{{end}}
	{{if or (eq .Primative "pythondict") (eq .Primative "pythonlist") }}
	"bytes"
	pickle "github.com/hydrogen18/stalecucumber"
	{{else if eq .Primative "pythonlist"}}
	"bytes"
	pickle "github.com/hydrogen18/stalecucumber"
	{{end}}
)

func (t *{{ .Type }}) Scan(value interface{}) error {

	if value == nil {
		return nil
	}

	switch v := value.(type) {
	{{if eq .Primative "string"}}
		case []byte:
			*t = {{ .Type }}(string(v))

		case string:
			*t = {{ .Type }}(v)

		case *string:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative "int"}}
		case []byte:
			i, err := strconv.Atoi(string(v))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to int %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(i)

		case int:
			*t = {{ .Type }}(v)

		case *int:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative "bool"}}
		case []byte:
			b, err := strconv.ParseBool(string(v))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to bool %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(b)

		case bool:
			*t = {{ .Type }}(v)

		case *bool:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative  "pythondict"}}
		case []byte:
			dict, err := pickle.DictString(pickle.Unpickle(bytes.NewReader(v)))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to dict %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(dict)

	{{else if eq .Primative  "pythonlist"}}
		case []byte:
			list := make({{ .Type }},0)
			err := pickle.UnpackInto(&list).From(pickle.Unpickle(bytes.NewReader(v)))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to list %v", reflect.TypeOf(t), value, err)
			}
			*t = list

	{{end}}
		default:
			return fmt.Errorf("%s Can't convert '%v' to {{ .Primative }}", reflect.TypeOf(t), value)
	}

	return nil
}

func (t {{ .Type }}) Value() (driver.Value, error) {

	{{if or (eq .Primative "pythondict") (eq .Primative "pythonlist") }}
		buf := new(bytes.Buffer)
		if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
			return nil, err
		}
		return buf.Bytes(), nil
	{{else}}
		return {{ .Primative }}(t), nil
	{{end}}
}
`

/*
	if value != nil {
		 return nil
	}

	switch v := value.(type) {
	case string:
		*t = {{ .Type }}(v)
		return nil
	case []byte:
		*t = {{ .Type }}(v)
		return nil
	case nil:
		return nil
	default:
		return fmt.Errorf("{{ .Type }}: Underlying value %v is not convertable to a string", reflect.TypeOf(value))
	}
}
*/

type Scanner struct {
	Package   string
	Primative string
	Type      string
}

var (
	primativeType string
	typeName      string
)

func init() {
	flag.StringVar(&primativeType, "primative", "", "Corresponding primative type")
	flag.StringVar(&typeName, "type", "", "Name of type")
}

func main() {
	log.SetFlags(0)
	flag.Parse()

	if typeName == "" {
		log.Fatal("Need to provide --type")
	}

	if primativeType == "" {
		log.Fatal("Need to provide --primative")
	}

	packageName, err := getPackageName()
	if err != nil {
		log.Fatal(err)
	}

	if err := validatePrimative(primativeType); err != nil {
		log.Fatal(err)
	}

	scanner := Scanner{
		Package:   packageName,
		Primative: primativeType,
		Type:      typeName,
	}

	filename := fmt.Sprintf("sql_%s.go", strings.ToLower(typeName))
	file, err := os.Create(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	if err := SqlType(file, scanner); err != nil {
		log.Fatal(err)
	}
}

func SqlType(writer io.Writer, scanner Scanner) error {
	t := template.Must(template.New("scanner").Parse(ScannerTemplate))

	buf := &bytes.Buffer{}
	if err := t.Execute(buf, scanner); err != nil {
		return errors.Wrap(err, "error excuting template")
	}

	b, err := format.Source(buf.Bytes())
	if err != nil {
		return errors.Wrap(err, "error sourcing go struct")
	}

	if _, err := writer.Write(b); err != nil {
		return errors.Wrap(err, "error writing to file")
	}

	return nil
}

func getPackageName() (string, error) {
	directory := "."

	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		return "", err
	}

	return pkg.Name, err
}

func validatePrimative(primativeType string) error {
	switch primativeType {
	case "string":
		fallthrough
	case "bool":
		fallthrough
	case "pythondict":
		fallthrough
	case "pythonlist":
		return nil
	default:
		return errors.Errorf("Invalid primative '%s'", primativeType)
	}
}

/*
func (t *{{ .Type }}) Scan(value interface{}) error {
	fmt.Println("VALUE", value, reflect.TypeOf(value))

	s, err := ConvertString(value)
	if err != nil {
		return errors.Wrapf(err, "%s Can't convert '%v' to string %s", reflect.TypeOf(t), value, s)
	}
	*t = RewardTargetId(s)
	return nil
}

func (t RewardTargetId) Value() (driver.Value, error) {
	return string(t), nil
}

func ConvertString(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertInt(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertFloat(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertBool(value interface{}) (bool, error) {
	b, err := driver.Bool.ConvertValue(value)
	if err != nil {
		return err
	}
	return b.(bool)
}

func (t *StringList) Scan(value interface{}) error {

	if value == nil {
		return nil
	}

	buf, ok := value.([]byte)
	if !ok {
		return errors.Errorf("%s Can't cast '%v' to []byte", reflect.TypeOf(t), value)
	}

	reader := bytes.NewReader(buf)

	list, err := pickle.ListOrTuple(pickle.Unpickle(reader))
	if err != nil {
		return errors.Wrapf(err, "%s Can't convert '%v' to list", reflect.TypeOf(t), value)
	}

	fmt.Println("LIST", list)

	slist := make([]string, 0, len(list))
	for _, l := range list {
		slist = append(slist, l.(string))
	}
	*t = slist
	return nil
}

func (t StringList) Value() (driver.Value, error) {
	buf := new(bytes.Buffer)
	if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (t StringListList) Value() (driver.Value, error) {
	buf := new(bytes.Buffer)
	if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
*/
<commit_msg>adding python dict<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	//	pickle "github.com/hydrogen18/stalecucumber"
	"github.com/pkg/errors"
	"go/build"
	"go/format"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
)

// value is one of these
//    int64
//    float64
//    bool
//    []byte
//    string
//    time.Time
//    nil - for NULL values

/*

)

func (t *{{ .Type }}) Scan(value interface{}) error {
	s, ok := value.({{ .Primative }})
	if !ok {
		return fmt.Errorf("Can't convert %v to {{ .Primative }}", value)
	}

	*t = {{ .Type }}(s)
	return nil
}

func (t {{ .Type }}) Value() (driver.Value, error) {
	return {{ .Primative }}(t), nil
}
*/

const StringTemplate = ``

const ScannerTemplate = `
// DO NOT EDIT - Auto generated by sqltype for {{ .Type }}

package {{ .Package }}

import (
	"fmt"
	"reflect"
	"database/sql/driver"
	{{if or (eq .Primative "int") (eq .Primative "bool") }}
	"strconv"
	{{end}}
	{{if or (eq .Primative "pythondict") (eq .Primative "pythonstringdict") }}
	"bytes"
	pickle "github.com/hydrogen18/stalecucumber"
	{{else if eq .Primative "pythonlist"}}
	"bytes"
	pickle "github.com/hydrogen18/stalecucumber"
	{{end}}
)

func (t *{{ .Type }}) Scan(value interface{}) error {

	if value == nil {
		return nil
	}

	switch v := value.(type) {
	{{if eq .Primative "string"}}
		case []byte:
			*t = {{ .Type }}(string(v))

		case string:
			*t = {{ .Type }}(v)

		case *string:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative "int"}}
		case []byte:
			i, err := strconv.Atoi(string(v))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to int %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(i)

		case int:
			*t = {{ .Type }}(v)

		case *int:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative "bool"}}
		case []byte:
			b, err := strconv.ParseBool(string(v))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to bool %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(b)

		case bool:
			*t = {{ .Type }}(v)

		case *bool:
			*t = {{ .Type }}(*v)

	{{else if eq .Primative  "pythondict"}}
		case []byte:
			dict, err := pickle.Dict(pickle.Unpickle(bytes.NewReader(v)))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to dict %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(dict)

	{{else if eq .Primative  "pythonstringdict"}}
		case []byte:
			dict, err := pickle.DictString(pickle.Unpickle(bytes.NewReader(v)))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to dict %v", reflect.TypeOf(t), value, err)
			}
			*t = {{ .Type }}(dict)

	{{else if eq .Primative  "pythonlist"}}
		case []byte:
			list := make({{ .Type }},0)
			err := pickle.UnpackInto(&list).From(pickle.Unpickle(bytes.NewReader(v)))
			if err != nil {
				return fmt.Errorf("%s Can't convert '%v' to list %v", reflect.TypeOf(t), value, err)
			}
			*t = list

	{{end}}
		default:
			return fmt.Errorf("%s Can't convert '%v' to {{ .Primative }}", reflect.TypeOf(t), value)
	}

	return nil
}

func (t {{ .Type }}) Value() (driver.Value, error) {

	{{if or (eq .Primative "pythondict") (eq .Primative "pythonlist") (eq .Primative "pythonstringdict") }}
		buf := new(bytes.Buffer)
		if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
			return nil, err
		}
		return buf.Bytes(), nil
	{{else}}
		return {{ .Primative }}(t), nil
	{{end}}
}
`

/*
	if value != nil {
		 return nil
	}

	switch v := value.(type) {
	case string:
		*t = {{ .Type }}(v)
		return nil
	case []byte:
		*t = {{ .Type }}(v)
		return nil
	case nil:
		return nil
	default:
		return fmt.Errorf("{{ .Type }}: Underlying value %v is not convertable to a string", reflect.TypeOf(value))
	}
}
*/

type Scanner struct {
	Package   string
	Primative string
	Type      string
}

var (
	primativeType string
	typeName      string
)

func init() {
	flag.StringVar(&primativeType, "primative", "", "Corresponding primative type")
	flag.StringVar(&typeName, "type", "", "Name of type")
}

func main() {
	log.SetFlags(0)
	flag.Parse()

	if typeName == "" {
		log.Fatal("Need to provide --type")
	}

	if primativeType == "" {
		log.Fatal("Need to provide --primative")
	}

	packageName, err := getPackageName()
	if err != nil {
		log.Fatal(err)
	}

	if err := validatePrimative(primativeType); err != nil {
		log.Fatal(err)
	}

	scanner := Scanner{
		Package:   packageName,
		Primative: primativeType,
		Type:      typeName,
	}

	filename := fmt.Sprintf("sql_%s.go", strings.ToLower(typeName))
	file, err := os.Create(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	if err := SqlType(file, scanner); err != nil {
		log.Fatal(err)
	}
}

func SqlType(writer io.Writer, scanner Scanner) error {
	t := template.Must(template.New("scanner").Parse(ScannerTemplate))

	buf := &bytes.Buffer{}
	if err := t.Execute(buf, scanner); err != nil {
		return errors.Wrap(err, "error excuting template")
	}

	b, err := format.Source(buf.Bytes())
	if err != nil {
		return errors.Wrap(err, "error sourcing go struct")
	}

	if _, err := writer.Write(b); err != nil {
		return errors.Wrap(err, "error writing to file")
	}

	return nil
}

func getPackageName() (string, error) {
	directory := "."

	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		return "", err
	}

	return pkg.Name, err
}

func validatePrimative(primativeType string) error {
	switch primativeType {
	case "string":
		fallthrough
	case "bool":
		fallthrough
	case "pythonstringdict":
		fallthrough
	case "pythondict":
		fallthrough
	case "pythonlist":
		return nil
	default:
		return errors.Errorf("Invalid primative '%s'", primativeType)
	}
}

/*
func (t *{{ .Type }}) Scan(value interface{}) error {
	fmt.Println("VALUE", value, reflect.TypeOf(value))

	s, err := ConvertString(value)
	if err != nil {
		return errors.Wrapf(err, "%s Can't convert '%v' to string %s", reflect.TypeOf(t), value, s)
	}
	*t = RewardTargetId(s)
	return nil
}

func (t RewardTargetId) Value() (driver.Value, error) {
	return string(t), nil
}

func ConvertString(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertInt(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertFloat(value interface{}) (string, error) {
	switch t := value.(type) {
	case string:
		return t, nil
	case []byte:
		return string(t), nil
	case nil:
		return "", nil
	default:
		return "", errors.Errorf("Underlying value %v is not a string")
	}
}

func ConvertBool(value interface{}) (bool, error) {
	b, err := driver.Bool.ConvertValue(value)
	if err != nil {
		return err
	}
	return b.(bool)
}

func (t *StringList) Scan(value interface{}) error {

	if value == nil {
		return nil
	}

	buf, ok := value.([]byte)
	if !ok {
		return errors.Errorf("%s Can't cast '%v' to []byte", reflect.TypeOf(t), value)
	}

	reader := bytes.NewReader(buf)

	list, err := pickle.ListOrTuple(pickle.Unpickle(reader))
	if err != nil {
		return errors.Wrapf(err, "%s Can't convert '%v' to list", reflect.TypeOf(t), value)
	}

	fmt.Println("LIST", list)

	slist := make([]string, 0, len(list))
	for _, l := range list {
		slist = append(slist, l.(string))
	}
	*t = slist
	return nil
}

func (t StringList) Value() (driver.Value, error) {
	buf := new(bytes.Buffer)
	if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (t StringListList) Value() (driver.Value, error) {
	buf := new(bytes.Buffer)
	if _, err := pickle.NewPickler(buf).Pickle(t); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
*/
<|endoftext|>


<commit_before>package cmd

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

	"github.com/pkg/browser"
	"github.com/spf13/cobra"
	"github.com/stormforger/cli/api"
	"github.com/stormforger/cli/api/testrun"
	"github.com/stormforger/cli/internal/stringutil"
)

const defaultNFRData = `version: "0.1"
requirements:
- test.completed: true
- checks:
    select: success_rate
    test: ["=", 1]
- http.error_ratio:
    test: ["=", 0]
`

var (
	// testRunLaunchCmd represents the test run launch command
	testRunLaunchCmd = &cobra.Command{
		Use:   "launch <test-case-ref>",
		Short: "Create and launch a new test run",
		Long: fmt.Sprintf(`Create and launch a new test run based on given test case

<test-case-ref> can be 'organisation-name/test-case-name' or 'test-case-uid'.

Examples
--------
* Launch by organisation and test case name

  forge test-case launch acme-inc/checkout

* Alternatively the test case UID can also be provided

  forge test-case launch xPSX5KXM

Configuration
-------------
You can specify configuration for a test run that will overwrite what is defined
in your JavaScript definition.

* Available cluster sizings:
  * %s

Available cluster regions are available at https://docs.stormforger.com/reference/test-cluster/#cluster-region
`,
			strings.Join(validSizings, "\n  * ")),
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				log.Fatal("Missing argument: test case reference")
			}

			if len(args) > 1 {
				log.Fatal("Too many arguments")
			}

			if testRunLaunchOpts.ClusterRegion != "" && !stringutil.InSlice(testRunLaunchOpts.ClusterRegion, validRegions) {
				log.Fatalf("%s is not a valid region", testRunLaunchOpts.ClusterRegion)
			}

			if testRunLaunchOpts.ClusterSizing != "" && !stringutil.InSlice(testRunLaunchOpts.ClusterSizing, validSizings) {
				log.Fatalf("%s is not a valid sizing", testRunLaunchOpts.ClusterSizing)
			}
		},
		Run: func(cmd *cobra.Command, args []string) {
			client := NewClient()
			MainTestRunLaunch(client, args[0], testRunLaunchOpts)
		},
	}

	testRunLaunchOpts testRunLaunchCmdOpts

	validRegions = []string{
		"ap-east-1",
		"ap-northeast-1",
		"ap-northeast-2",
		"ap-south-1",
		"ap-southeast-1",
		"ap-southeast-2",
		"ca-central-1",
		"eu-central-1",
		"eu-north-1",
		"eu-west-1",
		"eu-west-2",
		"eu-west-3",
		"sa-east-1",
		"us-east-1",
		"us-east-2",
		"us-west-1",
		"us-west-2",
	}

	validSizings = []string{
		"preflight",
		"tiny",
		"small",
		"medium",
		"large",
		"xlarge",
		"2xlarge",
	}
)

type testRunLaunchCmdOpts struct {
	OpenInBrowser bool

	Title                    string
	Notes                    string
	JavascriptDefinitionFile string

	ClusterRegion         string
	ClusterSizing         string
	Watch                 bool
	MaxWatchTime          time.Duration
	CheckNFR              string
	DisableGzip           bool
	SkipWait              bool
	DumpTraffic           bool
	SessionValidationMode bool
	Validate              bool
	TestRunIDOutputFile   string
}

func init() {
	TestCaseCmd.AddCommand(testRunLaunchCmd)

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.TestRunIDOutputFile, "uid-file", "", "Output file for the test-run id")

	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.OpenInBrowser, "open", false, "Open test run in browser")

	testRunLaunchCmd.Flags().StringVarP(&testRunLaunchOpts.Title, "title", "t", "", "Descriptive title of test run")
	testRunLaunchCmd.Flags().StringVarP(&testRunLaunchOpts.Notes, "notes", "n", "", "Longer description (Markdown supported)")

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.ClusterRegion, "region", "", "Region to start test in")
	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.ClusterSizing, "sizing", "", "Cluster sizing to use")

	testRunLaunchCmd.Flags().BoolVarP(&testRunLaunchOpts.Watch, "watch", "w", false, "Automatically watch newly launched test run")
	testRunLaunchCmd.Flags().DurationVar(&testRunLaunchOpts.MaxWatchTime, "watch-timeout", 0, "Maximum duration in seconds to watch")

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.JavascriptDefinitionFile, "test-case-file", "", "Update the test-case definition from this file before the launch")
	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.CheckNFR, "nfr-check-file", "", "Check test result against NFR definition (implies --watch)")

	// options for debugging
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.DisableGzip, "disable-gzip", false, "Globally disable gzip")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.SkipWait, "skip-wait", false, "Ignore defined waits")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.DumpTraffic, "dump-traffic", false, "Create traffic dump")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.SessionValidationMode, "session-validation-mode", false, "Enable session validation mode")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.Validate, "validate", false, "Perform validation run")
}

// MainTestRunLaunch runs a test-case and allows watching and validation that test-run.
// testCaseSpec is required and specifies the test-case to launch.
func MainTestRunLaunch(client *api.Client, testCaseSpec string, testRunLaunchOpts testRunLaunchCmdOpts) {
	testCaseUID := mustLookupTestCase(client, testCaseSpec)

	launchOptions := api.TestRunLaunchOptions{
		Title: testRunLaunchOpts.Title,
		Notes: testRunLaunchOpts.Notes,

		ClusterRegion:         testRunLaunchOpts.ClusterRegion,
		ClusterSizing:         testRunLaunchOpts.ClusterSizing,
		DisableGzip:           testRunLaunchOpts.DisableGzip,
		SkipWait:              testRunLaunchOpts.SkipWait,
		DumpTraffic:           testRunLaunchOpts.DumpTraffic,
		SessionValidationMode: testRunLaunchOpts.SessionValidationMode,
	}
	if testRunLaunchOpts.JavascriptDefinitionFile != "" {
		filename, reader, err := readFromStdinOrReadFromArgument(testRunLaunchOpts.JavascriptDefinitionFile, "test-case.js")
		if err != nil {
			log.Fatalf("Failed to open %s: %v", filename, err)
		}

		launchOptions.JavascriptDefinition.Filename = filename
		launchOptions.JavascriptDefinition.Reader = reader
	}

	if testRunLaunchOpts.Validate {
		launchOptions.SessionValidationMode = true
		launchOptions.ClusterSizing = "preflight"
	}

	status, response, err := client.TestRunCreate(testCaseUID, launchOptions)
	if err != nil {
		log.Fatal(err)
	}

	if !status {
		fmt.Fprintln(os.Stderr, "Could not launch test run!")
		fmt.Println(response)

		os.Exit(1)
	}

	testRun, err := testrun.UnmarshalSingle(strings.NewReader(response))
	if err != nil {
		log.Fatal(err)
	}

	if testRunLaunchOpts.TestRunIDOutputFile != "" {
		f := testRunLaunchOpts.TestRunIDOutputFile
		err := ioutil.WriteFile(f, []byte(testRun.ID), 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write file: %v\n", err)
			os.Exit(1)
		}
	}

	if rootOpts.OutputFormat == "json" {
		fmt.Println(string(response))
	} else {
		// FIXME can we integrate this into testrun.UnmarshalSingle somehow?
		meta, err := api.UnmarshalMeta(strings.NewReader(response))
		if err != nil {
			log.Fatal(err)
		}

		if launchOptions.JavascriptDefinition.Reader != nil {
			fmt.Println("Test-Case successfully updated")
		}

		fmt.Printf(`Launching test %s
UID: %s
Web URL: %s
`,
			testRun.Scope,
			testRun.ID,
			meta.Links.SelfWeb,
		)

		fmt.Printf("Configuration: %s cluster in %s\n", testRun.TestConfiguration.ClusterSizing, testRun.TestConfiguration.ClusterRegion)

		if testRun.TestConfiguration.DisableGzip {
			fmt.Print("  [\u2713] Disabled GZIP\n")
		}
		if testRun.TestConfiguration.SkipWait {
			fmt.Print("  [\u2713] Skip Waits\n")
		}
		if testRun.TestConfiguration.DumpTrafficFull {
			fmt.Print("  [\u2713] Traffic Dump\n")
		}
		if testRun.TestConfiguration.SessionValidationMode {
			fmt.Print("  [\u2713] Session Validation Mode\n")
		}

		if testRunLaunchOpts.OpenInBrowser {
			fmt.Printf("Opening %s in browser...\n", meta.Links.SelfWeb)
			err = browser.OpenURL(meta.Links.SelfWeb)
			if err != nil {
				log.Fatal(err)
			}
		}
	}

	if testRunLaunchOpts.Watch || testRunLaunchOpts.CheckNFR != "" || testRunLaunchOpts.Validate {
		if rootOpts.OutputFormat != "json" {
			fmt.Println("\nWatching...")
		}

		watchTestRun(testRun.ID, testRunLaunchOpts.MaxWatchTime.Round(time.Second).Seconds(), rootOpts.OutputFormat)

		if testRunLaunchOpts.CheckNFR != "" || testRunLaunchOpts.Validate {
			fmt.Println("Test finished, running non-functional checks...")

			fileName := ""
			var nfrData io.Reader
			if testRunLaunchOpts.CheckNFR != "" {
				fileName = filepath.Base(testRunLaunchOpts.CheckNFR)
				nfrData, err = os.OpenFile(testRunLaunchOpts.CheckNFR, os.O_RDONLY, 0755)
				if err != nil {
					log.Fatal(err)
				}
			} else {
				fileName = "validation.yml"
				nfrData = bytes.NewBufferString(defaultNFRData)
			}

			runNfrCheck(*client, testRun.ID, fileName, nfrData)
		} else {
			result := fetchTestRun(*client, testRun.ID)
			fmt.Println(string(result))
		}
	}
}
<commit_msg>fix: parse and format errors from the API for tc launch nicely (#163)<commit_after>package cmd

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

	"github.com/pkg/browser"
	"github.com/spf13/cobra"
	"github.com/stormforger/cli/api"
	"github.com/stormforger/cli/api/testrun"
	"github.com/stormforger/cli/internal/stringutil"
)

const defaultNFRData = `version: "0.1"
requirements:
- test.completed: true
- checks:
    select: success_rate
    test: ["=", 1]
- http.error_ratio:
    test: ["=", 0]
`

var (
	// testRunLaunchCmd represents the test run launch command
	testRunLaunchCmd = &cobra.Command{
		Use:   "launch <test-case-ref>",
		Short: "Create and launch a new test run",
		Long: fmt.Sprintf(`Create and launch a new test run based on given test case

<test-case-ref> can be 'organisation-name/test-case-name' or 'test-case-uid'.

Examples
--------
* Launch by organisation and test case name

  forge test-case launch acme-inc/checkout

* Alternatively the test case UID can also be provided

  forge test-case launch xPSX5KXM

Configuration
-------------
You can specify configuration for a test run that will overwrite what is defined
in your JavaScript definition.

* Available cluster sizings:
  * %s

Available cluster regions are available at https://docs.stormforger.com/reference/test-cluster/#cluster-region
`,
			strings.Join(validSizings, "\n  * ")),
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				log.Fatal("Missing argument: test case reference")
			}

			if len(args) > 1 {
				log.Fatal("Too many arguments")
			}

			if testRunLaunchOpts.ClusterRegion != "" && !stringutil.InSlice(testRunLaunchOpts.ClusterRegion, validRegions) {
				log.Fatalf("%s is not a valid region", testRunLaunchOpts.ClusterRegion)
			}

			if testRunLaunchOpts.ClusterSizing != "" && !stringutil.InSlice(testRunLaunchOpts.ClusterSizing, validSizings) {
				log.Fatalf("%s is not a valid sizing", testRunLaunchOpts.ClusterSizing)
			}
		},
		Run: func(cmd *cobra.Command, args []string) {
			client := NewClient()
			MainTestRunLaunch(client, args[0], testRunLaunchOpts)
		},
	}

	testRunLaunchOpts testRunLaunchCmdOpts

	validRegions = []string{
		"ap-east-1",
		"ap-northeast-1",
		"ap-northeast-2",
		"ap-south-1",
		"ap-southeast-1",
		"ap-southeast-2",
		"ca-central-1",
		"eu-central-1",
		"eu-north-1",
		"eu-west-1",
		"eu-west-2",
		"eu-west-3",
		"sa-east-1",
		"us-east-1",
		"us-east-2",
		"us-west-1",
		"us-west-2",
	}

	validSizings = []string{
		"preflight",
		"tiny",
		"small",
		"medium",
		"large",
		"xlarge",
		"2xlarge",
	}
)

type testRunLaunchCmdOpts struct {
	OpenInBrowser bool

	Title                    string
	Notes                    string
	JavascriptDefinitionFile string

	ClusterRegion         string
	ClusterSizing         string
	Watch                 bool
	MaxWatchTime          time.Duration
	CheckNFR              string
	DisableGzip           bool
	SkipWait              bool
	DumpTraffic           bool
	SessionValidationMode bool
	Validate              bool
	TestRunIDOutputFile   string
}

func init() {
	TestCaseCmd.AddCommand(testRunLaunchCmd)

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.TestRunIDOutputFile, "uid-file", "", "Output file for the test-run id")

	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.OpenInBrowser, "open", false, "Open test run in browser")

	testRunLaunchCmd.Flags().StringVarP(&testRunLaunchOpts.Title, "title", "t", "", "Descriptive title of test run")
	testRunLaunchCmd.Flags().StringVarP(&testRunLaunchOpts.Notes, "notes", "n", "", "Longer description (Markdown supported)")

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.ClusterRegion, "region", "", "Region to start test in")
	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.ClusterSizing, "sizing", "", "Cluster sizing to use")

	testRunLaunchCmd.Flags().BoolVarP(&testRunLaunchOpts.Watch, "watch", "w", false, "Automatically watch newly launched test run")
	testRunLaunchCmd.Flags().DurationVar(&testRunLaunchOpts.MaxWatchTime, "watch-timeout", 0, "Maximum duration in seconds to watch")

	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.JavascriptDefinitionFile, "test-case-file", "", "Update the test-case definition from this file before the launch")
	testRunLaunchCmd.Flags().StringVar(&testRunLaunchOpts.CheckNFR, "nfr-check-file", "", "Check test result against NFR definition (implies --watch)")

	// options for debugging
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.DisableGzip, "disable-gzip", false, "Globally disable gzip")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.SkipWait, "skip-wait", false, "Ignore defined waits")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.DumpTraffic, "dump-traffic", false, "Create traffic dump")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.SessionValidationMode, "session-validation-mode", false, "Enable session validation mode")
	testRunLaunchCmd.Flags().BoolVar(&testRunLaunchOpts.Validate, "validate", false, "Perform validation run")
}

// MainTestRunLaunch runs a test-case and allows watching and validation that test-run.
// testCaseSpec is required and specifies the test-case to launch.
func MainTestRunLaunch(client *api.Client, testCaseSpec string, testRunLaunchOpts testRunLaunchCmdOpts) {
	testCaseUID := mustLookupTestCase(client, testCaseSpec)

	launchOptions := api.TestRunLaunchOptions{
		Title: testRunLaunchOpts.Title,
		Notes: testRunLaunchOpts.Notes,

		ClusterRegion:         testRunLaunchOpts.ClusterRegion,
		ClusterSizing:         testRunLaunchOpts.ClusterSizing,
		DisableGzip:           testRunLaunchOpts.DisableGzip,
		SkipWait:              testRunLaunchOpts.SkipWait,
		DumpTraffic:           testRunLaunchOpts.DumpTraffic,
		SessionValidationMode: testRunLaunchOpts.SessionValidationMode,
	}
	if testRunLaunchOpts.JavascriptDefinitionFile != "" {
		filename, reader, err := readFromStdinOrReadFromArgument(testRunLaunchOpts.JavascriptDefinitionFile, "test-case.js")
		if err != nil {
			log.Fatalf("Failed to open %s: %v", filename, err)
		}

		launchOptions.JavascriptDefinition.Filename = filename
		launchOptions.JavascriptDefinition.Reader = reader
	}

	if testRunLaunchOpts.Validate {
		launchOptions.SessionValidationMode = true
		launchOptions.ClusterSizing = "preflight"
	}

	status, response, err := client.TestRunCreate(testCaseUID, launchOptions)
	if err != nil {
		log.Fatal(err)
	}

	if !status {
		errorMeta, err := api.UnmarshalErrorMeta(strings.NewReader(response))
		if err != nil {
			log.Fatal(err)
		}

		printValidationResultHuman(os.Stderr, launchOptions.JavascriptDefinition.Filename, status, errorMeta)
		cmdExit(status)
	}

	testRun, err := testrun.UnmarshalSingle(strings.NewReader(response))
	if err != nil {
		log.Fatal(err)
	}

	if testRunLaunchOpts.TestRunIDOutputFile != "" {
		f := testRunLaunchOpts.TestRunIDOutputFile
		err := ioutil.WriteFile(f, []byte(testRun.ID), 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write file: %v\n", err)
			os.Exit(1)
		}
	}

	if rootOpts.OutputFormat == "json" {
		fmt.Println(string(response))
	} else {
		// FIXME can we integrate this into testrun.UnmarshalSingle somehow?
		meta, err := api.UnmarshalMeta(strings.NewReader(response))
		if err != nil {
			log.Fatal(err)
		}

		if launchOptions.JavascriptDefinition.Reader != nil {
			fmt.Println("Test-Case successfully updated")
		}

		fmt.Printf(`Launching test %s
UID: %s
Web URL: %s
`,
			testRun.Scope,
			testRun.ID,
			meta.Links.SelfWeb,
		)

		fmt.Printf("Configuration: %s cluster in %s\n", testRun.TestConfiguration.ClusterSizing, testRun.TestConfiguration.ClusterRegion)

		if testRun.TestConfiguration.DisableGzip {
			fmt.Print("  [\u2713] Disabled GZIP\n")
		}
		if testRun.TestConfiguration.SkipWait {
			fmt.Print("  [\u2713] Skip Waits\n")
		}
		if testRun.TestConfiguration.DumpTrafficFull {
			fmt.Print("  [\u2713] Traffic Dump\n")
		}
		if testRun.TestConfiguration.SessionValidationMode {
			fmt.Print("  [\u2713] Session Validation Mode\n")
		}

		if testRunLaunchOpts.OpenInBrowser {
			fmt.Printf("Opening %s in browser...\n", meta.Links.SelfWeb)
			err = browser.OpenURL(meta.Links.SelfWeb)
			if err != nil {
				log.Fatal(err)
			}
		}
	}

	if testRunLaunchOpts.Watch || testRunLaunchOpts.CheckNFR != "" || testRunLaunchOpts.Validate {
		if rootOpts.OutputFormat != "json" {
			fmt.Println("\nWatching...")
		}

		watchTestRun(testRun.ID, testRunLaunchOpts.MaxWatchTime.Round(time.Second).Seconds(), rootOpts.OutputFormat)

		if testRunLaunchOpts.CheckNFR != "" || testRunLaunchOpts.Validate {
			fmt.Println("Test finished, running non-functional checks...")

			fileName := ""
			var nfrData io.Reader
			if testRunLaunchOpts.CheckNFR != "" {
				fileName = filepath.Base(testRunLaunchOpts.CheckNFR)
				nfrData, err = os.OpenFile(testRunLaunchOpts.CheckNFR, os.O_RDONLY, 0755)
				if err != nil {
					log.Fatal(err)
				}
			} else {
				fileName = "validation.yml"
				nfrData = bytes.NewBufferString(defaultNFRData)
			}

			runNfrCheck(*client, testRun.ID, fileName, nfrData)
		} else {
			result := fetchTestRun(*client, testRun.ID)
			fmt.Println(string(result))
		}
	}
}
<|endoftext|>


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

// init is u-root's standard userspace init process.
//
// init is intended to be the first process run by the kernel when it boots up.
// init does some basic initialization (mount file systems, turn on loopback)
// and then tries to execute, in order, /inito, a uinit (either in /bin, /bbin,
// or /ubin), and then a shell (/bin/defaultsh and /bin/sh).
package main

import (
	"flag"
	"fmt"
	"log"
	"os/exec"

	"github.com/u-root/u-root/pkg/libinit"
)

// initCmds has all the bits needed to continue
// the init process after some initial setup.
type initCmds struct {
	cmds []*exec.Cmd
}

var (
	verbose = flag.Bool("v", false, "print all build commands")
	test    = flag.Bool("test", false, "Test mode: don't try to set control tty")
	debug   = func(string, ...interface{}) {}
)

func main() {
	flag.Parse()

	log.Printf("Welcome to u-root!")
	fmt.Println(`                              _`)
	fmt.Println(`   _   _      _ __ ___   ___ | |_`)
	fmt.Println(`  | | | |____| '__/ _ \ / _ \| __|`)
	fmt.Println(`  | |_| |____| | | (_) | (_) | |_`)
	fmt.Println(`   \__,_|    |_|  \___/ \___/ \__|`)
	fmt.Println()

	log.SetPrefix("init: ")

	if *verbose {
		debug = log.Printf
	}

	// Before entering an interactive shell, decrease the loglevel because
	// spamming non-critical logs onto the shell frustrates users. The logs
	// are still accessible through kernel logs buffers (on most kernels).
	quiet()

	libinit.SetEnv()
	libinit.CreateRootfs()
	libinit.NetInit()

	// osInitGo wraps all the kernel-specific (i.e. non-portable) stuff.
	// It returns an initCmds struct derived from kernel-specific information
	// to be used in the rest of init.
	ic := osInitGo()

	cmdCount := libinit.RunCommands(debug, ic.cmds...)
	if cmdCount == 0 {
		log.Printf("No suitable executable found in %v", ic.cmds)
	}

	// We need to reap all children before exiting.
	log.Printf("Waiting for orphaned children")
	libinit.WaitOrphans()
	log.Printf("All commands exited")
	log.Printf("Syncing filesystems")
	if err := quiesce(); err != nil {
		log.Printf("%v", err)
	}
	log.Printf("Exiting...")
}
<commit_msg>cmds/core/init: fix flag message<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// init is u-root's standard userspace init process.
//
// init is intended to be the first process run by the kernel when it boots up.
// init does some basic initialization (mount file systems, turn on loopback)
// and then tries to execute, in order, /inito, a uinit (either in /bin, /bbin,
// or /ubin), and then a shell (/bin/defaultsh and /bin/sh).
package main

import (
	"flag"
	"fmt"
	"log"
	"os/exec"

	"github.com/u-root/u-root/pkg/libinit"
)

// initCmds has all the bits needed to continue
// the init process after some initial setup.
type initCmds struct {
	cmds []*exec.Cmd
}

var (
	verbose = flag.Bool("v", false, "Enable libinit debugging (includes showing commands that are run)")
	test    = flag.Bool("test", false, "Test mode: don't try to set control tty")
	debug   = func(string, ...interface{}) {}
)

func main() {
	flag.Parse()

	log.Printf("Welcome to u-root!")
	fmt.Println(`                              _`)
	fmt.Println(`   _   _      _ __ ___   ___ | |_`)
	fmt.Println(`  | | | |____| '__/ _ \ / _ \| __|`)
	fmt.Println(`  | |_| |____| | | (_) | (_) | |_`)
	fmt.Println(`   \__,_|    |_|  \___/ \___/ \__|`)
	fmt.Println()

	log.SetPrefix("init: ")

	if *verbose {
		debug = log.Printf
	}

	// Before entering an interactive shell, decrease the loglevel because
	// spamming non-critical logs onto the shell frustrates users. The logs
	// are still accessible through kernel logs buffers (on most kernels).
	quiet()

	libinit.SetEnv()
	libinit.CreateRootfs()
	libinit.NetInit()

	// osInitGo wraps all the kernel-specific (i.e. non-portable) stuff.
	// It returns an initCmds struct derived from kernel-specific information
	// to be used in the rest of init.
	ic := osInitGo()

	cmdCount := libinit.RunCommands(debug, ic.cmds...)
	if cmdCount == 0 {
		log.Printf("No suitable executable found in %v", ic.cmds)
	}

	// We need to reap all children before exiting.
	log.Printf("Waiting for orphaned children")
	libinit.WaitOrphans()
	log.Printf("All commands exited")
	log.Printf("Syncing filesystems")
	if err := quiesce(); err != nil {
		log.Printf("%v", err)
	}
	log.Printf("Exiting...")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"

	rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
	"github.com/tendermint/tmlibs/log"
)

const (
	sendTimeout = 10 * time.Second
	// see https://github.com/tendermint/go-rpc/blob/develop/server/handlers.go#L313
	pingPeriod = (30 * 9 / 10) * time.Second
)

type transacter struct {
	Target      string
	Rate        int
	Connections int

	conns   []*websocket.Conn
	wg      sync.WaitGroup
	stopped bool

	logger log.Logger
}

func newTransacter(target string, connections int, rate int) *transacter {
	return &transacter{
		Target:      target,
		Rate:        rate,
		Connections: connections,
		conns:       make([]*websocket.Conn, connections),
		logger:      log.NewNopLogger(),
	}
}

// SetLogger lets you set your own logger
func (t *transacter) SetLogger(l log.Logger) {
	t.logger = l
}

// Start opens N = `t.Connections` connections to the target and creates read
// and write goroutines for each connection.
func (t *transacter) Start() error {
	t.stopped = false

	for i := 0; i < t.Connections; i++ {
		c, _, err := connect(t.Target)
		if err != nil {
			return err
		}
		t.conns[i] = c
	}

	t.wg.Add(2 * t.Connections)
	for i := 0; i < t.Connections; i++ {
		go t.sendLoop(i)
		go t.receiveLoop(i)
	}

	return nil
}

// Stop closes the connections.
func (t *transacter) Stop() {
	t.stopped = true
	t.wg.Wait()
	for _, c := range t.conns {
		c.Close()
	}
}

// receiveLoop reads messages from the connection (empty in case of
// `broadcast_tx_async`).
func (t *transacter) receiveLoop(connIndex int) {
	c := t.conns[connIndex]
	defer t.wg.Done()
	for {
		_, _, err := c.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
				t.logger.Error("failed to read response", "err", err)
			}
			return
		}
		if t.stopped {
			return
		}
	}
}

// sendLoop generates transactions at a given rate.
func (t *transacter) sendLoop(connIndex int) {
	c := t.conns[connIndex]
	logger := t.logger.With("addr", c.RemoteAddr())

	var txNumber = 0

	pingsTicker := time.NewTicker(pingPeriod)
	txsTicker := time.NewTicker(1 * time.Second)
	defer func() {
		pingsTicker.Stop()
		txsTicker.Stop()
		t.wg.Done()
	}()

	for {
		select {
		case <-txsTicker.C:
			startTime := time.Now()

			for i := 0; i < t.Rate; i++ {
				// each transaction embeds connection index and tx number
				tx := generateTx(connIndex, txNumber)
				paramsJson, err := json.Marshal(map[string]interface{}{"tx": hex.EncodeToString(tx)})
				if err != nil {
					fmt.Printf("failed to encode params: %v\n", err)
					os.Exit(1)
				}
				rawParamsJson := json.RawMessage(paramsJson)

				c.SetWriteDeadline(time.Now().Add(sendTimeout))
				err = c.WriteJSON(rpctypes.RPCRequest{
					JSONRPC: "2.0",
					ID:      "",
					Method:  "broadcast_tx_async",
					Params:  &rawParamsJson,
				})
				if err != nil {
					fmt.Printf("%v. Try increasing the connections count and reducing the rate.\n", errors.Wrap(err, "txs send failed"))
					os.Exit(1)
				}

				txNumber++
			}

			timeToSend := time.Now().Sub(startTime)
			time.Sleep(time.Second - timeToSend)
			logger.Info(fmt.Sprintf("sent %d transactions", t.Rate), "took", timeToSend)
		case <-pingsTicker.C:
			// Right now go-rpc server closes the connection in the absence of pings
			c.SetWriteDeadline(time.Now().Add(sendTimeout))
			if err := c.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				logger.Error("failed to write ping message", "err", err)
			}
		}

		if t.stopped {
			// To cleanly close a connection, a client should send a close
			// frame and wait for the server to close the connection.
			c.SetWriteDeadline(time.Now().Add(sendTimeout))
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				logger.Error("failed to write close message", "err", err)
			}

			return
		}
	}
}

func connect(host string) (*websocket.Conn, *http.Response, error) {
	u := url.URL{Scheme: "ws", Host: host, Path: "/websocket"}
	return websocket.DefaultDialer.Dial(u.String(), nil)
}

func generateTx(a int, b int) []byte {
	tx := make([]byte, 250)
	binary.PutUvarint(tx[:32], uint64(a))
	binary.PutUvarint(tx[32:64], uint64(b))
	if _, err := rand.Read(tx[234:]); err != nil {
		panic(errors.Wrap(err, "failed to generate transaction"))
	}
	return tx
}
<commit_msg>[tm-bench] increase pong write timeout by overriding the default handler<commit_after>package main

import (
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"

	rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
	"github.com/tendermint/tmlibs/log"
)

const (
	sendTimeout = 10 * time.Second
	// see https://github.com/tendermint/go-rpc/blob/develop/server/handlers.go#L313
	pingPeriod = (30 * 9 / 10) * time.Second
)

type transacter struct {
	Target      string
	Rate        int
	Connections int

	conns   []*websocket.Conn
	wg      sync.WaitGroup
	stopped bool

	logger log.Logger
}

func newTransacter(target string, connections int, rate int) *transacter {
	return &transacter{
		Target:      target,
		Rate:        rate,
		Connections: connections,
		conns:       make([]*websocket.Conn, connections),
		logger:      log.NewNopLogger(),
	}
}

// SetLogger lets you set your own logger
func (t *transacter) SetLogger(l log.Logger) {
	t.logger = l
}

// Start opens N = `t.Connections` connections to the target and creates read
// and write goroutines for each connection.
func (t *transacter) Start() error {
	t.stopped = false

	for i := 0; i < t.Connections; i++ {
		c, _, err := connect(t.Target)
		if err != nil {
			return err
		}
		t.conns[i] = c
	}

	t.wg.Add(2 * t.Connections)
	for i := 0; i < t.Connections; i++ {
		go t.sendLoop(i)
		go t.receiveLoop(i)
	}

	return nil
}

// Stop closes the connections.
func (t *transacter) Stop() {
	t.stopped = true
	t.wg.Wait()
	for _, c := range t.conns {
		c.Close()
	}
}

// receiveLoop reads messages from the connection (empty in case of
// `broadcast_tx_async`).
func (t *transacter) receiveLoop(connIndex int) {
	c := t.conns[connIndex]
	defer t.wg.Done()
	for {
		_, _, err := c.ReadMessage()
		if err != nil {
			if !websocket.IsCloseError(err, websocket.CloseNormalClosure) {
				t.logger.Error("failed to read response", "err", err)
			}
			return
		}
		if t.stopped {
			return
		}
	}
}

// sendLoop generates transactions at a given rate.
func (t *transacter) sendLoop(connIndex int) {
	c := t.conns[connIndex]

	c.SetPingHandler(func(message string) error {
		err := c.WriteControl(websocket.PongMessage, []byte(message), time.Now().Add(sendTimeout))
		if err == websocket.ErrCloseSent {
			return nil
		} else if e, ok := err.(net.Error); ok && e.Temporary() {
			return nil
		}
		return err
	})

	logger := t.logger.With("addr", c.RemoteAddr())

	var txNumber = 0

	pingsTicker := time.NewTicker(pingPeriod)
	txsTicker := time.NewTicker(1 * time.Second)
	defer func() {
		pingsTicker.Stop()
		txsTicker.Stop()
		t.wg.Done()
	}()

	for {
		select {
		case <-txsTicker.C:
			startTime := time.Now()

			for i := 0; i < t.Rate; i++ {
				// each transaction embeds connection index and tx number
				tx := generateTx(connIndex, txNumber)
				paramsJson, err := json.Marshal(map[string]interface{}{"tx": hex.EncodeToString(tx)})
				if err != nil {
					fmt.Printf("failed to encode params: %v\n", err)
					os.Exit(1)
				}
				rawParamsJson := json.RawMessage(paramsJson)

				c.SetWriteDeadline(time.Now().Add(sendTimeout))
				err = c.WriteJSON(rpctypes.RPCRequest{
					JSONRPC: "2.0",
					ID:      "",
					Method:  "broadcast_tx_async",
					Params:  &rawParamsJson,
				})
				if err != nil {
					fmt.Printf("%v. Try increasing the connections count and reducing the rate.\n", errors.Wrap(err, "txs send failed"))
					os.Exit(1)
				}

				txNumber++
			}

			timeToSend := time.Now().Sub(startTime)
			time.Sleep(time.Second - timeToSend)
			logger.Info(fmt.Sprintf("sent %d transactions", t.Rate), "took", timeToSend)
		case <-pingsTicker.C:
			// Right now go-rpc server closes the connection in the absence of pings
			c.SetWriteDeadline(time.Now().Add(sendTimeout))
			if err := c.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				logger.Error("failed to write ping message", "err", err)
			}
		}

		if t.stopped {
			// To cleanly close a connection, a client should send a close
			// frame and wait for the server to close the connection.
			c.SetWriteDeadline(time.Now().Add(sendTimeout))
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				logger.Error("failed to write close message", "err", err)
			}

			return
		}
	}
}

func connect(host string) (*websocket.Conn, *http.Response, error) {
	u := url.URL{Scheme: "ws", Host: host, Path: "/websocket"}
	return websocket.DefaultDialer.Dial(u.String(), nil)
}

func generateTx(a int, b int) []byte {
	tx := make([]byte, 250)
	binary.PutUvarint(tx[:32], uint64(a))
	binary.PutUvarint(tx[32:64], uint64(b))
	if _, err := rand.Read(tx[234:]); err != nil {
		panic(errors.Wrap(err, "failed to generate transaction"))
	}
	return tx
}
<|endoftext|>


<commit_before>package hashvalues

import (
	"hash"
	"net/url"
)

type HashValues struct {
	Values   *url.Values
	hashfunc hash.Hash
	hashkey  []byte
}

func NewHashValues(hashkey []byte, hashfunc hash.Hash) *HashValues {
	return &HashValues{
		Values:   &url.Values{},
		hashfunc: hashfunc,
		hashkey:  hashkey,
	}
}

func (h *HashValues) Set(key, value string) {
	h.Values.Set(key, value)
}

func (h *HashValues) Add(key, value string) {
	h.Values.Add(key, value)
}

func (h *HashValues) Del(key string) {
	h.Values.Del(key)
}

func (h *HashValues) Get(key string) string {
	return h.Values.Get(key)
}
<commit_msg>Add Parse.<commit_after>package hashvalues

import (
	"crypto/hmac"
	"errors"
	"hash"
	"net/url"
)

type HashValues struct {
	Values   url.Values
	hashfunc func() hash.Hash
	hashkey  []byte
}

func NewHashValues(hashkey []byte, hashfunc func() hash.Hash) *HashValues {
	return &HashValues{
		Values:   url.Values{},
		hashfunc: hashfunc,
		hashkey:  hashkey,
	}
}

func (h *HashValues) Set(key, value string) {
	h.Values.Set(key, value)
}

func (h *HashValues) Add(key, value string) {
	h.Values.Add(key, value)
}

func (h *HashValues) Del(key string) {
	h.Values.Del(key)
}

func (h *HashValues) Get(key string) string {
	return h.Values.Get(key)
}

func (h *HashValues) Parse(message string) error {
	var err error
	if hmac.Equal(h.hashkey, hmac.New(h.hashfunc, h.hashkey).Sum([]byte(message))) {
		h.Values, err = url.ParseQuery(message)
	} else {
		err = errors.New("wrong key!")
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/subtle"
	"encoding/base64"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/nfnt/resize"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/oliamb/cutter"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/rlmcpherson/s3gof3r"
)

var (
	maxAge           int
	securityKey      []byte
	resultBucketName string
	useRRS           bool

	httpClient   *http.Client
	resultBucket *s3gof3r.Bucket
)

func main() {
	securityKey = []byte(mustGetenv("SECURITY_KEY"))
	resultBucketName = mustGetenv("RESULT_STORAGE_BUCKET")

	if maxAgeStr := os.Getenv("MAX_AGE"); maxAgeStr != "" {
		var err error
		if maxAge, err = strconv.Atoi(maxAgeStr); err != nil {
			log.Fatal("invalid MAX_AGE setting")
		}
	}
	if rrs := os.Getenv("USE_RRS"); rrs == "true" || rrs == "1" {
		useRRS = true
	}

	keys, err := s3gof3r.EnvKeys()
	if err != nil {
		log.Fatal(err)
	}
	resultBucket = s3gof3r.New(s3gof3r.DefaultDomain, keys).Bucket(resultBucketName)
	resultBucket.Md5Check = true
	httpClient = resultBucket.Client

	router := httprouter.New()
	router.HEAD("/:signature/:size/*source", handleResize)
	router.GET("/:signature/:size/*source", handleResize)
	log.Fatal(http.ListenAndServe(":8888", router))
}

func handleResize(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	log.Printf(req.Method + " " + req.URL.Path)
	sourceURL, err := url.Parse(strings.TrimPrefix(params.ByName("source"), "/"))
	if err != nil || !(sourceURL.Scheme == "http" || sourceURL.Scheme == "https") {
		http.Error(w, "invalid source URL", 400)
		return
	}

	sig := params.ByName("signature")
	pathToVerify := strings.TrimPrefix(req.URL.Path, "/"+sig+"/")
	if err := validateSignature(sig, pathToVerify); err != nil {
		http.Error(w, "invalid signature", 401)
		return
	}

	width, height, err := parseWidthAndHeight(params.ByName("size"))
	if err != nil {
		http.Error(w, "invalid height requested", 400)
		return
	}

	// TODO(bgentry): normalize path. Support for custom root path? ala RESULT_STORAGE_AWS_STORAGE_ROOT_PATH

	// try to get stored result
	r, h, err := resultBucket.GetReader(req.URL.Path, nil)
	if err != nil {
		generateThumbnail(w, req, sourceURL.String(), width, height)
		return
	}

	// return stored result
	length, err := strconv.Atoi(h.Get("Content-Length"))
	if err != nil {
		fmt.Printf("invalid result content-length: %s", err)
		// TODO: try to generate instead of erroring w/ 500?
		http.Error(w, err.Error(), 500)
		return
	}

	setResultHeaders(w, &result{
		ContentType:   "image/jpeg", // TODO: use stored content type
		ContentLength: length,
		ETag:          strings.Trim(h.Get("Etag"), `"`),
		Path:          req.URL.Path,
	})
	if _, err = io.Copy(w, r); err != nil {
		fmt.Printf("copying from stored result: %s", err)
		http.Error(w, err.Error(), 500)
		return
	}
}

func generateThumbnail(w http.ResponseWriter, req *http.Request, sourceURL string, width, height uint) {
	resp, err := httpClient.Get(sourceURL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		copyHeader(w.Header(), resp.Header)
		io.Copy(w, resp.Body)
		return
	}

	contentType := resp.Header.Get("Content-Type")
	if !strings.HasPrefix(contentType, "image/") {
		http.Error(w, fmt.Sprintf("invalid content type %q", contentType), 500)
		return
	}

	img, _, err := image.Decode(resp.Body)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	// crop to final aspect ratio before resizing
	croppedImg, err := cutter.Crop(img, cutter.Config{
		Width:   int(width),
		Height:  int(height),
		Mode:    cutter.Centered,
		Options: cutter.Ratio,
	})

	imgResized := resize.Resize(width, height, croppedImg, resize.Bicubic)
	var buf bytes.Buffer
	if err := jpeg.Encode(&buf, imgResized, nil); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	res := &result{
		ContentType:   "image/jpeg",
		ContentLength: buf.Len(),
		Data:          buf.Bytes(), // TODO: check if I need to copy this
		ETag:          computeHexMD5(buf.Bytes()),
		Path:          req.URL.Path,
	}
	setResultHeaders(w, res)
	if req.Method != "HEAD" {
		if _, err = buf.WriteTo(w); err != nil {
			log.Printf("writing buffer to response: %s", err)
		}
	}

	go storeResult(res)
}

func setResultHeaders(w http.ResponseWriter, result *result) {
	w.Header().Set("Content-Type", result.ContentType)
	w.Header().Set("Content-Length", strconv.Itoa(result.ContentLength))
	w.Header().Set("ETag", `"`+result.ETag+`"`)
	setCacheHeaders(w)
}

func storeResult(res *result) {
	h := make(http.Header)
	h.Set("Content-Type", res.ContentType)
	if useRRS {
		h.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
	}
	w, err := resultBucket.PutWriter(res.Path, h, nil)
	if err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
		return
	}
	defer w.Close()
	if _, err = w.Write(res.Data); err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
		return
	}
	if err = w.Close(); err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
	}
}

type result struct {
	Data          []byte
	ContentType   string
	ContentLength int
	ETag          string
	Path          string
}

func computeHexMD5(data []byte) string {
	h := md5.New()
	h.Write(data)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func mustGetenv(name string) string {
	value := os.Getenv(name)
	if value == "" {
		log.Fatalf("missing %s env", name)
	}
	return value
}

func parseWidthAndHeight(str string) (width, height uint, err error) {
	sizeParts := strings.Split(str, "x")
	if len(sizeParts) != 2 {
		err = fmt.Errorf("invalid size requested")
		return
	}
	width64, err := strconv.ParseUint(sizeParts[0], 10, 64)
	if err != nil {
		err = fmt.Errorf("invalid width requested")
		return
	}
	height64, err := strconv.ParseUint(sizeParts[1], 10, 64)
	if err != nil {
		err = fmt.Errorf("invalid height requested")
		return
	}
	return uint(width64), uint(height64), nil
}

func setCacheHeaders(w http.ResponseWriter) {
	w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d,public", maxAge))
	w.Header().Set("Expires", time.Now().UTC().Add(time.Duration(maxAge)*time.Second).Format(http.TimeFormat))
}

func validateSignature(sig, pathPart string) error {
	h := hmac.New(sha1.New, securityKey)
	if _, err := h.Write([]byte(pathPart)); err != nil {
		return err
	}
	actualSig := base64.StdEncoding.EncodeToString(h.Sum(nil))
	// constant-time string comparison
	if subtle.ConstantTimeCompare([]byte(sig), []byte(actualSig)) != 1 {
		return fmt.Errorf("signature mismatch")
	}
	return nil
}
<commit_msg>support PORT env<commit_after>package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/subtle"
	"encoding/base64"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/nfnt/resize"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/oliamb/cutter"
	"github.com/opendoor-labs/gothumb/Godeps/_workspace/src/github.com/rlmcpherson/s3gof3r"
)

var (
	maxAge           int
	securityKey      []byte
	resultBucketName string
	useRRS           bool

	httpClient   *http.Client
	resultBucket *s3gof3r.Bucket
)

func main() {
	securityKey = []byte(mustGetenv("SECURITY_KEY"))
	resultBucketName = mustGetenv("RESULT_STORAGE_BUCKET")

	if maxAgeStr := os.Getenv("MAX_AGE"); maxAgeStr != "" {
		var err error
		if maxAge, err = strconv.Atoi(maxAgeStr); err != nil {
			log.Fatal("invalid MAX_AGE setting")
		}
	}
	if rrs := os.Getenv("USE_RRS"); rrs == "true" || rrs == "1" {
		useRRS = true
	}

	keys, err := s3gof3r.EnvKeys()
	if err != nil {
		log.Fatal(err)
	}
	resultBucket = s3gof3r.New(s3gof3r.DefaultDomain, keys).Bucket(resultBucketName)
	resultBucket.Md5Check = true
	httpClient = resultBucket.Client

	router := httprouter.New()
	router.HEAD("/:signature/:size/*source", handleResize)
	router.GET("/:signature/:size/*source", handleResize)
	port := os.Getenv("PORT")
	if port == "" {
		port = "8888"
	}
	log.Fatal(http.ListenAndServe(":"+port, router))
}

func handleResize(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	log.Printf(req.Method + " " + req.URL.Path)
	sourceURL, err := url.Parse(strings.TrimPrefix(params.ByName("source"), "/"))
	if err != nil || !(sourceURL.Scheme == "http" || sourceURL.Scheme == "https") {
		http.Error(w, "invalid source URL", 400)
		return
	}

	sig := params.ByName("signature")
	pathToVerify := strings.TrimPrefix(req.URL.Path, "/"+sig+"/")
	if err := validateSignature(sig, pathToVerify); err != nil {
		http.Error(w, "invalid signature", 401)
		return
	}

	width, height, err := parseWidthAndHeight(params.ByName("size"))
	if err != nil {
		http.Error(w, "invalid height requested", 400)
		return
	}

	// TODO(bgentry): normalize path. Support for custom root path? ala RESULT_STORAGE_AWS_STORAGE_ROOT_PATH

	// try to get stored result
	r, h, err := resultBucket.GetReader(req.URL.Path, nil)
	if err != nil {
		generateThumbnail(w, req, sourceURL.String(), width, height)
		return
	}

	// return stored result
	length, err := strconv.Atoi(h.Get("Content-Length"))
	if err != nil {
		fmt.Printf("invalid result content-length: %s", err)
		// TODO: try to generate instead of erroring w/ 500?
		http.Error(w, err.Error(), 500)
		return
	}

	setResultHeaders(w, &result{
		ContentType:   "image/jpeg", // TODO: use stored content type
		ContentLength: length,
		ETag:          strings.Trim(h.Get("Etag"), `"`),
		Path:          req.URL.Path,
	})
	if _, err = io.Copy(w, r); err != nil {
		fmt.Printf("copying from stored result: %s", err)
		http.Error(w, err.Error(), 500)
		return
	}
}

func generateThumbnail(w http.ResponseWriter, req *http.Request, sourceURL string, width, height uint) {
	resp, err := httpClient.Get(sourceURL)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		copyHeader(w.Header(), resp.Header)
		io.Copy(w, resp.Body)
		return
	}

	contentType := resp.Header.Get("Content-Type")
	if !strings.HasPrefix(contentType, "image/") {
		http.Error(w, fmt.Sprintf("invalid content type %q", contentType), 500)
		return
	}

	img, _, err := image.Decode(resp.Body)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	// crop to final aspect ratio before resizing
	croppedImg, err := cutter.Crop(img, cutter.Config{
		Width:   int(width),
		Height:  int(height),
		Mode:    cutter.Centered,
		Options: cutter.Ratio,
	})

	imgResized := resize.Resize(width, height, croppedImg, resize.Bicubic)
	var buf bytes.Buffer
	if err := jpeg.Encode(&buf, imgResized, nil); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	res := &result{
		ContentType:   "image/jpeg",
		ContentLength: buf.Len(),
		Data:          buf.Bytes(), // TODO: check if I need to copy this
		ETag:          computeHexMD5(buf.Bytes()),
		Path:          req.URL.Path,
	}
	setResultHeaders(w, res)
	if req.Method != "HEAD" {
		if _, err = buf.WriteTo(w); err != nil {
			log.Printf("writing buffer to response: %s", err)
		}
	}

	go storeResult(res)
}

func setResultHeaders(w http.ResponseWriter, result *result) {
	w.Header().Set("Content-Type", result.ContentType)
	w.Header().Set("Content-Length", strconv.Itoa(result.ContentLength))
	w.Header().Set("ETag", `"`+result.ETag+`"`)
	setCacheHeaders(w)
}

func storeResult(res *result) {
	h := make(http.Header)
	h.Set("Content-Type", res.ContentType)
	if useRRS {
		h.Set("x-amz-storage-class", "REDUCED_REDUNDANCY")
	}
	w, err := resultBucket.PutWriter(res.Path, h, nil)
	if err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
		return
	}
	defer w.Close()
	if _, err = w.Write(res.Data); err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
		return
	}
	if err = w.Close(); err != nil {
		log.Printf("storing result for %s: %s", res.Path, err)
	}
}

type result struct {
	Data          []byte
	ContentType   string
	ContentLength int
	ETag          string
	Path          string
}

func computeHexMD5(data []byte) string {
	h := md5.New()
	h.Write(data)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func mustGetenv(name string) string {
	value := os.Getenv(name)
	if value == "" {
		log.Fatalf("missing %s env", name)
	}
	return value
}

func parseWidthAndHeight(str string) (width, height uint, err error) {
	sizeParts := strings.Split(str, "x")
	if len(sizeParts) != 2 {
		err = fmt.Errorf("invalid size requested")
		return
	}
	width64, err := strconv.ParseUint(sizeParts[0], 10, 64)
	if err != nil {
		err = fmt.Errorf("invalid width requested")
		return
	}
	height64, err := strconv.ParseUint(sizeParts[1], 10, 64)
	if err != nil {
		err = fmt.Errorf("invalid height requested")
		return
	}
	return uint(width64), uint(height64), nil
}

func setCacheHeaders(w http.ResponseWriter) {
	w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d,public", maxAge))
	w.Header().Set("Expires", time.Now().UTC().Add(time.Duration(maxAge)*time.Second).Format(http.TimeFormat))
}

func validateSignature(sig, pathPart string) error {
	h := hmac.New(sha1.New, securityKey)
	if _, err := h.Write([]byte(pathPart)); err != nil {
		return err
	}
	actualSig := base64.StdEncoding.EncodeToString(h.Sum(nil))
	// constant-time string comparison
	if subtle.ConstantTimeCompare([]byte(sig), []byte(actualSig)) != 1 {
		return fmt.Errorf("signature mismatch")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"

	"code.google.com/p/gogoprotobuf/proto"

	cspb "github.com/grobian/carbonserver/carbonserverpb"
)

type zipper string

var Zipper zipper

// FIXME(dgryski): extract the http.Get + unproto code into its own function

func (z zipper) Find(metric string) (cspb.GlobResponse, error) {

	u, _ := url.Parse(string(z) + "/metrics/find/")

	u.RawQuery = url.Values{
		"query":  []string{metric},
		"format": []string{"protobuf"},
	}.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Printf("Find: http.Get: %+v\n", err)
		return cspb.GlobResponse{}, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Find: ioutil.ReadAll: %+v\n", err)
		return cspb.GlobResponse{}, err
	}

	var pbresp cspb.GlobResponse

	err = proto.Unmarshal(body, &pbresp)
	if err != nil {
		log.Printf("Find: proto.Unmarshal: %+v\n", err)
		return cspb.GlobResponse{}, err
	}

	return pbresp, nil
}

func (z zipper) Render(metric, from, until string) (cspb.FetchResponse, error) {

	u, _ := url.Parse(string(z) + "/render/")

	u.RawQuery = url.Values{
		"target": []string{metric},
		"format": []string{"protobuf"},
		"from":   []string{from},
		"until":  []string{until},
	}.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Printf("Render: http.Get: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Render: ioutil.ReadAll: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}

	var pbresp cspb.FetchResponse

	err = proto.Unmarshal(body, &pbresp)
	if err != nil {
		log.Printf("Render: proto.Unmarshal: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}

	return pbresp, nil
}

func queryHandler(w http.ResponseWriter, r *http.Request) {

	target := r.FormValue("target")
	from := r.FormValue("from")
	until := r.FormValue("until")

	// query zipper for find
	glob, err := Zipper.Find(target)
	if err != nil {
		return
	}

	var results []cspb.FetchResponse

	// for each server in find response query render
	// TODO(dgryski): run this in parallel
	for _, m := range glob.GetMatches() {
		if m.GetIsLeaf() {
			r, err := Zipper.Render(m.GetPath(), from, until)
			if err != nil {
				continue
			}
			results = append(results, r)
		}
	}

	w.Header().Set("Content-Type", "application/json")
	jEnc := json.NewEncoder(w)
	jEnc.Encode(results)
}

func main() {

	z := flag.String("z", "", "zipper")
	port := flag.Int("p", 8080, "port")

	flag.Parse()

	if *z == "" {
		log.Fatal("no zipper (-z) provided")
	}

	if _, err := url.Parse(*z); err != nil {
		log.Fatal("unable to parze zipper:", err)
	}

	Zipper = zipper(*z)

	http.HandleFunc("/query", queryHandler)

	log.Println("listening on port", *port)
	log.Fatalln(http.ListenAndServe(":"+strconv.Itoa(*port), nil))

}
<commit_msg>match graphite's API endpoint better<commit_after>package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"

	"code.google.com/p/gogoprotobuf/proto"

	cspb "github.com/grobian/carbonserver/carbonserverpb"
)

type zipper string

var Zipper zipper

// FIXME(dgryski): extract the http.Get + unproto code into its own function

func (z zipper) Find(metric string) (cspb.GlobResponse, error) {

	u, _ := url.Parse(string(z) + "/metrics/find/")

	u.RawQuery = url.Values{
		"query":  []string{metric},
		"format": []string{"protobuf"},
	}.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Printf("Find: http.Get: %+v\n", err)
		return cspb.GlobResponse{}, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Find: ioutil.ReadAll: %+v\n", err)
		return cspb.GlobResponse{}, err
	}

	var pbresp cspb.GlobResponse

	err = proto.Unmarshal(body, &pbresp)
	if err != nil {
		log.Printf("Find: proto.Unmarshal: %+v\n", err)
		return cspb.GlobResponse{}, err
	}

	return pbresp, nil
}

func (z zipper) Render(metric, from, until string) (cspb.FetchResponse, error) {

	u, _ := url.Parse(string(z) + "/render/")

	u.RawQuery = url.Values{
		"target": []string{metric},
		"format": []string{"protobuf"},
		"from":   []string{from},
		"until":  []string{until},
	}.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Printf("Render: http.Get: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Render: ioutil.ReadAll: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}

	var pbresp cspb.FetchResponse

	err = proto.Unmarshal(body, &pbresp)
	if err != nil {
		log.Printf("Render: proto.Unmarshal: %s: %+v\n", metric, err)
		return cspb.FetchResponse{}, err
	}

	return pbresp, nil
}

func renderHandler(w http.ResponseWriter, r *http.Request) {

	target := r.FormValue("target")
	from := r.FormValue("from")
	until := r.FormValue("until")

	// query zipper for find
	glob, err := Zipper.Find(target)
	if err != nil {
		return
	}

	var results []cspb.FetchResponse

	// for each server in find response query render
	// TODO(dgryski): run this in parallel
	for _, m := range glob.GetMatches() {
		if m.GetIsLeaf() {
			r, err := Zipper.Render(m.GetPath(), from, until)
			if err != nil {
				continue
			}
			results = append(results, r)
		}
	}

	w.Header().Set("Content-Type", "application/json")
	jEnc := json.NewEncoder(w)
	jEnc.Encode(results)
}

func main() {

	z := flag.String("z", "", "zipper")
	port := flag.Int("p", 8080, "port")

	flag.Parse()

	if *z == "" {
		log.Fatal("no zipper (-z) provided")
	}

	if _, err := url.Parse(*z); err != nil {
		log.Fatal("unable to parze zipper:", err)
	}

	Zipper = zipper(*z)

	http.HandleFunc("/render/", renderHandler)

	log.Println("listening on port", *port)
	log.Fatalln(http.ListenAndServe(":"+strconv.Itoa(*port), nil))

}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"
	"path/filepath"
	"runtime"

	"github.com/cuigh/auxo/app"
	"github.com/cuigh/auxo/app/flag"
	_ "github.com/cuigh/auxo/cache/memory"
	"github.com/cuigh/auxo/config"
	"github.com/cuigh/auxo/data/valid"
	"github.com/cuigh/auxo/log"
	"github.com/cuigh/auxo/net/web"
	"github.com/cuigh/auxo/net/web/filter"
	"github.com/cuigh/auxo/net/web/filter/auth"
	"github.com/cuigh/auxo/net/web/renderer/jet"
	"github.com/cuigh/swirl/biz"
	"github.com/cuigh/swirl/controller"
	"github.com/cuigh/swirl/misc"
	"github.com/cuigh/swirl/model"
	"github.com/cuigh/swirl/scaler"
	"github.com/cuigh/swirl/security"
)

func main() {
	misc.BindOptions()

	app.Name = "Swirl"
	app.Version = "0.8.0"
	app.Desc = "A web management UI for Docker, focused on swarm cluster"
	app.Action = func(ctx *app.Context) {
		err := config.UnmarshalOption("swirl", &misc.Options)
		if err != nil {
			log.Get(app.Name).Error("Failed to load options: ", err)
			os.Exit(1)
		}

		setting, err := biz.Setting.Get()
		if err != nil {
			log.Get(app.Name).Error("Failed to load settings: ", err)
			os.Exit(1)
		}

		biz.Stack.Migrate()
		if setting.Metrics.Prometheus != "" {
			scaler.Start()
		}
		app.Run(server(setting))
	}
	app.Flags.Register(flag.All)
	app.Start()
}

func server(setting *model.Setting) *web.Server {
	ws := web.Auto()

	// customize error handler
	ws.ErrorHandler.OnCode(http.StatusNotFound, func(ctx web.Context, err error) {
		if ctx.IsAJAX() {
			ctx.Status(http.StatusNotFound).HTML(http.StatusText(http.StatusNotFound)) // nolint: gas
		} else {
			ctx.Status(http.StatusNotFound).Render("404", nil) // nolint: gas
		}
	})
	ws.ErrorHandler.OnCode(http.StatusForbidden, func(ctx web.Context, err error) {
		if ctx.IsAJAX() {
			ctx.Status(http.StatusForbidden).HTML("You do not have permission to perform this operation") // nolint: gas
		} else {
			ctx.Status(http.StatusForbidden).Render("403", nil) // nolint: gas
		}
	})

	// set render
	ws.Validator = &valid.Validator{Tag: "valid"}
	ws.Renderer = jet.Must(jet.Debug(config.GetBool("debug")), jet.VarMap(misc.Funcs), jet.VarMap(map[string]interface{}{
		"language":   setting.Language,
		"version":    app.Version,
		"go_version": runtime.Version(),
		"time":       misc.FormatTime(setting.TimeZone.Offset),
		"i18n":       misc.Message(setting.Language),
	}))

	// register global filters
	ws.Use(filter.NewRecover())

	// register static handlers
	ws.File("/favicon.ico", filepath.Join(filepath.Dir(app.Path()), "assets/swirl/img/favicon.ico"))
	ws.Static("/assets", filepath.Join(filepath.Dir(app.Path()), "assets"))

	// create biz group
	form := &auth.Form{
		Identifier:        security.Identifier,
		Timeout:           misc.Options.AuthTimeout,
		SlidingExpiration: true,
	}
	g := ws.Group("", form, filter.NewAuthorizer(security.Checker))

	// register auth handlers
	g.Post("/login", form.LoginJSON(security.Validator(setting)), web.WithName("login"), web.WithAuthorize(web.AuthAnonymous))
	g.Get("/logout", form.Logout, web.WithName("logout"), web.WithAuthorize(web.AuthAuthenticated))

	// register controllers
	g.Handle("", controller.Home())
	g.Handle("/profile", controller.Profile())
	g.Handle("/registry", controller.Registry())
	g.Handle("/node", controller.Node())
	g.Handle("/service", controller.Service(), web.FilterFunc(security.Permiter))
	g.Handle("/service/template", controller.Template())
	g.Handle("/stack", controller.Stack())
	g.Handle("/network", controller.Network())
	g.Handle("/secret", controller.Secret())
	g.Handle("/config", controller.Config())
	g.Handle("/task", controller.Task())
	g.Handle("/container", controller.Container())
	g.Handle("/image", controller.Image())
	g.Handle("/volume", controller.Volume())
	g.Handle("/system/user", controller.User())
	g.Handle("/system/role", controller.Role())
	g.Handle("/system/setting", controller.Setting())
	g.Handle("/system/event", controller.Event())
	g.Handle("/system/chart", controller.Chart())

	return ws
}
<commit_msg>Bump version to 0.8.1<commit_after>package main

import (
	"net/http"
	"os"
	"path/filepath"
	"runtime"

	"github.com/cuigh/auxo/app"
	"github.com/cuigh/auxo/app/flag"
	_ "github.com/cuigh/auxo/cache/memory"
	"github.com/cuigh/auxo/config"
	"github.com/cuigh/auxo/data/valid"
	"github.com/cuigh/auxo/log"
	"github.com/cuigh/auxo/net/web"
	"github.com/cuigh/auxo/net/web/filter"
	"github.com/cuigh/auxo/net/web/filter/auth"
	"github.com/cuigh/auxo/net/web/renderer/jet"
	"github.com/cuigh/swirl/biz"
	"github.com/cuigh/swirl/controller"
	"github.com/cuigh/swirl/misc"
	"github.com/cuigh/swirl/model"
	"github.com/cuigh/swirl/scaler"
	"github.com/cuigh/swirl/security"
)

func main() {
	misc.BindOptions()

	app.Name = "Swirl"
	app.Version = "0.8.1"
	app.Desc = "A web management UI for Docker, focused on swarm cluster"
	app.Action = func(ctx *app.Context) {
		err := config.UnmarshalOption("swirl", &misc.Options)
		if err != nil {
			log.Get(app.Name).Error("Failed to load options: ", err)
			os.Exit(1)
		}

		setting, err := biz.Setting.Get()
		if err != nil {
			log.Get(app.Name).Error("Failed to load settings: ", err)
			os.Exit(1)
		}

		biz.Stack.Migrate()
		if setting.Metrics.Prometheus != "" {
			scaler.Start()
		}
		app.Run(server(setting))
	}
	app.Flags.Register(flag.All)
	app.Start()
}

func server(setting *model.Setting) *web.Server {
	ws := web.Auto()

	// customize error handler
	ws.ErrorHandler.OnCode(http.StatusNotFound, func(ctx web.Context, err error) {
		if ctx.IsAJAX() {
			ctx.Status(http.StatusNotFound).HTML(http.StatusText(http.StatusNotFound)) // nolint: gas
		} else {
			ctx.Status(http.StatusNotFound).Render("404", nil) // nolint: gas
		}
	})
	ws.ErrorHandler.OnCode(http.StatusForbidden, func(ctx web.Context, err error) {
		if ctx.IsAJAX() {
			ctx.Status(http.StatusForbidden).HTML("You do not have permission to perform this operation") // nolint: gas
		} else {
			ctx.Status(http.StatusForbidden).Render("403", nil) // nolint: gas
		}
	})

	// set render
	ws.Validator = &valid.Validator{Tag: "valid"}
	ws.Renderer = jet.Must(jet.Debug(config.GetBool("debug")), jet.VarMap(misc.Funcs), jet.VarMap(map[string]interface{}{
		"language":   setting.Language,
		"version":    app.Version,
		"go_version": runtime.Version(),
		"time":       misc.FormatTime(setting.TimeZone.Offset),
		"i18n":       misc.Message(setting.Language),
	}))

	// register global filters
	ws.Use(filter.NewRecover())

	// register static handlers
	ws.File("/favicon.ico", filepath.Join(filepath.Dir(app.Path()), "assets/swirl/img/favicon.ico"))
	ws.Static("/assets", filepath.Join(filepath.Dir(app.Path()), "assets"))

	// create biz group
	form := &auth.Form{
		Identifier:        security.Identifier,
		Timeout:           misc.Options.AuthTimeout,
		SlidingExpiration: true,
	}
	g := ws.Group("", form, filter.NewAuthorizer(security.Checker))

	// register auth handlers
	g.Post("/login", form.LoginJSON(security.Validator(setting)), web.WithName("login"), web.WithAuthorize(web.AuthAnonymous))
	g.Get("/logout", form.Logout, web.WithName("logout"), web.WithAuthorize(web.AuthAuthenticated))

	// register controllers
	g.Handle("", controller.Home())
	g.Handle("/profile", controller.Profile())
	g.Handle("/registry", controller.Registry())
	g.Handle("/node", controller.Node())
	g.Handle("/service", controller.Service(), web.FilterFunc(security.Permiter))
	g.Handle("/service/template", controller.Template())
	g.Handle("/stack", controller.Stack())
	g.Handle("/network", controller.Network())
	g.Handle("/secret", controller.Secret())
	g.Handle("/config", controller.Config())
	g.Handle("/task", controller.Task())
	g.Handle("/container", controller.Container())
	g.Handle("/image", controller.Image())
	g.Handle("/volume", controller.Volume())
	g.Handle("/system/user", controller.User())
	g.Handle("/system/role", controller.Role())
	g.Handle("/system/setting", controller.Setting())
	g.Handle("/system/event", controller.Event())
	g.Handle("/system/chart", controller.Chart())

	return ws
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"

	"github.com/rrawrriw/go-venv-lib"
)

func main() {
	curr, err := os.Getwd()
	handleError(err)

	src, err := venv.FindSrcDir(curr)
	handleError(err)

	bin := path.Join(src, "bin")
	err = venv.AppendEnvList("PATH", bin)
	handleError(err)

	fmt.Printf("export GOPATH=%v;\n", src)
	fmt.Printf("export PATH=%v;", os.Getenv("PATH"))

}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>replace append func with NewPath, remove env set<commit_after>package main

import (
	"fmt"
	"os"
	"path"

	"github.com/rrawrriw/go-venv-lib"
)

const (
	GOPATH = "GOPATH"
)

func main() {
	curr, err := os.Getwd()
	handleError(err)

	oldBin := path.Join(os.Getenv(GOPATH), "bin")

	src, err := venv.FindSrcDir(curr)
	handleError(err)

	newBin := path.Join(src, "bin")
	pathEnv := os.Getenv("PATH")
	newPath := venv.NewPath(pathEnv, oldBin, newBin)

	fmt.Printf("export GOPATH=%v;\n", src)
	fmt.Printf("export PATH=%v;\n", newPath)

	os.Exit(0)
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"bufio"
	"fmt"
	telegramBot "gopkg.in/telegram-bot-api.v4"
)

const UPDATES_TIMEOUT = 60

const COMMAND_ADD = "add"
const COMMAND_LIST = "list"
const COMMAND_CLOSE = "close"

func main() {
	log.Println("Trying to read 'token' file")
	token := readTokenFile()
	log.Println("Token acquired")

	bot := getBot(token)
	log.Printf("Authorized on account %s", bot.Self.UserName)

	for update := range getUpdatesChan(bot) {
		if update.Message == nil {
			continue
		}

		handleUpdate(update, bot)
	}
}

//Logic of messages handling
func handleUpdate(update telegramBot.Update, bot *telegramBot.BotAPI) {
	//log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)

	message := update.Message

	if message.IsCommand() {
		//commandArguments := message.CommandArguments()

		switch command := message.Command(); command {
		case COMMAND_ADD:

		case COMMAND_LIST:

		case COMMAND_CLOSE:

		default:
			sendReply(update, bot,
				fmt.Sprintf("I can't understart command '%s'", command))
		}
	}
}

func sendReply(update telegramBot.Update, bot *telegramBot.BotAPI, text string) {
	replyMessage := telegramBot.NewMessage(update.Message.Chat.ID, text)
	replyMessage.ReplyToMessageID = update.Message.MessageID

	bot.Send(replyMessage)
}

func getUpdatesChan(bot *telegramBot.BotAPI) <- chan telegramBot.Update {
	u := telegramBot.NewUpdate(0)

	u.Timeout = UPDATES_TIMEOUT

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}

	return updates
}

func getBot(token string) *telegramBot.BotAPI {
	bot, err := telegramBot.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	//bot.Debug = true

	return bot
}

func readTokenFile() string {
	file, err := os.Open("token")
	if err != nil {
		fmt.Println("token file reading error:", err)
		os.Exit(1)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Scan()

	return scanner.Text()
}
<commit_msg>add and list commands<commit_after>package main

import (
	"log"
	"os"
	"bufio"
	"fmt"
	telegramBotApi "gopkg.in/telegram-bot-api.v4"
	"bytes"
)

const UPDATES_TIMEOUT = 60

const COMMAND_ADD = "add"
const COMMAND_LIST = "list"
const COMMAND_CLOSE = "close"

var botApi *telegramBotApi.BotAPI

type Request struct {
	name string
}

type Bot struct {
	requests []Request
	botApi   *telegramBotApi.BotAPI
}

func main() {
	bot := getBot()

	for update := range bot.getUpdatesChan() {
		if update.Message == nil {
			continue
		}

		handleUpdate(update, bot)
	}
}

//Logic of messages handling
func handleUpdate(update telegramBotApi.Update, bot *Bot) {
	//log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)

	message := update.Message

	if message.IsCommand() {
		commandArguments := message.CommandArguments()

		switch command := message.Command(); command {
		case COMMAND_ADD:
			bot.addRequest(commandArguments)
			bot.sendReply(update, fmt.Sprintf("Request '%s' added", commandArguments))
		case COMMAND_LIST:
			bot.sendReply(update, bot.getRequestsText())
		case COMMAND_CLOSE:
			bot.sendReply(update, "Not implemented yet =)")
		default:
			bot.sendReply(update, fmt.Sprintf("I can't understart command '%s'", command))
		}
	}
}
func (bot *Bot) getRequestsText() string {
	if len(bot.requests) == 0 {
		return "No active requests at the moment"
	}

	var buffer bytes.Buffer

	for number, request := range bot.requests{
		buffer.WriteString(fmt.Sprintf("%d: %s\n", number, request.name))
	}

	return buffer.String()
}

func getBot() *Bot {
	log.Println("Trying to read 'token' file")
	token := readTokenFile()
	log.Println("Token acquired")
	botApi = getBotApi(token)
	log.Printf("Authorized on account %s", botApi.Self.UserName)
	bot := &Bot{botApi:botApi}
	return bot
}

func (bot *Bot) sendReply(update telegramBotApi.Update, text string) {
	replyMessage := telegramBotApi.NewMessage(update.Message.Chat.ID, text)
	replyMessage.ReplyToMessageID = update.Message.MessageID

	bot.botApi.Send(replyMessage)
}

func (bot *Bot) getUpdatesChan() <-chan telegramBotApi.Update {
	u := telegramBotApi.NewUpdate(0)

	u.Timeout = UPDATES_TIMEOUT

	updates, err := bot.botApi.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}

	return updates
}

func (bot *Bot) addRequest(name string) {
	request := Request{name}
	bot.requests = append(bot.requests, request)
}

func getBotApi(token string) *telegramBotApi.BotAPI {
	bot, err := telegramBotApi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	//bot.Debug = true

	return bot
}

func readTokenFile() string {
	file, err := os.Open("token")
	if err != nil {
		fmt.Println("token file reading error:", err)
		os.Exit(1)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Scan()

	return scanner.Text()
}
<|endoftext|>