<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"

	"github.com/dfordsoft/golib/fsutil"
	"github.com/gin-gonic/gin"
)

var (
	fontFiles   []string
	mutexMaking sync.Mutex
	books       = Books{}
	sha1ver     string // sha1 revision used to build the program
	buildTime   string // when the executable was built
)

// Books book collect
type Books struct {
	sync.Mutex
	items []*HistoryItem
}

func (books *Books) append(item *HistoryItem) {
	books.Lock()
	books.items = append(books.items, item)
	books.Unlock()
}

func (books *Books) clear() {
	books.Lock()
	books.items = []*HistoryItem{}
	books.Unlock()
}

func (books *Books) delete(name string) {
	books.Lock()
	for i, book := range books.items {
		if book.BookName == name {
			books.items = append(books.items[:i], books.items[i+1:]...)
			break
		}
	}
	books.Unlock()
}

// HistoryItem - 书籍记录，有4种状态，分别是有效，失败，进行，等待
type HistoryItem struct {
	TOCURL       string `template:"tocurl"`
	BookName     string `template:"name"`
	Status       string `template:"status"`
	DownloadLink string `template:"downloadLink"`
	DeleteLink   string `template:"deleteLink"`
}

func homePage(c *gin.Context) {
	c.HTML(http.StatusOK, "home.tmpl", gin.H{
		"title":     "GetNovel",
		"fontFiles": fontFiles,
		"items":     books.items,
	})
}

type GetNovelAuguments struct {
	TOCURL          string  `form:"tocurl"`
	Format          string  `form:"format"`
	PageType        string  `form:"pageType"`
	LeftMargin      int     `form:"leftMargin"`
	TopMargin       int     `form:"topMargin"`
	TitleFontSize   int     `form:"titleFontSize"`
	ContentFontSize int     `form:"contentFontSize"`
	LineSpacing     float32 `form:"lineSpacing"`
	PagesPerFile    int     `form:"pagesPerFile"`
	ChaptersPerFile int     `form:"chaptersPerFile"`
	FontFile        string  `form:"fontFile"`
	FromTitle       string  `form:"fromTitle"`
	ToTitle         string  `form:"toTitle"`
	FromChapter     int     `form:"fromChapter"`
	ToChapter       int     `form:"toChapter"`
}

func makeEbook(c *gin.Context) {
	var gnargs GetNovelAuguments
	if err := c.ShouldBindJSON(&gnargs); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("%v", err),
		})
		return
	}
	getnovel, _ := exec.LookPath(`getnovel`)

	if b, e := fsutil.FileExists(getnovel); e != nil || !b {
		if dir, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
			getnovel = filepath.Join(dir, `getnovel`)
		}
	}

	if b, e := fsutil.FileExists(getnovel); e != nil || !b {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "getnovel not found",
		})
		return
	}

	args := []string{
		"-f",
		gnargs.Format,
		"-p",
		gnargs.PageType,
		"--fontFile",
		gnargs.FontFile,
	}

	if gnargs.Format == "pdf" {
		args = append(args,
			fmt.Sprintf("--leftMargin=%d", gnargs.LeftMargin),
			fmt.Sprintf("--topMargin=%d", gnargs.TopMargin),
			fmt.Sprintf("--titleFontSize=%d", gnargs.TitleFontSize),
			fmt.Sprintf("--contentFontSize=%d", gnargs.ContentFontSize),
			fmt.Sprintf("--lineSpacing=%f", gnargs.LineSpacing),
			fmt.Sprintf("--pagesPerFile=%d", gnargs.PagesPerFile),
			fmt.Sprintf("--chaptersPerFile=%d", gnargs.ChaptersPerFile),
		)
	}
	if gnargs.FromTitle != "" {
		args = append(args, "--fromTitl", gnargs.FromTitle)
	}
	if gnargs.ToTitle != "" {
		args = append(args, "--toTitle", gnargs.ToTitle)
	}
	if gnargs.FromChapter != 0 {
		args = append(args, "--fromChapter", strconv.Itoa(gnargs.FromChapter))
	}
	if gnargs.ToChapter != 0 {
		args = append(args, "--toChapter", strconv.Itoa(gnargs.ToChapter))
	}
	args = append(args, gnargs.TOCURL)

	cmd := exec.Command(getnovel, args...)

	kindlegenName := `kindlegen`
	if runtime.GOOS == "windows" {
		kindlegenName = `kindlegen.exe`
	}
	kindlegenPath, _ := exec.LookPath(kindlegenName)
	if b, e := fsutil.FileExists(kindlegenPath); e != nil || !b {
		if dir, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
			kindlegenPath = filepath.Join(dir, kindlegenName)
		}
	}
	if !filepath.IsAbs(kindlegenPath) {
		kindlegenPath, _ = filepath.Abs(kindlegenPath)
	}
	cmd.Env = append(os.Environ(),
		"KINDLEGEN_PATH="+kindlegenPath, // ignored
	)
	go func() {
		item := &HistoryItem{
			TOCURL:   gnargs.TOCURL,
			BookName: gnargs.TOCURL,
			Status:   "等待制作",
		}
		books.append(item)

		mutexMaking.Lock()

		item.Status = "制作中"
		if err := cmd.Run(); err != nil {
			item.Status = "制作失败"
		} else {
			item.Status = "有效"

			bookPath := fmt.Sprintf("%s/%s.mobi", item.BookName, item.BookName)
			if b, e := fsutil.FileExists(bookPath); e != nil || !b {
				bookPath = fmt.Sprintf("%s/%s.epub", item.BookName, item.BookName)
			}
			if b, e := fsutil.FileExists(bookPath); e == nil && b {
				baseName := filepath.Base(bookPath)
				item.BookName = baseName
				item.DownloadLink = "/download/" + baseName[:len(baseName)-5] + "/" + baseName
				item.DeleteLink = "/delete/" + baseName[:len(baseName)-5] + "/" + baseName
			}
		}
		mutexMaking.Unlock()

		books.clear()
		scanEbooks()
	}()

	c.JSON(http.StatusOK, gin.H{})
}

func downloadBook(c *gin.Context) {
	path := c.Param("path")
	if path == "pdf" {
		path = ""
	}
	name := c.Param("name")
	c.File(filepath.Join(path, name))
}

func deleteBook(c *gin.Context) {
	path := c.Param("path")
	if path == "pdf" {
		path = ""
	}
	name := c.Param("name")
	os.Remove(filepath.Join(path, name))
	books.delete(name)
	c.Redirect(http.StatusFound, "/")
}

func scanEbooks() {
	matches, err := filepath.Glob("*.pdf")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     v,
				Status:       "有效",
				DownloadLink: "/download/pdf/" + v,
				DeleteLink:   "/delete/pdf/" + v,
			})
		}
	}

	matches, err = filepath.Glob("**/*.mobi")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     filepath.Base(v),
				Status:       "有效",
				DownloadLink: "/download/" + strings.Replace(v, "\\", "/", -1),
				DeleteLink:   "/delete/" + strings.Replace(v, "\\", "/", -1),
			})
		}
	}
	matches, err = filepath.Glob("**/*.epub")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     filepath.Base(v),
				Status:       "有效",
				DownloadLink: "/download/" + strings.Replace(v, "\\", "/", -1),
				DeleteLink:   "/delete/" + strings.Replace(v, "\\", "/", -1),
			})
		}
	}
}

func main() {
	addr := ":8089"
	if bind, ok := os.LookupEnv("BIND"); ok {
		addr = bind
	}
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.GET("/", homePage)
	r.GET("/download/:path/:name", downloadBook)
	r.GET("/delete/:path/:name", deleteBook)
	r.POST("/makeebook", makeEbook)
	// glob font files
	matches, err := filepath.Glob("fonts/*.ttf")
	if err != nil {
		panic(err)
	}
	for _, v := range matches {
		fontFiles = append(fontFiles, filepath.Base(v))
	}
	scanEbooks()
	r.Run(addr)
}
<commit_msg>(*)search font files in subdirectories<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"

	"github.com/dfordsoft/golib/fsutil"
	"github.com/gin-gonic/gin"
)

var (
	fontFiles   []string
	mutexMaking sync.Mutex
	books       = Books{}
	sha1ver     string // sha1 revision used to build the program
	buildTime   string // when the executable was built
)

// Books book collect
type Books struct {
	sync.Mutex
	items []*HistoryItem
}

func (books *Books) append(item *HistoryItem) {
	books.Lock()
	books.items = append(books.items, item)
	books.Unlock()
}

func (books *Books) clear() {
	books.Lock()
	books.items = []*HistoryItem{}
	books.Unlock()
}

func (books *Books) delete(name string) {
	books.Lock()
	for i, book := range books.items {
		if book.BookName == name {
			books.items = append(books.items[:i], books.items[i+1:]...)
			break
		}
	}
	books.Unlock()
}

// HistoryItem - 书籍记录，有4种状态，分别是有效，失败，进行，等待
type HistoryItem struct {
	TOCURL       string `template:"tocurl"`
	BookName     string `template:"name"`
	Status       string `template:"status"`
	DownloadLink string `template:"downloadLink"`
	DeleteLink   string `template:"deleteLink"`
}

func homePage(c *gin.Context) {
	c.HTML(http.StatusOK, "home.tmpl", gin.H{
		"title":     "GetNovel",
		"fontFiles": fontFiles,
		"items":     books.items,
	})
}

type GetNovelAuguments struct {
	TOCURL          string  `form:"tocurl"`
	Format          string  `form:"format"`
	PageType        string  `form:"pageType"`
	LeftMargin      int     `form:"leftMargin"`
	TopMargin       int     `form:"topMargin"`
	TitleFontSize   int     `form:"titleFontSize"`
	ContentFontSize int     `form:"contentFontSize"`
	LineSpacing     float32 `form:"lineSpacing"`
	PagesPerFile    int     `form:"pagesPerFile"`
	ChaptersPerFile int     `form:"chaptersPerFile"`
	FontFile        string  `form:"fontFile"`
	FromTitle       string  `form:"fromTitle"`
	ToTitle         string  `form:"toTitle"`
	FromChapter     int     `form:"fromChapter"`
	ToChapter       int     `form:"toChapter"`
}

func makeEbook(c *gin.Context) {
	var gnargs GetNovelAuguments
	if err := c.ShouldBindJSON(&gnargs); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("%v", err),
		})
		return
	}
	getnovel, _ := exec.LookPath(`getnovel`)

	if b, e := fsutil.FileExists(getnovel); e != nil || !b {
		if dir, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
			getnovel = filepath.Join(dir, `getnovel`)
		}
	}

	if b, e := fsutil.FileExists(getnovel); e != nil || !b {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "getnovel not found",
		})
		return
	}

	args := []string{
		"-f",
		gnargs.Format,
		"-p",
		gnargs.PageType,
		"--fontFile",
		gnargs.FontFile,
	}

	if gnargs.Format == "pdf" {
		args = append(args,
			fmt.Sprintf("--leftMargin=%d", gnargs.LeftMargin),
			fmt.Sprintf("--topMargin=%d", gnargs.TopMargin),
			fmt.Sprintf("--titleFontSize=%d", gnargs.TitleFontSize),
			fmt.Sprintf("--contentFontSize=%d", gnargs.ContentFontSize),
			fmt.Sprintf("--lineSpacing=%f", gnargs.LineSpacing),
			fmt.Sprintf("--pagesPerFile=%d", gnargs.PagesPerFile),
			fmt.Sprintf("--chaptersPerFile=%d", gnargs.ChaptersPerFile),
		)
	}
	if gnargs.FromTitle != "" {
		args = append(args, "--fromTitl", gnargs.FromTitle)
	}
	if gnargs.ToTitle != "" {
		args = append(args, "--toTitle", gnargs.ToTitle)
	}
	if gnargs.FromChapter != 0 {
		args = append(args, "--fromChapter", strconv.Itoa(gnargs.FromChapter))
	}
	if gnargs.ToChapter != 0 {
		args = append(args, "--toChapter", strconv.Itoa(gnargs.ToChapter))
	}
	args = append(args, gnargs.TOCURL)

	cmd := exec.Command(getnovel, args...)

	kindlegenName := `kindlegen`
	if runtime.GOOS == "windows" {
		kindlegenName = `kindlegen.exe`
	}
	kindlegenPath, _ := exec.LookPath(kindlegenName)
	if b, e := fsutil.FileExists(kindlegenPath); e != nil || !b {
		if dir, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
			kindlegenPath = filepath.Join(dir, kindlegenName)
		}
	}
	if !filepath.IsAbs(kindlegenPath) {
		kindlegenPath, _ = filepath.Abs(kindlegenPath)
	}
	cmd.Env = append(os.Environ(),
		"KINDLEGEN_PATH="+kindlegenPath, // ignored
	)
	go func() {
		item := &HistoryItem{
			TOCURL:   gnargs.TOCURL,
			BookName: gnargs.TOCURL,
			Status:   "等待制作",
		}
		books.append(item)

		mutexMaking.Lock()

		item.Status = "制作中"
		if err := cmd.Run(); err != nil {
			item.Status = "制作失败"
		} else {
			item.Status = "有效"

			bookPath := fmt.Sprintf("%s/%s.mobi", item.BookName, item.BookName)
			if b, e := fsutil.FileExists(bookPath); e != nil || !b {
				bookPath = fmt.Sprintf("%s/%s.epub", item.BookName, item.BookName)
			}
			if b, e := fsutil.FileExists(bookPath); e == nil && b {
				baseName := filepath.Base(bookPath)
				item.BookName = baseName
				item.DownloadLink = "/download/" + baseName[:len(baseName)-5] + "/" + baseName
				item.DeleteLink = "/delete/" + baseName[:len(baseName)-5] + "/" + baseName
			}
		}
		mutexMaking.Unlock()

		books.clear()
		scanEbooks()
	}()

	c.JSON(http.StatusOK, gin.H{})
}

func downloadBook(c *gin.Context) {
	path := c.Param("path")
	if path == "pdf" {
		path = ""
	}
	name := c.Param("name")
	c.File(filepath.Join(path, name))
}

func deleteBook(c *gin.Context) {
	path := c.Param("path")
	if path == "pdf" {
		path = ""
	}
	name := c.Param("name")
	os.Remove(filepath.Join(path, name))
	books.delete(name)
	c.Redirect(http.StatusFound, "/")
}

func scanEbooks() {
	matches, err := filepath.Glob("*.pdf")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     v,
				Status:       "有效",
				DownloadLink: "/download/pdf/" + v,
				DeleteLink:   "/delete/pdf/" + v,
			})
		}
	}

	matches, err = filepath.Glob("**/*.mobi")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     filepath.Base(v),
				Status:       "有效",
				DownloadLink: "/download/" + strings.Replace(v, "\\", "/", -1),
				DeleteLink:   "/delete/" + strings.Replace(v, "\\", "/", -1),
			})
		}
	}
	matches, err = filepath.Glob("**/*.epub")
	if err == nil {
		for _, v := range matches {
			books.append(&HistoryItem{
				BookName:     filepath.Base(v),
				Status:       "有效",
				DownloadLink: "/download/" + strings.Replace(v, "\\", "/", -1),
				DeleteLink:   "/delete/" + strings.Replace(v, "\\", "/", -1),
			})
		}
	}
}

func main() {
	addr := ":8089"
	if bind, ok := os.LookupEnv("BIND"); ok {
		addr = bind
	}
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.GET("/", homePage)
	r.GET("/download/:path/:name", downloadBook)
	r.GET("/delete/:path/:name", deleteBook)
	r.POST("/makeebook", makeEbook)
	// glob font files
	matches, err := filepath.Glob("fonts/*.ttf")
	if err != nil {
		panic(err)
	}
	for _, v := range matches {
		fontFiles = append(fontFiles, filepath.Base(v))
	}
	matches, err = filepath.Glob("fonts/**/*.ttf")
	for _, v := range matches {
		fontFiles = append(fontFiles, filepath.Base(v))
	}
	scanEbooks()
	r.Run(addr)
}
<|endoftext|>


<commit_before>package jd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"strings"
)

type option string

const (
	MULTISET option = "multiset"
	SET      option = "set"
)

func checkOption(want option, options ...option) bool {
	for _, o := range options {
		if o == want {
			return true
		}
	}
	return false
}

func ReadJsonFile(filename string, options ...option) (JsonNode, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return unmarshal(bytes, options...)
}

func ReadJsonString(s string, options ...option) (JsonNode, error) {
	return unmarshal([]byte(s), options...)
}

func unmarshal(bytes []byte, options ...option) (JsonNode, error) {
	if strings.TrimSpace(string(bytes)) == "" {
		return voidNode{}, nil
	}
	var v interface{}
	err := json.Unmarshal(bytes, &v)
	if err != nil {
		return nil, err
	}
	n, err := NewJsonNode(v, options...)
	if err != nil {
		return nil, err
	}
	return n, nil
}

func ReadDiffFile(filename string, options ...option) (Diff, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return readDiff(string(bytes), options...)
}

func ReadDiffString(s string, options ...option) (Diff, error) {
	return readDiff(s, options...)
}

func readDiff(s string, options ...option) (Diff, error) {
	diff := Diff{}
	diffLines := strings.Split(s, "\n")
	const (
		INIT = iota
		AT   = iota
		OLD  = iota
		NEW  = iota
	)
	var de DiffElement
	var state = INIT
	for i, dl := range diffLines {
		if len(dl) == 0 {
			continue
		}
		header := dl[:1]
		// Validate state transistion.
		switch state {
		case INIT:
			if header != "@" {
				return errorAt(i, "Unexpected %c. Expecteding @.", dl[0])
			}
		case AT:
			if header != "-" && header != "+" {
				return errorAt(i, "Unexpected %c. Expecting - or +.", dl[0])
			}
		case OLD:
			if header != "@" && header != "-" && header != "+" {
				return errorAt(i, "Unexpected %c. Expecting + or @.", dl[0])
			}
		case NEW:
			if header != "+" && header != "@" {
				return errorAt(i, "Unexpected %c. Expecteding + or @.", dl[0])
			}
		}
		// Process line.
		switch header {
		case "@":
			if state != INIT {
				// Save the previous diff element.
				errString := checkDiffElement(de)
				if errString != "" {
					return errorAt(i, errString)
				}
				diff = append(diff, de)
			}
			p := Path{}
			//print(dl[1:], "\n")
			err := json.Unmarshal([]byte(dl[1:]), &p)
			if err != nil {
				return errorAt(i, "Invalid path. %v", err.Error())
			}
			de = DiffElement{
				Path:      p,
				OldValues: []JsonNode{},
				NewValues: []JsonNode{},
			}
			state = AT
		case "-":
			v, err := ReadJsonString(dl[1:], options...)
			if err != nil {
				return errorAt(i, "Invalid value. %v", err.Error())
			}
			de.OldValues = append(de.OldValues, v)
			state = OLD
		case "+":
			v, err := ReadJsonString(dl[1:], options...)
			if err != nil {
				return errorAt(i, "Invalid value. %v", err.Error())
			}
			de.NewValues = append(de.NewValues, v)
			state = NEW
		default:
			errorAt(i, "Unexpected %v.", dl[0])
		}
	}
	if state == AT {
		// @ is not a valid terminal state.
		return errorAt(len(diffLines), "Unexpected end of diff. Expecting - or +.")
	}
	if state != INIT {
		// Save the last diff element.
		// Empty string diff is valid so state could be INIT
		errString := checkDiffElement(de)
		if errString != "" {
			return errorAt(len(diffLines), errString)
		}
		diff = append(diff, de)
	}
	return diff, nil
}

func checkDiffElement(de DiffElement) string {
	if len(de.NewValues) > 1 || len(de.OldValues) > 1 {
		// Must be a set.
		if len(de.Path) == 0 || !reflect.DeepEqual(de.Path[len(de.Path)-1], map[string]interface{}{}) {
			return "Expected path to end with {} for sets."
		}
	}
	return ""
}

func errorAt(lineZeroIndex int, err string, i ...interface{}) (Diff, error) {
	line := lineZeroIndex + 1
	e := fmt.Sprintf(err, i...)
	return nil, fmt.Errorf("Invalid diff at line %v. %v", line, e)
}
<commit_msg>Removed debugging line<commit_after>package jd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"strings"
)

type option string

const (
	MULTISET option = "multiset"
	SET      option = "set"
)

func checkOption(want option, options ...option) bool {
	for _, o := range options {
		if o == want {
			return true
		}
	}
	return false
}

func ReadJsonFile(filename string, options ...option) (JsonNode, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return unmarshal(bytes, options...)
}

func ReadJsonString(s string, options ...option) (JsonNode, error) {
	return unmarshal([]byte(s), options...)
}

func unmarshal(bytes []byte, options ...option) (JsonNode, error) {
	if strings.TrimSpace(string(bytes)) == "" {
		return voidNode{}, nil
	}
	var v interface{}
	err := json.Unmarshal(bytes, &v)
	if err != nil {
		return nil, err
	}
	n, err := NewJsonNode(v, options...)
	if err != nil {
		return nil, err
	}
	return n, nil
}

func ReadDiffFile(filename string, options ...option) (Diff, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return readDiff(string(bytes), options...)
}

func ReadDiffString(s string, options ...option) (Diff, error) {
	return readDiff(s, options...)
}

func readDiff(s string, options ...option) (Diff, error) {
	diff := Diff{}
	diffLines := strings.Split(s, "\n")
	const (
		INIT = iota
		AT   = iota
		OLD  = iota
		NEW  = iota
	)
	var de DiffElement
	var state = INIT
	for i, dl := range diffLines {
		if len(dl) == 0 {
			continue
		}
		header := dl[:1]
		// Validate state transistion.
		switch state {
		case INIT:
			if header != "@" {
				return errorAt(i, "Unexpected %c. Expecteding @.", dl[0])
			}
		case AT:
			if header != "-" && header != "+" {
				return errorAt(i, "Unexpected %c. Expecting - or +.", dl[0])
			}
		case OLD:
			if header != "@" && header != "-" && header != "+" {
				return errorAt(i, "Unexpected %c. Expecting + or @.", dl[0])
			}
		case NEW:
			if header != "+" && header != "@" {
				return errorAt(i, "Unexpected %c. Expecteding + or @.", dl[0])
			}
		}
		// Process line.
		switch header {
		case "@":
			if state != INIT {
				// Save the previous diff element.
				errString := checkDiffElement(de)
				if errString != "" {
					return errorAt(i, errString)
				}
				diff = append(diff, de)
			}
			p := Path{}
			err := json.Unmarshal([]byte(dl[1:]), &p)
			if err != nil {
				return errorAt(i, "Invalid path. %v", err.Error())
			}
			de = DiffElement{
				Path:      p,
				OldValues: []JsonNode{},
				NewValues: []JsonNode{},
			}
			state = AT
		case "-":
			v, err := ReadJsonString(dl[1:], options...)
			if err != nil {
				return errorAt(i, "Invalid value. %v", err.Error())
			}
			de.OldValues = append(de.OldValues, v)
			state = OLD
		case "+":
			v, err := ReadJsonString(dl[1:], options...)
			if err != nil {
				return errorAt(i, "Invalid value. %v", err.Error())
			}
			de.NewValues = append(de.NewValues, v)
			state = NEW
		default:
			errorAt(i, "Unexpected %v.", dl[0])
		}
	}
	if state == AT {
		// @ is not a valid terminal state.
		return errorAt(len(diffLines), "Unexpected end of diff. Expecting - or +.")
	}
	if state != INIT {
		// Save the last diff element.
		// Empty string diff is valid so state could be INIT
		errString := checkDiffElement(de)
		if errString != "" {
			return errorAt(len(diffLines), errString)
		}
		diff = append(diff, de)
	}
	return diff, nil
}

func checkDiffElement(de DiffElement) string {
	if len(de.NewValues) > 1 || len(de.OldValues) > 1 {
		// Must be a set.
		if len(de.Path) == 0 || !reflect.DeepEqual(de.Path[len(de.Path)-1], map[string]interface{}{}) {
			return "Expected path to end with {} for sets."
		}
	}
	return ""
}

func errorAt(lineZeroIndex int, err string, i ...interface{}) (Diff, error) {
	line := lineZeroIndex + 1
	e := fmt.Sprintf(err, i...)
	return nil, fmt.Errorf("Invalid diff at line %v. %v", line, e)
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/nomad/helper/uuid"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

func TestNodes_List(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	var qm *QueryMeta
	var out []*NodeListStub
	var err error

	testutil.WaitForResult(func() (bool, error) {
		out, qm, err = nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Check that we got valid QueryMeta.
	assertQueryMeta(t, qm)
}

func TestNodes_PrefixList(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	var qm *QueryMeta
	var out []*NodeListStub
	var err error

	// Get the node ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Find node based on four character prefix
	out, qm, err = nodes.PrefixList(nodeID[:4])
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if n := len(out); n != 1 {
		t.Fatalf("expected 1 node, got: %d ", n)
	}

	// Check that we got valid QueryMeta.
	assertQueryMeta(t, qm)
}

func TestNodes_Info(t *testing.T) {
	t.Parallel()
	startTime := time.Now().Unix()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Retrieving a non-existent node returns error
	_, _, err := nodes.Info("12345678-abcd-efab-cdef-123456789abc", nil)
	if err == nil || !strings.Contains(err.Error(), "not found") {
		t.Fatalf("expected not found error, got: %#v", err)
	}

	// Get the node ID
	var nodeID, dc string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		dc = out[0].Datacenter
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Querying for existing nodes returns properly
	result, qm, err := nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertQueryMeta(t, qm)

	// Check that the result is what we expect
	if result.ID != nodeID || result.Datacenter != dc {
		t.Fatalf("expected %s (%s), got: %s (%s)",
			nodeID, dc,
			result.ID, result.Datacenter)
	}

	// Check that the StatusUpdatedAt field is being populated correctly
	if result.StatusUpdatedAt < startTime {
		t.Fatalf("start time: %v, status updated: %v", startTime, result.StatusUpdatedAt)
	}
}

func TestNodes_ToggleDrain(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Wait for node registration and get the ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Check for drain mode
	out, _, err := nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if out.Drain {
		t.Fatalf("drain mode should be off")
	}

	// Toggle it on
	wm, err := nodes.ToggleDrain(nodeID, true, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertWriteMeta(t, wm)

	// Check again
	out, _, err = nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if !out.Drain {
		t.Fatalf("drain mode should be on")
	}

	// Toggle off again
	wm, err = nodes.ToggleDrain(nodeID, false, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertWriteMeta(t, wm)

	// Check again
	out, _, err = nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if out.Drain {
		t.Fatalf("drain mode should be off")
	}
}

func TestNodes_Allocations(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	// Looking up by a non-existent node returns nothing. We
	// don't check the index here because it's possible the node
	// has already registered, in which case we will get a non-
	// zero result anyways.
	allocs, _, err := nodes.Allocations("nope", nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if n := len(allocs); n != 0 {
		t.Fatalf("expected 0 allocs, got: %d", n)
	}
}

func TestNodes_ForceEvaluate(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Force-eval on a non-existent node fails
	_, _, err := nodes.ForceEvaluate("12345678-abcd-efab-cdef-123456789abc", nil)
	if err == nil || !strings.Contains(err.Error(), "not found") {
		t.Fatalf("expected not found error, got: %#v", err)
	}

	// Wait for node registration and get the ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Try force-eval again. We don't check the WriteMeta because
	// there are no allocations to process, so we would get an index
	// of zero. Same goes for the eval ID.
	_, _, err = nodes.ForceEvaluate(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestNodes_Sort(t *testing.T) {
	t.Parallel()
	nodes := []*NodeListStub{
		{CreateIndex: 2},
		{CreateIndex: 1},
		{CreateIndex: 5},
	}
	sort.Sort(NodeIndexSort(nodes))

	expect := []*NodeListStub{
		{CreateIndex: 5},
		{CreateIndex: 2},
		{CreateIndex: 1},
	}
	if !reflect.DeepEqual(nodes, expect) {
		t.Fatalf("\n\n%#v\n\n%#v", nodes, expect)
	}
}

func TestNodes_GC(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	err := nodes.GC(uuid.Generate(), nil)
	require.NotNil(err)
	require.Contains(err.Error(), "Unknown node")
}

func TestNodes_GcAlloc(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	err := nodes.GcAlloc(uuid.Generate(), nil)
	require.NotNil(err)
	require.Contains(err.Error(), "unknown allocation")
}
<commit_msg>fix test<commit_after>package api

import (
	"fmt"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/nomad/helper/uuid"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

func TestNodes_List(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	var qm *QueryMeta
	var out []*NodeListStub
	var err error

	testutil.WaitForResult(func() (bool, error) {
		out, qm, err = nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Check that we got valid QueryMeta.
	assertQueryMeta(t, qm)
}

func TestNodes_PrefixList(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	var qm *QueryMeta
	var out []*NodeListStub
	var err error

	// Get the node ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Find node based on four character prefix
	out, qm, err = nodes.PrefixList(nodeID[:4])
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if n := len(out); n != 1 {
		t.Fatalf("expected 1 node, got: %d ", n)
	}

	// Check that we got valid QueryMeta.
	assertQueryMeta(t, qm)
}

func TestNodes_Info(t *testing.T) {
	t.Parallel()
	startTime := time.Now().Unix()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Retrieving a non-existent node returns error
	_, _, err := nodes.Info("12345678-abcd-efab-cdef-123456789abc", nil)
	if err == nil || !strings.Contains(err.Error(), "not found") {
		t.Fatalf("expected not found error, got: %#v", err)
	}

	// Get the node ID
	var nodeID, dc string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		dc = out[0].Datacenter
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Querying for existing nodes returns properly
	result, qm, err := nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertQueryMeta(t, qm)

	// Check that the result is what we expect
	if result.ID != nodeID || result.Datacenter != dc {
		t.Fatalf("expected %s (%s), got: %s (%s)",
			nodeID, dc,
			result.ID, result.Datacenter)
	}

	// Check that the StatusUpdatedAt field is being populated correctly
	if result.StatusUpdatedAt < startTime {
		t.Fatalf("start time: %v, status updated: %v", startTime, result.StatusUpdatedAt)
	}
}

func TestNodes_ToggleDrain(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Wait for node registration and get the ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Check for drain mode
	out, _, err := nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if out.Drain {
		t.Fatalf("drain mode should be off")
	}

	// Toggle it on
	wm, err := nodes.ToggleDrain(nodeID, true, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertWriteMeta(t, wm)

	// Check again
	out, _, err = nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if !out.Drain {
		t.Fatalf("drain mode should be on")
	}

	// Toggle off again
	wm, err = nodes.ToggleDrain(nodeID, false, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	assertWriteMeta(t, wm)

	// Check again
	out, _, err = nodes.Info(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if out.Drain {
		t.Fatalf("drain mode should be off")
	}
}

func TestNodes_Allocations(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	// Looking up by a non-existent node returns nothing. We
	// don't check the index here because it's possible the node
	// has already registered, in which case we will get a non-
	// zero result anyways.
	allocs, _, err := nodes.Allocations("nope", nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if n := len(allocs); n != 0 {
		t.Fatalf("expected 0 allocs, got: %d", n)
	}
}

func TestNodes_ForceEvaluate(t *testing.T) {
	t.Parallel()
	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
		c.DevMode = true
	})
	defer s.Stop()
	nodes := c.Nodes()

	// Force-eval on a non-existent node fails
	_, _, err := nodes.ForceEvaluate("12345678-abcd-efab-cdef-123456789abc", nil)
	if err == nil || !strings.Contains(err.Error(), "not found") {
		t.Fatalf("expected not found error, got: %#v", err)
	}

	// Wait for node registration and get the ID
	var nodeID string
	testutil.WaitForResult(func() (bool, error) {
		out, _, err := nodes.List(nil)
		if err != nil {
			return false, err
		}
		if n := len(out); n != 1 {
			return false, fmt.Errorf("expected 1 node, got: %d", n)
		}
		nodeID = out[0].ID
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})

	// Try force-eval again. We don't check the WriteMeta because
	// there are no allocations to process, so we would get an index
	// of zero. Same goes for the eval ID.
	_, _, err = nodes.ForceEvaluate(nodeID, nil)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestNodes_Sort(t *testing.T) {
	t.Parallel()
	nodes := []*NodeListStub{
		{CreateIndex: 2},
		{CreateIndex: 1},
		{CreateIndex: 5},
	}
	sort.Sort(NodeIndexSort(nodes))

	expect := []*NodeListStub{
		{CreateIndex: 5},
		{CreateIndex: 2},
		{CreateIndex: 1},
	}
	if !reflect.DeepEqual(nodes, expect) {
		t.Fatalf("\n\n%#v\n\n%#v", nodes, expect)
	}
}

func TestNodes_GC(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	err := nodes.GC(uuid.Generate(), nil)
	require.NotNil(err)
	require.True(structs.IsErrUnknownNode(err))
}

func TestNodes_GcAlloc(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	c, s := makeClient(t, nil, nil)
	defer s.Stop()
	nodes := c.Nodes()

	err := nodes.GcAlloc(uuid.Generate(), nil)
	require.NotNil(err)
	require.True(structs.IsErrUnknownAllocation(err))
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"net/http"
	"sort"

	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/permission"
)

func addRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleCreate) {
		return permission.ErrUnauthorized
	}
	_, err := permission.NewRole(r.FormValue("name"), r.FormValue("context"))
	if err == nil {
		w.WriteHeader(http.StatusCreated)
	}
	return err
}

func removeRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleDelete) {
		return permission.ErrUnauthorized
	}
	err := permission.DestroyRole(r.URL.Query().Get(":name"))
	if err == permission.ErrRoleNotFound {
		return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
	}
	return err
}

func listRoles(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	roles, err := permission.ListRoles()
	if err != nil {
		return err
	}
	b, err := json.Marshal(roles)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/json")
	_, err = w.Write(b)
	return err
}

func addPermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleUpdate) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	role, err := permission.FindRole(roleName)
	if err != nil {
		return err
	}
	err = r.ParseForm()
	if err != nil {
		return err
	}
	return role.AddPermissions(r.Form["permission"]...)
}

func removePermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleUpdate) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	permName := r.URL.Query().Get(":permission")
	role, err := permission.FindRole(roleName)
	if err != nil {
		return err
	}
	return role.RemovePermissions(permName)
}

func assignRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleAssign) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	email := r.FormValue("email")
	contextValue := r.FormValue("context")
	user, err := auth.GetUserByEmail(email)
	if err != nil {
		return err
	}
	return user.AddRole(roleName, contextValue)
}

func dissociateRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	roleName := r.URL.Query().Get(":name")
	email := r.URL.Query().Get(":email")
	contextValue := r.URL.Query().Get("context")
	user, err := auth.GetUserByEmail(email)
	if err != nil {
		return err
	}
	return user.RemoveRole(roleName, contextValue)
}

type permissionData struct {
	Name     string
	Contexts []string
}

func listPermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	lst := permission.PermissionRegistry.Permissions()
	sort.Sort(lst)
	permList := make([]permissionData, len(lst))
	for i, perm := range lst {
		contexts := perm.AllowedContexts()
		contextNames := make([]string, len(contexts))
		for j, ctx := range contexts {
			contextNames[j] = string(ctx)
		}
		permList[i] = permissionData{
			Name:     perm.FullName(),
			Contexts: contextNames,
		}
	}
	w.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(permList)
}
<commit_msg>api: fix status codes in roles routes<commit_after>package api

import (
	"encoding/json"
	"net/http"
	"sort"

	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/permission"
)

func addRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleCreate) {
		return permission.ErrUnauthorized
	}
	_, err := permission.NewRole(r.FormValue("name"), r.FormValue("context"))
	if err == nil {
		w.WriteHeader(http.StatusCreated)
	}
	return err
}

func removeRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleDelete) {
		return permission.ErrUnauthorized
	}
	err := permission.DestroyRole(r.URL.Query().Get(":name"))
	if err == permission.ErrRoleNotFound {
		return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
	}
	if err == nil {
		w.WriteHeader(http.StatusOK)
	}
	return err
}

func listRoles(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	roles, err := permission.ListRoles()
	if err != nil {
		return err
	}
	b, err := json.Marshal(roles)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/json")
	_, err = w.Write(b)
	return err
}

func addPermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleUpdate) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	role, err := permission.FindRole(roleName)
	if err != nil {
		return err
	}
	err = r.ParseForm()
	if err != nil {
		return err
	}
	err = role.AddPermissions(r.Form["permission"]...)
	if err == nil {
		w.WriteHeader(http.StatusOK)
	}
	return err
}

func removePermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleUpdate) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	permName := r.URL.Query().Get(":permission")
	role, err := permission.FindRole(roleName)
	if err != nil {
		return err
	}
	err = role.RemovePermissions(permName)
	if err == nil {
		w.WriteHeader(http.StatusOK)
	}
	return err
}

func assignRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if !permission.Check(t, permission.PermRoleAssign) {
		return permission.ErrUnauthorized
	}
	roleName := r.URL.Query().Get(":name")
	email := r.FormValue("email")
	contextValue := r.FormValue("context")
	user, err := auth.GetUserByEmail(email)
	if err != nil {
		return err
	}
	err = user.AddRole(roleName, contextValue)
	if err == nil {
		w.WriteHeader(http.StatusOK)
	}
	return err
}

func dissociateRole(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	roleName := r.URL.Query().Get(":name")
	email := r.URL.Query().Get(":email")
	contextValue := r.URL.Query().Get("context")
	user, err := auth.GetUserByEmail(email)
	if err != nil {
		return err
	}
	err = user.RemoveRole(roleName, contextValue)
	if err == nil {
		w.WriteHeader(http.StatusOK)
	}
	return err
}

type permissionData struct {
	Name     string
	Contexts []string
}

func listPermissions(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	lst := permission.PermissionRegistry.Permissions()
	sort.Sort(lst)
	permList := make([]permissionData, len(lst))
	for i, perm := range lst {
		contexts := perm.AllowedContexts()
		contextNames := make([]string, len(contexts))
		for j, ctx := range contexts {
			contextNames[j] = string(ctx)
		}
		permList[i] = permissionData{
			Name:     perm.FullName(),
			Contexts: contextNames,
		}
	}
	w.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(permList)
}
<|endoftext|>


<commit_before>/*
Package detour provides a net.Conn interface which detects blockage
of a site automatically and try to access it through alternative dialer.

Basically, if a site is not whitelisted, it has follow steps:
1. Dial in parallel
2. Return to caller if any connection is established
3. Read/write to all connections
4. After sucessfully read from a connection, stick with it and close others.
*/
package detour

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/getlantern/golog"
)

var TimeoutToConnect = 30 * time.Second
var DelayBeforeDetour = 1 * time.Second

// if DirectAddrCh is set, when a direct connection is closed without any error,
// the connection's remote address (in host:port format) will be send to it
var DirectAddrCh chan string

var (
	log = golog.LoggerFor("detour")
)

type dialFunc func(network, addr string) (net.Conn, error)

type Conn struct {
	muConn sync.RWMutex
	// the underlie connections, access to it should be protected by muConn.
	conns []conn

	// the chan to receive result of any read operation
	chRead chan ioResult
	// the chan to receive result of any write operation
	chWrite chan ioResult

	// keep track of the total bytes read in this connection, atomic
	readBytes uint64

	network, addr string
}

// The data structure to pass result of io operation back from underlie connection
type ioResult struct {
	// number of bytes processed
	n int
	// io error, if any
	err error
	// the underlie connection that actually do the io operation
	conn conn
}

type connType int

const (
	connTypeDirect connType = iota
	connTypeDetour connType = iota
)

type conn interface {
	ConnType() connType
	Valid() bool
	SetInvalid()
	FirstRead(b []byte, ch chan ioResult)
	FollowupRead(b []byte, ch chan ioResult)
	Write(b []byte, ch chan ioResult)
	Close()
}

func typeOf(c conn) string {
	var connTypeDesc = []string{
		"direct",
		"detour",
	}
	return connTypeDesc[c.ConnType()]
}

// Dialer returns a function with same signature of net.Dialer.Dial().
func Dialer(df dialFunc) dialFunc {
	return func(network, addr string) (net.Conn, error) {
		dc := &Conn{network: network, addr: addr, conns: []conn{}, chRead: make(chan ioResult), chWrite: make(chan ioResult)}
		// buffered channel, as we may send twice to it but only receive once
		chAnyConn := make(chan conn, 1)
		ch := make(chan conn)
		go func() {
			if !whitelisted(addr) {
				DialDirect(network, addr, ch)
				time.Sleep(DelayBeforeDetour)
			}
			DialDetour(network, addr, df, ch)
		}()
		go func() {
			t := time.NewTimer(TimeoutToConnect)
			for i := 0; i < 2; i++ {
				select {
				case conn := <-ch:
					if dc.anyDataReceived() {
						log.Debugf("Drop a %s connection established too late to %s", typeOf(conn), dc.addr)
						conn.Close()
						return
					}
					dc.muConn.Lock()
					dc.conns = append(dc.conns, conn)
					dc.muConn.Unlock()
					chAnyConn <- conn
				case <-t.C:
					if i == 0 {
						chAnyConn <- nil
					}
					return
				}
			}
		}()
		// return to caller if any connection available
		if anyConn := <-chAnyConn; anyConn != nil {
			return dc, nil
		}
		return nil, fmt.Errorf("Timeout dialing both direct and detour connection to %s", addr)
	}
}

func (dc *Conn) runOnValidConn(f func(conn)) (count int) {
	dc.muConn.RLock()
	defer dc.muConn.RUnlock()
	for _, conn := range dc.conns {
		if conn.Valid() {
			f(conn)
			count++
		}
	}
	return
}

func (dc *Conn) anyDataReceived() bool {
	return atomic.LoadUint64(&dc.readBytes) > 0
}

func (dc *Conn) incReadBytes(n int) {
	atomic.AddUint64(&dc.readBytes, uint64(n))
}

// Read() implements the function from net.Conn
func (dc *Conn) Read(b []byte) (n int, err error) {
	log.Tracef("Initiate a read request to %s", dc.addr)
	if dc.anyDataReceived() {
		return dc.followupRead(b)
	}
	count := dc.runOnValidConn(func(conn conn) {
		conn.FirstRead(b, dc.chRead)
	})
	for i := 0; i < count; i++ {
		result := <-dc.chRead
		n, err = result.n, result.err
		if err != nil && err != io.EOF {
			log.Tracef("Read from %s through %s failed, set as invalid: %s", dc.addr, typeOf(result.conn), err)
			result.conn.SetInvalid()
			// skip failed connection
			continue
		}
		log.Tracef("Read %d bytes from %s connection to %s", n, typeOf(result.conn), dc.addr)
		dc.incReadBytes(n)
		dc.runOnValidConn(func(c conn) {
			if c != result.conn {
				log.Tracef("Set %s connection to %s as invalid", typeOf(c), dc.addr)
				c.SetInvalid()
				// direct connection failed
				if c.ConnType() == connTypeDirect {
					log.Tracef("Add %s to whitelist", dc.addr)
					AddToWl(dc.addr, false)
				}
			}
		})
		return
	}
	return
}

// followUpRead is called by Read() if a connection's state already settled
func (dc *Conn) followupRead(b []byte) (n int, err error) {
	dc.runOnValidConn(func(conn conn) {
		conn.FollowupRead(b, dc.chRead)
	})
	result := <-dc.chRead
	dc.incReadBytes(result.n)
	return result.n, result.err
}

// Write() implements the function from net.Conn
func (dc *Conn) Write(b []byte) (n int, err error) {
	log.Tracef("Initiate a write request to %s", dc.addr)
	if dc.anyDataReceived() {
		return dc.followUpWrite(b)
	}
	var count int
	if isNonIdempotentRequest(b) {
		count = dc.writeNonIdeomponent(b)
	} else {
		count = dc.runOnValidConn(func(conn conn) {
			conn.Write(b, dc.chWrite)
		})
	}
	for i := 0; i < count; i++ {
		result := <-dc.chWrite
		if n, err = result.n, result.err; err != nil {
			log.Tracef("Error writing %s connection to %s, %d attempt: %s", typeOf(result.conn), dc.addr, i+1, err)
			continue
		}
		log.Tracef("Wrote %d bytes to %s connection to %s", n, typeOf(result.conn), dc.addr)
		return
	}
	return
}

func (dc *Conn) writeNonIdeomponent(b []byte) (count int) {
	dc.muConn.RLock()
	defer dc.muConn.RUnlock()
	log.Tracef("For non ideomponent operation to %s, try write directly first", dc.addr)
	for _, conn := range dc.conns {
		if conn.Valid() && conn.ConnType() == connTypeDirect {
			conn.Write(b, dc.chWrite)
			count++
			return
		}
	}
	log.Tracef("No valid direct connection to %s, write to other (detour)", dc.addr)
	for _, conn := range dc.conns {
		if conn.Valid() {
			conn.Write(b, dc.chWrite)
			count++
			return
		}
	}
	return
}

// followUpWrite is called by Write() if a connection's state already settled
func (dc *Conn) followUpWrite(b []byte) (n int, err error) {
	dc.runOnValidConn(func(conn conn) {
		conn.Write(b, dc.chWrite)
	})
	result := <-dc.chWrite
	return result.n, result.err
}

// Close() implements the function from net.Conn
func (dc *Conn) Close() error {
	log.Tracef("Closing connection to %s", dc.addr)
	dc.runOnValidConn(func(conn conn) {
		conn.Close()
	})
	return nil
}

// LocalAddr() implements the function from net.Conn
func (dc *Conn) LocalAddr() net.Addr {
	return nil
}

// RemoteAddr() implements the function from net.Conn
func (dc *Conn) RemoteAddr() net.Addr {
	return nil
}

// SetDeadline() implements the function from net.Conn
func (dc *Conn) SetDeadline(t time.Time) error {
	dc.SetReadDeadline(t)
	dc.SetWriteDeadline(t)
	return nil
}

// SetReadDeadline() implements the function from net.Conn
func (dc *Conn) SetReadDeadline(t time.Time) error {
	return nil
}

// SetWriteDeadline() implements the function from net.Conn
func (dc *Conn) SetWriteDeadline(t time.Time) error {
	return nil
}

var nonIdempotentMethods = [][]byte{
	[]byte("POST "),
	[]byte("PATCH "),
}

// ref section 9.1.2 of https://www.ietf.org/rfc/rfc2616.txt.
// checks against non-idemponent methods actually,
// as we consider the https handshake phase to be idemponent.
func isNonIdempotentRequest(b []byte) bool {
	if len(b) > 4 {
		for _, m := range nonIdempotentMethods {
			if bytes.HasPrefix(b, m) {
				return true
			}
		}
	}
	return false
}
<commit_msg>detour use chan instead of slice to store connections<commit_after>/*
Package detour provides a net.Conn interface which detects blockage
of a site automatically and try to access it through alternative dialer.

Basically, if a site is not whitelisted, it has follow steps:
1. Dial in parallel
2. Return to caller if any connection is established
3. Read/write to all connections
4. After sucessfully read from a connection, stick with it and close others.
*/
package detour

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"sync/atomic"
	"time"

	"github.com/getlantern/golog"
)

var TimeoutToConnect = 30 * time.Second
var DelayBeforeDetour = 1 * time.Second

// if DirectAddrCh is set, when a direct connection is closed without any error,
// the connection's remote address (in host:port format) will be send to it
var DirectAddrCh chan string

var (
	log = golog.LoggerFor("detour")
)

type dialFunc func(network, addr string) (net.Conn, error)

type Conn struct {
	// the underlie connections, uses buffered channel as ring queue.
	conns chan conn

	// the chan to receive result of any read operation
	chRead chan ioResult
	// the chan to receive result of any write operation
	chWrite chan ioResult

	// keep track of the total bytes read in this connection, atomic
	readBytes uint64

	network, addr string
}

// The data structure to pass result of io operation back from underlie connection
type ioResult struct {
	// number of bytes processed
	n int
	// io error, if any
	err error
	// the underlie connection that actually do the io operation
	conn conn
}

type connType int

const (
	connTypeDirect connType = iota
	connTypeDetour connType = iota
)

type conn interface {
	ConnType() connType
	Valid() bool
	SetInvalid()
	FirstRead(b []byte, ch chan ioResult)
	FollowupRead(b []byte, ch chan ioResult)
	Write(b []byte, ch chan ioResult)
	Close()
}

func typeOf(c conn) string {
	var connTypeDesc = []string{
		"direct",
		"detour",
	}
	return connTypeDesc[c.ConnType()]
}

// Dialer returns a function with same signature of net.Dialer.Dial().
func Dialer(df dialFunc) dialFunc {
	return func(network, addr string) (net.Conn, error) {
		dc := &Conn{network: network, addr: addr, conns: make(chan conn, 2), chRead: make(chan ioResult), chWrite: make(chan ioResult)}
		// buffered channel, as we may send twice to it but only receive once
		chAnyConn := make(chan conn, 1)
		ch := make(chan conn)
		go func() {
			if !whitelisted(addr) {
				DialDirect(network, addr, ch)
				time.Sleep(DelayBeforeDetour)
			}
			DialDetour(network, addr, df, ch)
		}()
		go func() {
			t := time.NewTimer(TimeoutToConnect)
			for i := 0; i < 2; i++ {
				select {
				case conn := <-ch:
					if dc.anyDataReceived() {
						log.Debugf("Drop a %s connection established too late to %s", typeOf(conn), dc.addr)
						conn.Close()
						return
					}
					dc.conns <- conn
					chAnyConn <- conn
				case <-t.C:
					if i == 0 {
						chAnyConn <- nil
					}
					return
				}
			}
		}()
		// return to caller if any connection available
		if anyConn := <-chAnyConn; anyConn != nil {
			return dc, nil
		}
		return nil, fmt.Errorf("Timeout dialing both direct and detour connection to %s", addr)
	}
}

func (dc *Conn) runOnValidConn(f func(conn)) (count int) {
	for i := 0; i < len(dc.conns); i++ {
		conn := <-dc.conns
		if !conn.Valid() {
			conn.Close()
			continue
		}
		f(conn)
		dc.conns <- conn
		count++
	}
	return
}

func (dc *Conn) anyDataReceived() bool {
	return atomic.LoadUint64(&dc.readBytes) > 0
}

func (dc *Conn) incReadBytes(n int) {
	atomic.AddUint64(&dc.readBytes, uint64(n))
}

// Read() implements the function from net.Conn
func (dc *Conn) Read(b []byte) (n int, err error) {
	log.Tracef("Initiate a read request to %s", dc.addr)
	if dc.anyDataReceived() {
		return dc.followupRead(b)
	}
	count := dc.runOnValidConn(func(conn conn) {
		conn.FirstRead(b, dc.chRead)
	})
	for i := 0; i < count; i++ {
		result := <-dc.chRead
		n, err = result.n, result.err
		if err != nil && err != io.EOF {
			log.Tracef("Read from %s through %s failed, set as invalid: %s", dc.addr, typeOf(result.conn), err)
			result.conn.SetInvalid()
			// skip failed connection
			continue
		}
		log.Tracef("Read %d bytes from %s connection to %s", n, typeOf(result.conn), dc.addr)
		dc.incReadBytes(n)
		dc.runOnValidConn(func(c conn) {
			if c != result.conn {
				log.Tracef("Set %s connection to %s as invalid", typeOf(c), dc.addr)
				c.SetInvalid()
				// direct connection failed
				if c.ConnType() == connTypeDirect {
					log.Tracef("Add %s to whitelist", dc.addr)
					AddToWl(dc.addr, false)
				}
			}
		})
		return
	}
	return
}

// followUpRead is called by Read() if a connection's state already settled
func (dc *Conn) followupRead(b []byte) (n int, err error) {
	dc.runOnValidConn(func(conn conn) {
		conn.FollowupRead(b, dc.chRead)
	})
	result := <-dc.chRead
	dc.incReadBytes(result.n)
	return result.n, result.err
}

// Write() implements the function from net.Conn
func (dc *Conn) Write(b []byte) (n int, err error) {
	log.Tracef("Initiate a write request to %s", dc.addr)
	if dc.anyDataReceived() {
		return dc.followUpWrite(b)
	}
	var count int
	if isNonIdempotentRequest(b) {
		count = dc.writeNonIdeomponent(b)
	} else {
		count = dc.runOnValidConn(func(conn conn) {
			conn.Write(b, dc.chWrite)
		})
	}
	for i := 0; i < count; i++ {
		result := <-dc.chWrite
		if n, err = result.n, result.err; err != nil {
			log.Tracef("Error writing %s connection to %s, %d attempt: %s", typeOf(result.conn), dc.addr, i+1, err)
			continue
		}
		log.Tracef("Wrote %d bytes to %s connection to %s", n, typeOf(result.conn), dc.addr)
		return
	}
	return
}

func (dc *Conn) writeNonIdeomponent(b []byte) (count int) {
	log.Tracef("For non ideomponent operation to %s, try write directly first", dc.addr)
	for i := 0; i < len(dc.conns); i++ {
		conn := <-dc.conns
		if conn.Valid() && conn.ConnType() == connTypeDirect {
			conn.Write(b, dc.chWrite)
			dc.conns <- conn
			count++
			return
		}
	}
	log.Tracef("No valid direct connection to %s, write to other (detour)", dc.addr)
	for i := 0; i < len(dc.conns); i++ {
		conn := <-dc.conns
		if conn.Valid() {
			conn.Write(b, dc.chWrite)
			dc.conns <- conn
			count++
			return
		}
	}
	return
}

// followUpWrite is called by Write() if a connection's state already settled
func (dc *Conn) followUpWrite(b []byte) (n int, err error) {
	dc.runOnValidConn(func(conn conn) {
		conn.Write(b, dc.chWrite)
	})
	result := <-dc.chWrite
	return result.n, result.err
}

// Close() implements the function from net.Conn
func (dc *Conn) Close() error {
	log.Tracef("Closing connection to %s", dc.addr)
	dc.runOnValidConn(func(conn conn) {
		conn.Close()
	})
	return nil
}

// LocalAddr() implements the function from net.Conn
func (dc *Conn) LocalAddr() net.Addr {
	return nil
}

// RemoteAddr() implements the function from net.Conn
func (dc *Conn) RemoteAddr() net.Addr {
	return nil
}

// SetDeadline() implements the function from net.Conn
func (dc *Conn) SetDeadline(t time.Time) error {
	dc.SetReadDeadline(t)
	dc.SetWriteDeadline(t)
	return nil
}

// SetReadDeadline() implements the function from net.Conn
func (dc *Conn) SetReadDeadline(t time.Time) error {
	return nil
}

// SetWriteDeadline() implements the function from net.Conn
func (dc *Conn) SetWriteDeadline(t time.Time) error {
	return nil
}

var nonIdempotentMethods = [][]byte{
	[]byte("POST "),
	[]byte("PATCH "),
}

// ref section 9.1.2 of https://www.ietf.org/rfc/rfc2616.txt.
// checks against non-idemponent methods actually,
// as we consider the https handshake phase to be idemponent.
func isNonIdempotentRequest(b []byte) bool {
	if len(b) > 4 {
		for _, m := range nonIdempotentMethods {
			if bytes.HasPrefix(b, m) {
				return true
			}
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Package reqid creates request IDs and stores them in Contexts.
package reqid

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"net/http"

	"chain/log"
)

// key is an unexported type for keys defined in this package.
// This prevents collisions with keys defined in other packages.
type key int

const (
	// reqIDKey is the key for request IDs in Contexts.  It is
	// unexported; clients use NewContext and FromContext
	// instead of using this key directly.
	reqIDKey key = iota
	// subReqIDKey is the key for sub-request IDs in Contexts.  It is
	// unexported; clients use NewSubContext and FromSubContext
	// instead of using this key directly.
	subReqIDKey
	// coreIDKey is the key for Chain-Core-ID request header field values.
	// It is only for statistics; don't use it for authorization.
	coreIDKey
	// pathKey is the key for the request path being handled.
	pathKey
)

const Unknown = "unknown_req_id"

// New generates a random request ID.
func New() string {
	// Given n IDs of length b bits, the probability that there will be a collision is bounded by
	// the number of pairs of IDs multiplied by the probability that any pair might collide:
	// p ≤ n(n - 1)/2 * 1/(2^b)
	//
	// We assume an upper bound of 1000 req/sec, which means that in a week there will be
	// n = 1000 * 604800 requests. If l = 10, b = 8*10, then p ≤ 1.512e-7, which is a suitably
	// low probability.
	l := 10
	b := make([]byte, l)
	_, err := rand.Read(b)
	if err != nil {
		log.Printf(context.Background(), "error making reqID")
	}
	return hex.EncodeToString(b)
}

// NewContext returns a new Context that carries reqid.
// It also adds a log prefix to print the request ID using
// package chain/log.
func NewContext(ctx context.Context, reqid string) context.Context {
	ctx = context.WithValue(ctx, reqIDKey, reqid)
	ctx = log.AddPrefixkv(ctx, "reqid", reqid)
	return ctx
}

// FromContext returns the request ID stored in ctx,
// or Unknown, if there is none.
func FromContext(ctx context.Context) string {
	reqID, ok := ctx.Value(reqIDKey).(string)
	if !ok {
		return Unknown
	}
	return reqID
}

// CoreIDFromContext returns the Chain-Core-ID stored in ctx,
// or the empty string.
func CoreIDFromContext(ctx context.Context) string {
	id, _ := ctx.Value(coreIDKey).(string)
	return id
}

// PathFromContext returns the HTTP path stored in ctx,
// or the empty string.
func PathFromContext(ctx context.Context) string {
	path, _ := ctx.Value(pathKey).(string)
	return path
}

// NewSubContext returns a new Context that carries subreqid
// It also adds a log prefix to print the sub-request ID using
// package chain/log.
func NewSubContext(ctx context.Context, reqid string) context.Context {
	ctx = context.WithValue(ctx, subReqIDKey, reqid)
	ctx = log.AddPrefixkv(ctx, "subreqid", reqid)
	return ctx
}

// FromSubContext returns the sub-request ID stored in ctx,
// or Unknown if there is none
func FromSubContext(ctx context.Context) string {
	subReqID, ok := ctx.Value(subReqIDKey).(string)
	if !ok {
		return Unknown
	}
	return subReqID
}

func Handler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		// TODO(kr): take half of request ID from the client
		id := New()
		ctx = NewContext(ctx, id)
		ctx = context.WithValue(ctx, pathKey, req.URL.Path)
		if coreID := req.Header.Get("Chain-Core-ID"); coreID != "" {
			ctx = context.WithValue(ctx, coreIDKey, coreID)
			ctx = log.AddPrefixkv(ctx, "coreid", coreID)
		}

		defer func() {
			if err := recover(); err != nil {
				log.Printkv(ctx,
					"message", "panic",
					"remote-addr", req.RemoteAddr,
					"error", err,
				)
			}
		}()
		w.Header().Add("Chain-Request-Id", id)
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}
<commit_msg>net/http/reqid: remove unused exported constant<commit_after>// Package reqid creates request IDs and stores them in Contexts.
package reqid

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"net/http"

	"chain/log"
)

// key is an unexported type for keys defined in this package.
// This prevents collisions with keys defined in other packages.
type key int

const (
	// reqIDKey is the key for request IDs in Contexts.  It is
	// unexported; clients use NewContext and FromContext
	// instead of using this key directly.
	reqIDKey key = iota
	// subReqIDKey is the key for sub-request IDs in Contexts.  It is
	// unexported; clients use NewSubContext and FromSubContext
	// instead of using this key directly.
	subReqIDKey
	// coreIDKey is the key for Chain-Core-ID request header field values.
	// It is only for statistics; don't use it for authorization.
	coreIDKey
	// pathKey is the key for the request path being handled.
	pathKey
)

// New generates a random request ID.
func New() string {
	// Given n IDs of length b bits, the probability that there will be a collision is bounded by
	// the number of pairs of IDs multiplied by the probability that any pair might collide:
	// p ≤ n(n - 1)/2 * 1/(2^b)
	//
	// We assume an upper bound of 1000 req/sec, which means that in a week there will be
	// n = 1000 * 604800 requests. If l = 10, b = 8*10, then p ≤ 1.512e-7, which is a suitably
	// low probability.
	l := 10
	b := make([]byte, l)
	_, err := rand.Read(b)
	if err != nil {
		log.Printf(context.Background(), "error making reqID")
	}
	return hex.EncodeToString(b)
}

// NewContext returns a new Context that carries reqid.
// It also adds a log prefix to print the request ID using
// package chain/log.
func NewContext(ctx context.Context, reqid string) context.Context {
	ctx = context.WithValue(ctx, reqIDKey, reqid)
	ctx = log.AddPrefixkv(ctx, "reqid", reqid)
	return ctx
}

// FromContext returns the request ID stored in ctx,
// if any.
func FromContext(ctx context.Context) string {
	reqID, _ := ctx.Value(reqIDKey).(string)
	return reqID
}

// CoreIDFromContext returns the Chain-Core-ID stored in ctx,
// or the empty string.
func CoreIDFromContext(ctx context.Context) string {
	id, _ := ctx.Value(coreIDKey).(string)
	return id
}

// PathFromContext returns the HTTP path stored in ctx,
// or the empty string.
func PathFromContext(ctx context.Context) string {
	path, _ := ctx.Value(pathKey).(string)
	return path
}

// NewSubContext returns a new Context that carries subreqid
// It also adds a log prefix to print the sub-request ID using
// package chain/log.
func NewSubContext(ctx context.Context, reqid string) context.Context {
	ctx = context.WithValue(ctx, subReqIDKey, reqid)
	ctx = log.AddPrefixkv(ctx, "subreqid", reqid)
	return ctx
}

// FromSubContext returns the sub-request ID stored in ctx,
// if any.
func FromSubContext(ctx context.Context) string {
	subReqID, _ := ctx.Value(subReqIDKey).(string)
	return subReqID
}

func Handler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		// TODO(kr): take half of request ID from the client
		id := New()
		ctx = NewContext(ctx, id)
		ctx = context.WithValue(ctx, pathKey, req.URL.Path)
		if coreID := req.Header.Get("Chain-Core-ID"); coreID != "" {
			ctx = context.WithValue(ctx, coreIDKey, coreID)
			ctx = log.AddPrefixkv(ctx, "coreid", coreID)
		}

		defer func() {
			if err := recover(); err != nil {
				log.Printkv(ctx,
					"message", "panic",
					"remote-addr", req.RemoteAddr,
					"error", err,
				)
			}
		}()
		w.Header().Add("Chain-Request-Id", id)
		handler.ServeHTTP(w, req.WithContext(ctx))
	})
}
<|endoftext|>


<commit_before>// +build integration

// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package integration

import (
	"testing"
	"time"

	"github.com/m3db/m3/src/dbnode/client"
	"github.com/m3db/m3/src/dbnode/generated/proto/annotation"
	"github.com/m3db/m3/src/dbnode/namespace"
	"github.com/m3db/m3/src/dbnode/persist/fs"
	"github.com/m3db/m3/src/dbnode/retention"
	"github.com/m3db/m3/src/dbnode/storage"
	"github.com/m3db/m3/src/dbnode/ts"
	xclock "github.com/m3db/m3/src/x/clock"
	"github.com/m3db/m3/src/x/ident"
	xtime "github.com/m3db/m3/src/x/time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

const (
	blockSize  = 2 * time.Hour
	blockSizeT = 24 * time.Hour
	testDataPointsCount = 60
)

var (
	gaugePayload   = &annotation.Payload{MetricType: annotation.MetricType_GAUGE}
	counterPayload = &annotation.Payload{MetricType: annotation.MetricType_COUNTER, HandleValueResets: true}
)

func TestReadAggregateWrite(t *testing.T) {
//	t.Skip("flaky")
	var (
		start                   = time.Now()
		testSetup, srcNs, trgNs = setupServer(t)
		storageOpts             = testSetup.StorageOpts()
		log                     = storageOpts.InstrumentOptions().Logger()
	)

	// Stop the server.
	defer func() {
		require.NoError(t, testSetup.StopServer())
		log.Debug("server is now down")
		testSetup.Close()
	}()

	session, err := testSetup.M3DBClient().DefaultSession()
	require.NoError(t, err)
	nowFn := storageOpts.ClockOptions().NowFn()

	// Write test data.
	dpTimeStart := nowFn().Truncate(blockSizeT)

	// "aab" ID is stored to the same shard 0 same as "foo", this is important
	// for a test to store them to the same shard to test data consistency
	err = session.WriteTagged(srcNs.ID(), ident.StringID("aab"),
		ident.MustNewTagStringsIterator("__name__", "cpu", "job", "job1"),
		dpTimeStart, 15, xtime.Second, annotationBytes(t, gaugePayload))

	dpTime := dpTimeStart
	for a := 0; a < testDataPointsCount; a++ {
		if a < 10 {
			dpTime = dpTime.Add(10 * time.Minute)
			continue
		}
		err = session.WriteTagged(srcNs.ID(), ident.StringID("foo"),
			ident.MustNewTagStringsIterator("__name__", "cpu", "job", "job1"),
			dpTime, 42.1+float64(a), xtime.Nanosecond, annotationBytes(t, counterPayload))
		require.NoError(t, err)
		dpTime = dpTime.Add(10 * time.Minute)
	}
	log.Info("test data written", zap.Duration("took", time.Since(start)))

	log.Info("waiting till data is cold flushed")
	start = time.Now()
	expectedSourceBlocks := 5
	flushed := xclock.WaitUntil(func() bool {
		for i := 0; i < expectedSourceBlocks; i++ {
			blockStart := dpTimeStart.Add(time.Duration(i) * blockSize)
			_, ok, err := fs.FileSetAt(testSetup.FilesystemOpts().FilePathPrefix(), srcNs.ID(), 0, blockStart, 1)
			require.NoError(t, err)
			if !ok {
				return false
			}
		}
		return true
	}, time.Minute)
	require.True(t, flushed)
	log.Info("verified data has been cold flushed", zap.Duration("took", time.Since(start)))

	aggOpts, err := storage.NewAggregateTilesOptions(
		dpTimeStart, dpTimeStart.Add(blockSizeT), time.Hour,
		trgNs.ID(),
		storageOpts.InstrumentOptions(),
	)
	require.NoError(t, err)

	log.Info("Starting aggregation")
	start = time.Now()
	processedTileCount, err := testSetup.DB().AggregateTiles(
		storageOpts.ContextPool().Get(),
		srcNs.ID(), trgNs.ID(),
		aggOpts)
	log.Info("Finished aggregation", zap.Duration("took", time.Since(start)))
	require.NoError(t, err)
	assert.Equal(t, int64(10), processedTileCount)

	log.Info("validating aggregated data")

	// check shard 0 as we wrote both aab and foo to this shard.
	flushState, err := testSetup.DB().FlushState(trgNs.ID(), 0, dpTimeStart)
	require.NoError(t, err)
	require.Equal(t, 1, flushState.ColdVersionRetrievable)
	require.Equal(t, 1, flushState.ColdVersionFlushed)

	log.Info("waiting till aggregated data is readable")
	start = time.Now()
	readable := xclock.WaitUntil(func() bool {
		series, err := session.Fetch(trgNs.ID(), ident.StringID("foo"), dpTimeStart, dpTimeStart.Add(blockSizeT))
		require.NoError(t, err)
		return series.Next()
	}, time.Minute)
	require.True(t, readable)
	log.Info("verified data is readable", zap.Duration("took", time.Since(start)))

	expectedDps := []ts.Datapoint{
		{Timestamp: dpTimeStart, Value: 15},
	}
	fetchAndValidate(t, session, trgNs.ID(),
		ident.StringID("aab"),
		dpTimeStart, nowFn(),
		expectedDps, xtime.Second, gaugePayload)

	expectedDps = []ts.Datapoint{
		{Timestamp: dpTimeStart.Add(100 * time.Minute), Value: 52.1},
		{Timestamp: dpTimeStart.Add(110 * time.Minute), Value: 53.1},
		{Timestamp: dpTimeStart.Add(170 * time.Minute), Value: 59.1},
		{Timestamp: dpTimeStart.Add(230 * time.Minute), Value: 65.1},
		{Timestamp: dpTimeStart.Add(290 * time.Minute), Value: 71.1},
		{Timestamp: dpTimeStart.Add(350 * time.Minute), Value: 77.1},
		{Timestamp: dpTimeStart.Add(410 * time.Minute), Value: 83.1},
		{Timestamp: dpTimeStart.Add(470 * time.Minute), Value: 89.1},
		{Timestamp: dpTimeStart.Add(530 * time.Minute), Value: 95.1},
		{Timestamp: dpTimeStart.Add(590 * time.Minute), Value: 101.1},
	}

	fetchAndValidate(t, session, trgNs.ID(),
		ident.StringID("foo"),
		dpTimeStart, nowFn(),
		expectedDps, xtime.Nanosecond, counterPayload)
}

func fetchAndValidate(
	t *testing.T,
	session client.Session,
	nsID ident.ID,
	id ident.ID,
	startInclusive, endExclusive time.Time,
	expectedDP []ts.Datapoint,
	expectedUnit xtime.Unit,
	expectedAnnotation *annotation.Payload,
) {
	series, err := session.Fetch(nsID, id, startInclusive, endExclusive)
	require.NoError(t, err)

	actual := make([]ts.Datapoint, 0, len(expectedDP))
	first := true
	for series.Next() {
		dp, unit, annotation := series.Current()
		if first {
			assert.Equal(t, expectedAnnotation, annotationPayload(t, annotation))
			first = false
		}
		assert.Equal(t, expectedUnit, unit)
		dp.TimestampNanos = 0
		actual = append(actual, dp)
	}

	assert.Equal(t, expectedDP, actual)
}

func setupServer(t *testing.T) (TestSetup, namespace.Metadata, namespace.Metadata) {
	var (
		rOpts    = retention.NewOptions().SetRetentionPeriod(500 * blockSize).SetBlockSize(blockSize).SetBufferPast(0).SetBufferFuture(0)
		rOptsT   = retention.NewOptions().SetRetentionPeriod(100 * blockSize).SetBlockSize(blockSizeT).SetBufferPast(0).SetBufferFuture(0)
		idxOpts  = namespace.NewIndexOptions().SetEnabled(true).SetBlockSize(blockSize)
		idxOptsT = namespace.NewIndexOptions().SetEnabled(true).SetBlockSize(blockSizeT)
		nsOpts   = namespace.NewOptions().
				SetRetentionOptions(rOpts).
				SetIndexOptions(idxOpts).
				SetColdWritesEnabled(true)
		nsOptsT = namespace.NewOptions().
			SetRetentionOptions(rOptsT).
			SetIndexOptions(idxOptsT)

		fixedNow = time.Now().Truncate(blockSizeT).Add(11*blockSize)
	)

	srcNs, err := namespace.NewMetadata(testNamespaces[0], nsOpts)
	require.NoError(t, err)
	trgNs, err := namespace.NewMetadata(testNamespaces[1], nsOptsT)
	require.NoError(t, err)

	testOpts := NewTestOptions(t).
		SetNamespaces([]namespace.Metadata{srcNs, trgNs}).
		SetWriteNewSeriesAsync(true).
		SetNumShards(1).
		SetFetchRequestTimeout(time.Second * 30).
		SetNowFn(func() time.Time {
			return fixedNow
		})

	testSetup := newTestSetupWithCommitLogAndFilesystemBootstrapper(t, testOpts)

	// Start the server.
	require.NoError(t, testSetup.StartServer())

	return testSetup, srcNs, trgNs
}

func annotationBytes(t *testing.T, payload *annotation.Payload) ts.Annotation {
	if payload != nil {
		annotationBytes, err := payload.Marshal()
		require.NoError(t, err)
		return annotationBytes
	}
	return nil
}

func annotationPayload(t *testing.T, annotationBytes ts.Annotation) *annotation.Payload {
	if annotationBytes != nil {
		payload := &annotation.Payload{}
		require.NoError(t, payload.Unmarshal(annotationBytes))
		return payload
	}
	return nil
}
<commit_msg>[dbnode] Resurrect flaky test skip (#2868)<commit_after>// +build integration

// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package integration

import (
	"testing"
	"time"

	"github.com/m3db/m3/src/dbnode/client"
	"github.com/m3db/m3/src/dbnode/generated/proto/annotation"
	"github.com/m3db/m3/src/dbnode/namespace"
	"github.com/m3db/m3/src/dbnode/persist/fs"
	"github.com/m3db/m3/src/dbnode/retention"
	"github.com/m3db/m3/src/dbnode/storage"
	"github.com/m3db/m3/src/dbnode/ts"
	xclock "github.com/m3db/m3/src/x/clock"
	"github.com/m3db/m3/src/x/ident"
	xtime "github.com/m3db/m3/src/x/time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

const (
	blockSize  = 2 * time.Hour
	blockSizeT = 24 * time.Hour
	testDataPointsCount = 60
)

var (
	gaugePayload   = &annotation.Payload{MetricType: annotation.MetricType_GAUGE}
	counterPayload = &annotation.Payload{MetricType: annotation.MetricType_COUNTER, HandleValueResets: true}
)

func TestReadAggregateWrite(t *testing.T) {
	t.Skip("flaky")
	var (
		start                   = time.Now()
		testSetup, srcNs, trgNs = setupServer(t)
		storageOpts             = testSetup.StorageOpts()
		log                     = storageOpts.InstrumentOptions().Logger()
	)

	// Stop the server.
	defer func() {
		require.NoError(t, testSetup.StopServer())
		log.Debug("server is now down")
		testSetup.Close()
	}()

	session, err := testSetup.M3DBClient().DefaultSession()
	require.NoError(t, err)
	nowFn := storageOpts.ClockOptions().NowFn()

	// Write test data.
	dpTimeStart := nowFn().Truncate(blockSizeT)

	// "aab" ID is stored to the same shard 0 same as "foo", this is important
	// for a test to store them to the same shard to test data consistency
	err = session.WriteTagged(srcNs.ID(), ident.StringID("aab"),
		ident.MustNewTagStringsIterator("__name__", "cpu", "job", "job1"),
		dpTimeStart, 15, xtime.Second, annotationBytes(t, gaugePayload))

	dpTime := dpTimeStart
	for a := 0; a < testDataPointsCount; a++ {
		if a < 10 {
			dpTime = dpTime.Add(10 * time.Minute)
			continue
		}
		err = session.WriteTagged(srcNs.ID(), ident.StringID("foo"),
			ident.MustNewTagStringsIterator("__name__", "cpu", "job", "job1"),
			dpTime, 42.1+float64(a), xtime.Nanosecond, annotationBytes(t, counterPayload))
		require.NoError(t, err)
		dpTime = dpTime.Add(10 * time.Minute)
	}
	log.Info("test data written", zap.Duration("took", time.Since(start)))

	log.Info("waiting till data is cold flushed")
	start = time.Now()
	expectedSourceBlocks := 5
	flushed := xclock.WaitUntil(func() bool {
		for i := 0; i < expectedSourceBlocks; i++ {
			blockStart := dpTimeStart.Add(time.Duration(i) * blockSize)
			_, ok, err := fs.FileSetAt(testSetup.FilesystemOpts().FilePathPrefix(), srcNs.ID(), 0, blockStart, 1)
			require.NoError(t, err)
			if !ok {
				return false
			}
		}
		return true
	}, time.Minute)
	require.True(t, flushed)
	log.Info("verified data has been cold flushed", zap.Duration("took", time.Since(start)))

	aggOpts, err := storage.NewAggregateTilesOptions(
		dpTimeStart, dpTimeStart.Add(blockSizeT), time.Hour,
		trgNs.ID(),
		storageOpts.InstrumentOptions(),
	)
	require.NoError(t, err)

	log.Info("Starting aggregation")
	start = time.Now()
	processedTileCount, err := testSetup.DB().AggregateTiles(
		storageOpts.ContextPool().Get(),
		srcNs.ID(), trgNs.ID(),
		aggOpts)
	log.Info("Finished aggregation", zap.Duration("took", time.Since(start)))
	require.NoError(t, err)
	assert.Equal(t, int64(10), processedTileCount)

	log.Info("validating aggregated data")

	// check shard 0 as we wrote both aab and foo to this shard.
	flushState, err := testSetup.DB().FlushState(trgNs.ID(), 0, dpTimeStart)
	require.NoError(t, err)
	require.Equal(t, 1, flushState.ColdVersionRetrievable)
	require.Equal(t, 1, flushState.ColdVersionFlushed)

	log.Info("waiting till aggregated data is readable")
	start = time.Now()
	readable := xclock.WaitUntil(func() bool {
		series, err := session.Fetch(trgNs.ID(), ident.StringID("foo"), dpTimeStart, dpTimeStart.Add(blockSizeT))
		require.NoError(t, err)
		return series.Next()
	}, time.Minute)
	require.True(t, readable)
	log.Info("verified data is readable", zap.Duration("took", time.Since(start)))

	expectedDps := []ts.Datapoint{
		{Timestamp: dpTimeStart, Value: 15},
	}
	fetchAndValidate(t, session, trgNs.ID(),
		ident.StringID("aab"),
		dpTimeStart, nowFn(),
		expectedDps, xtime.Second, gaugePayload)

	expectedDps = []ts.Datapoint{
		{Timestamp: dpTimeStart.Add(100 * time.Minute), Value: 52.1},
		{Timestamp: dpTimeStart.Add(110 * time.Minute), Value: 53.1},
		{Timestamp: dpTimeStart.Add(170 * time.Minute), Value: 59.1},
		{Timestamp: dpTimeStart.Add(230 * time.Minute), Value: 65.1},
		{Timestamp: dpTimeStart.Add(290 * time.Minute), Value: 71.1},
		{Timestamp: dpTimeStart.Add(350 * time.Minute), Value: 77.1},
		{Timestamp: dpTimeStart.Add(410 * time.Minute), Value: 83.1},
		{Timestamp: dpTimeStart.Add(470 * time.Minute), Value: 89.1},
		{Timestamp: dpTimeStart.Add(530 * time.Minute), Value: 95.1},
		{Timestamp: dpTimeStart.Add(590 * time.Minute), Value: 101.1},
	}

	fetchAndValidate(t, session, trgNs.ID(),
		ident.StringID("foo"),
		dpTimeStart, nowFn(),
		expectedDps, xtime.Nanosecond, counterPayload)
}

func fetchAndValidate(
	t *testing.T,
	session client.Session,
	nsID ident.ID,
	id ident.ID,
	startInclusive, endExclusive time.Time,
	expectedDP []ts.Datapoint,
	expectedUnit xtime.Unit,
	expectedAnnotation *annotation.Payload,
) {
	series, err := session.Fetch(nsID, id, startInclusive, endExclusive)
	require.NoError(t, err)

	actual := make([]ts.Datapoint, 0, len(expectedDP))
	first := true
	for series.Next() {
		dp, unit, annotation := series.Current()
		if first {
			assert.Equal(t, expectedAnnotation, annotationPayload(t, annotation))
			first = false
		}
		assert.Equal(t, expectedUnit, unit)
		dp.TimestampNanos = 0
		actual = append(actual, dp)
	}

	assert.Equal(t, expectedDP, actual)
}

func setupServer(t *testing.T) (TestSetup, namespace.Metadata, namespace.Metadata) {
	var (
		rOpts    = retention.NewOptions().SetRetentionPeriod(500 * blockSize).SetBlockSize(blockSize).SetBufferPast(0).SetBufferFuture(0)
		rOptsT   = retention.NewOptions().SetRetentionPeriod(100 * blockSize).SetBlockSize(blockSizeT).SetBufferPast(0).SetBufferFuture(0)
		idxOpts  = namespace.NewIndexOptions().SetEnabled(true).SetBlockSize(blockSize)
		idxOptsT = namespace.NewIndexOptions().SetEnabled(true).SetBlockSize(blockSizeT)
		nsOpts   = namespace.NewOptions().
				SetRetentionOptions(rOpts).
				SetIndexOptions(idxOpts).
				SetColdWritesEnabled(true)
		nsOptsT = namespace.NewOptions().
			SetRetentionOptions(rOptsT).
			SetIndexOptions(idxOptsT)

		fixedNow = time.Now().Truncate(blockSizeT).Add(11*blockSize)
	)

	srcNs, err := namespace.NewMetadata(testNamespaces[0], nsOpts)
	require.NoError(t, err)
	trgNs, err := namespace.NewMetadata(testNamespaces[1], nsOptsT)
	require.NoError(t, err)

	testOpts := NewTestOptions(t).
		SetNamespaces([]namespace.Metadata{srcNs, trgNs}).
		SetWriteNewSeriesAsync(true).
		SetNumShards(1).
		SetFetchRequestTimeout(time.Second * 30).
		SetNowFn(func() time.Time {
			return fixedNow
		})

	testSetup := newTestSetupWithCommitLogAndFilesystemBootstrapper(t, testOpts)

	// Start the server.
	require.NoError(t, testSetup.StartServer())

	return testSetup, srcNs, trgNs
}

func annotationBytes(t *testing.T, payload *annotation.Payload) ts.Annotation {
	if payload != nil {
		annotationBytes, err := payload.Marshal()
		require.NoError(t, err)
		return annotationBytes
	}
	return nil
}

func annotationPayload(t *testing.T, annotationBytes ts.Annotation) *annotation.Payload {
	if annotationBytes != nil {
		payload := &annotation.Payload{}
		require.NoError(t, payload.Unmarshal(annotationBytes))
		return payload
	}
	return nil
}
<|endoftext|>


<commit_before>
package main

import (
    "fmt"
    "../GoLang/fibonacci"
    "../GoLang/exponenciacao"
    "../GoLang/fatorial"
    "../GoLang/hanoi"
    "../GoLang/bubblesort"
    "../GoLang/selectionsort"
    "../GoLang/insertionsort"
)

func main() {
    fmt.Println("Fibonacci : ", fibonacci.Fibonacci(9))
    fmt.Println("Exponenciacao : ", exponenciacao.Exponenciacao(5, 5))
    fmt.Println("Fatorial : ", fatorial.Fatorial(6))
    fmt.Println("Hanoi : ")
    hanoi.Hanoi(0, 2, 1, 3)
    slice := []int{5, 2, 1, 6, 9, 8, 7, 3, 4}
    fmt.Println("Slice : ", slice)
    fmt.Println("BubbleSort : ", bubblesort.BubbleSort(slice))
    fmt.Println("SelectionSort : ", selectionsort.SelectionSort(slice))
    fmt.Println("InsertionSort : ", insertionsort.InsertionSort(slice))
}
<commit_msg>Adicionado exemplo do mergesort no main.go<commit_after>
package main

import (
    "fmt"
    "../GoLang/fibonacci"
    "../GoLang/exponenciacao"
    "../GoLang/fatorial"
    "../GoLang/hanoi"
    "../GoLang/bubblesort"
    "../GoLang/selectionsort"
    "../GoLang/insertionsort"
    "../GoLang/mergesort"
)

func main() {
    fmt.Println("Fibonacci : ", fibonacci.Fibonacci(9))
    fmt.Println("Exponenciacao : ", exponenciacao.Exponenciacao(5, 5))
    fmt.Println("Fatorial : ", fatorial.Fatorial(6))
    fmt.Println("Hanoi : ")
    hanoi.Hanoi(0, 2, 1, 3)
    slice := []int{5, 2, 1, 6, 9, 8, 7, 3, 4}
    fmt.Println("Slice : ", slice)
    fmt.Println("BubbleSort : ", bubblesort.BubbleSort(slice))
    fmt.Println("SelectionSort : ", selectionsort.SelectionSort(slice))
    fmt.Println("InsertionSort : ", insertionsort.InsertionSort(slice))
    fmt.Println("MergeSort : ", mergesort.MergeSort(slice))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
    "time"

	"github.com/open-lambda/load-balancer/balancer"
	"github.com/open-lambda/load-balancer/balancer/serverPick"
	"github.com/open-lambda/load-balancer/balancer/test/client"
	"github.com/open-lambda/load-balancer/balancer/test/server"
)

type Config struct {
	Servers []string
	LBAddr  string
}

func readConfig(filename string) *Config {
	fd, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}

	decoder := json.NewDecoder(fd)
	conf := Config{}

	err = decoder.Decode(&conf)
	if err != nil {
		log.Fatalf("could not decode config file: %v", err)
	}

	return &conf
}

func main() {
	conf := readConfig("local.conf")
	for i := 0; i < len(conf.Servers); i++ {
		go server.RunServer(conf.Servers[i])
	}

	chooser := serverPick.NewFirstTwo(conf.Servers)
	lb := new(balancer.LoadBalancer)
	lb.Init(conf.LBAddr, chooser, 5)
	go lb.Run()
    time.Sleep(time.Second)
	for i := 0; ; i++ {
		fmt.Printf("Client's been run %v time(s)\n", i)
		client.RunClient(conf.LBAddr)
	}
}
<commit_msg>fixed formatting<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/open-lambda/load-balancer/balancer"
	"github.com/open-lambda/load-balancer/balancer/serverPick"
	"github.com/open-lambda/load-balancer/balancer/test/client"
	"github.com/open-lambda/load-balancer/balancer/test/server"
)

type Config struct {
	Servers []string
	LBAddr  string
}

func readConfig(filename string) *Config {
	fd, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}

	decoder := json.NewDecoder(fd)
	conf := Config{}

	err = decoder.Decode(&conf)
	if err != nil {
		log.Fatalf("could not decode config file: %v", err)
	}

	return &conf
}

func main() {
	conf := readConfig("local.conf")
	for i := 0; i < len(conf.Servers); i++ {
		go server.RunServer(conf.Servers[i])
	}

	chooser := serverPick.NewFirstTwo(conf.Servers)
	lb := new(balancer.LoadBalancer)
	lb.Init(conf.LBAddr, chooser, 5)
	go lb.Run()
	time.Sleep(time.Second)
	for i := 0; ; i++ {
		fmt.Printf("Client's been run %v time(s)\n", i)
		client.RunClient(conf.LBAddr)
	}
}
<|endoftext|>


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

// The testing package provides support for automated testing of Go packages.
// It is intended to be used in concert with the ``gotest'' utility, which automates
// execution of any function of the form
//     func TestXxx(*testing.T)
// where Xxx can by any alphanumeric string (but the first letter must not be in
// [a-z]) and serves to identify the test routine.
// These TestXxx routines should be declared within the package they are testing.
package testing

import (
	"flag";
	"fmt";
	"os";
	"runtime";
)

// Report as tests are run; default is silent for success.
var chatty = flag.Bool("chatty", false, "chatty")

// Insert tabs after newlines - but not the last one
func tabify(s string) string {
	for i := 0; i < len(s) - 1; i++ {	// -1 because if last char is newline, don't bother
		if s[i] == '\n' {
			return s[0:i+1] + "\t" + tabify(s[i+1:len(s)]);
		}
	}
	return s
}

// T is a type passed to Test functions to manage test state and support formatted test logs.
// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
	errors	string;
	failed	bool;
	ch	chan *T;
}

// Fail marks the Test function as having failed but continues execution.
func (t *T) Fail() {
	t.failed = true
}

// FailNow marks the Test function as having failed and stops its execution.
// Execution will continue at the next Test.
func (t *T) FailNow() {
	t.Fail();
	t.ch <- t;
	runtime.Goexit();
}

// Log formats its arguments using default formatting, analogous to Print(),
// and records the text in the error log.
func (t *T) Log(args ...) {
	t.errors += "\t" + tabify(fmt.Sprintln(args));
}

// Log formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
func (t *T) Logf(format string, args ...) {
	t.errors += tabify(fmt.Sprintf("\t" + format, args));
	l := len(t.errors);
	if l > 0 && t.errors[l-1] != '\n' {
		t.errors += "\n"
	}
}

// Error is equivalent to Log() followed by Fail().
func (t *T) Error(args ...) {
	t.Log(args);
	t.Fail();
}

// Errorf is equivalent to Logf() followed by Fail().
func (t *T) Errorf(format string, args ...) {
	t.Logf(format, args);
	t.Fail();
}

// Fatal is equivalent to Log() followed by FailNow().
func (t *T) Fatal(args ...) {
	t.Log(args);
	t.FailNow();
}

// Fatalf is equivalent to Logf() followed by FailNow().
func (t *T) Fatalf(format string, args ...) {
	t.Logf(format, args);
	t.FailNow();
}

// An internal type but exported because it is cross-package; part of the implementation
// of gotest.
type Test struct {
	Name string;
	F func(*T);
}

func tRunner(t *T, test *Test) {
	test.F(t);
	t.ch <- t;
}

// An internal function but exported because it is cross-package; part of the implementation
// of gotest.
func Main(tests []Test) {
	flag.Parse();
	ok := true;
	if len(tests) == 0 {
		println("testing: warning: no tests to run");
	}
	for i := 0; i < len(tests); i++ {
		if *chatty {
			println("=== RUN ", tests[i].Name);
		}
		t := new(T);
		t.ch = make(chan *T);
		go tRunner(t, &tests[i]);
		<-t.ch;
		if t.failed {
			println("--- FAIL:", tests[i].Name);
			print(t.errors);
			ok = false;
		} else if *chatty {
			println("--- PASS:", tests[i].Name);
			print(t.errors);
		}
	}
	if !ok {
		println("FAIL");
		os.Exit(1);
	}
	println("PASS");
}
<commit_msg>testing: add t.Failed() bool<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The testing package provides support for automated testing of Go packages.
// It is intended to be used in concert with the ``gotest'' utility, which automates
// execution of any function of the form
//     func TestXxx(*testing.T)
// where Xxx can by any alphanumeric string (but the first letter must not be in
// [a-z]) and serves to identify the test routine.
// These TestXxx routines should be declared within the package they are testing.
package testing

import (
	"flag";
	"fmt";
	"os";
	"runtime";
)

// Report as tests are run; default is silent for success.
var chatty = flag.Bool("chatty", false, "chatty")

// Insert final newline if needed and tabs after internal newlines.
func tabify(s string) string {
	n := len(s);
	if n > 0 && s[n-1] != '\n' {
		s += "\n";
		n++;
	}
	for i := 0; i < n - 1; i++ {	// -1 to avoid final newline
		if s[i] == '\n' {
			return s[0:i+1] + "\t" + tabify(s[i+1:n]);
		}
	}
	return s
}

// T is a type passed to Test functions to manage test state and support formatted test logs.
// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
	errors	string;
	failed	bool;
	ch	chan *T;
}

// Fail marks the Test function as having failed but continues execution.
func (t *T) Fail() {
	t.failed = true
}

// Failed returns whether the Test function has failed.
func (t *T) Failed() bool {
	return t.failed
}

// FailNow marks the Test function as having failed and stops its execution.
// Execution will continue at the next Test.
func (t *T) FailNow() {
	t.Fail();
	t.ch <- t;
	runtime.Goexit();
}

// Log formats its arguments using default formatting, analogous to Print(),
// and records the text in the error log.
func (t *T) Log(args ...) {
	t.errors += "\t" + tabify(fmt.Sprintln(args));
}

// Log formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
func (t *T) Logf(format string, args ...) {
	t.errors += "\t" + tabify(fmt.Sprintf(format, args));
}

// Error is equivalent to Log() followed by Fail().
func (t *T) Error(args ...) {
	t.Log(args);
	t.Fail();
}

// Errorf is equivalent to Logf() followed by Fail().
func (t *T) Errorf(format string, args ...) {
	t.Logf(format, args);
	t.Fail();
}

// Fatal is equivalent to Log() followed by FailNow().
func (t *T) Fatal(args ...) {
	t.Log(args);
	t.FailNow();
}

// Fatalf is equivalent to Logf() followed by FailNow().
func (t *T) Fatalf(format string, args ...) {
	t.Logf(format, args);
	t.FailNow();
}

// An internal type but exported because it is cross-package; part of the implementation
// of gotest.
type Test struct {
	Name string;
	F func(*T);
}

func tRunner(t *T, test *Test) {
	test.F(t);
	t.ch <- t;
}

// An internal function but exported because it is cross-package; part of the implementation
// of gotest.
func Main(tests []Test) {
	flag.Parse();
	ok := true;
	if len(tests) == 0 {
		println("testing: warning: no tests to run");
	}
	for i := 0; i < len(tests); i++ {
		if *chatty {
			println("=== RUN ", tests[i].Name);
		}
		t := new(T);
		t.ch = make(chan *T);
		go tRunner(t, &tests[i]);
		<-t.ch;
		if t.failed {
			println("--- FAIL:", tests[i].Name);
			print(t.errors);
			ok = false;
		} else if *chatty {
			println("--- PASS:", tests[i].Name);
			print(t.errors);
		}
	}
	if !ok {
		println("FAIL");
		os.Exit(1);
	}
	println("PASS");
}
<|endoftext|>