<commit_before>package upload

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/subutai-io/agent/log"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
)

type share struct {
	Token  string   `json:"token"`
	Id     string   `json:"id"`
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
	Repo   string   `json:"repo"`
}

//Handler function works with income upload requests, makes sanity checks, etc
func Handler(w http.ResponseWriter, r *http.Request) (hash, owner string) {
	r.ParseMultipartForm(32 << 20)
	if len(r.MultipartForm.Value["token"]) == 0 || len(db.CheckToken(r.MultipartForm.Value["token"][0])) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Not authorized"))
		log.Warn(r.RemoteAddr + " - rejecting unauthorized upload request")
		return
	}

	owner = db.CheckToken(r.MultipartForm.Value["token"][0])

	file, header, err := r.FormFile("file")
	if log.Check(log.WarnLevel, "Failed to parse POST form", err) {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Cannot get file from request"))
		return
	}
	defer file.Close()

	if !сheckLength(owner, r.Header.Get("Content-Length")) {
		w.WriteHeader(http.StatusNotAcceptable)
		w.Write([]byte("Storage quota exceeded"))
		log.Warn("User " + owner + " exceeded storage quota, rejecting upload")
		return
	}

	out, err := os.Create(config.Storage.Path + header.Filename)
	if log.Check(log.WarnLevel, "Unable to create the file for writing", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Cannot create file"))
		return
	}
	defer out.Close()

	limit := int64(db.QuotaLeft(owner))
	f := io.Reader(file)
	if limit != -1 {
		f = io.LimitReader(file, limit)
	}

	// write the content from POST to the file
	if copied, err := io.Copy(out, f); limit != -1 && (copied == limit || err != nil) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to write file or storage quota exceeded"))
		log.Warn("User " + owner + " exceeded storage quota, removing file")
		os.Remove(config.Storage.Path + header.Filename)
		return
	} else {
		db.QuotaUsageSet(owner, int(copied))
		log.Info("User " + owner + ", quota usage +" + strconv.Itoa(int(copied)))
	}

	hash = Hash(config.Storage.Path + header.Filename)
	if len(hash) == 0 {
		log.Warn("Failed to calculate hash for " + header.Filename)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to calculate hash"))
		return
	}

	os.Rename(config.Storage.Path+header.Filename, config.Storage.Path+hash)
	log.Info("File received: " + header.Filename + "(" + hash + ")")

	return hash, owner
}

func Hash(file string, algo ...string) string {
	f, err := os.Open(file)
	log.Check(log.WarnLevel, "Opening file "+file, err)
	defer f.Close()

	hash := md5.New()
	if len(algo) != 0 {
		switch algo[0] {
		case "sha512":
			hash = sha512.New()
		case "sha256":
			hash = sha256.New()
		case "sha1":
			hash = sha1.New()
		}
	}
	if _, err := io.Copy(hash, f); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func Delete(w http.ResponseWriter, r *http.Request) string {
	hash := r.URL.Query().Get("id")
	token := r.URL.Query().Get("token")
	if len(hash) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty file id"))
		log.Warn(r.RemoteAddr + " - empty file id")
		return ""
	}
	if len(token) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Empty token"))
		log.Warn(r.RemoteAddr + " - empty token")
		return ""
	}
	user := db.CheckToken(token)
	info := db.Info(hash)
	if len(info) == 0 {
		log.Warn("File not found by hash")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File not found"))
		return ""
	}

	repo := strings.Split(r.URL.EscapedPath(), "/")
	if len(repo) < 4 {
		log.Warn(r.URL.EscapedPath() + " - bad deletion request")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Bad request"))
		return ""
	}

	if db.CheckRepo(user, repo[3], hash) == 0 {
		log.Warn("File " + info["name"] + "(" + hash + ") in " + repo[3] + " repo is not owned by " + user + ", rejecting deletion request")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File " + info["name"] + " not found or it has different owner"))
		return ""
	}

	f, err := os.Stat(config.Storage.Path + hash)
	if !log.Check(log.WarnLevel, "Reading file stats", err) {
		db.QuotaUsageSet(user, -int(f.Size()))
		log.Info("User " + user + ", quota usage -" + strconv.Itoa(int(f.Size())))
	}

	if db.Delete(user, repo[3], hash) == 0 {
		log.Warn("Removing " + hash + " from disk")
		// torrent.Delete(hash)
		if log.Check(log.WarnLevel, "Removing "+info["name"]+"from disk", os.Remove(config.Storage.Path+hash)) {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("Failed to remove file"))
			return ""
		}
	}

	log.Info("Removing " + info["name"] + " from " + repo[3] + " repo")
	return hash
}

func Share(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		if len(r.FormValue("json")) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty json"))
			log.Warn("Share request: empty json, nothing to do")
			return
		}
		var data share
		if log.Check(log.WarnLevel, "Parsing share request json", json.Unmarshal([]byte(r.FormValue("json")), &data)) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Failed to parse json body"))
			return
		}
		if len(data.Token) == 0 || len(db.CheckToken(data.Token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			log.Warn("Empty or invalid token, rejecting share request")
			return
		}
		if len(data.Id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			log.Warn("Empty file id, rejecting share request")
			return
		}
		if len(data.Repo) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty repo name"))
			log.Warn("Empty repo name, rejecting share request")
			return
		}
		owner := db.CheckToken(data.Token)
		if db.CheckRepo(owner, data.Repo, data.Id) == 0 {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to share another's file, rejecting")
			return
		}
		for _, v := range data.Add {
			log.Info("Sharing " + data.Id + " with " + v)
			db.ShareWith(data.Id, owner, v)
		}
		for _, v := range data.Remove {
			log.Info("Unsharing " + data.Id + " with " + v)
			db.UnshareWith(data.Id, owner, v)
		}
	} else if r.Method == "GET" {
		id := r.URL.Query().Get("id")
		if len(id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			return
		}
		token := r.URL.Query().Get("token")
		if len(token) == 0 || len(db.CheckToken(token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			return
		}
		owner := db.CheckToken(token)
		repo := r.URL.Query().Get("repo")
		if len(repo) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Repository not specified"))
			return
		}
		if db.CheckRepo(owner, repo, id) == 0 {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to request scope of another's file, rejecting")
			return
		}
		js, _ := json.Marshal(db.GetScope(id, owner))
		w.Write(js)
	}
}

func сheckLength(user, length string) bool {
	l, err := strconv.Atoi(length)
	if err != nil || len(length) == 0 || l < db.QuotaLeft(user) || db.QuotaLeft(user) == -1 {
		return true
	}
	return false
}

func Quota(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		user := r.URL.Query().Get("user")
		fix := r.URL.Query().Get("fix")
		token := r.URL.Query().Get("token")

		if len(token) == 0 || len(db.CheckToken(token)) == 0 || db.CheckToken(token) != "Hub" && db.CheckToken(token) != "subutai" && db.CheckToken(token) != user {
			w.Write([]byte("Forbidden"))
			w.WriteHeader(http.StatusForbidden)
			return
		}

		if len(user) != 0 {
			q, _ := json.Marshal(map[string]int{
				"quota": db.QuotaGet(user),
				"used":  db.QuotaUsageGet(user),
				"left":  db.QuotaLeft(user)})
			w.Write([]byte(q))
		}
		if user == "subutai" && len(fix) != 0 {
			db.QuotaUsageCorrect()
		}

	} else if r.Method == "POST" {
		user := r.FormValue("user")
		quota := r.FormValue("quota")
		token := r.FormValue("token")

		if len(token) == 0 || len(db.CheckToken(token)) == 0 || db.CheckToken(token) != "Hub" && db.CheckToken(token) != "subutai" {
			w.Write([]byte("Forbidden"))
			w.WriteHeader(http.StatusForbidden)
			return
		}

		if len(user) == 0 || len(quota) == 0 {
			w.Write([]byte("Please specify username and quota value"))
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		if q, err := strconv.Atoi(quota); err != nil || q < -1 {
			w.Write([]byte("Invalid quota value"))
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		db.QuotaSet(user, quota)
		log.Info("New quota for " + user + " is " + quota)
		w.Write([]byte("Ok"))
		w.WriteHeader(http.StatusOK)
	}
}
<commit_msg>Fixed removing another's files with invalid token<commit_after>package upload

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/subutai-io/agent/log"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
)

type share struct {
	Token  string   `json:"token"`
	Id     string   `json:"id"`
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
	Repo   string   `json:"repo"`
}

//Handler function works with income upload requests, makes sanity checks, etc
func Handler(w http.ResponseWriter, r *http.Request) (hash, owner string) {
	r.ParseMultipartForm(32 << 20)
	if len(r.MultipartForm.Value["token"]) == 0 || len(db.CheckToken(r.MultipartForm.Value["token"][0])) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Not authorized"))
		log.Warn(r.RemoteAddr + " - rejecting unauthorized upload request")
		return
	}

	owner = db.CheckToken(r.MultipartForm.Value["token"][0])

	file, header, err := r.FormFile("file")
	if log.Check(log.WarnLevel, "Failed to parse POST form", err) {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Cannot get file from request"))
		return
	}
	defer file.Close()

	if !сheckLength(owner, r.Header.Get("Content-Length")) {
		w.WriteHeader(http.StatusNotAcceptable)
		w.Write([]byte("Storage quota exceeded"))
		log.Warn("User " + owner + " exceeded storage quota, rejecting upload")
		return
	}

	out, err := os.Create(config.Storage.Path + header.Filename)
	if log.Check(log.WarnLevel, "Unable to create the file for writing", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Cannot create file"))
		return
	}
	defer out.Close()

	limit := int64(db.QuotaLeft(owner))
	f := io.Reader(file)
	if limit != -1 {
		f = io.LimitReader(file, limit)
	}

	// write the content from POST to the file
	if copied, err := io.Copy(out, f); limit != -1 && (copied == limit || err != nil) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to write file or storage quota exceeded"))
		log.Warn("User " + owner + " exceeded storage quota, removing file")
		os.Remove(config.Storage.Path + header.Filename)
		return
	} else {
		db.QuotaUsageSet(owner, int(copied))
		log.Info("User " + owner + ", quota usage +" + strconv.Itoa(int(copied)))
	}

	hash = Hash(config.Storage.Path + header.Filename)
	if len(hash) == 0 {
		log.Warn("Failed to calculate hash for " + header.Filename)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to calculate hash"))
		return
	}

	os.Rename(config.Storage.Path+header.Filename, config.Storage.Path+hash)
	log.Info("File received: " + header.Filename + "(" + hash + ")")

	return hash, owner
}

func Hash(file string, algo ...string) string {
	f, err := os.Open(file)
	log.Check(log.WarnLevel, "Opening file "+file, err)
	defer f.Close()

	hash := md5.New()
	if len(algo) != 0 {
		switch algo[0] {
		case "sha512":
			hash = sha512.New()
		case "sha256":
			hash = sha256.New()
		case "sha1":
			hash = sha1.New()
		}
	}
	if _, err := io.Copy(hash, f); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func Delete(w http.ResponseWriter, r *http.Request) string {
	hash := r.URL.Query().Get("id")
	token := r.URL.Query().Get("token")
	if len(hash) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty file id"))
		log.Warn(r.RemoteAddr + " - empty file id")
		return ""
	}
	user := db.CheckToken(token)
	if len(token) == 0 || len(user) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Failed to authorize using provided token"))
		log.Warn(r.RemoteAddr + " - Failed to authorize using provided token")
		return ""
	}
	info := db.Info(hash)
	if len(info) == 0 {
		log.Warn("File not found by hash")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File not found"))
		return ""
	}

	repo := strings.Split(r.URL.EscapedPath(), "/")
	if len(repo) < 4 {
		log.Warn(r.URL.EscapedPath() + " - bad deletion request")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Bad request"))
		return ""
	}

	if db.CheckRepo(user, repo[3], hash) == 0 {
		log.Warn("File " + info["name"] + "(" + hash + ") in " + repo[3] + " repo is not owned by " + user + ", rejecting deletion request")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File " + info["name"] + " not found or it has different owner"))
		return ""
	}

	f, err := os.Stat(config.Storage.Path + hash)
	if !log.Check(log.WarnLevel, "Reading file stats", err) {
		db.QuotaUsageSet(user, -int(f.Size()))
		log.Info("User " + user + ", quota usage -" + strconv.Itoa(int(f.Size())))
	}

	if db.Delete(user, repo[3], hash) == 0 {
		log.Warn("Removing " + hash + " from disk")
		// torrent.Delete(hash)
		if log.Check(log.WarnLevel, "Removing "+info["name"]+"from disk", os.Remove(config.Storage.Path+hash)) {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("Failed to remove file"))
			return ""
		}
	}

	log.Info("Removing " + info["name"] + " from " + repo[3] + " repo")
	return hash
}

func Share(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		if len(r.FormValue("json")) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty json"))
			log.Warn("Share request: empty json, nothing to do")
			return
		}
		var data share
		if log.Check(log.WarnLevel, "Parsing share request json", json.Unmarshal([]byte(r.FormValue("json")), &data)) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Failed to parse json body"))
			return
		}
		if len(data.Token) == 0 || len(db.CheckToken(data.Token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			log.Warn("Empty or invalid token, rejecting share request")
			return
		}
		if len(data.Id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			log.Warn("Empty file id, rejecting share request")
			return
		}
		if len(data.Repo) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty repo name"))
			log.Warn("Empty repo name, rejecting share request")
			return
		}
		owner := db.CheckToken(data.Token)
		if db.CheckRepo(owner, data.Repo, data.Id) == 0 {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to share another's file, rejecting")
			return
		}
		for _, v := range data.Add {
			log.Info("Sharing " + data.Id + " with " + v)
			db.ShareWith(data.Id, owner, v)
		}
		for _, v := range data.Remove {
			log.Info("Unsharing " + data.Id + " with " + v)
			db.UnshareWith(data.Id, owner, v)
		}
	} else if r.Method == "GET" {
		id := r.URL.Query().Get("id")
		if len(id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			return
		}
		token := r.URL.Query().Get("token")
		if len(token) == 0 || len(db.CheckToken(token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			return
		}
		owner := db.CheckToken(token)
		repo := r.URL.Query().Get("repo")
		if len(repo) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Repository not specified"))
			return
		}
		if db.CheckRepo(owner, repo, id) == 0 {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to request scope of another's file, rejecting")
			return
		}
		js, _ := json.Marshal(db.GetScope(id, owner))
		w.Write(js)
	}
}

func сheckLength(user, length string) bool {
	l, err := strconv.Atoi(length)
	if err != nil || len(length) == 0 || l < db.QuotaLeft(user) || db.QuotaLeft(user) == -1 {
		return true
	}
	return false
}

func Quota(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		user := r.URL.Query().Get("user")
		fix := r.URL.Query().Get("fix")
		token := r.URL.Query().Get("token")

		if len(token) == 0 || len(db.CheckToken(token)) == 0 || db.CheckToken(token) != "Hub" && db.CheckToken(token) != "subutai" && db.CheckToken(token) != user {
			w.Write([]byte("Forbidden"))
			w.WriteHeader(http.StatusForbidden)
			return
		}

		if len(user) != 0 {
			q, _ := json.Marshal(map[string]int{
				"quota": db.QuotaGet(user),
				"used":  db.QuotaUsageGet(user),
				"left":  db.QuotaLeft(user)})
			w.Write([]byte(q))
		}
		if user == "subutai" && len(fix) != 0 {
			db.QuotaUsageCorrect()
		}

	} else if r.Method == "POST" {
		user := r.FormValue("user")
		quota := r.FormValue("quota")
		token := r.FormValue("token")

		if len(token) == 0 || len(db.CheckToken(token)) == 0 || db.CheckToken(token) != "Hub" && db.CheckToken(token) != "subutai" {
			w.Write([]byte("Forbidden"))
			w.WriteHeader(http.StatusForbidden)
			return
		}

		if len(user) == 0 || len(quota) == 0 {
			w.Write([]byte("Please specify username and quota value"))
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		if q, err := strconv.Atoi(quota); err != nil || q < -1 {
			w.Write([]byte("Invalid quota value"))
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		db.QuotaSet(user, quota)
		log.Info("New quota for " + user + " is " + quota)
		w.Write([]byte("Ok"))
		w.WriteHeader(http.StatusOK)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: urlparse <url>\n")
	}
	flag.Parse()

	var r io.Reader = os.Stdin
	if arg := flag.Arg(0); arg != "" {
		r = strings.NewReader(arg)
	}

	var buf bytes.Buffer
	io.Copy(&buf, r)

	u, err := url.Parse(buf.String())
	if err != nil {
		log.Fatal(err)
	}

	pprint(u)
}

func pprint(u *url.URL) {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "Scheme: %v\n", u.Scheme)
	fmt.Fprintf(&buf, "Host: %v\n", u.Hostname())
	fmt.Fprintf(&buf, "Port: %v\n", u.Port())
	fmt.Fprintf(&buf, "User: %v\n", u.User)
	fmt.Fprintf(&buf, "Path: %v\n", u.Path)

	fmt.Fprintf(&buf, "Query:\n")
	var keys []string
	for key := range u.Query() {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	w := tabwriter.NewWriter(&buf, 0, 2, 2, ' ', 0)
	for _, key := range keys {
		fmt.Fprintf(w, "  %v:\t%v\n", key, u.Query().Get(key))
	}
	w.Flush()
	fmt.Fprintf(&buf, "Fragment: %v\n", u.Fragment)

	fmt.Println(buf.String())
}
<commit_msg>urlparse: read from stdin<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"
	"sort"
	"text/tabwriter"
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: urlparse <url>\n")
	}
	flag.Parse()

	s := bufio.NewScanner(os.Stdin)
	for s.Scan() {
		line := s.Text()
		u, err := url.Parse(line)
		if err != nil {
			log.Fatal(err)
		}
		pprint(u)
	}

}

func pprint(u *url.URL) {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "Scheme: %v\n", u.Scheme)
	fmt.Fprintf(&buf, "Host: %v\n", u.Hostname())
	fmt.Fprintf(&buf, "Port: %v\n", u.Port())
	fmt.Fprintf(&buf, "User: %v\n", u.User)
	fmt.Fprintf(&buf, "Path: %v\n", u.Path)

	fmt.Fprintf(&buf, "Query:\n")
	var keys []string
	for key := range u.Query() {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	w := tabwriter.NewWriter(&buf, 0, 2, 2, ' ', 0)
	for _, key := range keys {
		fmt.Fprintf(w, "  %v:\t%v\n", key, u.Query().Get(key))
	}
	w.Flush()
	fmt.Fprintf(&buf, "Fragment: %v\n", u.Fragment)

	fmt.Println(buf.String())
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"google.golang.org/api/serviceusage/v1beta1"
)

func resourceGoogleProjectServices() *schema.Resource {
	return &schema.Resource{
		Create: resourceGoogleProjectServicesCreate,
		Read:   resourceGoogleProjectServicesRead,
		Update: resourceGoogleProjectServicesUpdate,
		Delete: resourceGoogleProjectServicesDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"project": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"services": {
				Type:     schema.TypeSet,
				Required: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},
			"disable_on_destroy": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
		},
	}
}

// These services can only be enabled as a side-effect of enabling other services,
// so don't bother storing them in the config or using them for diffing.
var ignoreProjectServices = map[string]struct{}{
	"containeranalysis.googleapis.com": struct{}{},
	"dataproc-control.googleapis.com":  struct{}{},
	"source.googleapis.com":            struct{}{},
}

func resourceGoogleProjectServicesCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Get("project").(string)

	// Get services from config
	cfgServices := getConfigServices(d)

	// Get services from API
	apiServices, err := getApiServices(pid, config, ignoreProjectServices)
	if err != nil {
		return fmt.Errorf("Error creating services: %v", err)
	}

	// This call disables any APIs that aren't defined in cfgServices,
	// and enables all of those that are
	err = reconcileServices(cfgServices, apiServices, config, pid)
	if err != nil {
		return fmt.Errorf("Error creating services: %v", err)
	}

	d.SetId(pid)
	return resourceGoogleProjectServicesRead(d, meta)
}

func resourceGoogleProjectServicesRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	services, err := getApiServices(d.Id(), config, ignoreProjectServices)
	if err != nil {
		return err
	}

	d.Set("project", d.Id())
	d.Set("services", services)
	return nil
}

func resourceGoogleProjectServicesUpdate(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]: Updating google_project_services")
	config := meta.(*Config)
	pid := d.Get("project").(string)

	// Get services from config
	cfgServices := getConfigServices(d)

	// Get services from API
	apiServices, err := getApiServices(pid, config, ignoreProjectServices)
	if err != nil {
		return fmt.Errorf("Error updating services: %v", err)
	}

	// This call disables any APIs that aren't defined in cfgServices,
	// and enables all of those that are
	err = reconcileServices(cfgServices, apiServices, config, pid)
	if err != nil {
		return fmt.Errorf("Error updating services: %v", err)
	}

	return resourceGoogleProjectServicesRead(d, meta)
}

func resourceGoogleProjectServicesDelete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]: Deleting google_project_services")

	if disable := d.Get("disable_on_destroy"); !(disable.(bool)) {
		log.Printf("Not disabling service '%s', because disable_on_destroy is false.", d.Id())
		d.SetId("")
		return nil
	}

	config := meta.(*Config)
	services := resourceServices(d)
	for _, s := range services {
		disableService(s, d.Id(), config)
	}
	d.SetId("")
	return nil
}

// This function ensures that the services enabled for a project exactly match that
// in a config by disabling any services that are returned by the API but not present
// in the config
func reconcileServices(cfgServices, apiServices []string, config *Config, pid string) error {
	// Helper to convert slice to map
	m := func(vals []string) map[string]struct{} {
		sm := make(map[string]struct{})
		for _, s := range vals {
			sm[s] = struct{}{}
		}
		return sm
	}

	cfgMap := m(cfgServices)
	apiMap := m(apiServices)

	for k, _ := range apiMap {
		if _, ok := cfgMap[k]; !ok {
			// The service in the API is not in the config; disable it.
			err := disableService(k, pid, config)
			if err != nil {
				return err
			}
		} else {
			// The service exists in the config and the API, so we don't need
			// to re-enable it
			delete(cfgMap, k)
		}
	}

	keys := make([]string, 0, len(cfgMap))
	for k, _ := range cfgMap {
		keys = append(keys, k)
	}
	err := enableServices(keys, pid, config)
	if err != nil {
		return err
	}
	return nil
}

// Retrieve services defined in a config
func getConfigServices(d *schema.ResourceData) (services []string) {
	if v, ok := d.GetOk("services"); ok {
		for _, svc := range v.(*schema.Set).List() {
			services = append(services, svc.(string))
		}
	}
	return
}

// Retrieve a project's services from the API
func getApiServices(pid string, config *Config, ignore map[string]struct{}) ([]string, error) {
	apiServices := make([]string, 0)
	// Get services from the API
	token := ""
	for paginate := true; paginate; {
		svcResp, err := config.clientServiceUsage.Services.List("projects/" + pid).PageToken(token).Filter("state:ENABLED").Do()
		if err != nil {
			return apiServices, err
		}
		for _, v := range svcResp.Services {
			// names are returned as projects/{project-number}/services/{service-name}
			nameParts := strings.Split(v.Name, "/")
			name := nameParts[len(nameParts)-1]
			if _, ok := ignore[name]; !ok {
				apiServices = append(apiServices, name)
			}
		}
		token = svcResp.NextPageToken
		paginate = token != ""
	}
	return apiServices, nil
}

func enableService(s, pid string, config *Config) error {
	return enableServices([]string{s}, pid, config)
}

func enableServices(s []string, pid string, config *Config) error {
	err := retryTime(func() error {
		var sop *serviceusage.Operation
		var err error
		if len(s) > 1 {
			req := &serviceusage.BatchEnableServicesRequest{ServiceIds: s}
			sop, err = config.clientServiceUsage.Services.BatchEnable("projects/"+pid, req).Do()
		} else if len(s) == 1 {
			name := fmt.Sprintf("projects/%s/services/%s", pid, s[0])
			sop, err = config.clientServiceUsage.Services.Enable(name, &serviceusage.EnableServiceRequest{}).Do()
		} else {
			// No services to enable
			return nil
		}
		if err != nil {
			return err
		}
		_, waitErr := serviceUsageOperationWait(config, sop, "api to enable")
		if waitErr != nil {
			return waitErr
		}
		return nil
	}, 10)
	if err != nil {
		return fmt.Errorf("Error enabling service %q for project %q: %v", s, pid, err)
	}
	return nil
}

func disableService(s, pid string, config *Config) error {
	err := retryTime(func() error {
		name := fmt.Sprintf("projects/%s/services/%s", pid, s)
		sop, err := config.clientServiceUsage.Services.Disable(name, &serviceusage.DisableServiceRequest{}).Do()
		if err != nil {
			return err
		}
		// Wait for the operation to complete
		_, waitErr := serviceUsageOperationWait(config, sop, "api to disable")
		if waitErr != nil {
			return waitErr
		}
		return nil
	}, 10)
	if err != nil {
		return fmt.Errorf("Error disabling service %q for project %q: %v", s, pid, err)
	}
	return nil
}

func resourceServices(d *schema.ResourceData) []string {
	// Calculate the tags
	var services []string
	if s := d.Get("services"); s != nil {
		ss := s.(*schema.Set)
		services = make([]string, ss.Len())
		for i, v := range ss.List() {
			services[i] = v.(string)
		}
	}
	return services
}
<commit_msg>Guard against eventually consistent services<commit_after>package google

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/serviceusage/v1beta1"
)

func resourceGoogleProjectServices() *schema.Resource {
	return &schema.Resource{
		Create: resourceGoogleProjectServicesCreate,
		Read:   resourceGoogleProjectServicesRead,
		Update: resourceGoogleProjectServicesUpdate,
		Delete: resourceGoogleProjectServicesDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"project": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"services": {
				Type:     schema.TypeSet,
				Required: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},
			"disable_on_destroy": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
		},
	}
}

// These services can only be enabled as a side-effect of enabling other services,
// so don't bother storing them in the config or using them for diffing.
var ignoreProjectServices = map[string]struct{}{
	"containeranalysis.googleapis.com": struct{}{},
	"dataproc-control.googleapis.com":  struct{}{},
	"source.googleapis.com":            struct{}{},
}

func resourceGoogleProjectServicesCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Get("project").(string)

	// Get services from config
	cfgServices := getConfigServices(d)

	// Get services from API
	apiServices, err := getApiServices(pid, config, ignoreProjectServices)
	if err != nil {
		return fmt.Errorf("Error creating services: %v", err)
	}

	// This call disables any APIs that aren't defined in cfgServices,
	// and enables all of those that are
	err = reconcileServices(cfgServices, apiServices, config, pid)
	if err != nil {
		return fmt.Errorf("Error creating services: %v", err)
	}

	d.SetId(pid)
	return resourceGoogleProjectServicesRead(d, meta)
}

func resourceGoogleProjectServicesRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	services, err := getApiServices(d.Id(), config, ignoreProjectServices)
	if err != nil {
		return err
	}

	d.Set("project", d.Id())
	d.Set("services", services)
	return nil
}

func resourceGoogleProjectServicesUpdate(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]: Updating google_project_services")
	config := meta.(*Config)
	pid := d.Get("project").(string)

	// Get services from config
	cfgServices := getConfigServices(d)

	// Get services from API
	apiServices, err := getApiServices(pid, config, ignoreProjectServices)
	if err != nil {
		return fmt.Errorf("Error updating services: %v", err)
	}

	// This call disables any APIs that aren't defined in cfgServices,
	// and enables all of those that are
	err = reconcileServices(cfgServices, apiServices, config, pid)
	if err != nil {
		return fmt.Errorf("Error updating services: %v", err)
	}

	return resourceGoogleProjectServicesRead(d, meta)
}

func resourceGoogleProjectServicesDelete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG]: Deleting google_project_services")

	if disable := d.Get("disable_on_destroy"); !(disable.(bool)) {
		log.Printf("Not disabling service '%s', because disable_on_destroy is false.", d.Id())
		d.SetId("")
		return nil
	}

	config := meta.(*Config)
	services := resourceServices(d)
	for _, s := range services {
		disableService(s, d.Id(), config)
	}
	d.SetId("")
	return nil
}

// This function ensures that the services enabled for a project exactly match that
// in a config by disabling any services that are returned by the API but not present
// in the config
func reconcileServices(cfgServices, apiServices []string, config *Config, pid string) error {
	// Helper to convert slice to map
	m := func(vals []string) map[string]struct{} {
		sm := make(map[string]struct{})
		for _, s := range vals {
			sm[s] = struct{}{}
		}
		return sm
	}

	cfgMap := m(cfgServices)
	apiMap := m(apiServices)

	for k, _ := range apiMap {
		if _, ok := cfgMap[k]; !ok {
			// The service in the API is not in the config; disable it.
			err := disableService(k, pid, config)
			if err != nil {
				return err
			}
		} else {
			// The service exists in the config and the API, so we don't need
			// to re-enable it
			delete(cfgMap, k)
		}
	}

	keys := make([]string, 0, len(cfgMap))
	for k, _ := range cfgMap {
		keys = append(keys, k)
	}
	err := enableServices(keys, pid, config)
	if err != nil {
		return err
	}
	return nil
}

// Retrieve services defined in a config
func getConfigServices(d *schema.ResourceData) (services []string) {
	if v, ok := d.GetOk("services"); ok {
		for _, svc := range v.(*schema.Set).List() {
			services = append(services, svc.(string))
		}
	}
	return
}

// Retrieve a project's services from the API
func getApiServices(pid string, config *Config, ignore map[string]struct{}) ([]string, error) {
	apiServices := make([]string, 0)
	// Get services from the API
	token := ""
	for paginate := true; paginate; {
		svcResp, err := config.clientServiceUsage.Services.List("projects/" + pid).PageToken(token).Filter("state:ENABLED").Do()
		if err != nil {
			return apiServices, err
		}
		for _, v := range svcResp.Services {
			// names are returned as projects/{project-number}/services/{service-name}
			nameParts := strings.Split(v.Name, "/")
			name := nameParts[len(nameParts)-1]
			if _, ok := ignore[name]; !ok {
				apiServices = append(apiServices, name)
			}
		}
		token = svcResp.NextPageToken
		paginate = token != ""
	}
	return apiServices, nil
}

func enableService(s, pid string, config *Config) error {
	return enableServices([]string{s}, pid, config)
}

func enableServices(s []string, pid string, config *Config) error {
	err := retryTime(func() error {
		var sop *serviceusage.Operation
		var err error
		if len(s) > 1 {
			req := &serviceusage.BatchEnableServicesRequest{ServiceIds: s}
			sop, err = config.clientServiceUsage.Services.BatchEnable("projects/"+pid, req).Do()
		} else if len(s) == 1 {
			name := fmt.Sprintf("projects/%s/services/%s", pid, s[0])
			sop, err = config.clientServiceUsage.Services.Enable(name, &serviceusage.EnableServiceRequest{}).Do()
		} else {
			// No services to enable
			return nil
		}
		if err != nil {
			return err
		}
		_, waitErr := serviceUsageOperationWait(config, sop, "api to enable")
		if waitErr != nil {
			return waitErr
		}
		services, err := getApiServices(pid, config, map[string]struct{}{})
		if err != nil {
			return err
		}
		var missing []string
		for _, toEnable := range s {
			var found bool
			for _, service := range services {
				if service == toEnable {
					found = true
					break
				}
			}
			if !found {
				missing = append(missing, toEnable)
			}
		}
		if len(missing) > 0 {
			// spoof a googleapi Error so retryTime will try again
			return &googleapi.Error{
				Code:    503, // haha, get it, service unavailable
				Message: fmt.Sprintf("The services %s are still being enabled for project %q. This isn't a real API error, this is just eventual consistency.", strings.Join(missing, ", "), pid),
			}
		}
		return nil
	}, 10)
	if err != nil {
		return fmt.Errorf("Error enabling service %q for project %q: %v", s, pid, err)
	}
	return nil
}

func disableService(s, pid string, config *Config) error {
	err := retryTime(func() error {
		name := fmt.Sprintf("projects/%s/services/%s", pid, s)
		sop, err := config.clientServiceUsage.Services.Disable(name, &serviceusage.DisableServiceRequest{}).Do()
		if err != nil {
			return err
		}
		// Wait for the operation to complete
		_, waitErr := serviceUsageOperationWait(config, sop, "api to disable")
		if waitErr != nil {
			return waitErr
		}
		return nil
	}, 10)
	if err != nil {
		return fmt.Errorf("Error disabling service %q for project %q: %v", s, pid, err)
	}
	return nil
}

func resourceServices(d *schema.ResourceData) []string {
	// Calculate the tags
	var services []string
	if s := d.Get("services"); s != nil {
		ss := s.(*schema.Set)
		services = make([]string, ss.Len())
		for i, v := range ss.List() {
			services[i] = v.(string)
		}
	}
	return services
}
<|endoftext|>


<commit_before>package database

import (
	"encoding/json"

	"github.com/asuleymanov/golos-go/transports"
	"github.com/asuleymanov/golos-go/types"
	"github.com/pkg/errors"
)

const apiID = "database_api"

type API struct {
	caller transports.Caller
}

func NewAPI(caller transports.Caller) *API {
	return &API{caller}
}

var emptyParams = []string{}

func (api *API) raw(method string, params interface{}) (*json.RawMessage, error) {
	var resp json.RawMessage
	if err := api.caller.Call("call", []interface{}{apiID, method, params}, &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to call %v\n", apiID, method)
	}
	return &resp, nil
}

//GetBlockHeader api request get_block_header
func (api *API) GetBlockHeader(blockNum uint32) (*BlockHeader, error) {
	raw, err := api.raw("get_block_header", []uint32{blockNum})
	if err != nil {
		return nil, err
	}
	var resp BlockHeader
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_block_header response", apiID)
	}
	resp.Number = blockNum
	return &resp, nil
}

//GetBlock api request get_block
func (api *API) GetBlock(blockNum uint32) (*Block, error) {
	raw, err := api.raw("get_block", []uint32{blockNum})
	if err != nil {
		return nil, err
	}
	var resp Block
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_block response", apiID)
	}
	resp.Number = blockNum
	return &resp, nil
}

//GetOpsInBlock api request get_ops_in_block
func (api *API) GetOpsInBlock(blockNum uint32, onlyVirtual bool) ([]*types.OperationObject, error) {
	raw, err := api.raw("get_ops_in_block", []interface{}{blockNum, onlyVirtual})
	if err != nil {
		return nil, err
	}
	var resp []*types.OperationObject
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_ops_in_block response", apiID)
	}
	return resp, nil
}

//GetConfig api request get_config
func (api *API) GetConfig() (*Config, error) {
	raw, err := api.raw("get_config", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp Config
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_config response", apiID)
	}
	return &resp, nil
}

//GetDynamicGlobalProperties api request get_dynamic_global_properties
func (api *API) GetDynamicGlobalProperties() (*DynamicGlobalProperties, error) {
	raw, err := api.raw("get_dynamic_global_properties", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp DynamicGlobalProperties
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_dynamic_global_properties response", apiID)
	}
	return &resp, nil
}

//GetChainProperties api request get_chain_properties
func (api *API) GetChainProperties() (*ChainProperties, error) {
	raw, err := api.raw("get_chain_properties", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp ChainProperties
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_chain_properties response", apiID)
	}
	return &resp, nil
}

//GetHardforkVersion api request get_hardfork_version
func (api *API) GetHardforkVersion() (string, error) {
	raw, err := api.raw("get_hardfork_version", emptyParams)
	if err != nil {
		return "", err
	}
	var resp string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return "", errors.Wrapf(err, "golos: %v: failed to unmarshal get_hardfork_version response", apiID)
	}
	return resp, nil
}

//GetNextScheduledHardfork api request get_next_scheduled_hardfork
func (api *API) GetNextScheduledHardfork() (*NextScheduledHardfork, error) {
	raw, err := api.raw("get_next_scheduled_hardfork", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp NextScheduledHardfork
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_next_scheduled_hardfork response", apiID)
	}
	return &resp, nil
}

//GetAccounts api request get_accounts
func (api *API) GetAccounts(accountNames []string) ([]*Account, error) {
	raw, err := api.raw("get_accounts", [][]string{accountNames})
	if err != nil {
		return nil, err
	}
	var resp []*Account
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_accounts response", apiID)
	}
	return resp, nil
}

//LookupAccountNames api request lookup_account_names
func (api *API) LookupAccountNames(accountNames []string) ([]*LookupAccountNames, error) {
	raw, err := api.raw("lookup_account_names", [][]string{accountNames})
	if err != nil {
		return nil, err
	}
	var resp []*LookupAccountNames
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal lookup_account_names response", apiID)
	}
	return resp, nil
}

//LookupAccounts api request lookup_accounts
func (api *API) LookupAccounts(lowerBoundName string, limit uint32) ([]string, error) {
	raw, err := api.raw("lookup_accounts", []interface{}{lowerBoundName, limit})
	if err != nil {
		return nil, err
	}
	var resp []string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal lookup_accounts response", apiID)
	}
	return resp, nil
}

//GetAccountCount api request get_account_count
func (api *API) GetAccountCount() (uint32, error) {
	raw, err := api.raw("get_account_count", emptyParams)
	if err != nil {
		return 0, err
	}
	var resp uint32
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return 0, errors.Wrapf(err, "golos: %v: failed to unmarshal get_account_count response", apiID)
	}
	return resp, nil
}

//GetOwnerHistory api request get_owner_history
func (api *API) GetOwnerHistory(accountName string) ([]*OwnerHistory, error) {
	raw, err := api.raw("get_owner_history", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*OwnerHistory
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_owner_history response", apiID)
	}
	return resp, nil
}

//GetRecoveryRequest api request get_recovery_request
func (api *API) GetRecoveryRequest(accountName string) (*json.RawMessage, error) {
	return api.raw("get_recovery_request", []interface{}{accountName})
}

//GetEscrow api request get_escrow
func (api *API) GetEscrow(from string, escrowID uint32) (*json.RawMessage, error) {
	return api.raw("get_escrow", []interface{}{from, escrowID})
}

//GetWithdrawRoutes api request get_withdraw_routes
func (api *API) GetWithdrawRoutes(accountName string, withdrawRouteType string) (*json.RawMessage, error) {
	return api.raw("get_withdraw_routes", []interface{}{accountName, withdrawRouteType})
}

//GetAccountBandwidth api request get_account_bandwidth
/*
bandwidthType:
post = 0
forum = 1
market = 2
old_forum = 3
old_market = 4
*/
func (api *API) GetAccountBandwidth(accountName string, bandwidthType uint32) (*Bandwidth, error) {
	raw, err := api.raw("get_account_bandwidth", []interface{}{accountName, bandwidthType})
	if err != nil {
		return nil, err
	}
	var resp *Bandwidth
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_account_bandwidth response", apiID)
	}
	return resp, nil
}

//GetSavingsWithdrawFrom api request get_savings_withdraw_from
func (api *API) GetSavingsWithdrawFrom(accountName string) ([]*SavingsWithdraw, error) {
	raw, err := api.raw("get_savings_withdraw_from", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*SavingsWithdraw
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_savings_withdraw_from response", apiID)
	}
	return resp, nil
}

//GetSavingsWithdrawTo api request get_savings_withdraw_to
func (api *API) GetSavingsWithdrawTo(accountName string) ([]*SavingsWithdraw, error) {
	raw, err := api.raw("get_savings_withdraw_to", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*SavingsWithdraw
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_savings_withdraw_to response", apiID)
	}
	return resp, nil
}

//GetConversionRequests api request get_conversion_requests
func (api *API) GetConversionRequests(accountName string) ([]*ConversionRequests, error) {
	raw, err := api.raw("get_conversion_requests", []string{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*ConversionRequests
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_conversion_requests response", apiID)
	}
	return resp, nil
}

//GetTransactionHex api request get_transaction_hex
func (api *API) GetTransactionHex(trx *types.Transaction) (*json.RawMessage, error) {
	return api.raw("get_transaction_hex", []interface{}{&trx})
}

//GetTransaction api request get_transaction
func (api *API) GetTransaction(id string) (*types.Transaction, error) {
	raw, err := api.raw("get_transaction", []string{id})
	if err != nil {
		return nil, err
	}
	var resp types.Transaction
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_transaction response", apiID)
	}
	return &resp, nil
}

//get_required_signatures

//GetPotentialSignatures api request get_potential_signatures
func (api *API) GetPotentialSignatures(trx *types.Transaction) ([]string, error) {
	raw, err := api.raw("get_potential_signatures", []interface{}{&trx})
	if err != nil {
		return nil, err
	}
	var resp []string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_potential_signatures response", apiID)
	}
	return resp, nil
}

//GetVerifyAuthority api request verify_authority
func (api *API) GetVerifyAuthority(trx *types.Transaction) (bool, error) {
	raw, err := api.raw("verify_authority", []interface{}{&trx})
	if err != nil {
		return false, err
	}
	var resp bool
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return false, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

func (api *API) GetProposedTransaction(account string) (*ProposalObject, error) {
	raw, err := api.raw("get_proposed_transaction", []interface{}{account})
	if err != nil {
		return nil, err
	}
	resp := ProposalObject{}
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return &resp, nil
}

func (api *API) GetDatabaseInfo() (*DatabaseInfo, error) {
	raw, err := api.raw("get_database_info", []interface{}{})
	if err != nil {
		return nil, err
	}
	resp := DatabaseInfo{}
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return &resp, nil
}

func (api *API) GetVestingDelegations(account, from string, opts ...interface{}) ([]VestingDelegation, error) {
	params := []interface{}{account, from}
	switch len(opts) {
	case 0:
		params = append(params, 100, "delegated")
	case 1:
		params = append(params, opts[0], "delegated")
	default:
		params = append(params, opts...)
	}
	raw, err := api.raw("get_vesting_delegations", params)
	if err != nil {
		return nil, err
	}
	resp := make([]VestingDelegation, 0)
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

func (api *API) GetExpiringVestingDelegations(account string, from types.Time, opts ...interface{}) ([]VestingDelegationExpiration, error) {
	params := []interface{}{account, from}
	switch len(opts) {
	case 0:
		params = append(params, 100)
	default:
		params = append(params, opts...)
	}
	raw, err := api.raw("get_expiring_vesting_delegations", params)
	if err != nil {
		return nil, err
	}
	resp := make([]VestingDelegationExpiration, 0)
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

//verify_account_authority
<commit_msg>Remove moved methods.<commit_after>package database

import (
	"encoding/json"

	"github.com/asuleymanov/golos-go/transports"
	"github.com/asuleymanov/golos-go/types"
	"github.com/pkg/errors"
)

const apiID = "database_api"

type API struct {
	caller transports.Caller
}

func NewAPI(caller transports.Caller) *API {
	return &API{caller}
}

var emptyParams = []string{}

func (api *API) raw(method string, params interface{}) (*json.RawMessage, error) {
	var resp json.RawMessage
	if err := api.caller.Call("call", []interface{}{apiID, method, params}, &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to call %v\n", apiID, method)
	}
	return &resp, nil
}

//GetBlockHeader api request get_block_header
func (api *API) GetBlockHeader(blockNum uint32) (*BlockHeader, error) {
	raw, err := api.raw("get_block_header", []uint32{blockNum})
	if err != nil {
		return nil, err
	}
	var resp BlockHeader
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_block_header response", apiID)
	}
	resp.Number = blockNum
	return &resp, nil
}

//GetBlock api request get_block
func (api *API) GetBlock(blockNum uint32) (*Block, error) {
	raw, err := api.raw("get_block", []uint32{blockNum})
	if err != nil {
		return nil, err
	}
	var resp Block
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_block response", apiID)
	}
	resp.Number = blockNum
	return &resp, nil
}

//GetConfig api request get_config
func (api *API) GetConfig() (*Config, error) {
	raw, err := api.raw("get_config", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp Config
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_config response", apiID)
	}
	return &resp, nil
}

//GetDynamicGlobalProperties api request get_dynamic_global_properties
func (api *API) GetDynamicGlobalProperties() (*DynamicGlobalProperties, error) {
	raw, err := api.raw("get_dynamic_global_properties", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp DynamicGlobalProperties
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_dynamic_global_properties response", apiID)
	}
	return &resp, nil
}

//GetChainProperties api request get_chain_properties
func (api *API) GetChainProperties() (*ChainProperties, error) {
	raw, err := api.raw("get_chain_properties", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp ChainProperties
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_chain_properties response", apiID)
	}
	return &resp, nil
}

//GetHardforkVersion api request get_hardfork_version
func (api *API) GetHardforkVersion() (string, error) {
	raw, err := api.raw("get_hardfork_version", emptyParams)
	if err != nil {
		return "", err
	}
	var resp string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return "", errors.Wrapf(err, "golos: %v: failed to unmarshal get_hardfork_version response", apiID)
	}
	return resp, nil
}

//GetNextScheduledHardfork api request get_next_scheduled_hardfork
func (api *API) GetNextScheduledHardfork() (*NextScheduledHardfork, error) {
	raw, err := api.raw("get_next_scheduled_hardfork", emptyParams)
	if err != nil {
		return nil, err
	}
	var resp NextScheduledHardfork
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_next_scheduled_hardfork response", apiID)
	}
	return &resp, nil
}

//GetAccounts api request get_accounts
func (api *API) GetAccounts(accountNames []string) ([]*Account, error) {
	raw, err := api.raw("get_accounts", [][]string{accountNames})
	if err != nil {
		return nil, err
	}
	var resp []*Account
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_accounts response", apiID)
	}
	return resp, nil
}

//LookupAccountNames api request lookup_account_names
func (api *API) LookupAccountNames(accountNames []string) ([]*LookupAccountNames, error) {
	raw, err := api.raw("lookup_account_names", [][]string{accountNames})
	if err != nil {
		return nil, err
	}
	var resp []*LookupAccountNames
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal lookup_account_names response", apiID)
	}
	return resp, nil
}

//LookupAccounts api request lookup_accounts
func (api *API) LookupAccounts(lowerBoundName string, limit uint32) ([]string, error) {
	raw, err := api.raw("lookup_accounts", []interface{}{lowerBoundName, limit})
	if err != nil {
		return nil, err
	}
	var resp []string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal lookup_accounts response", apiID)
	}
	return resp, nil
}

//GetAccountCount api request get_account_count
func (api *API) GetAccountCount() (uint32, error) {
	raw, err := api.raw("get_account_count", emptyParams)
	if err != nil {
		return 0, err
	}
	var resp uint32
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return 0, errors.Wrapf(err, "golos: %v: failed to unmarshal get_account_count response", apiID)
	}
	return resp, nil
}

//GetOwnerHistory api request get_owner_history
func (api *API) GetOwnerHistory(accountName string) ([]*OwnerHistory, error) {
	raw, err := api.raw("get_owner_history", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*OwnerHistory
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_owner_history response", apiID)
	}
	return resp, nil
}

//GetRecoveryRequest api request get_recovery_request
func (api *API) GetRecoveryRequest(accountName string) (*json.RawMessage, error) {
	return api.raw("get_recovery_request", []interface{}{accountName})
}

//GetEscrow api request get_escrow
func (api *API) GetEscrow(from string, escrowID uint32) (*json.RawMessage, error) {
	return api.raw("get_escrow", []interface{}{from, escrowID})
}

//GetWithdrawRoutes api request get_withdraw_routes
func (api *API) GetWithdrawRoutes(accountName string, withdrawRouteType string) (*json.RawMessage, error) {
	return api.raw("get_withdraw_routes", []interface{}{accountName, withdrawRouteType})
}

//GetAccountBandwidth api request get_account_bandwidth
/*
bandwidthType:
post = 0
forum = 1
market = 2
old_forum = 3
old_market = 4
*/
func (api *API) GetAccountBandwidth(accountName string, bandwidthType uint32) (*Bandwidth, error) {
	raw, err := api.raw("get_account_bandwidth", []interface{}{accountName, bandwidthType})
	if err != nil {
		return nil, err
	}
	var resp *Bandwidth
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_account_bandwidth response", apiID)
	}
	return resp, nil
}

//GetSavingsWithdrawFrom api request get_savings_withdraw_from
func (api *API) GetSavingsWithdrawFrom(accountName string) ([]*SavingsWithdraw, error) {
	raw, err := api.raw("get_savings_withdraw_from", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*SavingsWithdraw
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_savings_withdraw_from response", apiID)
	}
	return resp, nil
}

//GetSavingsWithdrawTo api request get_savings_withdraw_to
func (api *API) GetSavingsWithdrawTo(accountName string) ([]*SavingsWithdraw, error) {
	raw, err := api.raw("get_savings_withdraw_to", []interface{}{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*SavingsWithdraw
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_savings_withdraw_to response", apiID)
	}
	return resp, nil
}

//GetConversionRequests api request get_conversion_requests
func (api *API) GetConversionRequests(accountName string) ([]*ConversionRequests, error) {
	raw, err := api.raw("get_conversion_requests", []string{accountName})
	if err != nil {
		return nil, err
	}
	var resp []*ConversionRequests
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_conversion_requests response", apiID)
	}
	return resp, nil
}

//GetTransactionHex api request get_transaction_hex
func (api *API) GetTransactionHex(trx *types.Transaction) (*json.RawMessage, error) {
	return api.raw("get_transaction_hex", []interface{}{&trx})
}

//get_required_signatures

//GetPotentialSignatures api request get_potential_signatures
func (api *API) GetPotentialSignatures(trx *types.Transaction) ([]string, error) {
	raw, err := api.raw("get_potential_signatures", []interface{}{&trx})
	if err != nil {
		return nil, err
	}
	var resp []string
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal get_potential_signatures response", apiID)
	}
	return resp, nil
}

//GetVerifyAuthority api request verify_authority
func (api *API) GetVerifyAuthority(trx *types.Transaction) (bool, error) {
	raw, err := api.raw("verify_authority", []interface{}{&trx})
	if err != nil {
		return false, err
	}
	var resp bool
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return false, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

func (api *API) GetProposedTransaction(account string) (*ProposalObject, error) {
	raw, err := api.raw("get_proposed_transaction", []interface{}{account})
	if err != nil {
		return nil, err
	}
	resp := ProposalObject{}
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return &resp, nil
}

func (api *API) GetDatabaseInfo() (*DatabaseInfo, error) {
	raw, err := api.raw("get_database_info", []interface{}{})
	if err != nil {
		return nil, err
	}
	resp := DatabaseInfo{}
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return &resp, nil
}

func (api *API) GetVestingDelegations(account, from string, opts ...interface{}) ([]VestingDelegation, error) {
	params := []interface{}{account, from}
	switch len(opts) {
	case 0:
		params = append(params, 100, "delegated")
	case 1:
		params = append(params, opts[0], "delegated")
	default:
		params = append(params, opts...)
	}
	raw, err := api.raw("get_vesting_delegations", params)
	if err != nil {
		return nil, err
	}
	resp := make([]VestingDelegation, 0)
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

func (api *API) GetExpiringVestingDelegations(account string, from types.Time, opts ...interface{}) ([]VestingDelegationExpiration, error) {
	params := []interface{}{account, from}
	switch len(opts) {
	case 0:
		params = append(params, 100)
	default:
		params = append(params, opts...)
	}
	raw, err := api.raw("get_expiring_vesting_delegations", params)
	if err != nil {
		return nil, err
	}
	resp := make([]VestingDelegationExpiration, 0)
	if err := json.Unmarshal([]byte(*raw), &resp); err != nil {
		return nil, errors.Wrapf(err, "golos: %v: failed to unmarshal verify_authority response", apiID)
	}
	return resp, nil
}

//verify_account_authority
<|endoftext|>


<commit_before>package cli

import "github.com/tucnak/climax"

type CLI struct {
	Ctrl *Controller
}

func New(ctlr *Controller) (c *CLI) {
	c = &CLI{
		Ctrl: ctlr,
	}

	return
}

func (c *CLI) Run() {
	dcdr := climax.New("dcdr")
	dcdr.Brief = "Decider: CLI for decider feature flags."
	dcdr.Version = "stable"

	cmds := c.Commands()

	for _, cmd := range cmds {
		dcdr.AddCommand(cmd)
	}

	dcdr.Run()
}

func (c *CLI) Commands() []climax.Command {
	return []climax.Command{
		{
			Name:  "list",
			Brief: "list all feature flags",
			Usage: `[-p=] "<prefix>" list all flags with a matching prefix`,
			Help:  `Lists all feature flags. Use -p to match flags by a prefix.`,

			Flags: []climax.Flag{
				{
					Name:     "prefix",
					Short:    "p",
					Usage:    `--prefix="<flag_name>"`,
					Help:     `List only flags with matching prefix.`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-p "flag_"`,
					Description: `Matches 'flag_name'`,
				},
			},

			Handle: c.Ctrl.List,
		},
		{
			Name:  "set",
			Brief: "create or update a feature flag",
			Usage: `set -name flag_name -type [boolean|percentile] -value [0.0-1.0|true/false] -comment "flag description"`,
			Help:  `set creates or updates a feature flag.`,

			Flags: []climax.Flag{
				{
					Name:     "name",
					Short:    "n",
					Usage:    `--name="flag_name"`,
					Help:     `the name of the falg to set`,
					Variable: true,
				},
				{
					Name:     "type",
					Short:    "t",
					Usage:    `--type=[boolean|percentile]`,
					Help:     `the type of flag to set`,
					Variable: true,
				},
				{
					Name:     "value",
					Short:    "v",
					Usage:    `--value=0.0-1.0 or true|false`,
					Help:     `the value of the flag`,
					Variable: true,
				},
				{
					Name:     "comment",
					Short:    "c",
					Usage:    `--comment="flag description"`,
					Help:     `an optional comment or description`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-n "flag_name" -t percentile -v 0.5 -c "the flag desc"`,
					Description: `sets a percentile flag to 50%`,
				},
				{
					Usecase:     `-n "flag_name" -t boolean -v false -c "the flag desc"`,
					Description: `sets a boolean flag to false`,
				},
			},

			Handle: c.Ctrl.Set,
		},
		{
			Name:  "delete",
			Brief: "delete a feature flag",
			Usage: `[-n=] "<name>" delete flag with matching name`,
			Help:  `Delete a feature flag matching --name`,

			Flags: []climax.Flag{
				{
					Name:     "name",
					Short:    "n",
					Usage:    `--name="<flag_name>"`,
					Help:     `Name of the flag to delete`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-n "flag_name"`,
					Description: `Deletes 'flag_name'`,
				},
			},

			Handle: c.Ctrl.Delete,
		},
		{
			Name:  "init",
			Brief: "init the audit repo",
			Usage: `--create creates an empty audit repo and pushes to origin`,
			Help: `Clones the RepoUrl into the RepoPath from ~/.dcdr. Creates a new
			repo if --create is passed.`,

			Flags: []climax.Flag{
				{
					Name:     "create",
					Short:    "c",
					Usage:    `--create`,
					Help:     `Create a new empty repo`,
					Variable: false,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     ``,
					Description: `clone RepoUrl into the RepoPath from ~/.dcdr`,
				},
				{
					Usecase:     `--create`,
					Description: `create a new empty repo`,
				},
			},

			Handle: c.Ctrl.Init,
		},
	}
}
<commit_msg>add version<commit_after>package cli

import "github.com/tucnak/climax"

const Version = "0.1"

type CLI struct {
	Ctrl *Controller
}

func New(ctlr *Controller) (c *CLI) {
	c = &CLI{
		Ctrl: ctlr,
	}

	return
}

func (c *CLI) Run() {
	dcdr := climax.New("dcdr")
	dcdr.Brief = "Decider: CLI for decider feature flags."
	dcdr.Version = Version

	cmds := c.Commands()

	for _, cmd := range cmds {
		dcdr.AddCommand(cmd)
	}

	dcdr.Run()
}

func (c *CLI) Commands() []climax.Command {
	return []climax.Command{
		{
			Name:  "list",
			Brief: "list all feature flags",
			Usage: `[-p=] "<prefix>" list all flags with a matching prefix`,
			Help:  `Lists all feature flags. Use -p to match flags by a prefix.`,

			Flags: []climax.Flag{
				{
					Name:     "prefix",
					Short:    "p",
					Usage:    `--prefix="<flag_name>"`,
					Help:     `List only flags with matching prefix.`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-p "flag_"`,
					Description: `Matches 'flag_name'`,
				},
			},

			Handle: c.Ctrl.List,
		},
		{
			Name:  "set",
			Brief: "create or update a feature flag",
			Usage: `set -name flag_name -type [boolean|percentile] -value [0.0-1.0|true/false] -comment "flag description"`,
			Help:  `set creates or updates a feature flag.`,

			Flags: []climax.Flag{
				{
					Name:     "name",
					Short:    "n",
					Usage:    `--name="flag_name"`,
					Help:     `the name of the falg to set`,
					Variable: true,
				},
				{
					Name:     "type",
					Short:    "t",
					Usage:    `--type=[boolean|percentile]`,
					Help:     `the type of flag to set`,
					Variable: true,
				},
				{
					Name:     "value",
					Short:    "v",
					Usage:    `--value=0.0-1.0 or true|false`,
					Help:     `the value of the flag`,
					Variable: true,
				},
				{
					Name:     "comment",
					Short:    "c",
					Usage:    `--comment="flag description"`,
					Help:     `an optional comment or description`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-n "flag_name" -t percentile -v 0.5 -c "the flag desc"`,
					Description: `sets a percentile flag to 50%`,
				},
				{
					Usecase:     `-n "flag_name" -t boolean -v false -c "the flag desc"`,
					Description: `sets a boolean flag to false`,
				},
			},

			Handle: c.Ctrl.Set,
		},
		{
			Name:  "delete",
			Brief: "delete a feature flag",
			Usage: `[-n=] "<name>" delete flag with matching name`,
			Help:  `Delete a feature flag matching --name`,

			Flags: []climax.Flag{
				{
					Name:     "name",
					Short:    "n",
					Usage:    `--name="<flag_name>"`,
					Help:     `Name of the flag to delete`,
					Variable: true,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     `-n "flag_name"`,
					Description: `Deletes 'flag_name'`,
				},
			},

			Handle: c.Ctrl.Delete,
		},
		{
			Name:  "init",
			Brief: "init the audit repo",
			Usage: `--create creates an empty audit repo and pushes to origin`,
			Help: `Clones the RepoUrl into the RepoPath from ~/.dcdr. Creates a new
			repo if --create is passed.`,

			Flags: []climax.Flag{
				{
					Name:     "create",
					Short:    "c",
					Usage:    `--create`,
					Help:     `Create a new empty repo`,
					Variable: false,
				},
			},

			Examples: []climax.Example{
				{
					Usecase:     ``,
					Description: `clone RepoUrl into the RepoPath from ~/.dcdr`,
				},
				{
					Usecase:     `--create`,
					Description: `create a new empty repo`,
				},
			},

			Handle: c.Ctrl.Init,
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/codegangsta/cli"
	"github.com/sirupsen/logrus"
)

var (
	shipyardHost string
	logger       = logrus.New()
)

func main() {
	cfg, err := loadConfig()
	if err != nil {
		if err != ErrConfigDoesNotExist {
			logger.Fatal(err)
		}
	}
	if cfg != nil {
		sUrl := os.Getenv("SHIPYARD_URL")
		if sUrl == "" {
			cfg.Url = sUrl
		}
	}
	app := cli.NewApp()
	app.Name = "shipyard"
	app.Usage = "manage a shipyard cluster"
	app.Version = "2.0.1"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{}
	app.Commands = []cli.Command{
		loginCommand,
		changePasswordCommand,
		accountsCommand,
		addAccountCommand,
		deleteAccountCommand,
		containersCommand,
		containerInspectCommand,
		runCommand,
		stopCommand,
		restartCommand,
		scaleCommand,
		logsCommand,
		destroyCommand,
		engineListCommand,
		engineAddCommand,
		engineRemoveCommand,
		engineInspectCommand,
		serviceKeysListCommand,
		serviceKeyCreateCommand,
		serviceKeyRemoveCommand,
		extensionsCommand,
		addExtensionCommand,
		removeExtensionCommand,
		webhookKeysListCommand,
		webhookKeyCreateCommand,
		webhookKeyRemoveCommand,
		infoCommand,
		eventsCommand,
	}
	app.Run(os.Args)
}
<commit_msg>bump version for cli<commit_after>package main

import (
	"os"

	"github.com/codegangsta/cli"
	"github.com/sirupsen/logrus"
)

var (
	shipyardHost string
	logger       = logrus.New()
)

func main() {
	cfg, err := loadConfig()
	if err != nil {
		if err != ErrConfigDoesNotExist {
			logger.Fatal(err)
		}
	}
	if cfg != nil {
		sUrl := os.Getenv("SHIPYARD_URL")
		if sUrl == "" {
			cfg.Url = sUrl
		}
	}
	app := cli.NewApp()
	app.Name = "shipyard"
	app.Usage = "manage a shipyard cluster"
	app.Version = "2.0.3"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{}
	app.Commands = []cli.Command{
		loginCommand,
		changePasswordCommand,
		accountsCommand,
		addAccountCommand,
		deleteAccountCommand,
		containersCommand,
		containerInspectCommand,
		runCommand,
		stopCommand,
		restartCommand,
		scaleCommand,
		logsCommand,
		destroyCommand,
		engineListCommand,
		engineAddCommand,
		engineRemoveCommand,
		engineInspectCommand,
		serviceKeysListCommand,
		serviceKeyCreateCommand,
		serviceKeyRemoveCommand,
		extensionsCommand,
		addExtensionCommand,
		removeExtensionCommand,
		webhookKeysListCommand,
		webhookKeyCreateCommand,
		webhookKeyRemoveCommand,
		infoCommand,
		eventsCommand,
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package cli

import (
	"context"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/gate"
	"github.com/elpinal/coco3/parser"

	"github.com/elpinal/coco3/extra"
	eparser "github.com/elpinal/coco3/extra/parser"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

type CLI struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer

	config.Config

	db *sqlx.DB

	exitCh chan int
	doneCh chan struct{} // to ensure exiting just after exitCh received

	execute1 func([]byte) error
}

func (c *CLI) Run(args []string) int {
	c.exitCh = make(chan int)
	c.doneCh = make(chan struct{})
	// TODO: need to use a closure?
	defer close(c.doneCh)

	f := flag.NewFlagSet("coco3", flag.ContinueOnError)
	f.SetOutput(c.Err)
	f.Usage = func() {
		c.Err.Write([]byte("coco3 is a shell.\n"))
		c.Err.Write([]byte("Usage:\n"))
		f.PrintDefaults()
	}

	flagC := f.String("c", "", "take first argument as a command to execute")
	flagE := f.Bool("extra", c.Config.Extra, "switch to extra mode")
	if err := f.Parse(args); err != nil {
		return 2
	}

	for _, alias := range c.Config.Alias {
		eval.DefAlias(alias[0], alias[1])
	}

	for k, v := range c.Config.Env {
		err := os.Setenv(k, v)
		if err != nil {
			fmt.Fprintln(c.Err, err)
			return 1
		}
	}

	setpath(c.Config.Paths)

	if *flagE {
		// If -extra flag is on, enable extra mode on any command executions.
		c.execute1 = c.executeExtra
	} else {
		c.execute1 = c.execute
	}

	if len(c.Config.StartUpCommand) > 0 {
		done := make(chan struct{})
		go func() {
			if err := c.execute1(c.Config.StartUpCommand); err != nil {
				c.printExecError(err)
				c.exitCh <- 1
			}
			close(done)
		}()
		select {
		case code := <-c.exitCh:
			return code
		case <-done:
		}
	}

	if *flagC != "" {
		go func() {
			if err := c.execute1([]byte(*flagC)); err != nil {
				c.printExecError(err)
				c.exitCh <- 1
				return
			}
			c.exitCh <- 0
		}()
		return <-c.exitCh
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if len(f.Args()) > 0 {
		go c.runFiles(ctx, f.Args())
		return <-c.exitCh
	}

	conf := &c.Config
	conf.Init()
	db, err := sqlx.Connect("sqlite3", conf.HistFile)
	if err != nil {
		fmt.Fprintf(c.Err, "connecting history file: %v\n", err)
		return 1
	}
	_, err = db.Exec(schema)
	if err != nil {
		fmt.Fprintf(c.Err, "initializing history file: %v\n", err)
		return 1
	}
	var history []string
	err = db.Select(&history, "select line from command_info")
	if err != nil {
		fmt.Fprintf(c.Err, "restoring history: %v\n", err)
		return 1
	}
	histRunes := sanitizeHistory(history)
	g := gate.NewContext(ctx, conf, c.In, c.Out, c.Err, histRunes)
	c.db = db
	go func(ctx context.Context) {
		for {
			if err := c.interact(g); err != nil {
				c.printExecError(err)
				g.Clear()
			}
			select {
			case <-ctx.Done():
				return
			default:
			}
		}
	}(ctx)
	return <-c.exitCh
}

func (c *CLI) printExecError(err error) {
	if pe, ok := err.(*eparser.ParseError); ok {
		fmt.Fprintln(c.Err, pe.Verbose())
	} else {
		fmt.Fprintln(c.Err, err)
	}
}

// setpath sets the PATH environment variable.
func setpath(args []string) {
	if len(args) == 0 {
		return
	}
	paths := filepath.SplitList(os.Getenv("PATH"))
	var newPaths []string
	for _, path := range paths {
		if contains(args, path) {
			continue
		}
		newPaths = append(newPaths, path)
	}
	newPaths = append(args, newPaths...)
	os.Setenv("PATH", strings.Join(newPaths, string(filepath.ListSeparator)))
}

func contains(xs []string, s string) bool {
	for _, x := range xs {
		if x == s {
			return true
		}
	}
	return false
}

func sanitizeHistory(history []string) [][]rune {
	histRunes := make([][]rune, 0, len(history))
	for _, line := range history {
		if line == "" {
			continue
		}
		l := len(histRunes)
		s := []rune(line)
		if l > 0 && compareRunes(histRunes[l-1], s) {
			continue
		}
		histRunes = append(histRunes, s)
	}
	return histRunes
}

func compareRunes(r1, r2 []rune) bool {
	if len(r1) != len(r2) {
		return false
	}
	for i, r := range r1 {
		if r2[i] != r {
			return false
		}
	}
	return true
}

func (c *CLI) interact(g gate.Gate) error {
	r, end, err := c.read(g)
	if err != nil {
		return err
	}
	if end {
		c.exitCh <- 0
		<-c.doneCh
		return nil
	}
	go c.writeHistory(r)
	if err := c.execute1([]byte(string(r))); err != nil {
		return err
	}
	g.Clear()
	return nil
}

func (c *CLI) read(g gate.Gate) ([]rune, bool, error) {
	defer c.Out.Write([]byte{'\n'})
	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := terminal.Restore(0, oldState); err != nil {
			fmt.Fprintln(c.Err, err)
		}
	}()
	r, end, err := g.Read()
	if err != nil {
		return nil, false, err
	}
	return r, end, nil
}

func (c *CLI) writeHistory(r []rune) {
	startTime := time.Now()
	_, err := c.db.Exec("insert into command_info (time, line) values ($1, $2)", startTime, string(r))
	if err != nil {
		fmt.Fprintf(c.Err, "saving history: %v\n", err)
		c.exitCh <- 1
	}
}

const schema = `
create table if not exists command_info (
    time datetime,
    line text
)`

func (c *CLI) execute(b []byte) error {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return err
	}
	e := eval.New(c.In, c.Out, c.Err, c.db)
	err = e.Eval(f.Lines)
	select {
	case code := <-e.ExitCh:
		c.exitCh <- code
		<-c.doneCh
	default:
	}
	return err
}

func (c *CLI) executeExtra(b []byte) error {
	cmd, err := eparser.Parse(b)
	if err != nil {
		return err
	}
	e := extra.New(extra.Option{DB: c.db})
	err = e.Eval(cmd)
	if err == nil {
		return nil
	}
	if pe, ok := err.(*eparser.ParseError); ok {
		pe.Src = string(b)
	}
	return err
}

func (c *CLI) runFiles(ctx context.Context, files []string) {
	for _, file := range files {
		b, err := ioutil.ReadFile(file)
		if err != nil {
			fmt.Fprintln(c.Err, err)
			c.exitCh <- 1
			return
		}
		if err := c.execute1(b); err != nil {
			fmt.Fprintln(c.Err, err)
			c.exitCh <- 1
			return
		}
		select {
		case <-ctx.Done():
			return
		default:
		}
	}
	c.exitCh <- 0
}
<commit_msg>Remove comment<commit_after>package cli

import (
	"context"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/gate"
	"github.com/elpinal/coco3/parser"

	"github.com/elpinal/coco3/extra"
	eparser "github.com/elpinal/coco3/extra/parser"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

type CLI struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer

	config.Config

	db *sqlx.DB

	exitCh chan int
	doneCh chan struct{} // to ensure exiting just after exitCh received

	execute1 func([]byte) error
}

func (c *CLI) Run(args []string) int {
	c.exitCh = make(chan int)
	c.doneCh = make(chan struct{})
	defer close(c.doneCh)

	f := flag.NewFlagSet("coco3", flag.ContinueOnError)
	f.SetOutput(c.Err)
	f.Usage = func() {
		c.Err.Write([]byte("coco3 is a shell.\n"))
		c.Err.Write([]byte("Usage:\n"))
		f.PrintDefaults()
	}

	flagC := f.String("c", "", "take first argument as a command to execute")
	flagE := f.Bool("extra", c.Config.Extra, "switch to extra mode")
	if err := f.Parse(args); err != nil {
		return 2
	}

	for _, alias := range c.Config.Alias {
		eval.DefAlias(alias[0], alias[1])
	}

	for k, v := range c.Config.Env {
		err := os.Setenv(k, v)
		if err != nil {
			fmt.Fprintln(c.Err, err)
			return 1
		}
	}

	setpath(c.Config.Paths)

	if *flagE {
		// If -extra flag is on, enable extra mode on any command executions.
		c.execute1 = c.executeExtra
	} else {
		c.execute1 = c.execute
	}

	if len(c.Config.StartUpCommand) > 0 {
		done := make(chan struct{})
		go func() {
			if err := c.execute1(c.Config.StartUpCommand); err != nil {
				c.printExecError(err)
				c.exitCh <- 1
			}
			close(done)
		}()
		select {
		case code := <-c.exitCh:
			return code
		case <-done:
		}
	}

	if *flagC != "" {
		go func() {
			if err := c.execute1([]byte(*flagC)); err != nil {
				c.printExecError(err)
				c.exitCh <- 1
				return
			}
			c.exitCh <- 0
		}()
		return <-c.exitCh
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if len(f.Args()) > 0 {
		go c.runFiles(ctx, f.Args())
		return <-c.exitCh
	}

	conf := &c.Config
	conf.Init()
	db, err := sqlx.Connect("sqlite3", conf.HistFile)
	if err != nil {
		fmt.Fprintf(c.Err, "connecting history file: %v\n", err)
		return 1
	}
	_, err = db.Exec(schema)
	if err != nil {
		fmt.Fprintf(c.Err, "initializing history file: %v\n", err)
		return 1
	}
	var history []string
	err = db.Select(&history, "select line from command_info")
	if err != nil {
		fmt.Fprintf(c.Err, "restoring history: %v\n", err)
		return 1
	}
	histRunes := sanitizeHistory(history)
	g := gate.NewContext(ctx, conf, c.In, c.Out, c.Err, histRunes)
	c.db = db
	go func(ctx context.Context) {
		for {
			if err := c.interact(g); err != nil {
				c.printExecError(err)
				g.Clear()
			}
			select {
			case <-ctx.Done():
				return
			default:
			}
		}
	}(ctx)
	return <-c.exitCh
}

func (c *CLI) printExecError(err error) {
	if pe, ok := err.(*eparser.ParseError); ok {
		fmt.Fprintln(c.Err, pe.Verbose())
	} else {
		fmt.Fprintln(c.Err, err)
	}
}

// setpath sets the PATH environment variable.
func setpath(args []string) {
	if len(args) == 0 {
		return
	}
	paths := filepath.SplitList(os.Getenv("PATH"))
	var newPaths []string
	for _, path := range paths {
		if contains(args, path) {
			continue
		}
		newPaths = append(newPaths, path)
	}
	newPaths = append(args, newPaths...)
	os.Setenv("PATH", strings.Join(newPaths, string(filepath.ListSeparator)))
}

func contains(xs []string, s string) bool {
	for _, x := range xs {
		if x == s {
			return true
		}
	}
	return false
}

func sanitizeHistory(history []string) [][]rune {
	histRunes := make([][]rune, 0, len(history))
	for _, line := range history {
		if line == "" {
			continue
		}
		l := len(histRunes)
		s := []rune(line)
		if l > 0 && compareRunes(histRunes[l-1], s) {
			continue
		}
		histRunes = append(histRunes, s)
	}
	return histRunes
}

func compareRunes(r1, r2 []rune) bool {
	if len(r1) != len(r2) {
		return false
	}
	for i, r := range r1 {
		if r2[i] != r {
			return false
		}
	}
	return true
}

func (c *CLI) interact(g gate.Gate) error {
	r, end, err := c.read(g)
	if err != nil {
		return err
	}
	if end {
		c.exitCh <- 0
		<-c.doneCh
		return nil
	}
	go c.writeHistory(r)
	if err := c.execute1([]byte(string(r))); err != nil {
		return err
	}
	g.Clear()
	return nil
}

func (c *CLI) read(g gate.Gate) ([]rune, bool, error) {
	defer c.Out.Write([]byte{'\n'})
	oldState, err := terminal.MakeRaw(0)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := terminal.Restore(0, oldState); err != nil {
			fmt.Fprintln(c.Err, err)
		}
	}()
	r, end, err := g.Read()
	if err != nil {
		return nil, false, err
	}
	return r, end, nil
}

func (c *CLI) writeHistory(r []rune) {
	startTime := time.Now()
	_, err := c.db.Exec("insert into command_info (time, line) values ($1, $2)", startTime, string(r))
	if err != nil {
		fmt.Fprintf(c.Err, "saving history: %v\n", err)
		c.exitCh <- 1
	}
}

const schema = `
create table if not exists command_info (
    time datetime,
    line text
)`

func (c *CLI) execute(b []byte) error {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return err
	}
	e := eval.New(c.In, c.Out, c.Err, c.db)
	err = e.Eval(f.Lines)
	select {
	case code := <-e.ExitCh:
		c.exitCh <- code
		<-c.doneCh
	default:
	}
	return err
}

func (c *CLI) executeExtra(b []byte) error {
	cmd, err := eparser.Parse(b)
	if err != nil {
		return err
	}
	e := extra.New(extra.Option{DB: c.db})
	err = e.Eval(cmd)
	if err == nil {
		return nil
	}
	if pe, ok := err.(*eparser.ParseError); ok {
		pe.Src = string(b)
	}
	return err
}

func (c *CLI) runFiles(ctx context.Context, files []string) {
	for _, file := range files {
		b, err := ioutil.ReadFile(file)
		if err != nil {
			fmt.Fprintln(c.Err, err)
			c.exitCh <- 1
			return
		}
		if err := c.execute1(b); err != nil {
			fmt.Fprintln(c.Err, err)
			c.exitCh <- 1
			return
		}
		select {
		case <-ctx.Done():
			return
		default:
		}
	}
	c.exitCh <- 0
}
<|endoftext|>


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

package tsdb

import (
	"io/ioutil"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestWriteAndReadbackTombStones(t *testing.T) {
	tmpdir, _ := ioutil.TempDir("", "test")
	defer os.RemoveAll(tmpdir)

	ref := uint64(0)

	stones := memTombstones{}
	// Generate the tombstones.
	for i := 0; i < 100; i++ {
		ref += uint64(rand.Int31n(10)) + 1
		numRanges := rand.Intn(5) + 1
		dranges := make(Intervals, 0, numRanges)
		mint := rand.Int63n(time.Now().UnixNano())
		for j := 0; j < numRanges; j++ {
			dranges = dranges.add(Interval{mint, mint + rand.Int63n(1000)})
			mint += rand.Int63n(1000) + 1
		}
		stones[ref] = dranges
	}

	require.NoError(t, writeTombstoneFile(tmpdir, stones))

	restr, err := readTombstones(tmpdir)
	require.NoError(t, err)

	// Compare the two readers.
	require.Equal(t, stones, restr)
}

func TestAddingNewIntervals(t *testing.T) {
	cases := []struct {
		exist Intervals
		new   Interval

		exp Intervals
	}{
		{
			new: Interval{1, 2},
			exp: Intervals{{1, 2}},
		},
		{
			exist: Intervals{{1, 2}},
			new:   Interval{1, 2},
			exp:   Intervals{{1, 2}},
		},
		{
			exist: Intervals{{1, 4}, {6, 6}},
			new:   Interval{5, 6},
			exp:   Intervals{{1, 6}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{21, 23},
			exp:   Intervals{{1, 10}, {12, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 2}, {3, 5}, {7, 7}},
			new:   Interval{6, 7},
			exp:   Intervals{{1, 2}, {3, 7}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{21, 25},
			exp:   Intervals{{1, 10}, {12, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{18, 23},
			exp:   Intervals{{1, 10}, {12, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{9, 23},
			exp:   Intervals{{1, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{9, 230},
			exp:   Intervals{{1, 230}},
		},
		{
			exist: Intervals{{5, 10}, {12, 20}, {25, 30}},
			new:   Interval{1, 4},
			exp:   Intervals{{1, 10}, {12, 20}, {25, 30}},
		},
		{
			exist: Intervals{{5, 10}, {12, 20}, {25, 30}},
			new:   Interval{11, 14},
			exp:   Intervals{{5, 20}, {25, 30}},
		},
	}

	for _, c := range cases {

		require.Equal(t, c.exp, c.exist.add(c.new))
	}
	return
}
<commit_msg>use test utils in tombstone_tests<commit_after>// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tsdb

import (
	"io/ioutil"
	"math/rand"
	"os"
	"testing"
	"time"
)

func TestWriteAndReadbackTombStones(t *testing.T) {
	tmpdir, _ := ioutil.TempDir("", "test")
	defer os.RemoveAll(tmpdir)

	ref := uint64(0)

	stones := memTombstones{}
	// Generate the tombstones.
	for i := 0; i < 100; i++ {
		ref += uint64(rand.Int31n(10)) + 1
		numRanges := rand.Intn(5) + 1
		dranges := make(Intervals, 0, numRanges)
		mint := rand.Int63n(time.Now().UnixNano())
		for j := 0; j < numRanges; j++ {
			dranges = dranges.add(Interval{mint, mint + rand.Int63n(1000)})
			mint += rand.Int63n(1000) + 1
		}
		stones[ref] = dranges
	}

	Ok(t, writeTombstoneFile(tmpdir, stones))

	restr, err := readTombstones(tmpdir)
	Ok(t, err)

	// Compare the two readers.
	Equals(t, stones, restr)
}

func TestAddingNewIntervals(t *testing.T) {
	cases := []struct {
		exist Intervals
		new   Interval

		exp Intervals
	}{
		{
			new: Interval{1, 2},
			exp: Intervals{{1, 2}},
		},
		{
			exist: Intervals{{1, 2}},
			new:   Interval{1, 2},
			exp:   Intervals{{1, 2}},
		},
		{
			exist: Intervals{{1, 4}, {6, 6}},
			new:   Interval{5, 6},
			exp:   Intervals{{1, 6}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{21, 23},
			exp:   Intervals{{1, 10}, {12, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 2}, {3, 5}, {7, 7}},
			new:   Interval{6, 7},
			exp:   Intervals{{1, 2}, {3, 7}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{21, 25},
			exp:   Intervals{{1, 10}, {12, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{18, 23},
			exp:   Intervals{{1, 10}, {12, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{9, 23},
			exp:   Intervals{{1, 23}, {25, 30}},
		},
		{
			exist: Intervals{{1, 10}, {12, 20}, {25, 30}},
			new:   Interval{9, 230},
			exp:   Intervals{{1, 230}},
		},
		{
			exist: Intervals{{5, 10}, {12, 20}, {25, 30}},
			new:   Interval{1, 4},
			exp:   Intervals{{1, 10}, {12, 20}, {25, 30}},
		},
		{
			exist: Intervals{{5, 10}, {12, 20}, {25, 30}},
			new:   Interval{11, 14},
			exp:   Intervals{{5, 20}, {25, 30}},
		},
	}

	for _, c := range cases {

		Equals(t, c.exp, c.exist.add(c.new))
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/goware/urlx"
	"github.com/valyala/fasthttp"
	"golang.org/x/net/http2"
)

type client interface {
	do() (code int, msTaken uint64, err error)
}

type bodyStreamProducer func() (io.ReadCloser, error)

type clientOpts struct {
	HTTP2 bool

	maxConns  uint64
	timeout   time.Duration
	tlsConfig *tls.Config

	headers     *headersList
	url, method string

	body    *string
	bodProd bodyStreamProducer

	bytesRead, bytesWritten *int64
}

type fasthttpClient struct {
	client *fasthttp.Client

	headers     *fasthttp.RequestHeader
	url, method string

	body    *string
	bodProd bodyStreamProducer
}

func newFastHTTPClient(opts *clientOpts) client {
	c := new(fasthttpClient)
	c.client = &fasthttp.Client{
		MaxConnsPerHost:               int(opts.maxConns),
		ReadTimeout:                   opts.timeout,
		WriteTimeout:                  opts.timeout,
		DisableHeaderNamesNormalizing: true,
		TLSConfig:                     opts.tlsConfig,
		Dial: fasthttpDialFunc(
			opts.bytesRead, opts.bytesWritten,
		),
	}
	c.headers = headersToFastHTTPHeaders(opts.headers)
	c.url, c.method, c.body = opts.url, opts.method, opts.body
	c.bodProd = opts.bodProd
	return client(c)
}

func (c *fasthttpClient) do() (
	code int, msTaken uint64, err error,
) {
	// prepare the request
	req := fasthttp.AcquireRequest()
	resp := fasthttp.AcquireResponse()
	if c.headers != nil {
		c.headers.CopyTo(&req.Header)
	}
	req.Header.SetMethod(c.method)
	req.SetRequestURI(c.url)
	if c.body != nil {
		req.SetBodyString(*c.body)
	} else {
		bs, bserr := c.bodProd()
		if bserr != nil {
			return 0, 0, bserr
		}
		req.SetBodyStream(bs, -1)
	}

	// fire the request
	start := time.Now()
	err = c.client.Do(req, resp)
	if err != nil {
		code = -1
	} else {
		code = resp.StatusCode()
	}
	msTaken = uint64(time.Since(start).Nanoseconds() / 1000)

	// release resources
	fasthttp.ReleaseRequest(req)
	fasthttp.ReleaseResponse(resp)

	return
}

type httpClient struct {
	client *http.Client

	headers http.Header
	url     *url.URL
	method  string

	body    *string
	bodProd bodyStreamProducer
}

func newHTTPClient(opts *clientOpts) client {
	c := new(httpClient)
	tr := &http.Transport{
		TLSClientConfig:     opts.tlsConfig,
		MaxIdleConnsPerHost: int(opts.maxConns),
	}
	tr.DialContext = httpDialContextFunc(opts.bytesRead, opts.bytesWritten)
	if opts.HTTP2 {
		_ = http2.ConfigureTransport(tr)
	} else {
		tr.TLSNextProto = make(
			map[string]func(authority string, c *tls.Conn) http.RoundTripper,
		)
	}

	cl := &http.Client{
		Transport: tr,
		Timeout:   opts.timeout,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	c.client = cl

	c.headers = headersToHTTPHeaders(opts.headers)
	c.method, c.body, c.bodProd = opts.method, opts.body, opts.bodProd
	var err error
	c.url, err = urlx.Parse(opts.url)
	if err != nil {
		// opts.url guaranteed to be valid at this point
		panic(err)
	}

	return client(c)
}

func (c *httpClient) do() (
	code int, msTaken uint64, err error,
) {
	req := &http.Request{}

	req.Header = c.headers
	req.Method = c.method
	req.URL = c.url

	if host := req.Header.Get("Host"); host != "" {
		req.Host = host
	}

	if c.body != nil {
		br := strings.NewReader(*c.body)
		req.Body = ioutil.NopCloser(br)
	} else {
		bs, bserr := c.bodProd()
		if bserr != nil {
			return 0, 0, bserr
		}
		req.Body = bs
	}

	start := time.Now()
	resp, err := c.client.Do(req)
	if err != nil {
		code = -1
	} else {
		code = resp.StatusCode

		_, berr := io.Copy(ioutil.Discard, resp.Body)
		if berr != nil {
			err = berr
		}

		if cerr := resp.Body.Close(); cerr != nil {
			err = cerr
		}
	}
	msTaken = uint64(time.Since(start).Nanoseconds() / 1000)

	return
}

func headersToFastHTTPHeaders(h *headersList) *fasthttp.RequestHeader {
	if len(*h) == 0 {
		return nil
	}
	res := new(fasthttp.RequestHeader)
	for _, header := range *h {
		res.Set(header.key, header.value)
	}
	return res
}

func headersToHTTPHeaders(h *headersList) http.Header {
	if len(*h) == 0 {
		return http.Header{}
	}
	headers := http.Header{}

	for _, header := range *h {
		headers[header.key] = []string{header.value}
	}
	return headers
}
<commit_msg>clients: set ContentLength explicitly<commit_after>package main

import (
	"crypto/tls"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/goware/urlx"
	"github.com/valyala/fasthttp"
	"golang.org/x/net/http2"
)

type client interface {
	do() (code int, msTaken uint64, err error)
}

type bodyStreamProducer func() (io.ReadCloser, error)

type clientOpts struct {
	HTTP2 bool

	maxConns  uint64
	timeout   time.Duration
	tlsConfig *tls.Config

	headers     *headersList
	url, method string

	body    *string
	bodProd bodyStreamProducer

	bytesRead, bytesWritten *int64
}

type fasthttpClient struct {
	client *fasthttp.Client

	headers     *fasthttp.RequestHeader
	url, method string

	body    *string
	bodProd bodyStreamProducer
}

func newFastHTTPClient(opts *clientOpts) client {
	c := new(fasthttpClient)
	c.client = &fasthttp.Client{
		MaxConnsPerHost:               int(opts.maxConns),
		ReadTimeout:                   opts.timeout,
		WriteTimeout:                  opts.timeout,
		DisableHeaderNamesNormalizing: true,
		TLSConfig:                     opts.tlsConfig,
		Dial: fasthttpDialFunc(
			opts.bytesRead, opts.bytesWritten,
		),
	}
	c.headers = headersToFastHTTPHeaders(opts.headers)
	c.url, c.method, c.body = opts.url, opts.method, opts.body
	c.bodProd = opts.bodProd
	return client(c)
}

func (c *fasthttpClient) do() (
	code int, msTaken uint64, err error,
) {
	// prepare the request
	req := fasthttp.AcquireRequest()
	resp := fasthttp.AcquireResponse()
	if c.headers != nil {
		c.headers.CopyTo(&req.Header)
	}
	req.Header.SetMethod(c.method)
	req.SetRequestURI(c.url)
	if c.body != nil {
		req.SetBodyString(*c.body)
	} else {
		bs, bserr := c.bodProd()
		if bserr != nil {
			return 0, 0, bserr
		}
		req.SetBodyStream(bs, -1)
	}

	// fire the request
	start := time.Now()
	err = c.client.Do(req, resp)
	if err != nil {
		code = -1
	} else {
		code = resp.StatusCode()
	}
	msTaken = uint64(time.Since(start).Nanoseconds() / 1000)

	// release resources
	fasthttp.ReleaseRequest(req)
	fasthttp.ReleaseResponse(resp)

	return
}

type httpClient struct {
	client *http.Client

	headers http.Header
	url     *url.URL
	method  string

	body    *string
	bodProd bodyStreamProducer
}

func newHTTPClient(opts *clientOpts) client {
	c := new(httpClient)
	tr := &http.Transport{
		TLSClientConfig:     opts.tlsConfig,
		MaxIdleConnsPerHost: int(opts.maxConns),
	}
	tr.DialContext = httpDialContextFunc(opts.bytesRead, opts.bytesWritten)
	if opts.HTTP2 {
		_ = http2.ConfigureTransport(tr)
	} else {
		tr.TLSNextProto = make(
			map[string]func(authority string, c *tls.Conn) http.RoundTripper,
		)
	}

	cl := &http.Client{
		Transport: tr,
		Timeout:   opts.timeout,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	c.client = cl

	c.headers = headersToHTTPHeaders(opts.headers)
	c.method, c.body, c.bodProd = opts.method, opts.body, opts.bodProd
	var err error
	c.url, err = urlx.Parse(opts.url)
	if err != nil {
		// opts.url guaranteed to be valid at this point
		panic(err)
	}

	return client(c)
}

func (c *httpClient) do() (
	code int, msTaken uint64, err error,
) {
	req := &http.Request{}

	req.Header = c.headers
	req.Method = c.method
	req.URL = c.url

	if host := req.Header.Get("Host"); host != "" {
		req.Host = host
	}

	if c.body != nil {
		br := strings.NewReader(*c.body)
		req.ContentLength = int64(len(*c.body))
		req.Body = ioutil.NopCloser(br)
	} else {
		bs, bserr := c.bodProd()
		if bserr != nil {
			return 0, 0, bserr
		}
		req.Body = bs
	}

	start := time.Now()
	resp, err := c.client.Do(req)
	if err != nil {
		code = -1
	} else {
		code = resp.StatusCode

		_, berr := io.Copy(ioutil.Discard, resp.Body)
		if berr != nil {
			err = berr
		}

		if cerr := resp.Body.Close(); cerr != nil {
			err = cerr
		}
	}
	msTaken = uint64(time.Since(start).Nanoseconds() / 1000)

	return
}

func headersToFastHTTPHeaders(h *headersList) *fasthttp.RequestHeader {
	if len(*h) == 0 {
		return nil
	}
	res := new(fasthttp.RequestHeader)
	for _, header := range *h {
		res.Set(header.key, header.value)
	}
	return res
}

func headersToHTTPHeaders(h *headersList) http.Header {
	if len(*h) == 0 {
		return http.Header{}
	}
	headers := http.Header{}

	for _, header := range *h {
		headers[header.key] = []string{header.value}
	}
	return headers
}
<|endoftext|>