<commit_before>package gopaste

import (
	"bytes"
	"fmt"
	"github.com/aryann/difflib"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

var tmpl *template.Template

func trunc(s string, max int) string {
	if len(s) < max {
		return s
	}

	last := max - 3
	return s[:last] + "..."
}

func init() {
	tmpl = template.New("web")
	tmpl.Funcs(template.FuncMap{
		"trunc": trunc,
	})
	if _, err := tmpl.ParseGlob("*.template"); err != nil {
		log.Fatalf("template parsing: %v\n", err)
	}

}

////////////////////////////////////////////////////////////////////////////////

type Query struct {
	Request  *http.Request
	Response http.ResponseWriter
	Action   string
	Args     []string
}

func NewQuery(w http.ResponseWriter, req *http.Request) *Query {
	data := &Query{
		Request:  req,
		Response: w,
	}

	path := req.URL.Path
	parts := strings.Split(strings.Trim(path, "/"), "/")

	data.Action = parts[0]
	if len(parts) > 1 {
		data.Args = parts[1:]
	}

	return data
}

type HttpError struct {
	Message string
	Code    int
}

func (e HttpError) Error() string {
	return fmt.Sprintf("ERROR %d: %s", e.Code, e.Message)
}

func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	log.Printf("[web] %s %s %s", req.RemoteAddr, req.Method, req.URL.Path)

	q := NewQuery(w, req)
	if err := s.handle(q); err != nil {
		if e, ok := err.(HttpError); ok {
			http.Error(w, e.Error(), e.Code)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

type ActionFunc func(*Server, *Query) error

var handlers = map[string]ActionFunc{
	"":         (*Server).doMain,
	"annotate": (*Server).doAnnotate,
	"browse":   (*Server).doBrowse,
	"diff":     (*Server).doDiff,
	"new":      (*Server).doNew,
	"raw":      (*Server).doRaw,
	"static":   (*Server).doStatic,
	"view":     (*Server).doView,
}

func (s *Server) handle(d *Query) error {
	handler := handlers[d.Action]
	if handler == nil {
		return HttpError{fmt.Sprintf("'%s' not found", d.Request.URL), http.StatusNotFound}
	}

	return handler(s, d)
}

////////////////////////////////////////////////////////////////////////////////

func parsePasteId(str string) (int64, error) {
	id, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return InvalidPasteId, fmt.Errorf("invalid paste id '%s'", str)
	}
	return id, nil
}

// runTemplate executes a template and writes the results as HTML if successful
func runTemplate(w http.ResponseWriter, name string, data interface{}) error {
	buf := new(bytes.Buffer)
	err := tmpl.ExecuteTemplate(buf, name, data)
	if err != nil {
		return HttpError{fmt.Sprintf("error processing template %s: %v", name, err), http.StatusInternalServerError}
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	buf.WriteTo(w)

	return nil
}

////////////////////////////////////////////////////////////////////////////////

type AnyMap map[string]interface{}

func (s *Server) doMain(q *Query) error {
	opts := NewBrowseOpts()
	opts.PageSize = 10

	page, err := TopLevelPastes(s.Database, opts)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}

	return runTemplate(q.Response, "main", AnyMap{
		"MainPage":  true,
		"Title":     "Home",
		"Page":      page,
		"Languages": LanguageNamesSorted,
		"Channels":  []string{}, // TODO
	})
}

////////////////////////////////////////////////////////////////////////////////

type BrowseOpts struct {
	Page     int
	PageSize int
	Search   map[string]string
}

func NewBrowseOpts() *BrowseOpts {
	return &BrowseOpts{
		Page:     1,
		PageSize: 50,
		Search:   make(map[string]string),
	}
}

func (o *BrowseOpts) Parse(args []string) error {
	for i := 0; i+1 < len(args); i += 2 {
		key, err := url.QueryUnescape(args[i])
		if err != nil {
			return err
		}
		val, err := url.QueryUnescape(args[i+1])
		if err != nil {
			return err
		}
		switch key {
		case "page":
			pagenum, err := strconv.ParseInt(val, 10, 64)
			if err != nil {
				return fmt.Errorf("invalid page number: %s", val)
			}
			o.Page = int(pagenum)
		default:
			o.Search[key] = val
		}
	}

	return nil
}

func (o *BrowseOpts) String() string {
	var parts, keys []string

	for key := range o.Search {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	for _, key := range keys {
		parts = append(parts,
			url.QueryEscape(key),
			url.QueryEscape(o.Search[key]),
		)
	}

	if o.Page > 1 {
		parts = append(parts, "page", fmt.Sprint(o.Page))
	}

	return strings.Join(parts, "/")
}

func (o *BrowseOpts) NewPage(page int) *BrowseOpts {
	newOpts := NewBrowseOpts()
	newOpts.Page = page
	newOpts.PageSize = o.PageSize
	for k, v := range o.Search {
		newOpts.Search[k] = v
	}
	return newOpts
}

func (o *BrowseOpts) Prev() *BrowseOpts {
	return o.NewPage(o.Page - 1)
}

func (o *BrowseOpts) Next() *BrowseOpts {
	return o.NewPage(o.Page + 1)
}

func (o *BrowseOpts) Nearby(window int, max int) (pages []int) {
	min := 1
	var low, high int

	width := 2*window + 1
	if width >= max {
		low = min
		high = max
	} else {
		low = o.Page - window
		lowExtra := 0
		if low < min {
			lowExtra = min - low
			low = min
		}

		high = o.Page + window + lowExtra
		if high > max {
			low -= high - max
			high = max
		}
	}

	for n := low; n <= high; n++ {
		pages = append(pages, n)
	}

	return
}

func (s *Server) doBrowse(q *Query) error {
	opts := NewBrowseOpts()
	err := opts.Parse(q.Args)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	page, err := TopLevelPastes(s.Database, opts)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}

	return runTemplate(q.Response, "browse", AnyMap{
		"Title": "Browse pastes",
		"Page":  page,
		"Opts":  opts,
	})
}

////////////////////////////////////////////////////////////////////////////////

// doDiff displays the difference between two pastes.
func (s *Server) doDiff(q *Query) error {
	if len(q.Args) < 2 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	fromStr, toStr := q.Args[0], q.Args[1]

	fromId, err := parsePasteId(fromStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	toId, err := parsePasteId(toStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	from, err := GetPaste(s.Database, fromId)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if from == nil {
		return HttpError{fmt.Sprintf("paste %d not found", fromId), http.StatusNotFound}
	}

	to, err := GetPaste(s.Database, toId)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if to == nil {
		return HttpError{fmt.Sprintf("paste %d not found", toId), http.StatusNotFound}
	}

	diff := difflib.Diff(
		strings.Split(from.Content, "\n"),
		strings.Split(to.Content, "\n"),
	)

	diffText := ""
	for _, line := range diff {
		var prefix string
		switch line.Delta {
		case difflib.LeftOnly:
			prefix = "-"
		case difflib.RightOnly:
			prefix = "+"
		default:
			prefix = " "
		}
		diffText += prefix + line.Payload + "\n"
	}

	return runTemplate(q.Response, "diff", AnyMap{
		"Title":    fmt.Sprintf("Diff #%d / #%d", from.Id, to.Id),
		"From":     from,
		"To":       to,
		"DiffText": diffText,
	})
}

////////////////////////////////////////////////////////////////////////////////

// doNew adds a new top-level paste.
func (s *Server) doNew(q *Query) error {
	return s.handleNew(q, nil)
}

// doAnnotation adds a new annotation to an existing paste.
func (s *Server) doAnnotate(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	paste, err := GetPaste(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if paste == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	return s.handleNew(q, paste)
}

func (s *Server) handleNew(q *Query, parent *Paste) error {
	method := q.Request.Method
	switch method {
	case "GET", "HEAD":
		return s.displayNewPage(q, parent)
	case "POST":
		return s.insertNewPaste(q, parent)
	default:
		return HttpError{fmt.Sprintf("unsupported request method: %s", method), http.StatusNotImplemented}
	}
}

func (s *Server) displayNewPage(q *Query, parent *Paste) error {
	var title string
	if parent != nil {
		title = fmt.Sprintf("Annotating #%d: %s", parent.Id, parent.TitleDef())
	} else {
		title = "New paste"
	}

	return runTemplate(q.Response, "new", AnyMap{
		"Title":     title,
		"Annotates": parent,
		"Languages": LanguageNamesSorted,
		"Channels":  []string{}, // TODO
	})
}

func (s *Server) insertNewPaste(q *Query, parent *Paste) error {
	err := q.Request.ParseForm()
	if err != nil {
		return HttpError{fmt.Sprintf("error parsing form: %s", err.Error()), http.StatusInternalServerError}
	}

	paste := NewPaste(q.Request.PostForm)
	if parent != nil {
		paste.Annotates.Int64 = parent.RootId()
		paste.Annotates.Valid = true
		paste.Private = parent.Private
	}

	pasteId, err := InsertPaste(s.Database, paste)
	if err != nil {
		return HttpError{fmt.Sprintf("error inserting new paste: %s", err.Error()), http.StatusInternalServerError}
	}

	var newPath string
	if parent != nil {
		annotation, err := AnnotationOrdinal(s.Database, pasteId)
		if err != nil {
			return HttpError{fmt.Sprintf("error fetching paste %d: %s", pasteId, err.Error()), http.StatusInternalServerError}
		}

		newPath = fmt.Sprintf("/view/%d#a%d", parent.Id, annotation)
	} else {
		newPath = fmt.Sprintf("/view/%d", pasteId)
	}

	http.Redirect(q.Response, q.Request, newPath, http.StatusSeeOther)
	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doRaw returns the verbatim content of a paste as plain text.
func (s *Server) doRaw(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	paste, err := GetPaste(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if paste == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	q.Response.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprint(q.Response, paste.Content)

	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doStatic serves a single static file.
func (s *Server) doStatic(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	path := []string{"static"}
	path = append(path, q.Args...)
	http.ServeFile(q.Response, q.Request, filepath.Join(path...))

	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doView displays a paste and any annotations with syntax highlighting.
func (s *Server) doView(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	pasteData, err := GetPasteData(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if pasteData == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	return runTemplate(q.Response, "view", AnyMap{
		"Title":   fmt.Sprintf("Paste #%d: %s", pasteData.Paste.Id, pasteData.Paste.TitleDef()),
		"Content": pasteData,
	})
}
<commit_msg>Print errors to the terminal<commit_after>package gopaste

import (
	"bytes"
	"fmt"
	"github.com/aryann/difflib"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

var tmpl *template.Template

func trunc(s string, max int) string {
	if len(s) < max {
		return s
	}

	last := max - 3
	return s[:last] + "..."
}

func init() {
	tmpl = template.New("web")
	tmpl.Funcs(template.FuncMap{
		"trunc": trunc,
	})
	if _, err := tmpl.ParseGlob("*.template"); err != nil {
		log.Fatalf("template parsing: %v\n", err)
	}

}

////////////////////////////////////////////////////////////////////////////////

type Query struct {
	Request  *http.Request
	Response http.ResponseWriter
	Action   string
	Args     []string
}

func NewQuery(w http.ResponseWriter, req *http.Request) *Query {
	data := &Query{
		Request:  req,
		Response: w,
	}

	path := req.URL.Path
	parts := strings.Split(strings.Trim(path, "/"), "/")

	data.Action = parts[0]
	if len(parts) > 1 {
		data.Args = parts[1:]
	}

	return data
}

type HttpError struct {
	Message string
	Code    int
}

func (e HttpError) Error() string {
	return fmt.Sprintf("ERROR %d: %s", e.Code, e.Message)
}

func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	log.Printf("[web] %s %s %s", req.RemoteAddr, req.Method, req.URL.Path)

	q := NewQuery(w, req)
	if err := s.handle(q); err != nil {
		log.Printf("[web] %v", err)
		if e, ok := err.(HttpError); ok {
			http.Error(w, e.Error(), e.Code)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

type ActionFunc func(*Server, *Query) error

var handlers = map[string]ActionFunc{
	"":         (*Server).doMain,
	"annotate": (*Server).doAnnotate,
	"browse":   (*Server).doBrowse,
	"diff":     (*Server).doDiff,
	"new":      (*Server).doNew,
	"raw":      (*Server).doRaw,
	"static":   (*Server).doStatic,
	"view":     (*Server).doView,
}

func (s *Server) handle(d *Query) error {
	handler := handlers[d.Action]
	if handler == nil {
		return HttpError{fmt.Sprintf("'%s' not found", d.Request.URL), http.StatusNotFound}
	}

	return handler(s, d)
}

////////////////////////////////////////////////////////////////////////////////

func parsePasteId(str string) (int64, error) {
	id, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return InvalidPasteId, fmt.Errorf("invalid paste id '%s'", str)
	}
	return id, nil
}

// runTemplate executes a template and writes the results as HTML if successful
func runTemplate(w http.ResponseWriter, name string, data interface{}) error {
	buf := new(bytes.Buffer)
	err := tmpl.ExecuteTemplate(buf, name, data)
	if err != nil {
		return HttpError{fmt.Sprintf("error processing template %s: %v", name, err), http.StatusInternalServerError}
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	buf.WriteTo(w)

	return nil
}

////////////////////////////////////////////////////////////////////////////////

type AnyMap map[string]interface{}

func (s *Server) doMain(q *Query) error {
	opts := NewBrowseOpts()
	opts.PageSize = 10

	page, err := TopLevelPastes(s.Database, opts)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}

	return runTemplate(q.Response, "main", AnyMap{
		"MainPage":  true,
		"Title":     "Home",
		"Page":      page,
		"Languages": LanguageNamesSorted,
		"Channels":  []string{}, // TODO
	})
}

////////////////////////////////////////////////////////////////////////////////

type BrowseOpts struct {
	Page     int
	PageSize int
	Search   map[string]string
}

func NewBrowseOpts() *BrowseOpts {
	return &BrowseOpts{
		Page:     1,
		PageSize: 50,
		Search:   make(map[string]string),
	}
}

func (o *BrowseOpts) Parse(args []string) error {
	for i := 0; i+1 < len(args); i += 2 {
		key, err := url.QueryUnescape(args[i])
		if err != nil {
			return err
		}
		val, err := url.QueryUnescape(args[i+1])
		if err != nil {
			return err
		}
		switch key {
		case "page":
			pagenum, err := strconv.ParseInt(val, 10, 64)
			if err != nil {
				return fmt.Errorf("invalid page number: %s", val)
			}
			o.Page = int(pagenum)
		default:
			o.Search[key] = val
		}
	}

	return nil
}

func (o *BrowseOpts) String() string {
	var parts, keys []string

	for key := range o.Search {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	for _, key := range keys {
		parts = append(parts,
			url.QueryEscape(key),
			url.QueryEscape(o.Search[key]),
		)
	}

	if o.Page > 1 {
		parts = append(parts, "page", fmt.Sprint(o.Page))
	}

	return strings.Join(parts, "/")
}

func (o *BrowseOpts) NewPage(page int) *BrowseOpts {
	newOpts := NewBrowseOpts()
	newOpts.Page = page
	newOpts.PageSize = o.PageSize
	for k, v := range o.Search {
		newOpts.Search[k] = v
	}
	return newOpts
}

func (o *BrowseOpts) Prev() *BrowseOpts {
	return o.NewPage(o.Page - 1)
}

func (o *BrowseOpts) Next() *BrowseOpts {
	return o.NewPage(o.Page + 1)
}

func (o *BrowseOpts) Nearby(window int, max int) (pages []int) {
	min := 1
	var low, high int

	width := 2*window + 1
	if width >= max {
		low = min
		high = max
	} else {
		low = o.Page - window
		lowExtra := 0
		if low < min {
			lowExtra = min - low
			low = min
		}

		high = o.Page + window + lowExtra
		if high > max {
			low -= high - max
			high = max
		}
	}

	for n := low; n <= high; n++ {
		pages = append(pages, n)
	}

	return
}

func (s *Server) doBrowse(q *Query) error {
	opts := NewBrowseOpts()
	err := opts.Parse(q.Args)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	page, err := TopLevelPastes(s.Database, opts)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}

	return runTemplate(q.Response, "browse", AnyMap{
		"Title": "Browse pastes",
		"Page":  page,
		"Opts":  opts,
	})
}

////////////////////////////////////////////////////////////////////////////////

// doDiff displays the difference between two pastes.
func (s *Server) doDiff(q *Query) error {
	if len(q.Args) < 2 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	fromStr, toStr := q.Args[0], q.Args[1]

	fromId, err := parsePasteId(fromStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	toId, err := parsePasteId(toStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	from, err := GetPaste(s.Database, fromId)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if from == nil {
		return HttpError{fmt.Sprintf("paste %d not found", fromId), http.StatusNotFound}
	}

	to, err := GetPaste(s.Database, toId)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if to == nil {
		return HttpError{fmt.Sprintf("paste %d not found", toId), http.StatusNotFound}
	}

	diff := difflib.Diff(
		strings.Split(from.Content, "\n"),
		strings.Split(to.Content, "\n"),
	)

	diffText := ""
	for _, line := range diff {
		var prefix string
		switch line.Delta {
		case difflib.LeftOnly:
			prefix = "-"
		case difflib.RightOnly:
			prefix = "+"
		default:
			prefix = " "
		}
		diffText += prefix + line.Payload + "\n"
	}

	return runTemplate(q.Response, "diff", AnyMap{
		"Title":    fmt.Sprintf("Diff #%d / #%d", from.Id, to.Id),
		"From":     from,
		"To":       to,
		"DiffText": diffText,
	})
}

////////////////////////////////////////////////////////////////////////////////

// doNew adds a new top-level paste.
func (s *Server) doNew(q *Query) error {
	return s.handleNew(q, nil)
}

// doAnnotation adds a new annotation to an existing paste.
func (s *Server) doAnnotate(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	paste, err := GetPaste(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if paste == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	return s.handleNew(q, paste)
}

func (s *Server) handleNew(q *Query, parent *Paste) error {
	method := q.Request.Method
	switch method {
	case "GET", "HEAD":
		return s.displayNewPage(q, parent)
	case "POST":
		return s.insertNewPaste(q, parent)
	default:
		return HttpError{fmt.Sprintf("unsupported request method: %s", method), http.StatusNotImplemented}
	}
}

func (s *Server) displayNewPage(q *Query, parent *Paste) error {
	var title string
	if parent != nil {
		title = fmt.Sprintf("Annotating #%d: %s", parent.Id, parent.TitleDef())
	} else {
		title = "New paste"
	}

	return runTemplate(q.Response, "new", AnyMap{
		"Title":     title,
		"Annotates": parent,
		"Languages": LanguageNamesSorted,
		"Channels":  []string{}, // TODO
	})
}

func (s *Server) insertNewPaste(q *Query, parent *Paste) error {
	err := q.Request.ParseForm()
	if err != nil {
		return HttpError{fmt.Sprintf("error parsing form: %s", err.Error()), http.StatusInternalServerError}
	}

	paste := NewPaste(q.Request.PostForm)
	if parent != nil {
		paste.Annotates.Int64 = parent.RootId()
		paste.Annotates.Valid = true
		paste.Private = parent.Private
	}

	pasteId, err := InsertPaste(s.Database, paste)
	if err != nil {
		return HttpError{fmt.Sprintf("error inserting new paste: %s", err.Error()), http.StatusInternalServerError}
	}

	var newPath string
	if parent != nil {
		annotation, err := AnnotationOrdinal(s.Database, pasteId)
		if err != nil {
			return HttpError{fmt.Sprintf("error fetching paste %d: %s", pasteId, err.Error()), http.StatusInternalServerError}
		}

		newPath = fmt.Sprintf("/view/%d#a%d", parent.Id, annotation)
	} else {
		newPath = fmt.Sprintf("/view/%d", pasteId)
	}

	http.Redirect(q.Response, q.Request, newPath, http.StatusSeeOther)
	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doRaw returns the verbatim content of a paste as plain text.
func (s *Server) doRaw(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	paste, err := GetPaste(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if paste == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	q.Response.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprint(q.Response, paste.Content)

	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doStatic serves a single static file.
func (s *Server) doStatic(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	path := []string{"static"}
	path = append(path, q.Args...)
	http.ServeFile(q.Response, q.Request, filepath.Join(path...))

	return nil
}

////////////////////////////////////////////////////////////////////////////////

// doView displays a paste and any annotations with syntax highlighting.
func (s *Server) doView(q *Query) error {
	if len(q.Args) < 1 {
		return HttpError{"invalid request", http.StatusBadRequest}
	}

	idStr := q.Args[0]
	id, err := parsePasteId(idStr)
	if err != nil {
		return HttpError{err.Error(), http.StatusBadRequest}
	}

	pasteData, err := GetPasteData(s.Database, id)
	if err != nil {
		return HttpError{err.Error(), http.StatusInternalServerError}
	}
	if pasteData == nil {
		return HttpError{fmt.Sprintf("paste %d not found", id), http.StatusNotFound}
	}

	return runTemplate(q.Response, "view", AnyMap{
		"Title":   fmt.Sprintf("Paste #%d: %s", pasteData.Paste.Id, pasteData.Paste.TitleDef()),
		"Content": pasteData,
	})
}
<|endoftext|>


<commit_before>package sentry

import (
	"time"

	"github.com/getsentry/sentry-go"
	"github.com/sirupsen/logrus"
)

var (
	levelsMap = map[logrus.Level]sentry.Level{
		logrus.PanicLevel: sentry.LevelFatal,
		logrus.FatalLevel: sentry.LevelFatal,
		logrus.ErrorLevel: sentry.LevelError,
		logrus.WarnLevel:  sentry.LevelWarning,
		logrus.InfoLevel:  sentry.LevelInfo,
		logrus.DebugLevel: sentry.LevelDebug,
		logrus.TraceLevel: sentry.LevelDebug,
	}
)

type Options sentry.ClientOptions

type Hook struct {
	client       *sentry.Client
	levels       []logrus.Level
	tags         map[string]string
	release      string
	environment  string
	prefix       string
	flushTimeout time.Duration
}

func (hook *Hook) Levels() []logrus.Level {
	return hook.levels
}

func (hook *Hook) Fire(entry *logrus.Entry) error {
	exceptions := []sentry.Exception{}

	if err, ok := entry.Data[logrus.ErrorKey].(error); ok && err != nil {
		stacktrace := sentry.ExtractStacktrace(err)
		if stacktrace == nil {
			stacktrace = sentry.NewStacktrace()
		}
		exceptions = append(exceptions, sentry.Exception{
			Type:       entry.Message,
			Value:      err.Error(),
			Stacktrace: stacktrace,
		})
	}

	event := sentry.Event{
		Level:       levelsMap[entry.Level],
		Message:     hook.prefix + entry.Message,
		Extra:       map[string]interface{}(entry.Data),
		Tags:        hook.tags,
		Environment: hook.environment,
		Release:     hook.release,
		Exception:   exceptions,
	}

	hub := sentry.CurrentHub()
	hook.client.CaptureEvent(&event, nil, hub.Scope())

	return nil
}

func (hook *Hook) SetPrefix(prefix string) {
	hook.prefix = prefix
}

func (hook *Hook) SetTags(tags map[string]string) {
	hook.tags = tags
}

func (hook *Hook) AddTag(key, value string) {
	hook.tags[key] = value
}

func (hook *Hook) SetRelease(release string) {
	hook.release = release
}

func (hook *Hook) SetEnvironment(environment string) {
	hook.environment = environment
}

func (hook *Hook) SetFlushTimeout(timeout time.Duration) {
	hook.flushTimeout = timeout
}

func (hook *Hook) Flush() {
	hook.client.Flush(hook.flushTimeout)
}

func NewHook(options Options, levels ...logrus.Level) (*Hook, error) {
	client, err := sentry.NewClient(sentry.ClientOptions(options))
	if err != nil {
		return nil, err
	}

	hook := Hook{
		client: client,
		levels: levels,
		tags:   map[string]string{},
	}
	if len(hook.levels) == 0 {
		hook.levels = logrus.AllLevels
	}

	return &hook, nil
}
<commit_msg>set default timeout<commit_after>package sentry

import (
	"time"

	"github.com/getsentry/sentry-go"
	"github.com/sirupsen/logrus"
)

var (
	levelsMap = map[logrus.Level]sentry.Level{
		logrus.PanicLevel: sentry.LevelFatal,
		logrus.FatalLevel: sentry.LevelFatal,
		logrus.ErrorLevel: sentry.LevelError,
		logrus.WarnLevel:  sentry.LevelWarning,
		logrus.InfoLevel:  sentry.LevelInfo,
		logrus.DebugLevel: sentry.LevelDebug,
		logrus.TraceLevel: sentry.LevelDebug,
	}
)

type Options sentry.ClientOptions

type Hook struct {
	client       *sentry.Client
	levels       []logrus.Level
	tags         map[string]string
	release      string
	environment  string
	prefix       string
	flushTimeout time.Duration
}

func (hook *Hook) Levels() []logrus.Level {
	return hook.levels
}

func (hook *Hook) Fire(entry *logrus.Entry) error {
	exceptions := []sentry.Exception{}

	if err, ok := entry.Data[logrus.ErrorKey].(error); ok && err != nil {
		stacktrace := sentry.ExtractStacktrace(err)
		if stacktrace == nil {
			stacktrace = sentry.NewStacktrace()
		}
		exceptions = append(exceptions, sentry.Exception{
			Type:       entry.Message,
			Value:      err.Error(),
			Stacktrace: stacktrace,
		})
	}

	event := sentry.Event{
		Level:       levelsMap[entry.Level],
		Message:     hook.prefix + entry.Message,
		Extra:       map[string]interface{}(entry.Data),
		Tags:        hook.tags,
		Environment: hook.environment,
		Release:     hook.release,
		Exception:   exceptions,
	}

	hub := sentry.CurrentHub()
	hook.client.CaptureEvent(&event, nil, hub.Scope())

	return nil
}

func (hook *Hook) SetPrefix(prefix string) {
	hook.prefix = prefix
}

func (hook *Hook) SetTags(tags map[string]string) {
	hook.tags = tags
}

func (hook *Hook) AddTag(key, value string) {
	hook.tags[key] = value
}

func (hook *Hook) SetRelease(release string) {
	hook.release = release
}

func (hook *Hook) SetEnvironment(environment string) {
	hook.environment = environment
}

func (hook *Hook) SetFlushTimeout(timeout time.Duration) {
	hook.flushTimeout = timeout
}

func (hook *Hook) Flush() {
	hook.client.Flush(hook.flushTimeout)
}

func NewHook(options Options, levels ...logrus.Level) (*Hook, error) {
	client, err := sentry.NewClient(sentry.ClientOptions(options))
	if err != nil {
		return nil, err
	}

	hook := Hook{
		client:       client,
		levels:       levels,
		tags:         map[string]string{},
		flushTimeout: 10 * time.Second,
	}
	if len(hook.levels) == 0 {
		hook.levels = logrus.AllLevels
	}

	return &hook, nil
}
<|endoftext|>


<commit_before>package sexpconv

import (
	"sexp"
)

// Simplify translates semantic-rich forms into
// more generic and fundamental forms.
// For example, it converts DoTimes to While.
//
// It is necessary to call Simplify before compiling
// forms into IR because compiler does not recognize
// some high level constructs.
func Simplify(form sexp.Form) sexp.Form {
	switch form := form.(type) {
	case *sexp.Block:
		form.Forms = simplify(form.Forms)

	case *sexp.DoTimes:
		bindKey := &sexp.Bind{
			Name: form.Iter.Name,
			Init: ZeroValue(form.Iter.Typ),
		}
		form.Body.Forms = append(form.Body.Forms, &sexp.Rebind{
			Name: form.Iter.Name,
			Expr: _addX(form.Iter, 1),
		})
		loop := &sexp.While{
			Cond: _numLt(form.Iter, form.N),
			Body: form.Body,
		}
		return &sexp.Block{
			Forms: []sexp.Form{bindKey, loop},
			Scope: form.Scope,
		}
	}

	return form
}

func simplify(forms []sexp.Form) []sexp.Form {
	for i, form := range forms {
		forms[i] = Simplify(form)
	}
	return forms
}
<commit_msg>refactored sexpconv.Simplify with sexp.Rewrite<commit_after>package sexpconv

import (
	"sexp"
)

// Simplify translates semantic-rich forms into
// more generic and fundamental forms.
// For example, it converts DoTimes to While.
//
// It is necessary to call Simplify before compiling
// forms into IR because compiler does not recognize
// some high level constructs.
func Simplify(form sexp.Form) sexp.Form {
	return sexp.Rewrite(form, simplify)
}

func simplify(form sexp.Form) sexp.Form {
	switch form := form.(type) {
	case *sexp.Shr:
		return &sexp.Shl{
			Arg: form.Arg,
			N:   &sexp.Neg{Arg: form.N},
		}

	case *sexp.DoTimes:
		bindKey := &sexp.Bind{
			Name: form.Iter.Name,
			Init: ZeroValue(form.Iter.Typ),
		}
		form.Body.Forms = append(form.Body.Forms, &sexp.Rebind{
			Name: form.Iter.Name,
			Expr: _addX(form.Iter, 1),
		})
		loop := &sexp.While{
			Cond: _numLt(form.Iter, form.N),
			Body: form.Body,
		}
		return &sexp.Block{
			Forms: []sexp.Form{bindKey, loop},
			Scope: form.Scope,
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package orbitapi

import (
	"encoding/json"
	"net/http"
	"net/url"
	"strings"
)

var (
	orbitApiUrl = "http://api.orbitapi.com/"
)

type OrbitApi struct {
	apiKey string
	Result chan map[string]interface{}
}

func NewClient(apiKey string) (orbitapi *OrbitApi) {
	orbitapi = new(OrbitApi)
	orbitapi.apiKey = apiKey
	orbitapi.Result = make(chan map[string]interface{})
	return
}

func (o *OrbitApi) Get(uri string) error {

	getUrl := orbitApiUrl + uri
	req, err := http.NewRequest("GET", getUrl, nil)
	if err != nil {
		return err
	}

	req.Header.Add("X-Orbit-API-Key", o.apiKey)
	return o.doRequest(req)
}

func (o *OrbitApi) Post(uri string, args url.Values) error {

	postUrl := orbitApiUrl + uri
	args.Add("api_key", o.apiKey)
	req, err := http.NewRequest("POST", postUrl, strings.NewReader(args.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return o.doRequest(req)
}

func (o *OrbitApi) doRequest(req *http.Request) error {
	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return err
	}
	o.Result <- data
	return nil
}
<commit_msg>Commented some of the code.<commit_after>// Copyright 2014 DB Medialab.  All rights reserved.
// License: MIT

// Package orbitapi provides client access to the Orbit API (http://orbitapi.com/)
package orbitapi

import (
	"encoding/json"
	"net/http"
	"net/url"
	"strings"
)

var (
	// URL on which the Orbit API can be reached
	orbitApiUrl = "http://api.orbitapi.com/"
)

type OrbitApi struct {
	// Key to access the API with
	apiKey string

	// Result will be sent on this channel
	Result chan map[string]interface{}
}

// Create a new Orbit API client
func NewClient(apiKey string) (orbitapi *OrbitApi) {
	orbitapi = new(OrbitApi)
	orbitapi.apiKey = apiKey
	orbitapi.Result = make(chan map[string]interface{})
	return
}

// Send a new GET request to the API
func (o *OrbitApi) Get(uri string) error {
	getUrl := orbitApiUrl + uri
	req, err := http.NewRequest("GET", getUrl, nil)
	if err != nil {
		return err
	}

	// Get requests require the API key to be sent as a header
	req.Header.Add("X-Orbit-API-Key", o.apiKey)
	return o.doRequest(req)
}

// Send a new POST request to the API
func (o *OrbitApi) Post(uri string, args url.Values) error {
	postUrl := orbitApiUrl + uri
	// Post requests require the API key to be sent a key=value
	args.Add("api_key", o.apiKey)
	req, err := http.NewRequest("POST", postUrl, strings.NewReader(args.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return o.doRequest(req)
}

// Do the actual request and return the response on o.Result
func (o *OrbitApi) doRequest(req *http.Request) error {
	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var data map[string]interface{}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return err
	}
	o.Result <- data
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/bobziuchkovski/writ"
)

type Config struct {
	baseSubCommand

	ConfigNormalize ConfigNormalize
	ConfigSet       ConfigSet
	ConfigAdd       ConfigAdd
}

func (c *Config) Run(p writ.Path, positional []string) {

	base := c.Base().(*BoardgameUtil)

	config := base.GetConfig()

	fmt.Println("Path: " + config.Path())
	if secretPath := config.SecretPath(); secretPath != "" {
		fmt.Println("Secret path: " + secretPath)
	} else {
		fmt.Println("NO secret path in use")
	}

	devBlob, err := json.MarshalIndent(config.Dev, "", "\t")

	if err != nil {
		errAndQuit("Couldn't marshal dev: " + err.Error())
	}

	prodBlob, err := json.MarshalIndent(config.Prod, "", "\t")

	if err != nil {
		errAndQuit("Couldn't marshal prod: " + err.Error())
	}

	fmt.Println("Derived dev configuration:")
	fmt.Println(string(devBlob))

	fmt.Println("Derived prod configuration: ")
	fmt.Println(string(prodBlob))

}

func (c *Config) Name() string {
	return "config"
}

func (c *Config) Description() string {
	return "Allows viewing and modifying configuration files"
}

func (c *Config) HelpText() string {
	return c.Name() + ` run without arguments prints the derived config in use and the path that is being used.

It's a good way to debug config issues.`
}

func (c *Config) SubcommandObjects() []SubcommandObject {
	return []SubcommandObject{
		&c.ConfigSet,
		&c.ConfigAdd,
		&c.ConfigNormalize,
	}
}
<commit_msg>Make it so `boardgame-util config` with any positional parameters errors. Part of #655.<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/bobziuchkovski/writ"
)

type Config struct {
	baseSubCommand

	ConfigNormalize ConfigNormalize
	ConfigSet       ConfigSet
	ConfigAdd       ConfigAdd
}

func (c *Config) Run(p writ.Path, positional []string) {

	if len(positional) > 0 {
		p.Last().ExitHelp(errors.New(c.Name() + " doesn't take any positional parameters"))
	}

	base := c.Base().(*BoardgameUtil)

	config := base.GetConfig()

	fmt.Println("Path: " + config.Path())
	if secretPath := config.SecretPath(); secretPath != "" {
		fmt.Println("Secret path: " + secretPath)
	} else {
		fmt.Println("NO secret path in use")
	}

	devBlob, err := json.MarshalIndent(config.Dev, "", "\t")

	if err != nil {
		errAndQuit("Couldn't marshal dev: " + err.Error())
	}

	prodBlob, err := json.MarshalIndent(config.Prod, "", "\t")

	if err != nil {
		errAndQuit("Couldn't marshal prod: " + err.Error())
	}

	fmt.Println("Derived dev configuration:")
	fmt.Println(string(devBlob))

	fmt.Println("Derived prod configuration: ")
	fmt.Println(string(prodBlob))

}

func (c *Config) Name() string {
	return "config"
}

func (c *Config) Description() string {
	return "Allows viewing and modifying configuration files"
}

func (c *Config) HelpText() string {
	return c.Name() + ` run without arguments prints the derived config in use and the path that is being used.

It's a good way to debug config issues.`
}

func (c *Config) SubcommandObjects() []SubcommandObject {
	return []SubcommandObject{
		&c.ConfigSet,
		&c.ConfigAdd,
		&c.ConfigNormalize,
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The LUCI 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 machinetoken

import (
	"crypto/x509/pkix"
	"math/big"
	"testing"
	"time"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/clock/testclock"

	tokenserver "go.chromium.org/luci/tokenserver/api"
	admin "go.chromium.org/luci/tokenserver/api/admin/v1"
	"go.chromium.org/luci/tokenserver/appengine/impl/certconfig"

	. "github.com/smartystreets/goconvey/convey"
)

func TestInspectMachineTokenRPC(t *testing.T) {
	Convey("with mocked context", t, func() {
		ctx := testingContext(testingCA)
		signer := testingSigner()
		impl := InspectMachineTokenRPC{Signer: signer}
		tok := testingMachineToken(ctx, signer)

		Convey("Good token", func() {
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:        true,
				Signed:       true,
				NonExpired:   true,
				NonRevoked:   true,
				SigningKeyId: signer.KeyNameForTest(),
				CertCaName:   "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Broken signature", func() {
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok[:len(tok)-11] + "0" + tok[len(tok)-10:],
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "bad signature - crypto/rsa: verification error",
				Signed:           false,
				NonExpired:       true,
				NonRevoked:       true,
				CertCaName:       "Fake CA: fake.ca",
				SigningKeyId:     signer.KeyNameForTest(),
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Expired", func() {
			clock.Get(ctx).(testclock.TestClock).Add(time.Hour + 11*time.Minute)
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "expired",
				Signed:           true,
				NonExpired:       false,
				NonRevoked:       true,
				SigningKeyId:     signer.KeyNameForTest(),
				CertCaName:       "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Revoked cert", func() {
			// "Revoke" the certificate.
			certconfig.UpdateCRLSet(ctx, "Fake CA: fake.ca", certconfig.CRLShardCount,
				&pkix.CertificateList{
					TBSCertList: pkix.TBSCertificateList{
						RevokedCertificates: []pkix.RevokedCertificate{
							{SerialNumber: big.NewInt(4096)},
						},
					},
				})
			// This makes the token expired too.
			clock.Get(ctx).(testclock.TestClock).Add(time.Hour + 11*time.Minute)
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "expired", // "expired" 'beats' revocation
				Signed:           true,
				NonExpired:       false,
				NonRevoked:       false, // revoked now!
				SigningKeyId:     signer.KeyNameForTest(),
				CertCaName:       "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})
	})
}
<commit_msg>[token-server] Fix flake in rpc_inspect_machine_token_test.go.<commit_after>// Copyright 2016 The LUCI 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 machinetoken

import (
	"crypto/x509/pkix"
	"math/big"
	"strings"
	"testing"
	"time"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/clock/testclock"

	tokenserver "go.chromium.org/luci/tokenserver/api"
	admin "go.chromium.org/luci/tokenserver/api/admin/v1"
	"go.chromium.org/luci/tokenserver/appengine/impl/certconfig"

	. "github.com/smartystreets/goconvey/convey"
)

func TestInspectMachineTokenRPC(t *testing.T) {
	Convey("with mocked context", t, func() {
		ctx := testingContext(testingCA)
		signer := testingSigner()
		impl := InspectMachineTokenRPC{Signer: signer}
		tok := testingMachineToken(ctx, signer)

		Convey("Good token", func() {
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:        true,
				Signed:       true,
				NonExpired:   true,
				NonRevoked:   true,
				SigningKeyId: signer.KeyNameForTest(),
				CertCaName:   "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Broken signature", func() {
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok[:len(tok)-16] + strings.Repeat("0", 16),
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "bad signature - crypto/rsa: verification error",
				Signed:           false,
				NonExpired:       true,
				NonRevoked:       true,
				CertCaName:       "Fake CA: fake.ca",
				SigningKeyId:     signer.KeyNameForTest(),
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Expired", func() {
			clock.Get(ctx).(testclock.TestClock).Add(time.Hour + 11*time.Minute)
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "expired",
				Signed:           true,
				NonExpired:       false,
				NonRevoked:       true,
				SigningKeyId:     signer.KeyNameForTest(),
				CertCaName:       "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})

		Convey("Revoked cert", func() {
			// "Revoke" the certificate.
			certconfig.UpdateCRLSet(ctx, "Fake CA: fake.ca", certconfig.CRLShardCount,
				&pkix.CertificateList{
					TBSCertList: pkix.TBSCertificateList{
						RevokedCertificates: []pkix.RevokedCertificate{
							{SerialNumber: big.NewInt(4096)},
						},
					},
				})
			// This makes the token expired too.
			clock.Get(ctx).(testclock.TestClock).Add(time.Hour + 11*time.Minute)
			reply, err := impl.InspectMachineToken(ctx, &admin.InspectMachineTokenRequest{
				TokenType: tokenserver.MachineTokenType_LUCI_MACHINE_TOKEN,
				Token:     tok,
			})
			So(err, ShouldBeNil)
			So(reply, ShouldResemble, &admin.InspectMachineTokenResponse{
				Valid:            false,
				InvalidityReason: "expired", // "expired" 'beats' revocation
				Signed:           true,
				NonExpired:       false,
				NonRevoked:       false, // revoked now!
				SigningKeyId:     signer.KeyNameForTest(),
				CertCaName:       "Fake CA: fake.ca",
				TokenType: &admin.InspectMachineTokenResponse_LuciMachineToken{
					LuciMachineToken: &tokenserver.MachineTokenBody{
						MachineFqdn: "luci-token-server-test-1.fake.domain",
						IssuedBy:    "signer@testing.host",
						IssuedAt:    1422936306,
						Lifetime:    3600,
						CaId:        123,
						CertSn:      4096,
					},
				},
			})
		})
	})
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// 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 cstesting_test

import (
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"testing"
	"time"

	"github.com/corestoreio/csfw/util/cstesting"
	"github.com/stretchr/testify/assert"
)

func TestHTTPParallelUsers_WrongInterval(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			if s, ok := r.(string); ok {
				if have, want := s, "Unknown interval 2s. Only allowed time.Nanosecond, time.Microsecond, etc"; have != want {
					t.Errorf("Have: %v Want: %v", have, want)
				}

			} else {
				t.Fatalf("Expecting a string in the panic; Got: %#v", r)
			}
		} else {
			t.Fatal("Expecting a panic")
		}
	}()
	_ = cstesting.NewHTTPParallelUsers(1, 1, 1, time.Second*2)
}
func TestHTTPParallelUsers(t *testing.T) {
	startTime := time.Now()
	const (
		users        = 4
		loops        = 10
		rampUpPeriod = 2
	)
	tg := cstesting.NewHTTPParallelUsers(users, loops, rampUpPeriod, time.Second)
	req := httptest.NewRequest("GET", "http://corestore.io", nil)

	tg.AssertResponse = func(rec *httptest.ResponseRecorder) {
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderUserID))
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderLoopID))
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderSleep))
	}

	var reqCount = new(int32)
	tg.ServeHTTP(req, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//t.Logf("UserID %s LoopID %s Sleeping %s",
		//	rec.Header().Get(cstesting.HeaderUserID),
		//	rec.Header().Get(cstesting.HeaderLoopID),
		//	rec.Header().Get(cstesting.HeaderSleep),
		//)
		atomic.AddInt32(reqCount, 1)
	}))

	//t.Logf("Users %d Loops %d, RampUp %d", users, loops, rampUpPeriod)

	if have, want := *reqCount, int32(users*loops); have != want {
		t.Errorf("Request count mismatch! Have: %v Want: %v", have, want)
	}

	if have, want := int(time.Since(startTime).Seconds()), rampUpPeriod; have != want {
		t.Errorf("Test Running Time is weird! Have: %v Want: %v", have, want)
	}
}
<commit_msg>util/cstesting: Add TestHTTPParallelUsers_Single<commit_after>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// 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 cstesting_test

import (
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"testing"
	"time"

	"github.com/corestoreio/csfw/util/cstesting"
	"github.com/stretchr/testify/assert"
)

func TestHTTPParallelUsers_WrongInterval(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			if s, ok := r.(string); ok {
				if have, want := s, "Unknown interval 2s. Only allowed time.Nanosecond, time.Microsecond, etc"; have != want {
					t.Errorf("Have: %v Want: %v", have, want)
				}

			} else {
				t.Fatalf("Expecting a string in the panic; Got: %#v", r)
			}
		} else {
			t.Fatal("Expecting a panic")
		}
	}()
	_ = cstesting.NewHTTPParallelUsers(1, 1, 1, time.Second*2)
}

func TestHTTPParallelUsers_Single(t *testing.T) {
	tg := cstesting.NewHTTPParallelUsers(1, 1, 1, time.Nanosecond)
	req := httptest.NewRequest("GET", "http://corestore.io", nil)

	var reqCount int
	tg.ServeHTTP(req, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// no race here because one single iteration
		reqCount++
	}))
	if have, want := reqCount, 1; have != want {
		t.Errorf("Request count mismatch! Have: %v Want: %v", have, want)
	}
}

func TestHTTPParallelUsers_Long(t *testing.T) {
	startTime := time.Now()
	const (
		users        = 4
		loops        = 10
		rampUpPeriod = 2
	)
	tg := cstesting.NewHTTPParallelUsers(users, loops, rampUpPeriod, time.Second)
	req := httptest.NewRequest("GET", "http://corestore.io", nil)

	tg.AssertResponse = func(rec *httptest.ResponseRecorder) {
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderUserID))
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderLoopID))
		assert.NotEmpty(t, rec.Header().Get(cstesting.HeaderSleep))
	}

	var reqCount = new(int32)
	tg.ServeHTTP(req, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//t.Logf("UserID %s LoopID %s Sleeping %s",
		//	rec.Header().Get(cstesting.HeaderUserID),
		//	rec.Header().Get(cstesting.HeaderLoopID),
		//	rec.Header().Get(cstesting.HeaderSleep),
		//)
		atomic.AddInt32(reqCount, 1)
	}))

	//t.Logf("Users %d Loops %d, RampUp %d", users, loops, rampUpPeriod)

	if have, want := *reqCount, int32(users*loops); have != want {
		t.Errorf("Request count mismatch! Have: %v Want: %v", have, want)
	}

	if have, want := int(time.Since(startTime).Seconds()), rampUpPeriod; have != want {
		t.Errorf("Test Running Time is weird! Have: %v Want: %v", have, want)
	}
}
<|endoftext|>


<commit_before><commit_msg>Added 'TestInsertAVLRLa()' and 'TestInsertAVLRLb()'<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/mgierok/monujo/repository"
	"github.com/mgierok/monujo/repository/entities"
)

func PutTransaction() {

	var t entities.Transaction
	get(portfolioId, &t)
	get(date, &t)
	get(ticker, &t)
	get(price, &t)
	get(transactionOperationType, &t)
	get(currency, &t)
	get(shares, &t)
	get(commision, &t)
	get(exchangeRate, &t)
	get(tax, &t)

	summary := [][]string{
		[]string{"Portfolio ID", strconv.FormatInt(t.PortfolioId, 10)},
		[]string{"Date", t.Date},
		[]string{"Ticker", t.Ticker},
		[]string{"Price", strconv.FormatFloat(t.Price, 'f', -1, 64)},
		[]string{"Type", t.TransactionOperationType},
		[]string{"Currency", t.Currency},
		[]string{"Shares", strconv.FormatFloat(t.Shares, 'f', -1, 64)},
		[]string{"Commision", strconv.FormatFloat(t.Commision, 'f', -1, 64)},
		[]string{"Exchange Rate", strconv.FormatFloat(t.ExchangeRate, 'f', -1, 64)},
		[]string{"Tax", strconv.FormatFloat(t.Tax, 'f', -1, 64)},
	}
	DrawTable([]string{}, summary)

	transactionId, err := repository.StoreTransaction(t)
	LogError(err)

	fmt.Printf("Transaction has been recorded with an ID: %d\n", transactionId)
}

func get(f func(*entities.Transaction), t *entities.Transaction) {
	f(t)
}

func portfolioId(e *entities.Transaction) {
	fmt.Println("Choose portfolio")
	fmt.Println("")

	portfolios, err := repository.Portfolios()
	LogError(err)

	header := []string{
		"Portfolio Id",
		"Portfolio Name",
	}

	var dict = make(map[int64]string)
	var data [][]string
	for _, p := range portfolios {
		data = append(data, []string{p.PortfolioId.String, p.Name.String})
		portfolioId, _ := strconv.ParseInt(p.PortfolioId.String, 10, 64)
		dict[portfolioId] = p.Name.String
	}

	DrawTable(header, data)
	fmt.Println("")

	var input string
	fmt.Print("Portfolio ID: ")
	fmt.Scanln(&input)

	p, err := strconv.ParseInt(input, 10, 64)

	if nil != err {
		fmt.Printf("\n%sd is not a valid portfolio ID\n\n", input)
		get(portfolioId, e)
		return
	} else {
		_, exists := dict[p]
		if exists {
			e.PortfolioId = p
		} else {
			fmt.Printf("\n%d is not a valid portfolio ID\n\n", p)
			get(portfolioId, e)
			return
		}
	}
}

func date(e *entities.Transaction) {
	const layout = "2006-01-02"
	var now = time.Now().Format(layout)
	var d string

	fmt.Printf("Date (default: %q): ", now)
	fmt.Scanln(&d)

	d = strings.Trim(d, " ")
	if d == "" {
		d = now
	} else {
		_, err := time.Parse(layout, d)
		if err != nil {
			fmt.Println(err)
			fmt.Printf("\n%q is not a valid date format\n\n", d)
			get(date, e)
			return
		}
	}

	e.Date = d
}

func ticker(e *entities.Transaction) {
	fmt.Print("Ticker: ")
	var t string
	fmt.Scanln(&t)

	t = strings.Trim(t, " ")
	if t == "" {
		get(ticker, e)
		return
	}

	e.Ticker = strings.ToUpper(t)
}

func price(e *entities.Transaction) {
	fmt.Print("Price: ")
	var input string
	fmt.Scanln(&input)

	p, err := strconv.ParseFloat(input, 64)

	if err != nil {
		fmt.Printf("\n%s is not a valid price value\n\n", input)
		get(price, e)
		return
	}

	e.Price = p
}

func transactionOperationType(e *entities.Transaction) {
	fmt.Println("Choose type of transaction")
	fmt.Println("")

	operationTypes, err := repository.TransactionalOperationTypes()
	LogError(err)

	header := []string{
		"Transaction Type",
	}

	var dict = make(map[string]string)
	var data [][]string
	for _, ot := range operationTypes {
		dict[ot.Type] = ot.Type
		data = append(data, []string{ot.Type})
	}

	DrawTable(header, data)
	fmt.Println("")

	var ot string
	fmt.Print("Transaction type: ")
	fmt.Scanln(&ot)

	_, exists := dict[ot]
	if exists {
		e.TransactionOperationType = ot
	} else {
		fmt.Printf("\n%s is not a valid transaction type\n\n", ot)
		get(transactionOperationType, e)
		return
	}
}

func currency(e *entities.Transaction) {
	fmt.Println("Choose currency")
	fmt.Println("")

	currencies, err := repository.Currencies()
	LogError(err)

	header := []string{
		"Currency",
	}

	var dict = make(map[string]string)
	var data [][]string
	for _, c := range currencies {
		dict[c.Symbol] = c.Symbol
		data = append(data, []string{c.Symbol})
	}

	DrawTable(header, data)
	fmt.Println("")

	var c string
	fmt.Print("Currency: ")
	fmt.Scanln(&c)

	c = strings.ToUpper(c)

	_, exists := dict[c]
	if exists {
		e.Currency = c
	} else {
		fmt.Printf("\n%s is not a valid currency\n\n", c)
		get(currency, e)
		return
	}
}

func shares(e *entities.Transaction) {
	fmt.Print("Number of shares: ")
	var input string
	fmt.Scanln(&input)

	s, err := strconv.ParseFloat(input, 64)

	if err != nil {
		fmt.Printf("\n%s is not a valid share number value\n\n", input)
		get(shares, e)
		return
	}

	e.Shares = s
}

func exchangeRate(e *entities.Transaction) {
	fmt.Print("Exchange rate (default: 1):")
	var input string
	fmt.Scanln(&input)

	er, err := strconv.ParseFloat(input, 64)

	if input == "" {
		er = 1
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid exchange rate value\n\n", input)
			get(exchangeRate, e)
			return
		}
	}

	e.ExchangeRate = er
}

func commision(e *entities.Transaction) {
	fmt.Print("Commision (default: 0): ")
	var input string
	fmt.Scanln(&input)

	c, err := strconv.ParseFloat(input, 64)

	if input == "" {
		c = 0
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid commision value\n\n", input)
			get(commision, e)
			return
		}
	}

	e.Commision = c
}

func tax(e *entities.Transaction) {
	fmt.Print("Tax (default: 0): ")
	var input string
	fmt.Scanln(&input)

	t, err := strconv.ParseFloat(input, 64)

	if input == "" {
		t = 0
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid tax value\n\n", input)
			get(tax, e)
			return
		}
	}

	e.Tax = t
}
<commit_msg>clear window before every getters<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/mgierok/monujo/repository"
	"github.com/mgierok/monujo/repository/entities"
)

func PutTransaction() {

	var t entities.Transaction
	get(portfolioId, &t)
	get(date, &t)
	get(ticker, &t)
	get(price, &t)
	get(transactionOperationType, &t)
	get(currency, &t)
	get(shares, &t)
	get(commision, &t)
	get(exchangeRate, &t)
	get(tax, &t)

	summary := [][]string{
		[]string{"Portfolio ID", strconv.FormatInt(t.PortfolioId, 10)},
		[]string{"Date", t.Date},
		[]string{"Ticker", t.Ticker},
		[]string{"Price", strconv.FormatFloat(t.Price, 'f', -1, 64)},
		[]string{"Type", t.TransactionOperationType},
		[]string{"Currency", t.Currency},
		[]string{"Shares", strconv.FormatFloat(t.Shares, 'f', -1, 64)},
		[]string{"Commision", strconv.FormatFloat(t.Commision, 'f', -1, 64)},
		[]string{"Exchange Rate", strconv.FormatFloat(t.ExchangeRate, 'f', -1, 64)},
		[]string{"Tax", strconv.FormatFloat(t.Tax, 'f', -1, 64)},
	}
	DrawTable([]string{}, summary)

	transactionId, err := repository.StoreTransaction(t)
	LogError(err)

	fmt.Printf("Transaction has been recorded with an ID: %d\n", transactionId)
}

func get(f func(*entities.Transaction), t *entities.Transaction) {
	Clear()
	f(t)
}

func portfolioId(e *entities.Transaction) {
	fmt.Println("Choose portfolio")
	fmt.Println("")

	portfolios, err := repository.Portfolios()
	LogError(err)

	header := []string{
		"Portfolio Id",
		"Portfolio Name",
	}

	var dict = make(map[int64]string)
	var data [][]string
	for _, p := range portfolios {
		data = append(data, []string{p.PortfolioId.String, p.Name.String})
		portfolioId, _ := strconv.ParseInt(p.PortfolioId.String, 10, 64)
		dict[portfolioId] = p.Name.String
	}

	DrawTable(header, data)
	fmt.Println("")

	var input string
	fmt.Print("Portfolio ID: ")
	fmt.Scanln(&input)

	p, err := strconv.ParseInt(input, 10, 64)

	if nil != err {
		fmt.Printf("\n%sd is not a valid portfolio ID\n\n", input)
		get(portfolioId, e)
		return
	} else {
		_, exists := dict[p]
		if exists {
			e.PortfolioId = p
		} else {
			fmt.Printf("\n%d is not a valid portfolio ID\n\n", p)
			get(portfolioId, e)
			return
		}
	}
}

func date(e *entities.Transaction) {
	const layout = "2006-01-02"
	var now = time.Now().Format(layout)
	var d string

	fmt.Printf("Date (default: %q): ", now)
	fmt.Scanln(&d)

	d = strings.Trim(d, " ")
	if d == "" {
		d = now
	} else {
		_, err := time.Parse(layout, d)
		if err != nil {
			fmt.Println(err)
			fmt.Printf("\n%q is not a valid date format\n\n", d)
			get(date, e)
			return
		}
	}

	e.Date = d
}

func ticker(e *entities.Transaction) {
	fmt.Print("Ticker: ")
	var t string
	fmt.Scanln(&t)

	t = strings.Trim(t, " ")
	if t == "" {
		get(ticker, e)
		return
	}

	e.Ticker = strings.ToUpper(t)
}

func price(e *entities.Transaction) {
	fmt.Print("Price: ")
	var input string
	fmt.Scanln(&input)

	p, err := strconv.ParseFloat(input, 64)

	if err != nil {
		fmt.Printf("\n%s is not a valid price value\n\n", input)
		get(price, e)
		return
	}

	e.Price = p
}

func transactionOperationType(e *entities.Transaction) {
	fmt.Println("Choose type of transaction")
	fmt.Println("")

	operationTypes, err := repository.TransactionalOperationTypes()
	LogError(err)

	header := []string{
		"Transaction Type",
	}

	var dict = make(map[string]string)
	var data [][]string
	for _, ot := range operationTypes {
		dict[ot.Type] = ot.Type
		data = append(data, []string{ot.Type})
	}

	DrawTable(header, data)
	fmt.Println("")

	var ot string
	fmt.Print("Transaction type: ")
	fmt.Scanln(&ot)

	_, exists := dict[ot]
	if exists {
		e.TransactionOperationType = ot
	} else {
		fmt.Printf("\n%s is not a valid transaction type\n\n", ot)
		get(transactionOperationType, e)
		return
	}
}

func currency(e *entities.Transaction) {
	fmt.Println("Choose currency")
	fmt.Println("")

	currencies, err := repository.Currencies()
	LogError(err)

	header := []string{
		"Currency",
	}

	var dict = make(map[string]string)
	var data [][]string
	for _, c := range currencies {
		dict[c.Symbol] = c.Symbol
		data = append(data, []string{c.Symbol})
	}

	DrawTable(header, data)
	fmt.Println("")

	var c string
	fmt.Print("Currency: ")
	fmt.Scanln(&c)

	c = strings.ToUpper(c)

	_, exists := dict[c]
	if exists {
		e.Currency = c
	} else {
		fmt.Printf("\n%s is not a valid currency\n\n", c)
		get(currency, e)
		return
	}
}

func shares(e *entities.Transaction) {
	fmt.Print("Number of shares: ")
	var input string
	fmt.Scanln(&input)

	s, err := strconv.ParseFloat(input, 64)

	if err != nil {
		fmt.Printf("\n%s is not a valid share number value\n\n", input)
		get(shares, e)
		return
	}

	e.Shares = s
}

func exchangeRate(e *entities.Transaction) {
	fmt.Print("Exchange rate (default: 1):")
	var input string
	fmt.Scanln(&input)

	er, err := strconv.ParseFloat(input, 64)

	if input == "" {
		er = 1
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid exchange rate value\n\n", input)
			get(exchangeRate, e)
			return
		}
	}

	e.ExchangeRate = er
}

func commision(e *entities.Transaction) {
	fmt.Print("Commision (default: 0): ")
	var input string
	fmt.Scanln(&input)

	c, err := strconv.ParseFloat(input, 64)

	if input == "" {
		c = 0
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid commision value\n\n", input)
			get(commision, e)
			return
		}
	}

	e.Commision = c
}

func tax(e *entities.Transaction) {
	fmt.Print("Tax (default: 0): ")
	var input string
	fmt.Scanln(&input)

	t, err := strconv.ParseFloat(input, 64)

	if input == "" {
		t = 0
	} else {
		if err != nil {
			fmt.Printf("\n%s is not a valid tax value\n\n", input)
			get(tax, e)
			return
		}
	}

	e.Tax = t
}
<|endoftext|>


<commit_before>/* Selenium/Webdriver client.

Currently provides only WebDriver remote client.

Version: 0.4.0
*/
package selenium

import (
	"time"
)

/* Element finding options */
const (
	ById              = "id"
	ByXPATH           = "xpath"
	ByLinkText        = "link text"
	ByPartialLinkText = "partial link text"
	ByName            = "name"
	ByTagName         = "tag name"
	ByClassName       = "class name"
	ByCSSSelector     = "css selector"
)

/* Mouse buttons */
const (
	LeftButton = iota
	MiddleButton
	RightButton
)

/* Keys */
const (
	NullKey       = string('\ue000')
	CancelKey     = string('\ue001')
	HelpKey       = string('\ue002')
	BackspaceKey  = string('\ue003')
	TabKey        = string('\ue004')
	ClearKey      = string('\ue005')
	ReturnKey     = string('\ue006')
	EnterKey      = string('\ue007')
	ShiftKey      = string('\ue008')
	ControlKey    = string('\ue009')
	AltKey        = string('\ue00a')
	PauseKey      = string('\ue00b')
	EscapeKey     = string('\ue00c')
	SpaceKey      = string('\ue00d')
	PageUpKey     = string('\ue00e')
	PageDownKey   = string('\ue00f')
	EndKey        = string('\ue010')
	HomeKey       = string('\ue011')
	LeftArrowKey  = string('\ue012')
	UpArrowKey    = string('\ue013')
	RightArrowKey = string('\ue014')
	DownArrowKey  = string('\ue015')
	InsertKey     = string('\ue016')
	DeleteKey     = string('\ue017')
	SemicolonKey  = string('\ue018')
	EqualsKey     = string('\ue019')
	Numpad0Key    = string('\ue01a')
	Numpad1Key    = string('\ue01b')
	Numpad2Key    = string('\ue01c')
	Numpad3Key    = string('\ue01d')
	Numpad4Key    = string('\ue01e')
	Numpad5Key    = string('\ue01f')
	Numpad6Key    = string('\ue020')
	Numpad7Key    = string('\ue021')
	Numpad8Key    = string('\ue022')
	Numpad9Key    = string('\ue023')
	MultiplyKey   = string('\ue024')
	AddKey        = string('\ue025')
	SeparatorKey  = string('\ue026')
	SubstractKey  = string('\ue027')
	DecimalKey    = string('\ue028')
	DivideKey     = string('\ue029')
	F1Key         = string('\ue031')
	F2Key         = string('\ue032')
	F3Key         = string('\ue033')
	F4Key         = string('\ue034')
	F5Key         = string('\ue035')
	F6Key         = string('\ue036')
	F7Key         = string('\ue037')
	F8Key         = string('\ue038')
	F9Key         = string('\ue039')
	F10Key        = string('\ue03a')
	F11Key        = string('\ue03b')
	F12Key        = string('\ue03c')
	MetaKey       = string('\ue03d')
)

/* Browser capabilities, see
http://code.google.com/p/selenium/wiki/JsonWireProtocol#Capabilities_JSON_Object
*/
type Capabilities map[string]interface{}

/* Build object, part of Status return. */
type Build struct {
	Version, Revision, Time string
}

/* OS object, part of Status return. */
type OS struct {
	Arch, Name, Version string
}

type Java struct {
	Version string
}

/* Information retured by Status method. */
type Status struct {
	Java Java
	Build Build
	OS OS
}

/* Point */
type Point struct {
	X, Y int
}

/* Size */
type Size struct {
	Width, Height int
}

/* Cookie */
type Cookie struct {
	Name   string `json:"name"`
	Value  string `json:"value"`
	Path   string `json:"path"`
	Domain string `json:"domain"`
	Secure bool   `json:"secure"`
	Expiry uint   `json:"expiry"`
}

type WebDriver interface {
	/* Status (info) on server */
	Status() (*Status, error)

	/* Start a new session, return session id */
	NewSession() (string, error)

	/* Current session capabilities */
	Capabilities() (Capabilities, error)
	/* Set the amount of time, in microseconds, that asynchronous scripts are permitted to run before they are aborted.

	Note that Selenium/WebDriver timeouts are in milliseconds, timeout will be rounded to nearest millisecond.
	*/
	SetAsyncScriptTimeout(timeout time.Duration) error
	/* Set the amount of time, in milliseconds, the driver should wait when searching for elements.

	Note that Selenium/WebDriver timeouts are in milliseconds, timeout will be rounded to nearest millisecond.
	*/
	SetImplicitWaitTimeout(timeout time.Duration) error

	// IME
	/* List all available engines on the machine. */
	AvailableEngines() ([]string, error)
	/* Get the name of the active IME engine. */
	ActiveEngine() (string, error)
	/* Indicates whether IME input is active at the moment. */
	IsEngineActivated() (bool, error)
	/* De-activates the currently-active IME engine. */
	DeactivateEngine() error
	/* Make an engines active */
	ActivateEngine(engine string) error

	/* Quit (end) current session */
	Quit() error

	// Page information and manipulation
	/* Return id of current window handle. */
	CurrentWindowHandle() (string, error)
	/* Return ids of current open windows. */
	WindowHandles() ([]string, error)
	/* Current url. */
	CurrentURL() (string, error)
	/* Page title. */
	Title() (string, error)
	/* Get page source. */
	PageSource() (string, error)
	/* Close current window. */
	Close() error
	/* Switch to frame, frame parameter can be name or id. */
	SwitchFrame(frame string) error
	/* Swtich to window. */
	SwitchWindow(name string) error
	/* Close window. */
	CloseWindow(name string) error

	// Navigation
	/* Open url. */
	Get(url string) error
	/* Move forward in history. */
	Forward() error
	/* Move backward in history. */
	Back() error
	/* Refresh page. */
	Refresh() error

	// Finding element(s)
	/* Find, return one element. */
	FindElement(by, value string) (WebElement, error)
	/* Find, return list of elements. */
	FindElements(by, value string) ([]WebElement, error)
	/* Current active element. */
	ActiveElement() (WebElement, error)

	// Cookies
	/* Get all cookies */
	GetCookies() ([]Cookie, error)
	/* Add a cookies */
	AddCookie(cookie *Cookie) error
	/* Delete all cookies */
	DeleteAllCookies() error
	/* Delete a cookie */
	DeleteCookie(name string) error

	// Mouse
	/* Click mouse button, button should be on of RightButton, MiddleButton or
	LeftButton.
	*/
	Click(button int) error
	/* Dobule click */
	DoubleClick() error
	/* Mouse button down */
	ButtonDown() error
	/* Mouse button up */
	ButtonUp() error

	// Misc
	/* Send modifier key to active element.
	modifier can be one of ShiftKey, ControlKey, AltKey, MetaKey.
	*/
	SendModifier(modifier string, isDown bool) error
	Screenshot() ([]byte, error)

	// Alerts
	/* Dismiss current alert. */
	DismissAlert() error
	/* Accept current alert. */
	AcceptAlert() error
	/* Current alert text. */
	AlertText() (string, error)
	/* Set current alert text. */
	SetAlertText(text string) error

	// Scripts
	/* Execute a script. */
	ExecuteScript(script string, args []interface{}) (interface{}, error)
	/* Execute a script async. */
	ExecuteScriptAsync(script string, args []interface{}) (interface{}, error)
}

type WebElement interface {
	// Manipulation

	/* Click on element */
	Click() error
	/* Send keys (type) into element */
	SendKeys(keys string) error
	/* Submit */
	Submit() error
	/* Clear */
	Clear() error
	/* Move mouse to relative coordinates */
	MoveTo(xOffset, yOffset int) error

	// Finding

	/* Find children, return one element. */
	FindElement(by, value string) (WebElement, error)
	/* Find children, return list of elements. */
	FindElements(by, value string) ([]WebElement, error)

	// Porperties

	/* Element name */
	TagName() (string, error)
	/* Text of element */
	Text() (string, error)
	/* Check if element is selected. */
	IsSelected() (bool, error)
	/* Check if element is enabled. */
	IsEnabled() (bool, error)
	/* Check if element is displayed. */
	IsDisplayed() (bool, error)
	/* Get element attribute. */
	GetAttribute(name string) (string, error)
	/* Element location. */
	Location() (*Point, error)
	/* Element location once it has been scrolled into view. */
	LocationInView() (*Point, error)
	/* Element size */
	Size() (*Size, error)
	/* Get element CSS property value. */
	CSSProperty(name string) (string, error)
}
<commit_msg>VERSION and fmt<commit_after>/* Selenium/Webdriver client.

Currently provides only WebDriver remote client.

*/
package selenium

import (
	"time"
)

const (
	VERSION = "0.5.0" // Driver version
)

/* Element finding options */
const (
	ById              = "id"
	ByXPATH           = "xpath"
	ByLinkText        = "link text"
	ByPartialLinkText = "partial link text"
	ByName            = "name"
	ByTagName         = "tag name"
	ByClassName       = "class name"
	ByCSSSelector     = "css selector"
)

/* Mouse buttons */
const (
	LeftButton = iota
	MiddleButton
	RightButton
)

/* Keys */
const (
	NullKey       = string('\ue000')
	CancelKey     = string('\ue001')
	HelpKey       = string('\ue002')
	BackspaceKey  = string('\ue003')
	TabKey        = string('\ue004')
	ClearKey      = string('\ue005')
	ReturnKey     = string('\ue006')
	EnterKey      = string('\ue007')
	ShiftKey      = string('\ue008')
	ControlKey    = string('\ue009')
	AltKey        = string('\ue00a')
	PauseKey      = string('\ue00b')
	EscapeKey     = string('\ue00c')
	SpaceKey      = string('\ue00d')
	PageUpKey     = string('\ue00e')
	PageDownKey   = string('\ue00f')
	EndKey        = string('\ue010')
	HomeKey       = string('\ue011')
	LeftArrowKey  = string('\ue012')
	UpArrowKey    = string('\ue013')
	RightArrowKey = string('\ue014')
	DownArrowKey  = string('\ue015')
	InsertKey     = string('\ue016')
	DeleteKey     = string('\ue017')
	SemicolonKey  = string('\ue018')
	EqualsKey     = string('\ue019')
	Numpad0Key    = string('\ue01a')
	Numpad1Key    = string('\ue01b')
	Numpad2Key    = string('\ue01c')
	Numpad3Key    = string('\ue01d')
	Numpad4Key    = string('\ue01e')
	Numpad5Key    = string('\ue01f')
	Numpad6Key    = string('\ue020')
	Numpad7Key    = string('\ue021')
	Numpad8Key    = string('\ue022')
	Numpad9Key    = string('\ue023')
	MultiplyKey   = string('\ue024')
	AddKey        = string('\ue025')
	SeparatorKey  = string('\ue026')
	SubstractKey  = string('\ue027')
	DecimalKey    = string('\ue028')
	DivideKey     = string('\ue029')
	F1Key         = string('\ue031')
	F2Key         = string('\ue032')
	F3Key         = string('\ue033')
	F4Key         = string('\ue034')
	F5Key         = string('\ue035')
	F6Key         = string('\ue036')
	F7Key         = string('\ue037')
	F8Key         = string('\ue038')
	F9Key         = string('\ue039')
	F10Key        = string('\ue03a')
	F11Key        = string('\ue03b')
	F12Key        = string('\ue03c')
	MetaKey       = string('\ue03d')
)

/* Browser capabilities, see
http://code.google.com/p/selenium/wiki/JsonWireProtocol#Capabilities_JSON_Object
*/
type Capabilities map[string]interface{}

/* Build object, part of Status return. */
type Build struct {
	Version, Revision, Time string
}

/* OS object, part of Status return. */
type OS struct {
	Arch, Name, Version string
}

type Java struct {
	Version string
}

/* Information retured by Status method. */
type Status struct {
	Java  Java
	Build Build
	OS    OS
}

/* Point */
type Point struct {
	X, Y int
}

/* Size */
type Size struct {
	Width, Height int
}

/* Cookie */
type Cookie struct {
	Name   string `json:"name"`
	Value  string `json:"value"`
	Path   string `json:"path"`
	Domain string `json:"domain"`
	Secure bool   `json:"secure"`
	Expiry uint   `json:"expiry"`
}

type WebDriver interface {
	/* Status (info) on server */
	Status() (*Status, error)

	/* Start a new session, return session id */
	NewSession() (string, error)

	/* Current session capabilities */
	Capabilities() (Capabilities, error)
	/* Set the amount of time, in microseconds, that asynchronous scripts are permitted to run before they are aborted.

	Note that Selenium/WebDriver timeouts are in milliseconds, timeout will be rounded to nearest millisecond.
	*/
	SetAsyncScriptTimeout(timeout time.Duration) error
	/* Set the amount of time, in milliseconds, the driver should wait when searching for elements.

	Note that Selenium/WebDriver timeouts are in milliseconds, timeout will be rounded to nearest millisecond.
	*/
	SetImplicitWaitTimeout(timeout time.Duration) error

	// IME
	/* List all available engines on the machine. */
	AvailableEngines() ([]string, error)
	/* Get the name of the active IME engine. */
	ActiveEngine() (string, error)
	/* Indicates whether IME input is active at the moment. */
	IsEngineActivated() (bool, error)
	/* De-activates the currently-active IME engine. */
	DeactivateEngine() error
	/* Make an engines active */
	ActivateEngine(engine string) error

	/* Quit (end) current session */
	Quit() error

	// Page information and manipulation
	/* Return id of current window handle. */
	CurrentWindowHandle() (string, error)
	/* Return ids of current open windows. */
	WindowHandles() ([]string, error)
	/* Current url. */
	CurrentURL() (string, error)
	/* Page title. */
	Title() (string, error)
	/* Get page source. */
	PageSource() (string, error)
	/* Close current window. */
	Close() error
	/* Switch to frame, frame parameter can be name or id. */
	SwitchFrame(frame string) error
	/* Swtich to window. */
	SwitchWindow(name string) error
	/* Close window. */
	CloseWindow(name string) error

	// Navigation
	/* Open url. */
	Get(url string) error
	/* Move forward in history. */
	Forward() error
	/* Move backward in history. */
	Back() error
	/* Refresh page. */
	Refresh() error

	// Finding element(s)
	/* Find, return one element. */
	FindElement(by, value string) (WebElement, error)
	/* Find, return list of elements. */
	FindElements(by, value string) ([]WebElement, error)
	/* Current active element. */
	ActiveElement() (WebElement, error)

	// Cookies
	/* Get all cookies */
	GetCookies() ([]Cookie, error)
	/* Add a cookies */
	AddCookie(cookie *Cookie) error
	/* Delete all cookies */
	DeleteAllCookies() error
	/* Delete a cookie */
	DeleteCookie(name string) error

	// Mouse
	/* Click mouse button, button should be on of RightButton, MiddleButton or
	LeftButton.
	*/
	Click(button int) error
	/* Dobule click */
	DoubleClick() error
	/* Mouse button down */
	ButtonDown() error
	/* Mouse button up */
	ButtonUp() error

	// Misc
	/* Send modifier key to active element.
	modifier can be one of ShiftKey, ControlKey, AltKey, MetaKey.
	*/
	SendModifier(modifier string, isDown bool) error
	Screenshot() ([]byte, error)

	// Alerts
	/* Dismiss current alert. */
	DismissAlert() error
	/* Accept current alert. */
	AcceptAlert() error
	/* Current alert text. */
	AlertText() (string, error)
	/* Set current alert text. */
	SetAlertText(text string) error

	// Scripts
	/* Execute a script. */
	ExecuteScript(script string, args []interface{}) (interface{}, error)
	/* Execute a script async. */
	ExecuteScriptAsync(script string, args []interface{}) (interface{}, error)
}

type WebElement interface {
	// Manipulation

	/* Click on element */
	Click() error
	/* Send keys (type) into element */
	SendKeys(keys string) error
	/* Submit */
	Submit() error
	/* Clear */
	Clear() error
	/* Move mouse to relative coordinates */
	MoveTo(xOffset, yOffset int) error

	// Finding

	/* Find children, return one element. */
	FindElement(by, value string) (WebElement, error)
	/* Find children, return list of elements. */
	FindElements(by, value string) ([]WebElement, error)

	// Porperties

	/* Element name */
	TagName() (string, error)
	/* Text of element */
	Text() (string, error)
	/* Check if element is selected. */
	IsSelected() (bool, error)
	/* Check if element is enabled. */
	IsEnabled() (bool, error)
	/* Check if element is displayed. */
	IsDisplayed() (bool, error)
	/* Get element attribute. */
	GetAttribute(name string) (string, error)
	/* Element location. */
	Location() (*Point, error)
	/* Element location once it has been scrolled into view. */
	LocationInView() (*Point, error)
	/* Element size */
	Size() (*Size, error)
	/* Get element CSS property value. */
	CSSProperty(name string) (string, error)
}
<|endoftext|>


<commit_before>package handler

import (
	"fmt"
	"net/http"

	"code.uber.internal/infra/kraken/utils/log"
)

// Error defines an HTTP handler error which encapsulates status and headers
// to be set in the HTTP response.
type Error struct {
	status int
	header http.Header
	msg    string
}

// Errorf creates a new Error with Printf-style formatting. Defaults to 500 error.
func Errorf(format string, args ...interface{}) *Error {
	return &Error{
		status: http.StatusInternalServerError,
		header: http.Header{},
		msg:    fmt.Sprintf(format, args...),
	}
}

// ErrorStatus creates an empty message error with status s.
func ErrorStatus(s int) *Error {
	return Errorf("").Status(s)
}

// Status sets a custom status on e.
func (e *Error) Status(s int) *Error {
	e.status = s
	return e
}

// Header adds a custom header to e.
func (e *Error) Header(k, v string) *Error {
	e.header.Add(k, v)
	return e
}

// GetStatus returns the error status.
func (e *Error) GetStatus() int {
	return e.status
}

func (e *Error) Error() string {
	if e.msg == "" {
		return fmt.Sprintf("server error %d", e.status)
	}
	return fmt.Sprintf("server error %d: %s", e.status, e.msg)
}

// ErrHandler defines an HTTP handler which returns an error.
type ErrHandler func(http.ResponseWriter, *http.Request) error

// Wrap converts an ErrHandler into an http.HandlerFunc by handling the error
// returned by h.
func Wrap(h ErrHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var status int
		var errMsg string
		if err := h(w, r); err != nil {
			switch e := err.(type) {
			case *Error:
				for k, vs := range e.header {
					for _, v := range vs {
						w.Header().Add(k, v)
					}
				}
				status = e.status
				errMsg = e.msg
			default:
				status = http.StatusInternalServerError
				errMsg = e.Error()
			}
			w.WriteHeader(status)
			w.Write([]byte(errMsg))
		} else {
			status = http.StatusOK
		}
		log.Infof("%d %s %s %s", status, r.Method, r.URL.Path, errMsg)
	}
}
<commit_msg>Misc. logging fix up<commit_after>package handler

import (
	"fmt"
	"net/http"

	"code.uber.internal/infra/kraken/utils/log"
)

// Error defines an HTTP handler error which encapsulates status and headers
// to be set in the HTTP response.
type Error struct {
	status int
	header http.Header
	msg    string
}

// Errorf creates a new Error with Printf-style formatting. Defaults to 500 error.
func Errorf(format string, args ...interface{}) *Error {
	return &Error{
		status: http.StatusInternalServerError,
		header: http.Header{},
		msg:    fmt.Sprintf(format, args...),
	}
}

// ErrorStatus creates an empty message error with status s.
func ErrorStatus(s int) *Error {
	return Errorf("").Status(s)
}

// Status sets a custom status on e.
func (e *Error) Status(s int) *Error {
	e.status = s
	return e
}

// Header adds a custom header to e.
func (e *Error) Header(k, v string) *Error {
	e.header.Add(k, v)
	return e
}

// GetStatus returns the error status.
func (e *Error) GetStatus() int {
	return e.status
}

func (e *Error) Error() string {
	if e.msg == "" {
		return fmt.Sprintf("server error %d", e.status)
	}
	return fmt.Sprintf("server error %d: %s", e.status, e.msg)
}

// ErrHandler defines an HTTP handler which returns an error.
type ErrHandler func(http.ResponseWriter, *http.Request) error

// Wrap converts an ErrHandler into an http.HandlerFunc by handling the error
// returned by h.
func Wrap(h ErrHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var status int
		var errMsg string
		if err := h(w, r); err != nil {
			switch e := err.(type) {
			case *Error:
				for k, vs := range e.header {
					for _, v := range vs {
						w.Header().Add(k, v)
					}
				}
				status = e.status
				errMsg = e.msg
			default:
				status = http.StatusInternalServerError
				errMsg = e.Error()
			}
			w.WriteHeader(status)
			w.Write([]byte(errMsg))
		} else {
			status = http.StatusOK
		}
		if status >= 400 {
			log.Infof("%d %s %s %s", status, r.Method, r.URL.Path, errMsg)
		}
	}
}
<|endoftext|>


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

package swarm

import (
	"crypto/tls"
	"crypto/x509"
	"math/rand"

	"github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/storage"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type notFoundError struct{ error }

func (e notFoundError) NotFound() bool {
	return true
}

var errNoSwarmNode = notFoundError{errors.New("no swarm nodes available")}

const (
	uniqueDocumentID       = "swarm"
	swarmCollectionName    = "swarmnodes"
	swarmSecCollectionName = "swarmsec"
	nodeRetryCount         = 3
)

type NodeAddrs struct {
	UniqueID  string `bson:"_id"`
	Addresses []string
}

func chooseDBSwarmNode() (*docker.Client, error) {
	coll, err := nodeAddrCollection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var addrs NodeAddrs
	err = coll.FindId(uniqueDocumentID).One(&addrs)
	if err != nil && err != mgo.ErrNotFound {
		return nil, errors.WithStack(err)
	}
	if len(addrs.Addresses) == 0 {
		return nil, errors.Wrap(errNoSwarmNode, "")
	}
	var client *docker.Client
	initialIdx := rand.Intn(len(addrs.Addresses))
	var i int
	for ; i < nodeRetryCount; i++ {
		idx := (initialIdx + i) % len(addrs.Addresses)
		addr := addrs.Addresses[idx]
		client, err = newClient(addr)
		if err != nil {
			return nil, err
		}
		err = client.Ping()
		if err == nil {
			break
		}
	}
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if i > 0 {
		updateDBSwarmNodes(client)
	}
	return client, nil
}

func updateDBSwarmNodes(client *docker.Client) error {
	nodes, err := listValidNodes(client)
	if err != nil {
		return errors.WithStack(err)
	}
	var addrs []string
	for _, n := range nodes {
		if n.ManagerStatus == nil {
			continue
		}
		addr := n.Spec.Annotations.Labels[labelNodeDockerAddr.String()]
		if addr == "" {
			continue
		}
		addrs = append(addrs, addr)
	}
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	_, err = coll.UpsertId(uniqueDocumentID, bson.M{"$set": bson.M{"addresses": addrs}})
	if err != nil {
		return errors.WithStack(err)
	}
	return nil
}

func removeDBSwarmNodes() error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	err = coll.RemoveId(uniqueDocumentID)
	if err != nil && err != mgo.ErrNotFound {
		return errors.WithStack(err)
	}
	return nil
}

type NodeSec struct {
	Address    string `bson:"_id"`
	CaCert     []byte
	ClientCert []byte
	ClientKey  []byte
}

func addNodeCredentials(opts provision.AddNodeOptions) error {
	if opts.CaCert == nil && opts.ClientCert == nil && opts.ClientKey == nil {
		return nil
	}
	secColl, err := nodeSecurityCollection()
	if err != nil {
		return err
	}
	defer secColl.Close()
	data := NodeSec{
		Address:    opts.Address,
		CaCert:     opts.CaCert,
		ClientCert: opts.ClientCert,
		ClientKey:  opts.ClientKey,
	}
	_, err = secColl.UpsertId(data.Address, data)
	return errors.WithStack(err)
}

func getNodeCredentials(address string) (*tls.Config, error) {
	secColl, err := nodeSecurityCollection()
	if err != nil {
		return nil, err
	}
	var data NodeSec
	err = secColl.FindId(address).One(&data)
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, errors.WithStack(err)
	}
	tlsCert, err := tls.X509KeyPair(data.ClientCert, data.ClientKey)
	if err != nil {
		return nil, err
	}
	caPool := x509.NewCertPool()
	if !caPool.AppendCertsFromPEM(data.CaCert) {
		return nil, errors.New("could not add RootCA pem")
	}
	return &tls.Config{
		Certificates: []tls.Certificate{tlsCert},
		RootCAs:      caPool,
	}, nil
}

func nodeAddrCollection() (*storage.Collection, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return conn.Collection(swarmCollectionName), nil
}

func nodeSecurityCollection() (*storage.Collection, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return conn.Collection(swarmSecCollectionName), nil
}
<commit_msg>provision/swarm: fix collection leak<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package swarm

import (
	"crypto/tls"
	"crypto/x509"
	"math/rand"

	"github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/storage"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type notFoundError struct{ error }

func (e notFoundError) NotFound() bool {
	return true
}

var errNoSwarmNode = notFoundError{errors.New("no swarm nodes available")}

const (
	uniqueDocumentID       = "swarm"
	swarmCollectionName    = "swarmnodes"
	swarmSecCollectionName = "swarmsec"
	nodeRetryCount         = 3
)

type NodeAddrs struct {
	UniqueID  string `bson:"_id"`
	Addresses []string
}

func chooseDBSwarmNode() (*docker.Client, error) {
	coll, err := nodeAddrCollection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var addrs NodeAddrs
	err = coll.FindId(uniqueDocumentID).One(&addrs)
	if err != nil && err != mgo.ErrNotFound {
		return nil, errors.WithStack(err)
	}
	if len(addrs.Addresses) == 0 {
		return nil, errors.Wrap(errNoSwarmNode, "")
	}
	var client *docker.Client
	initialIdx := rand.Intn(len(addrs.Addresses))
	var i int
	for ; i < nodeRetryCount; i++ {
		idx := (initialIdx + i) % len(addrs.Addresses)
		addr := addrs.Addresses[idx]
		client, err = newClient(addr)
		if err != nil {
			return nil, err
		}
		err = client.Ping()
		if err == nil {
			break
		}
	}
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if i > 0 {
		updateDBSwarmNodes(client)
	}
	return client, nil
}

func updateDBSwarmNodes(client *docker.Client) error {
	nodes, err := listValidNodes(client)
	if err != nil {
		return errors.WithStack(err)
	}
	var addrs []string
	for _, n := range nodes {
		if n.ManagerStatus == nil {
			continue
		}
		addr := n.Spec.Annotations.Labels[labelNodeDockerAddr.String()]
		if addr == "" {
			continue
		}
		addrs = append(addrs, addr)
	}
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	_, err = coll.UpsertId(uniqueDocumentID, bson.M{"$set": bson.M{"addresses": addrs}})
	if err != nil {
		return errors.WithStack(err)
	}
	return nil
}

func removeDBSwarmNodes() error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	err = coll.RemoveId(uniqueDocumentID)
	if err != nil && err != mgo.ErrNotFound {
		return errors.WithStack(err)
	}
	return nil
}

type NodeSec struct {
	Address    string `bson:"_id"`
	CaCert     []byte
	ClientCert []byte
	ClientKey  []byte
}

func addNodeCredentials(opts provision.AddNodeOptions) error {
	if opts.CaCert == nil && opts.ClientCert == nil && opts.ClientKey == nil {
		return nil
	}
	secColl, err := nodeSecurityCollection()
	if err != nil {
		return err
	}
	defer secColl.Close()
	data := NodeSec{
		Address:    opts.Address,
		CaCert:     opts.CaCert,
		ClientCert: opts.ClientCert,
		ClientKey:  opts.ClientKey,
	}
	_, err = secColl.UpsertId(data.Address, data)
	return errors.WithStack(err)
}

func getNodeCredentials(address string) (*tls.Config, error) {
	secColl, err := nodeSecurityCollection()
	if err != nil {
		return nil, err
	}
	defer secColl.Close()
	var data NodeSec
	err = secColl.FindId(address).One(&data)
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, errors.WithStack(err)
	}
	tlsCert, err := tls.X509KeyPair(data.ClientCert, data.ClientKey)
	if err != nil {
		return nil, err
	}
	caPool := x509.NewCertPool()
	if !caPool.AppendCertsFromPEM(data.CaCert) {
		return nil, errors.New("could not add RootCA pem")
	}
	return &tls.Config{
		Certificates: []tls.Certificate{tlsCert},
		RootCAs:      caPool,
	}, nil
}

func nodeAddrCollection() (*storage.Collection, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return conn.Collection(swarmCollectionName), nil
}

func nodeSecurityCollection() (*storage.Collection, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return conn.Collection(swarmSecCollectionName), nil
}
<|endoftext|>


<commit_before>package binder

import (
	"reflect"
	"github.com/microcosm-cc/bluemonday"
)

var p = bluemonday.NewPolicy()

func xssFilter (ptr interface{}) {
	if kindOfData(ptr) == reflect.Struct {
		typ := reflect.TypeOf(ptr).Elem()
		val := reflect.ValueOf(ptr).Elem()
		for i := 0; i < typ.NumField(); i++ {
			typeField := typ.Field(i)
			structField := val.Field(i)
			if !structField.CanSet() {
				continue
			}
			structFieldKind := structField.Kind()
			xss := typeField.Tag.Get("xss")
			if structFieldKind == reflect.Struct {
				xssFilter(structField.Addr().Interface())
			}
			if xss == "true" && structFieldKind == reflect.String {
				structField.SetString(p.Sanitize(structField.String()))
			}
		}
	}
}

func init() {
	p.AllowAttrs("href").OnElements("a")
	p.AllowAttrs("src").OnElements("img")
	p.AllowStandardURLs()
	p.AllowElements("p")
}<commit_msg>添加常见富文本<commit_after>package binder

import (
	"reflect"
	"github.com/microcosm-cc/bluemonday"
)

var p = bluemonday.UGCPolicy().AllowElements("font").AllowAttrs("style", "align", "color", "size").Globally()

func xssFilter (ptr interface{}) {
	if kindOfData(ptr) == reflect.Struct {
		typ := reflect.TypeOf(ptr).Elem()
		val := reflect.ValueOf(ptr).Elem()
		for i := 0; i < typ.NumField(); i++ {
			typeField := typ.Field(i)
			structField := val.Field(i)
			if !structField.CanSet() {
				continue
			}
			structFieldKind := structField.Kind()
			xss := typeField.Tag.Get("xss")
			if structFieldKind == reflect.Struct {
				xssFilter(structField.Addr().Interface())
			}
			if xss == "true" && structFieldKind == reflect.String {
				structField.SetString(p.Sanitize(structField.String()))
			}
		}
	}
}<|endoftext|>


<commit_before>package mint_test

import "testing"
import "github.com/otiai10/mint"

func TestMint_ToBe(t *testing.T) {
	mint.Expect(t, 1).ToBe(1)
}
func TestMint_ToBe_Fail(t *testing.T) {
	r := mint.Expect(t, 2).Dry().ToBe(1).Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)
}

type MyStruct struct{}
func TestMint_TypeOf(t *testing.T) {
	mint.Expect(t, "foo").TypeOf("string")

	bar := MyStruct{}
	mint.Expect(t, bar).TypeOf("mint_test.MyStruct")
}
func TestMint_TypeOf_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().TypeOf("int").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)

	bar := MyStruct{}
	r = mint.Expect(t, bar).Dry().TypeOf("foo.Bar").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)
	mint.Expect(t, r.Message).ToBe("Expected type `foo.Bar`, but actual `mint_test.MyStruct`\n")
}

func TestMint_Not(t *testing.T) {
	mint.Expect(t, 100).Not().ToBe(200)
	mint.Expect(t, "foo").Not().TypeOf("int")
	mint.Expect(t, true).Not().ToBe(nil)
}
func TestMint_Not_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().Not().TypeOf("string").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).Not().ToBe(true)
}

// Blend is a shorhand to get testee
func TestMint_Blend(t *testing.T) {
	m := mint.Blend(t)
	// assert mint by using mint
	mint.Expect(t, m).TypeOf("*mint.Mint")
	mint.Expect(t, m.Expect("foo")).TypeOf("*mint.Testee")
}
<commit_msg>go fmt<commit_after>package mint_test

import "testing"
import "github.com/otiai10/mint"

func TestMint_ToBe(t *testing.T) {
	mint.Expect(t, 1).ToBe(1)
}
func TestMint_ToBe_Fail(t *testing.T) {
	r := mint.Expect(t, 2).Dry().ToBe(1).Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)
}

type MyStruct struct{}

func TestMint_TypeOf(t *testing.T) {
	mint.Expect(t, "foo").TypeOf("string")

	bar := MyStruct{}
	mint.Expect(t, bar).TypeOf("mint_test.MyStruct")
}
func TestMint_TypeOf_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().TypeOf("int").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)

	bar := MyStruct{}
	r = mint.Expect(t, bar).Dry().TypeOf("foo.Bar").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).ToBe(false)
	mint.Expect(t, r.Message).ToBe("Expected type `foo.Bar`, but actual `mint_test.MyStruct`\n")
}

func TestMint_Not(t *testing.T) {
	mint.Expect(t, 100).Not().ToBe(200)
	mint.Expect(t, "foo").Not().TypeOf("int")
	mint.Expect(t, true).Not().ToBe(nil)
}
func TestMint_Not_Fail(t *testing.T) {
	r := mint.Expect(t, "foo").Dry().Not().TypeOf("string").Result
	// assert mint by using mint
	mint.Expect(t, r.OK).Not().ToBe(true)
}

// Blend is a shorhand to get testee
func TestMint_Blend(t *testing.T) {
	m := mint.Blend(t)
	// assert mint by using mint
	mint.Expect(t, m).TypeOf("*mint.Mint")
	mint.Expect(t, m.Expect("foo")).TypeOf("*mint.Testee")
}
<|endoftext|>